From b35f7ac8c94f7c5dde8b9755d94c010a32ba5a28 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Mon, 31 May 2021 10:47:02 +0900 Subject: [PATCH] misaka: initial merge --- .github/workflows/build.yml | 40 +- .gitignore | 96 +- .gitmodules | 8 +- Makefile | 550 ++---- apps/about.c | 2 +- apps/compositor.c | 82 +- apps/demo.c | 6 + apps/demo.krk | 4 + apps/dhcp_bitbanger.c | 374 ++++ apps/du.c | 2 +- apps/fetch.c | 2 +- apps/file-browser.c | 8 +- apps/go-video.sh | 16 - apps/help-browser.c | 16 +- apps/ifconfig.c | 11 + apps/imgviewer.c | 2 +- apps/json-test.c | 6 +- apps/julia.c | 2 +- apps/killall.c | 2 +- apps/kuroko.c | 1166 ------------ apps/lspci.c | 12 +- apps/migrate.c | 2 +- apps/misaka-test.c | 66 + apps/msk.c | 4 +- apps/package-manager.c | 4 +- apps/pidof.c | 2 +- apps/plasma.c | 2 +- apps/pong.c | 4 +- apps/ps.c | 2 +- apps/pstree.c | 6 +- apps/readelf.c | 866 ++++++--- apps/reload_desktop.sh | 5 - apps/sdf-demo.c | 2 +- apps/set-resolution.c | 2 +- apps/set_wallpaper.sh | 12 - apps/sh.c | 3 +- apps/showdialog.c | 2 +- apps/sleep.c | 2 +- apps/splash-log.c | 85 +- apps/tar.c | 16 +- apps/terminal-font.h | Bin 175326 -> 175411 bytes apps/terminal-vga.c | 2 +- apps/terminal.c | 16 +- apps/test-cxx.c++ | 6 + apps/test-tls.c | 2 +- apps/test.sh | 5 - apps/tutorial.c | 8 +- apps/wallpaper-picker.c | 2 +- apps/weather-tool.c | 1 + base/etc/msk.conf | 2 +- base/{usr/bin => lib}/.dummy | 0 base/opt/asm-demo.s | 23 - base/opt/bochsrc.txt | 54 - base/opt/build.sh | 7 - base/opt/test.c | 6 - base/usr/include/ctype.h | 2 +- base/usr/include/errno.h | 2 +- base/usr/include/inttypes.h | 21 +- base/usr/include/kernel/arch/x86_64/acpi.h | 53 + base/usr/include/kernel/arch/x86_64/cmos.h | 5 + base/usr/include/kernel/arch/x86_64/irq.h | 87 + base/usr/include/kernel/arch/x86_64/mmu.h | 41 + base/usr/include/kernel/arch/x86_64/pml.h | 23 + base/usr/include/kernel/arch/x86_64/ports.h | 12 + base/usr/include/kernel/arch/x86_64/regs.h | 18 + base/usr/include/kernel/args.h | 9 +- base/usr/include/kernel/ata.h | 141 -- base/usr/include/kernel/bitset.h | 19 - base/usr/include/kernel/boot.h | 20 - base/usr/include/kernel/elf.h | 476 +++-- base/usr/include/kernel/ext2.h | 174 -- base/usr/include/kernel/generic.h | 22 + base/usr/include/kernel/gzip.h | 16 + base/usr/include/kernel/hashmap.h | 42 + base/usr/include/kernel/ipv4.h | 188 -- base/usr/include/kernel/list.h | 50 + base/usr/include/kernel/logging.h | 27 - base/usr/include/kernel/mem.h | 16 - base/usr/include/kernel/misc.h | 14 + base/usr/include/kernel/mmu.h | 2 + base/usr/include/kernel/mod/net.h | 2 + base/usr/include/kernel/mod/snd.h | 3 +- base/usr/include/kernel/module.h | 43 - base/usr/include/kernel/mouse.h | 2 + base/usr/include/kernel/multiboot.h | 88 +- base/usr/include/kernel/net/e1000.h | 102 ++ base/usr/include/kernel/pci.h | 4 +- base/usr/include/kernel/pipe.h | 13 +- base/usr/include/kernel/printf.h | 13 +- base/usr/include/kernel/process.h | 306 ++-- base/usr/include/kernel/procfs.h | 12 + base/usr/include/kernel/pty.h | 5 +- base/usr/include/kernel/ramdisk.h | 7 + base/usr/include/kernel/ringbuffer.h | 7 +- base/usr/include/kernel/shm.h | 11 +- base/usr/include/kernel/signal.h | 23 +- base/usr/include/kernel/spinlock.h | 19 + base/usr/include/kernel/{libc.h => string.h} | 13 +- base/usr/include/kernel/symboltable.h | 11 + base/usr/include/kernel/syscall.h | 32 + base/usr/include/kernel/system.h | 239 --- base/usr/include/kernel/task.h | 29 - base/usr/include/kernel/time.h | 6 + base/usr/include/kernel/{mod => }/tmpfs.h | 14 +- base/usr/include/kernel/tokenize.h | 3 +- base/usr/include/kernel/tree.h | 36 + base/usr/include/kernel/tss.h | 37 - base/usr/include/kernel/types.h | 22 +- base/usr/include/kernel/ubsan.h | 68 - base/usr/include/kernel/version.h | 16 +- base/usr/include/kernel/{fs.h => vfs.h} | 68 +- base/usr/include/kernel/video.h | 2 +- base/usr/include/kuroko | 1 - base/usr/include/memory.h | 2 + base/usr/include/setjmp.h | 2 +- base/usr/include/sys/socket.h | 1 + base/usr/include/sys/stat.h | 11 +- base/usr/include/sys/termios.h | 4 - base/usr/include/sys/types.h | 8 +- base/usr/include/syscall.h | 103 +- base/usr/include/syscall_nums.h | 10 + base/usr/include/termio.h | 3 + base/usr/include/toaru/pex.h | 2 +- base/usr/include/toaru/rline.h | 6 +- base/usr/include/toaru/termemu.h | 7 +- base/usr/include/toaru/yutani-server.h | 10 +- base/usr/include/unistd.h | 5 + base/usr/lib/.dummy | 0 build/x86_64.mk | 6 + ext/ext_cairo_renderer.c | 257 --- ext/ext_freetype_fonts.c | 329 ---- kernel/arch/x86_64/bootstrap.S | 179 ++ kernel/arch/x86_64/cmos.c | 248 +++ kernel/arch/x86_64/gdt.c | 107 ++ kernel/arch/x86_64/idt.c | 248 +++ kernel/arch/x86_64/irq.S | 221 +++ kernel/{ => arch/x86_64}/link.ld | 10 +- kernel/arch/x86_64/main.c | 319 ++++ kernel/arch/x86_64/mmu.c | 801 +++++++++ kernel/arch/x86_64/pic.c | 64 + kernel/arch/x86_64/pit.c | 39 + kernel/{sys/system.c => arch/x86_64/ports.c} | 53 +- kernel/arch/x86_64/ps2hid.c | 366 ++++ {modules => kernel/arch/x86_64}/serial.c | 132 +- kernel/arch/x86_64/smp.c | 299 ++++ kernel/arch/x86_64/user.c | 137 ++ {modules => kernel/arch/x86_64}/vbox.c | 106 +- {modules => kernel/arch/x86_64}/vmware.c | 70 +- {modules => kernel/audio}/ac97.c | 92 +- {modules => kernel/audio}/snd.c | 76 +- kernel/binfmt.c | 149 ++ kernel/boot.S | 60 - kernel/cpu/gdt.c | 113 -- kernel/cpu/idt.c | 53 - kernel/cpu/irq.c | 189 -- kernel/cpu/isr.c | 94 - kernel/devices/cmos.c | 194 -- kernel/devices/fpu.c | 142 -- kernel/devices/timer.c | 90 - kernel/ds/bitset.c | 65 - kernel/ds/hashmap.c | 1 - kernel/ds/list.c | 1 - kernel/ds/tree.c | 1 - kernel/gdt.S | 21 - kernel/generic.c | 80 + kernel/idt.S | 10 - kernel/irq.S | 67 - kernel/isr.S | 91 - kernel/main.c | 282 --- kernel/mem/mem.c | 566 ------ kernel/misc/args.c | 43 +- kernel/misc/elf.c | 335 ---- kernel/misc/elf64.c | 233 +++ kernel/misc/fbterm.c | 252 +++ kernel/misc/gzip.c | 490 +++++ kernel/misc/hashmap.c | 230 +++ kernel/misc/kprintf.c | 399 ++++- kernel/misc/lgcc.c | 11 - kernel/misc/list.c | 257 +++ kernel/misc/logging.c | 54 - kernel/{mem/alloc.c => misc/malloc.c} | 324 +--- kernel/misc/multiboot.c | 76 - kernel/{devices => misc}/pci.c | 105 +- kernel/{ds => misc}/ringbuffer.c | 25 +- kernel/{libc.c => misc/string.c} | 307 ++-- kernel/misc/tokenize.c | 12 +- kernel/misc/tree.c | 190 ++ kernel/misc/ubsan.c | 78 - kernel/net/e1000.c | 496 ++++++ kernel/net/ipv4.c | 29 + kernel/net/netif.c | 22 + kernel/net/socket.c | 68 + kernel/spin.c | 57 - kernel/sys/module.c | 441 ----- kernel/sys/panic.c | 102 -- kernel/sys/process.c | 1537 +++++++++------- kernel/{mem => sys}/shm.c | 122 +- kernel/sys/signal.c | 224 +-- kernel/sys/syscall.c | 1509 +++++++--------- kernel/sys/task.c | 538 ------ kernel/sys/version.c | 35 +- kernel/task.S | 64 - kernel/tss.S | 10 - kernel/user.S | 63 - {modules => kernel/vfs}/packetfs.c | 92 +- kernel/{fs => vfs}/pipe.c | 155 +- {modules => kernel/vfs}/portio.c | 33 +- {modules => kernel/vfs}/procfs.c | 370 ++-- kernel/{fs => vfs}/ramdisk.c | 55 +- kernel/vfs/random.c | 56 + {modules => kernel/vfs}/tarfs.c | 48 +- {modules => kernel/vfs}/tmpfs.c | 161 +- kernel/{fs => vfs}/tty.c | 64 +- kernel/{fs => vfs}/unixpipe.c | 42 +- kernel/{fs => vfs}/vfs.c | 148 +- {modules => kernel/vfs}/zero.c | 34 +- {modules => kernel/video}/lfbvideo.c | 330 +--- kuroko | 2 +- lib/decorations.c | 2 +- lib/graphics.c | 13 +- lib/hashmap.c | 4 +- lib/jpeg.c | 8 +- lib/menu.c | 24 +- lib/pex.c | 2 +- lib/rline.c | 194 +- lib/sdf.c | 6 +- lib/termemu.c | 2 +- lib/yutani.c | 8 +- libc/arch/x86_64/crt0.S | 8 + libc/{ => arch/x86_64}/crti.S | 6 +- libc/{ => arch/x86_64}/crtn.S | 5 +- libc/arch/x86_64/math.c | 84 + libc/{string => arch/x86_64}/memcpy.c | 0 libc/{string => arch/x86_64}/memset.c | 4 +- libc/arch/x86_64/setjmp.c | 40 + libc/crt0.S | 7 - libc/ctype/_ctype.c | 2 +- libc/ioctl/ioctl.c | 6 +- libc/main.c | 14 +- libc/math/math.c | 88 - libc/pthread/pthread.c | 8 +- libc/setjmp.S | 64 - libc/signal/kill.c | 4 +- libc/signal/signal.c | 2 +- libc/stdio/printf.c | 4 +- libc/stdio/stdio.c | 8 +- libc/stdlib/malloc.c | 8 +- libc/stdlib/putenv.c | 2 +- libc/stdlib/rand.c | 2 +- libc/string/str.c | 6 +- libc/sys/network.c | 153 +- libc/sys/sysfunc.c | 4 +- libc/unistd/fstat.c | 4 +- libc/unistd/lseek.c | 4 +- libc/unistd/pathconf.c | 14 + libc/unistd/read.c | 4 +- libc/unistd/sleep.c | 2 +- libc/unistd/stat.c | 4 +- libc/unistd/usleep.c | 4 +- libc/unistd/write.c | 2 +- linker/link.ld | 8 +- linker/linker.c | 141 +- modules/README.md | 91 - modules/ata.c | 895 ---------- modules/ataold.c | 408 ----- modules/debug_sh.c | 754 -------- modules/dospart.c | 130 -- modules/e1000.c | 480 ----- modules/ext2.c | 1660 ----------------- modules/hda.c | 51 - modules/iso9660.c | 509 ------ modules/net.c | 1678 ------------------ modules/pcnet.c | 375 ---- modules/pcspkr.c | 80 - modules/ps2kbd.c | 80 - modules/ps2mouse.c | 250 --- modules/random.c | 66 - modules/rtl.c | 421 ----- modules/test.c | 21 + modules/usbuhci.c | 50 - modules/vgadbg.c | 207 --- modules/vgalog.c | 173 -- modules/vidset.c | 41 - modules/xtest.c | 45 - util/activate.sh | 2 +- util/auto-dep.krk | 42 +- util/build-gcc.sh | 61 - util/build-in-docker.sh | 2 +- util/build-the-world.py | 772 -------- util/build-toolchain.sh | 34 + util/calc-size.sh | 9 - util/check-reqs.sh | 61 - util/check.sh | 11 - util/compiler-rt.S | 517 ------ util/createramdisk.py | 6 +- util/docker/Dockerfile | 7 + util/docker/README.md | 23 + util/fix-python.sh | 50 - util/generate-release-notes.sh | 39 - util/{generate_symbols.krk => gensym.krk} | 2 +- util/install-efi.sh | 6 - util/iso.py | 574 ------ util/libm.c | 1 + util/lm.c | 3 - util/mkdisk.sh | 54 - util/netinit.c | 703 -------- util/optimize.py | 21 - util/patches/binutils.patch | 64 - util/patches/gcc.patch | 127 -- util/process_log.py | 77 - util/prompt.sh | 18 - util/qemu-harness.py | 119 -- util/qemu.sh | 35 - util/readline._py | 100 -- util/ungz.c | 54 - util/update-devtable.py | 39 - util/update-extents.py | 303 ---- 317 files changed, 12311 insertions(+), 24364 deletions(-) create mode 100644 apps/demo.c create mode 100644 apps/demo.krk create mode 100644 apps/dhcp_bitbanger.c delete mode 100644 apps/go-video.sh create mode 100644 apps/ifconfig.c delete mode 100644 apps/kuroko.c create mode 100644 apps/misaka-test.c delete mode 100644 apps/reload_desktop.sh delete mode 100644 apps/set_wallpaper.sh create mode 100644 apps/test-cxx.c++ delete mode 100644 apps/test.sh rename base/{usr/bin => lib}/.dummy (100%) delete mode 100644 base/opt/asm-demo.s delete mode 100644 base/opt/bochsrc.txt delete mode 100755 base/opt/build.sh delete mode 100644 base/opt/test.c create mode 100644 base/usr/include/kernel/arch/x86_64/acpi.h create mode 100644 base/usr/include/kernel/arch/x86_64/cmos.h create mode 100644 base/usr/include/kernel/arch/x86_64/irq.h create mode 100644 base/usr/include/kernel/arch/x86_64/mmu.h create mode 100644 base/usr/include/kernel/arch/x86_64/pml.h create mode 100644 base/usr/include/kernel/arch/x86_64/ports.h create mode 100644 base/usr/include/kernel/arch/x86_64/regs.h delete mode 100644 base/usr/include/kernel/ata.h delete mode 100644 base/usr/include/kernel/bitset.h delete mode 100644 base/usr/include/kernel/boot.h delete mode 100644 base/usr/include/kernel/ext2.h create mode 100644 base/usr/include/kernel/generic.h create mode 100644 base/usr/include/kernel/gzip.h create mode 100644 base/usr/include/kernel/hashmap.h delete mode 100644 base/usr/include/kernel/ipv4.h create mode 100644 base/usr/include/kernel/list.h delete mode 100644 base/usr/include/kernel/logging.h delete mode 100644 base/usr/include/kernel/mem.h create mode 100644 base/usr/include/kernel/misc.h create mode 100644 base/usr/include/kernel/mmu.h delete mode 100644 base/usr/include/kernel/module.h create mode 100644 base/usr/include/kernel/net/e1000.h create mode 100644 base/usr/include/kernel/procfs.h create mode 100644 base/usr/include/kernel/ramdisk.h create mode 100644 base/usr/include/kernel/spinlock.h rename base/usr/include/kernel/{libc.h => string.h} (71%) create mode 100644 base/usr/include/kernel/symboltable.h create mode 100644 base/usr/include/kernel/syscall.h delete mode 100644 base/usr/include/kernel/system.h delete mode 100644 base/usr/include/kernel/task.h create mode 100644 base/usr/include/kernel/time.h rename base/usr/include/kernel/{mod => }/tmpfs.h (77%) create mode 100644 base/usr/include/kernel/tree.h delete mode 100644 base/usr/include/kernel/tss.h delete mode 100644 base/usr/include/kernel/ubsan.h rename base/usr/include/kernel/{fs.h => vfs.h} (73%) delete mode 120000 base/usr/include/kuroko create mode 100644 base/usr/include/memory.h create mode 100644 base/usr/include/termio.h delete mode 100644 base/usr/lib/.dummy create mode 100644 build/x86_64.mk delete mode 100644 ext/ext_cairo_renderer.c delete mode 100644 ext/ext_freetype_fonts.c create mode 100644 kernel/arch/x86_64/bootstrap.S create mode 100644 kernel/arch/x86_64/cmos.c create mode 100644 kernel/arch/x86_64/gdt.c create mode 100644 kernel/arch/x86_64/idt.c create mode 100644 kernel/arch/x86_64/irq.S rename kernel/{ => arch/x86_64}/link.ld (82%) create mode 100644 kernel/arch/x86_64/main.c create mode 100644 kernel/arch/x86_64/mmu.c create mode 100644 kernel/arch/x86_64/pic.c create mode 100644 kernel/arch/x86_64/pit.c rename kernel/{sys/system.c => arch/x86_64/ports.c} (50%) create mode 100644 kernel/arch/x86_64/ps2hid.c rename {modules => kernel/arch/x86_64}/serial.c (60%) create mode 100644 kernel/arch/x86_64/smp.c create mode 100644 kernel/arch/x86_64/user.c rename {modules => kernel/arch/x86_64}/vbox.c (85%) rename {modules => kernel/arch/x86_64}/vmware.c (91%) rename {modules => kernel/audio}/ac97.c (80%) rename {modules => kernel/audio}/snd.c (82%) create mode 100644 kernel/binfmt.c delete mode 100644 kernel/boot.S delete mode 100644 kernel/cpu/gdt.c delete mode 100644 kernel/cpu/idt.c delete mode 100644 kernel/cpu/irq.c delete mode 100644 kernel/cpu/isr.c delete mode 100644 kernel/devices/cmos.c delete mode 100644 kernel/devices/fpu.c delete mode 100644 kernel/devices/timer.c delete mode 100644 kernel/ds/bitset.c delete mode 120000 kernel/ds/hashmap.c delete mode 120000 kernel/ds/list.c delete mode 120000 kernel/ds/tree.c delete mode 100644 kernel/gdt.S create mode 100644 kernel/generic.c delete mode 100644 kernel/idt.S delete mode 100644 kernel/irq.S delete mode 100644 kernel/isr.S delete mode 100644 kernel/main.c delete mode 100644 kernel/mem/mem.c delete mode 100644 kernel/misc/elf.c create mode 100644 kernel/misc/elf64.c create mode 100644 kernel/misc/fbterm.c create mode 100644 kernel/misc/gzip.c create mode 100644 kernel/misc/hashmap.c delete mode 100644 kernel/misc/lgcc.c create mode 100644 kernel/misc/list.c delete mode 100644 kernel/misc/logging.c rename kernel/{mem/alloc.c => misc/malloc.c} (71%) delete mode 100644 kernel/misc/multiboot.c rename kernel/{devices => misc}/pci.c (51%) rename kernel/{ds => misc}/ringbuffer.c (87%) rename kernel/{libc.c => misc/string.c} (82%) create mode 100644 kernel/misc/tree.c delete mode 100644 kernel/misc/ubsan.c create mode 100644 kernel/net/e1000.c create mode 100644 kernel/net/ipv4.c create mode 100644 kernel/net/netif.c create mode 100644 kernel/net/socket.c delete mode 100644 kernel/spin.c delete mode 100644 kernel/sys/module.c delete mode 100644 kernel/sys/panic.c rename kernel/{mem => sys}/shm.c (66%) delete mode 100644 kernel/sys/task.c delete mode 100644 kernel/task.S delete mode 100644 kernel/tss.S delete mode 100644 kernel/user.S rename {modules => kernel/vfs}/packetfs.c (78%) rename kernel/{fs => vfs}/pipe.c (61%) rename {modules => kernel/vfs}/portio.c (70%) rename {modules => kernel/vfs}/procfs.c (65%) rename kernel/{fs => vfs}/ramdisk.c (58%) create mode 100644 kernel/vfs/random.c rename {modules => kernel/vfs}/tarfs.c (91%) rename {modules => kernel/vfs}/tmpfs.c (74%) rename kernel/{fs => vfs}/tty.c (90%) rename kernel/{fs => vfs}/unixpipe.c (78%) rename kernel/{fs => vfs}/vfs.c (85%) rename {modules => kernel/vfs}/zero.c (70%) rename {modules => kernel/video}/lfbvideo.c (50%) create mode 100644 libc/arch/x86_64/crt0.S rename libc/{ => arch/x86_64}/crti.S (56%) rename libc/{ => arch/x86_64}/crtn.S (66%) create mode 100644 libc/arch/x86_64/math.c rename libc/{string => arch/x86_64}/memcpy.c (100%) rename libc/{string => arch/x86_64}/memset.c (62%) create mode 100644 libc/arch/x86_64/setjmp.c delete mode 100644 libc/crt0.S delete mode 100644 libc/setjmp.S create mode 100644 libc/unistd/pathconf.c delete mode 100644 modules/README.md delete mode 100644 modules/ata.c delete mode 100644 modules/ataold.c delete mode 100644 modules/debug_sh.c delete mode 100644 modules/dospart.c delete mode 100644 modules/e1000.c delete mode 100644 modules/ext2.c delete mode 100644 modules/hda.c delete mode 100644 modules/iso9660.c delete mode 100644 modules/net.c delete mode 100644 modules/pcnet.c delete mode 100644 modules/pcspkr.c delete mode 100644 modules/ps2kbd.c delete mode 100644 modules/ps2mouse.c delete mode 100644 modules/random.c delete mode 100644 modules/rtl.c create mode 100644 modules/test.c delete mode 100644 modules/usbuhci.c delete mode 100644 modules/vgadbg.c delete mode 100644 modules/vgalog.c delete mode 100644 modules/vidset.c delete mode 100644 modules/xtest.c delete mode 100644 util/build-gcc.sh delete mode 100755 util/build-the-world.py create mode 100755 util/build-toolchain.sh delete mode 100755 util/calc-size.sh delete mode 100755 util/check-reqs.sh delete mode 100755 util/check.sh delete mode 100644 util/compiler-rt.S create mode 100644 util/docker/Dockerfile create mode 100644 util/docker/README.md delete mode 100755 util/fix-python.sh delete mode 100644 util/generate-release-notes.sh rename util/{generate_symbols.krk => gensym.krk} (97%) delete mode 100755 util/install-efi.sh delete mode 100755 util/iso.py create mode 100644 util/libm.c delete mode 100644 util/lm.c delete mode 100755 util/mkdisk.sh delete mode 100644 util/netinit.c delete mode 100644 util/optimize.py delete mode 100644 util/patches/binutils.patch delete mode 100644 util/patches/gcc.patch delete mode 100644 util/process_log.py delete mode 100755 util/prompt.sh delete mode 100755 util/qemu-harness.py delete mode 100644 util/qemu.sh delete mode 100644 util/readline._py delete mode 100644 util/ungz.c delete mode 100755 util/update-devtable.py delete mode 100755 util/update-extents.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06826cb3..3d66ab24 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,37 +8,19 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 - submodules: true + - name: Clone Kuroko + uses: actions/checkout@v2 + with: + repository: kuroko-lang/kuroko + path: kuroko - name: Pull Builder Image - run: docker pull toaruos/build-tools:1.8.x + run: docker pull toaruos/build-tools:1.99.x - name: Run Builder - run: docker run -v ${GITHUB_WORKSPACE}:/root/toaruos -w /root/toaruos -e LANG=C.UTF-8 -t toaruos/build-tools:1.8.x util/build-in-docker.sh + run: docker run -v ${GITHUB_WORKSPACE}:/root/misaka -w /root/misaka -e LANG=C.UTF-8 -t toaruos/build-tools:1.99.x util/build-in-docker.sh - name: Upload Branch Image uses: actions/upload-artifact@v2 with: - name: image - path: ./image.iso - - name: Draft Release notes - if: startsWith(github.ref, 'refs/tags/v') - run: bash util/generate-release-notes.sh > notes.md - - name: Create Release - if: startsWith(github.ref, 'refs/tags/v') - uses: actions/create-release@v1 - id: create_release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: ToaruOS ${{ github.ref }} - body_path: ./notes.md - draft: true - - name: Upload Release Image - if: startsWith(github.ref, 'refs/tags/v') - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./image.iso - asset_name: image.iso - asset_content_type: application/x-iso9660-image + name: build + path: | + ramdisk.tar + misaka-kernel diff --git a/.gitignore b/.gitignore index 9d6c9774..d458455e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,80 +1,28 @@ -*.so -*.a +*.aux +*.idx +*.ilg +*.ind +*.log *.o -*.iso -*.efi +*.a +*.out +*.pdf +*.so +*.swp +*.swn +*.toc +*.ko +*.pcap .gdb_history -/tags - -/.make/* -/base/bin/* -/base/lib/kuroko -/base/src -/_base -/cdrom/extra -/cdrom/kernel -/cdrom/netinit -/cdrom/mod/* -/cdrom/ramdisk.img -/cdrom/ramdisk.igz -/cdrom/boot.sys -/cdrom/fat.img -/fatbase/extra -/fatbase/kernel -/fatbase/netinit -/fatbase/mod/* -/fatbase/ramdisk.img -/fatbase/ramdisk.igz -/fatbase/efi/boot/bootia32.efi -/util/tarballs +/ramdisk.tar +/ramdisk.igz +/misaka-kernel.64 +/misaka-kernel +/kernel/symbols.S /util/build /util/local -/util/devtable -/util/tmp-gcc -/util/kuroko -/kernel/symbols.S -/base/usr/python +/util/cross +/base/bin/* /base/usr/bin/* /base/usr/lib/* -/base/usr/share/python-demos - -# Generic -/base/usr/share/aclocal -/base/usr/share/gtk-doc -/base/usr/share/man -/base/usr/share/info/ -/base/usr/share/doc/ -/base/usr/local - -# GMP -/base/usr/include/gmp.h - -# MPFR -/base/usr/include/mpf2mpfr.h -/base/usr/include/mpfr.h - -# MPC -/base/usr/include/mpc.h - -# zlib -/base/usr/include/zconf.h -/base/usr/include/zlib.h -/util/ungz - -# binutils -/base/usr/i686-pc-toaru - -# Freetype -/base/usr/include/freetype2 -/base/usr/include/ft2build.h -/base/usr/share/fonts - -# Cairo + Pixman -/base/usr/include/cairo -/base/usr/include/pixman-1 - -# SDL -/base/usr/include/SDL - -# Kuroko build files -/base/usr/share/kuroko +/.make/ diff --git a/.gitmodules b/.gitmodules index c8bf8f65..947d0181 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ +[submodule "util/binutils-gdb"] + path = util/binutils-gdb + url = ../../toaruos/binutils-gdb.git +[submodule "util/gcc"] + path = util/gcc + url = ../../toaruos/gcc [submodule "kuroko"] path = kuroko - url = git@github.com:kuroko-lang/kuroko + url = ../../kuroko-lang/kuroko diff --git a/Makefile b/Makefile index 4cc2a5b4..ce4ae183 100644 --- a/Makefile +++ b/Makefile @@ -1,170 +1,190 @@ -ifeq ($(TOOLCHAIN),) - ifeq ($(shell util/check.sh),y) - export PATH := $(shell util/activate.sh) - else - FOO := $(shell util/prompt.sh) - ifeq ($(shell util/check.sh),y) - export PATH := $(shell util/activate.sh) - else - $(error "No toolchain, and you did not ask to build it.") - endif - endif -endif +TOOLCHAIN=util +BASE=base +export PATH := $(shell $(TOOLCHAIN)/activate.sh) -# Prevents Make from removing intermediary files on failure -.SECONDARY: +include build/x86_64.mk -# Disable built-in rules -.SUFFIXES: +CC = ${TARGET}-gcc +NM = ${TARGET}-nm +CXX= ${TARGET}-g++ +AR = ${TARGET}-ar +AS = ${TARGET}-as +OC = ${TARGET}-objcopy -all: image.iso +KERNEL_CFLAGS = -ffreestanding -O2 -std=gnu11 -g -static +KERNEL_CFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter +KERNEL_CFLAGS += -pedantic -Wwrite-strings ${ARCH_KERNEL_CFLAGS} -TARGET_TRIPLET=i686-pc-toaru +# Defined constants for the kernel +KERNEL_CFLAGS += -D_KERNEL_ -DKERNEL_ARCH=${ARCH} +KERNEL_CFLAGS += -DKERNEL_GIT_TAG=`util/make-version` -# Userspace flags +KERNEL_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/*.c)) +KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c)) +KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/arch/${ARCH}/*.c)) -CC=$(TARGET_TRIPLET)-gcc -AR=$(TARGET_TRIPLET)-ar -AS=$(TARGET_TRIPLET)-as -CFLAGS= -O2 -s -std=gnu99 -I. -Iapps -pipe -mmmx -msse -msse2 -fplan9-extensions -Wall -Wextra -Wno-unused-parameter +KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/arch/${ARCH}/*.S))) -## -# C library objects from libc/ C sources (and setjmp, which is assembly) -LIBC_OBJS = $(patsubst %.c,%.o,$(wildcard libc/*.c)) -LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/*/*.c)) -LIBC_OBJS += libc/setjmp.o -LC=base/lib/libc.so +KERNEL_SOURCES = $(wildcard kernel/*.c) $(wildcard kernel/*/*.c) $(wildcard kernel/${ARCH}/*/*.c) +KERNEL_SOURCES += $(wildcard kernel/arch/${ARCH}/*.S) -## -# APPS = C sources from apps/ -# APPS_X = binaries -# APPS_Y = generated makefiles for binaries -# APPS_SH = shell scripts to copy to base/bin/ and mark executable -# APPS_SH_X = destinations for shell scripts -APPS=$(patsubst apps/%.c,%,$(wildcard apps/*.c)) -APPS_X=$(foreach app,$(APPS),base/bin/$(app)) +MODULES = $(patsubst %.c,%.ko,$(wildcard modules/*.c)) + +# Configs you can override. +SMP ?= 1 +RAM ?= 3G +EXTRA_ARGS ?= + +EMU = qemu-system-x86_64 +EMU_ARGS = -kernel misaka-kernel +EMU_ARGS += -M q35 +EMU_ARGS += -m $(RAM) +EMU_ARGS += -smp $(SMP) +EMU_ARGS += -no-reboot +#EMU_ARGS += -display none +EMU_ARGS += -serial mon:stdio +EMU_ARGS += -rtc base=localtime +EMU_ARGS += -soundhw pcspk,ac97 +EMU_ARGS += -netdev user,id=u1,hostfwd=tcp::5555-:23 -device e1000e,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=qemu-e1000e.pcap +EMU_ARGS += -netdev user,id=u2,hostfwd=tcp::5580-:80 -device e1000,netdev=u2 -object filter-dump,id=f2,netdev=u2,file=qemu.pcap +#EMU_ARGS += -hda toaruos-disk.img +EMU_KVM ?= -enable-kvm + +APPS=$(patsubst apps/%.c,%,$(wildcard apps/*.c)) $(patsubst apps/%.c++,%,$(wildcard apps/*.c++)) +APPS_X=$(foreach app,$(APPS),$(BASE)/bin/$(app)) APPS_Y=$(foreach app,$(APPS),.make/$(app).mak) APPS_SH=$(patsubst apps/%.sh,%.sh,$(wildcard apps/*.sh)) -APPS_SH_X=$(foreach app,$(APPS_SH),base/bin/$(app)) +APPS_SH_X=$(foreach app,$(APPS_SH),$(BASE)/bin/$(app)) APPS_KRK=$(patsubst apps/%.krk,%.krk,$(wildcard apps/*.krk)) -APPS_KRK_X=$(foreach app,$(APPS_KRK),base/bin/$(app)) +APPS_KRK_X=$(foreach app,$(APPS_KRK),$(BASE)/bin/$(app)) -## -# LIBS = C sources from lib/ -# LIBS_X = Shared libraries (.so) -# LIBS_Y = Generated makefiles for libraries LIBS=$(patsubst lib/%.c,%,$(wildcard lib/*.c)) -LIBS_X=$(foreach lib,$(LIBS),base/lib/libtoaru_$(lib).so) +LIBS_X=$(foreach lib,$(LIBS),$(BASE)/lib/libtoaru_$(lib).so) LIBS_Y=$(foreach lib,$(LIBS),.make/$(lib).lmak) -SOURCE_FILES = $(wildcard kernel/*.c kernel/*/*.c kernel/*/*/*.c modules/*.c) -SOURCE_FILES += $(wildcard apps/*.c linker/*.c libc/*.c libc/*/*.c lib/*.c) +KRK_MODS = $(patsubst kuroko/src/modules/module_%.c,$(BASE)/lib/kuroko/%.so,$(wildcard kuroko/src/modules/module_*.c)) +KRK_MODS_X = $(patsubst lib/kuroko/%.c,$(BASE)/lib/kuroko/%.so,$(wildcard lib/kuroko/*.c)) +KRK_MODS_Y = $(patsubst lib/kuroko/%.c,.make/%.kmak,$(wildcard lib/kuroko/*.c)) -tags: $(SOURCE_FILES) $(wildcard kuroko/src/*.c kuroko/src/*.h) - ctags -f tags $(SOURCE_FILES) $(wildcard kuroko/src/*.c kuroko/src/*.h) +CFLAGS= -O2 -std=gnu11 -I. -Iapps -fplan9-extensions -Wall -Wextra -Wno-unused-parameter -## -# Files that must be present in the ramdisk (apps, libraries) -RAMDISK_FILES= ${APPS_X} ${APPS_SH_X} ${APPS_KRK_X} ${LIBS_X} base/lib/ld.so base/lib/libm.so ${KUROKO_FILES} +LIBC_OBJS = $(patsubst %.c,%.o,$(wildcard libc/*.c)) +LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/*/*.c)) +LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/arch/${ARCH}/*.c)) -# Kernel / module flags +GCC_SHARED = $(BASE)/usr/lib/libgcc_s.so.1 $(BASE)/usr/lib/libgcc_s.so +LIBSTDCXX = $(BASE)/usr/lib/libstdc++.so.6.0.28 $(BASE)/usr/lib/libstdc++.so.6 $(BASE)/usr/lib/libstdc++.so -ifeq (,${USE_CLANG}) -KCC = $(TARGET_TRIPLET)-gcc -LGCC = -lgcc -EXTRALIB = -else -KCC = clang --target=i686-elf -static -Ibase/usr/include -nostdinc -mno-sse -LGCC = util/compiler-rt.o -EXTRALIB = util/compiler-rt.o -util/compiler-rt.o: util/compiler-rt.S - ${KAS} ${ASFLAGS} $< -o $@ -endif -KAS = $(TARGET_TRIPLET)-as -KLD = $(TARGET_TRIPLET)-ld -KNM = $(TARGET_TRIPLET)-nm +CRTS = $(BASE)/lib/crt0.o $(BASE)/lib/crti.o $(BASE)/lib/crtn.o -KCFLAGS = -O2 -std=c99 -KCFLAGS += -finline-functions -ffreestanding -KCFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format -KCFLAGS += -pedantic -fno-omit-frame-pointer -KCFLAGS += -D_KERNEL_ -KCFLAGS += -DKERNEL_GIT_TAG=$(shell util/make-version) -KASFLAGS = --32 +LC = $(BASE)/lib/libc.so $(GCC_SHARED) $(LIBSTDCXX) -## -# Kernel objects from kernel/ C sources -KERNEL_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/*.c)) -KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c)) -KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*/*.c)) +.PHONY: all system clean run shell -## -# Kernel objects from kernel/ assembly sources -KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/*.S))) -HEADERS = $(wildcard base/usr/include/kernel/*.h base/usr/include/kernel/*/*.h) +all: system +system: misaka-kernel $(MODULES) ramdisk.igz -# Kernel +%.ko: %.c + ${CC} -c ${KERNEL_CFLAGS} -o $@ $< -fatbase/kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o ${EXTRALIB} - ${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o $@ ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o ${LGCC} +ramdisk.igz: $(wildcard $(BASE)/* $(BASE)/*/* $(BASE)/*/*/*) $(APPS_X) $(LIBS_X) $(KRK_MODS_X) $(BASE)/bin/kuroko $(BASE)/lib/ld.so $(APPS_KRK_X) $(KRK_MODS) + python3 util/createramdisk.py -## -# Symbol table for the kernel. Instead of relying on getting -# the symbol table from our bootloader (eg. through ELF -# headers provided via multiboot structure), we have a dedicated -# object that build with all the symbols. This allows us to -# build the kernel as a flat binary or load it with less-capable -# multiboot loaders and still get symbols, which we need to -# load kernel modules and link them properly. -kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/generate_symbols.krk ${EXTRALIB} | util/kuroko +KRK_SRC = $(sort $(wildcard kuroko/src/*.c)) +$(BASE)/bin/kuroko: $(KRK_SRC) $(CRTS) | $(LC) + $(CC) -O2 -g -o $@ -Wl,--export-dynamic -Ikuroko/src $(KRK_SRC) kuroko/src/vendor/rline.c + +$(BASE)/lib/kuroko/%.so: kuroko/src/modules/module_%.c| dirs $(LC) + $(CC) -O2 -shared -fPIC -Ikuroko/src -o $@ $< + +$(BASE)/lib/libkuroko.so: $(KRK_SRC) | $(LC) + $(CC) -O2 -shared -fPIC -Ikuroko/src -o $@ $(filter-out kuroko/src/kuroko.c,$(KRK_SRC)) + +$(BASE)/lib/ld.so: linker/linker.c $(BASE)/lib/libc.a | dirs $(LC) + $(CC) -g -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $< + +run: system + ${EMU} ${EMU_ARGS} ${EMU_KVM} -append "root=/dev/ram0 start=live-session migrate $(EXTRA_ARGS)" -initrd ramdisk.igz + +shell: system + ${EMU} -m $(RAM) ${EMU_KVM} -kernel misaka-kernel -append "root=/dev/ram0 start=--headless migrate" -initrd ramdisk.igz \ + -nographic -no-reboot -audiodev none,id=id -serial null -serial mon:stdio \ + -fw_cfg name=opt/org.toaruos.gettyargs,string="-a local /dev/ttyS1" \ + -fw_cfg name=opt/org.toaruos.term,string=${TERM} + +misaka-kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o + ${CC} -g -T kernel/arch/${ARCH}/link.ld ${KERNEL_CFLAGS} -o $@.64 ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc + ${OC} -I elf64-x86-64 -O elf32-i386 $@.64 $@ + +kernel/sys/version.o: ${KERNEL_SOURCES} + +kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/gensym.krk -rm -f kernel/symbols.o - ${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o .toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} ${LGCC} - ${KNM} .toaruos-kernel -g | util/kuroko util/generate_symbols.krk > kernel/symbols.S - ${KAS} ${KASFLAGS} kernel/symbols.S -o $@ - -rm -f .toaruos-kernel - -## -# version.o should be rebuilt whenever the kernel changes -# in order to get fresh git commit hash information. -kernel/sys/version.o: kernel/*/*.c kernel/*.c + ${CC} -T kernel/arch/${ARCH}/link.ld ${KERNEL_CFLAGS} -o misaka-kernel.64 ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc + ${NM} misaka-kernel.64 -g | kuroko util/gensym.krk > kernel/symbols.S + ${CC} -c kernel/symbols.S -o $@ kernel/%.o: kernel/%.S - ${KAS} ${ASFLAGS} $< -o $@ + echo ${PATH} + ${CC} -c $< -o $@ + +HEADERS = $(wildcard base/usr/include/kernel/*.h) kernel/%.o: kernel/%.c ${HEADERS} - ${KCC} ${KCFLAGS} -nostdlib -g -c -o $@ $< + ${CC} ${KERNEL_CFLAGS} -nostdlib -g -Iinclude -c -o $@ $< -# Modules +clean: + -rm -f ${KERNEL_ASMOBJS} + -rm -f ${KERNEL_OBJS} + -rm -f kernel/symbols.o misaka-kernel misaka-kernel.64 + -rm -f ramdisk.tar ramdisk.igz + -rm -f $(APPS_Y) $(LIBS_Y) $(KRK_MODS_Y) $(KRK_MODS) + -rm -f $(APPS_X) $(LIBS_X) $(KRK_MODS_X) $(APPS_KRK_X) $(APPS_SH_X) + -rm -f $(BASE)/lib/crt0.o $(BASE)/lib/crti.o $(BASE)/lib/crtn.o + -rm -f $(BASE)/lib/libc.so $(BASE)/lib/libc.a + -rm -f $(LIBC_OBJS) $(BASE)/lib/ld.so $(BASE)/lib/libkuroko.so $(BASE)/lib/libm.so + -rm -f $(BASE)/bin/kuroko + -rm -f $(GCC_SHARED) $(LIBSTDCXX) -fatbase/mod: - @mkdir -p $@ +libc/%.o: libc/%.c base/usr/include/syscall.h + $(CC) -O2 -std=gnu11 -Wall -Wextra -Wno-unused-parameter -fPIC -c -o $@ $< -## -# Modules need to be installed on the boot image -MODULES = $(patsubst modules/%.c,fatbase/mod/%.ko,$(wildcard modules/*.c)) +.PHONY: libc +libc: $(BASE)/lib/libc.a $(BASE)/lib/libc.so -fatbase/mod/%.ko: modules/%.c ${HEADERS} | fatbase/mod - ${KCC} -nostdlib ${KCFLAGS} -c -o $@ $< +$(BASE)/lib/libc.a: ${LIBC_OBJS} $(CRTS) + $(AR) cr $@ $(LIBC_OBJS) -modules: ${MODULES} +$(BASE)/lib/libc.so: ${LIBC_OBJS} | $(CRTS) + ${CC} -nodefaultlibs -shared -fPIC -o $@ $^ -# Root Filesystem +$(BASE)/lib/crt%.o: libc/arch/${ARCH}/crt%.S + ${AS} -o $@ $< -base/dev: +$(BASE)/usr/lib/%: util/local/${TARGET}/lib/% | dirs + cp -a $< $@ + -strip $@ + +$(BASE)/lib/libm.so: util/libm.c + $(CC) -shared -nostdlib -fPIC -o $@ $< + +$(BASE)/dev: mkdir -p $@ -base/tmp: +$(BASE)/tmp: mkdir -p $@ -base/proc: +$(BASE)/proc: mkdir -p $@ -base/bin: +$(BASE)/bin: mkdir -p $@ -base/lib: +$(BASE)/lib: mkdir -p $@ -base/cdrom: +$(BASE)/cdrom: mkdir -p $@ -base/var: +$(BASE)/var: mkdir -p $@ -base/lib/kuroko: +$(BASE)/lib/kuroko: + mkdir -p $@ +$(BASE)/usr/lib: mkdir -p $@ fatbase/efi/boot: mkdir -p $@ @@ -172,271 +192,49 @@ cdrom: mkdir -p $@ .make: mkdir -p .make -dirs: base/dev base/tmp base/proc base/bin base/lib base/cdrom base/lib/kuroko cdrom base/var fatbase/efi/boot .make - -# C Library - -crts: base/lib/crt0.o base/lib/crti.o base/lib/crtn.o | dirs - -base/lib/crt%.o: libc/crt%.S - $(AS) -o $@ $< - -libc/setjmp.o: libc/setjmp.S - $(AS) -o $@ $< - -libc/%.o: libc/%.c - $(CC) $(CFLAGS) -fPIC -c -o $@ $< - -base/lib/libc.a: ${LIBC_OBJS} | dirs crts - $(AR) cr $@ $^ - -base/lib/libc.so: ${LIBC_OBJS} | dirs crts - $(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc - -base/lib/libm.so: util/lm.c | dirs crts - $(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc - -KUROKO_OBJS=$(patsubst %.c, %.o, $(filter-out kuroko/src/kuroko.c,$(sort $(wildcard kuroko/src/*.c)))) -kuroko/%.o: kuroko/%.c - $(CC) $(CFLAGS) -fPIC -c -o $@ $^ - -KUROKO_CMODS=$(patsubst kuroko/src/modules/module_%.c,%,$(wildcard kuroko/src/modules/module_*.c)) $(patsubst lib/kuroko/%.c,%,$(wildcard lib/kuroko/*.c)) -KUROKO_CMODS_X=$(foreach lib,$(KUROKO_CMODS),base/lib/kuroko/$(lib).so) -KUROKO_CMODS_Y=$(foreach lib,$(KUROKO_CMODS),.make/$(lib).kmak) -KUROKO_KRK_MODS=$(patsubst kuroko/modules/%.krk,base/lib/kuroko/%.krk,$(wildcard kuroko/modules/*.krk kuroko/modules/*/*.krk)) - -KUROKO_FILES=$(KUROKO_CMODS_X) $(KUROKO_KRK_MODS) base/lib/libkuroko.so - -base/lib/kuroko/%.krk: kuroko/modules/%.krk - @mkdir -p `dirname $@` - cp $< $@ - -MINIMAL_KUROKO = $(filter-out kuroko/src/modules/module_%,$(sort $(wildcard kuroko/src/*.c))) -util/kuroko: $(MINIMAL_KUROKO) - gcc -Ikuroko/src -DNO_RLINE -DSTATIC_ONLY -DKRK_DISABLE_THREADS -o $@ $^ - -.make/%.kmak: kuroko/src/modules/module_%.c util/auto-dep.krk | dirs util/kuroko - util/kuroko util/auto-dep.krk --makekurokomod $< > $@ - -.make/%.kmak: lib/kuroko/%.c util/auto-dep.krk | dirs util/kuroko - util/kuroko util/auto-dep.krk --makekurokomod $< > $@ - -ifeq (,$(findstring clean,$(MAKECMDGOALS))) --include ${KUROKO_CMODS_Y} -endif - -base/lib/libkuroko.so: $(KUROKO_OBJS) | dirs crts ${LC} - $(CC) $(CFLAGS) -shared -fPIC -o $@ $^ -lgcc - -# Userspace Linker/Loader - -base/lib/ld.so: linker/linker.c base/lib/libc.a | dirs - $(CC) -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $< - -# Shared Libraries -.make/%.lmak: lib/%.c util/auto-dep.krk | dirs crts util/kuroko - util/kuroko util/auto-dep.krk --makelib $< > $@ - -ifeq (,$(findstring clean,$(MAKECMDGOALS))) --include ${LIBS_Y} -endif - -# netinit needs to go in the CD/FAT root, so it gets built specially -fatbase/netinit: util/netinit.c base/lib/libc.a | dirs - $(CC) $(CFLAGS) -o $@ $< - -# Userspace applications - -.make/%.mak: apps/%.c util/auto-dep.krk | dirs crts util/kuroko - util/kuroko util/auto-dep.krk --make $< > $@ +dirs: $(BASE)/dev $(BASE)/tmp $(BASE)/proc $(BASE)/bin $(BASE)/lib $(BASE)/cdrom $(BASE)/usr/lib $(BASE)/lib/kuroko cdrom $(BASE)/var fatbase/efi/boot .make ifeq (,$(findstring clean,$(MAKECMDGOALS))) -include ${APPS_Y} +-include ${LIBS_Y} +-include ${KRK_MODS_Y} endif -base/bin/%.sh: apps/%.sh +.make/%.lmak: lib/%.c util/auto-dep.krk | dirs $(CRTS) + kuroko util/auto-dep.krk --makelib $< > $@ + +.make/%.mak: apps/%.c util/auto-dep.krk | dirs $(CRTS) + kuroko util/auto-dep.krk --make $< > $@ + +.make/%.mak: apps/%.c++ util/auto-dep.krk | dirs $(CRTS) + kuroko util/auto-dep.krk --make $< > $@ + +.make/%.kmak: lib/kuroko/%.c util/auto-dep.krk | dirs + kuroko util/auto-dep.krk --makekurokomod $< > $@ + +$(BASE)/bin/%.sh: apps/%.sh cp $< $@ chmod +x $@ -base/bin/%.krk: apps/%.krk +$(BASE)/bin/%.krk: apps/%.krk cp $< $@ chmod +x $@ -# Ramdisk -fatbase/ramdisk.igz: ${RAMDISK_FILES} $(shell find base) Makefile util/createramdisk.py | dirs - python3 util/createramdisk.py - gzip -c fatbase/ramdisk.img > fatbase/ramdisk.igz - rm fatbase/ramdisk.img +.PHONY: libs +libs: $(LIBS_X) -# CD image +.PHONY: apps +apps: $(APPS_X) -ifeq (,$(wildcard /usr/lib32/crt0-efi-ia32.o)) -$(error Missing GNU-EFI.) -endif +.PHONY: libstdcxx +libstdcxx: $(LIBSTDCXX) -EFI_XORRISO=-eltorito-alt-boot -e fat.img -no-emul-boot -isohybrid-gpt-basdat -EFI_BOOT=cdrom/fat.img -EFI_UPDATE=util/update-extents.py +util/local/${TARGET}/lib/libstdc++.so.6.0.28: | $(BASE)/lib/libm.so + cd util/build/gcc && make all-target-libstdc++-v3 && make install-target-libstdc++-v3 -image.iso: ${EFI_BOOT} cdrom/boot.sys fatbase/netinit ${MODULES} util/update-extents.py - xorriso -as mkisofs -R -J -c bootcat \ - -b boot.sys -no-emul-boot -boot-load-size full \ - ${EFI_XORRISO} \ - -o image.iso cdrom - ${EFI_UPDATE} - -# Boot loader - -## -# FAT EFI payload -# This is the filesystem the EFI loaders see, so it must contain -# the kernel, modules, and ramdisk, plus anything else we want -# available to the bootloader (eg., netinit). -cdrom/fat.img: fatbase/ramdisk.igz ${MODULES} fatbase/kernel fatbase/netinit fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi util/mkdisk.sh | dirs - util/mkdisk.sh $@ fatbase - -## -# For EFI, we build two laoders: ia32 and x64 -# We build them as ELF shared objects and the use objcopy to convert -# them to PE executables / DLLs (as expected by EFI). -EFI_CFLAGS=-fno-stack-protector -fpic -DEFI_PLATFORM -ffreestanding -fshort-wchar -I /usr/include/efi -mno-red-zone -EFI_SECTIONS=-j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc - -# ia32 -boot/efi.so: boot/cstuff.c boot/*.h - $(CC) ${EFI_CFLAGS} -I /usr/include/efi/ia32 -c -o boot/efi.o $< - $(LD) boot/efi.o /usr/lib32/crt0-efi-ia32.o -nostdlib -znocombreloc -T /usr/lib32/elf_ia32_efi.lds -shared -Bsymbolic -L /usr/lib32 -lefi -lgnuefi -o boot/efi.so - -fatbase/efi/boot/bootia32.efi: boot/efi.so - objcopy ${EFI_SECTIONS} --target=efi-app-ia32 $< $@ - -# x64 -boot/efi64.so: boot/cstuff.c boot/*.h - gcc ${EFI_CFLAGS} -I /usr/include/efi/x86_64 -DEFI_FUNCTION_WRAPPER -c -o boot/efi64.o $< - $(LD) boot/efi64.o /usr/lib/crt0-efi-x86_64.o -nostdlib -znocombreloc -T /usr/lib/elf_x86_64_efi.lds -shared -Bsymbolic -L /usr/lib -lefi -lgnuefi -o boot/efi64.so - -fatbase/efi/boot/bootx64.efi: boot/efi64.so - objcopy ${EFI_SECTIONS} --target=efi-app-x86_64 $< $@ - -# BIOS loader -cdrom/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | dirs - ${KLD} -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o - -boot/cstuff.o: boot/cstuff.c boot/*.h - ${CC} -c -Os -fno-strict-aliasing -finline-functions -ffreestanding -o $@ $< - -boot/boot.o: boot/boot.S - ${AS} -o $@ $< - -.PHONY: clean -clean: - rm -f base/lib/*.so - rm -f base/lib/libc.a - rm -f ${APPS_X} ${APPS_SH_X} - rm -f libc/*.o libc/*/*.o - rm -f image.iso - rm -f fatbase/ramdisk.img fatbase/ramdisk.igz - rm -f cdrom/boot.sys - rm -f boot/*.o - rm -f boot/*.efi - rm -f boot/*.so - rm -f cdrom/fat.img cdrom/kernel cdrom/mod/* cdrom/ramdisk.img - rm -f fatbase/kernel fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi - rm -f cdrom/netinit fatbase/netinit - rm -f ${KERNEL_OBJS} ${KERNEL_ASMOBJS} kernel/symbols.o kernel/symbols.S - rm -f base/lib/crt*.o - rm -f ${MODULES} - rm -f ${APPS_Y} ${LIBS_Y} ${EXT_LIBS_Y} - rm -f ${KUROKO_FILES} ${KUROKO_CMODS_Y} ${KUROKO_CMODS_X} - rm -f kuroko/src/*.o - rm -f util/kuroko - -ifneq (,$(findstring Microsoft,$(shell uname -r))) - QEMU_ARGS=-serial mon:stdio -m 1G -rtc base=localtime -vnc :0 -else - ifeq (,${NO_KVM}) - KVM=-enable-kvm - else - KVM= - endif - QEMU_ARGS=-serial mon:stdio -m 1G -soundhw ac97,pcspk ${KVM} -rtc base=localtime ${QEMU_EXTRA} -endif - - -.PHONY: run -run: image.iso - qemu-system-i386 -cdrom $< ${QEMU_ARGS} - -.PHONY: fast -fast: image.iso - qemu-system-i386 -cdrom $< ${QEMU_ARGS} \ - -fw_cfg name=opt/org.toaruos.bootmode,string=normal - -.PHONY: headless -headless: image.iso - @qemu-system-i386 -cdrom $< -m 1G ${KVM} -rtc base=localtime ${QEMU_EXTRA} \ - -serial null -serial mon:stdio \ - -nographic -no-reboot -audiodev none,id=id \ - -fw_cfg name=opt/org.toaruos.bootmode,string=headless \ - -fw_cfg name=opt/org.toaruos.gettyargs,string="-a local /dev/ttyS1" - -.PHONY: shell -shell: image.iso - @qemu-system-i386 -cdrom $< ${QEMU_ARGS} \ - -nographic -no-reboot \ - -fw_cfg name=opt/org.toaruos.bootmode,string=headless \ - -fw_cfg name=opt/org.toaruos.forceuser,string=local \ - -fw_cfg name=opt/org.toaruos.term,string=${TERM} /dev/null & \ - stty raw -echo && nc -l 127.0.0.1 8090 && stty sane && wait - -.PHONY: efi64 -efi64: image.iso - qemu-system-x86_64 -cdrom $< ${QEMU_ARGS} \ - -bios /usr/share/qemu/OVMF.fd - - -VMNAME=ToaruOS CD - -define virtualbox-runner = -.PHONY: $1 -$1: image.iso - -VBoxManage unregistervm "$(VMNAME)" --delete - VBoxManage createvm --name "$(VMNAME)" --ostype $2 --register - VBoxManage modifyvm "$(VMNAME)" --memory 1024 --vram 32 --audio pulse --audiocontroller ac97 --bioslogodisplaytime 1 --bioslogofadeout off --bioslogofadein off --biosbootmenu disabled $3 - VBoxManage storagectl "$(VMNAME)" --add ide --name "IDE" - VBoxManage storageattach "$(VMNAME)" --storagectl "IDE" --port 0 --device 0 --medium $$(shell pwd)/image.iso --type dvddrive - VBoxManage setextradata "$(VMNAME)" GUI/DefaultCloseAction PowerOff - VBoxManage startvm "$(VMNAME)" --type separate -endef - -$(eval $(call virtualbox-runner,virtualbox,"Other",)) -$(eval $(call virtualbox-runner,virtualbox-efi,"Other",--firmware efi)) -$(eval $(call virtualbox-runner,virtualbox-efi64,"Other_64",--firmware efi)) - -## -# Optional Extensions -# -# These optional extension libraries require third-party components to build, -# but allow the native applications to make use of functionality such as -# TrueType fonts or PNG images. You must have the necessary elements to build -# these already installed into your sysroot for this to work. -EXT_LIBS=$(patsubst ext/%.c,%,$(wildcard ext/*.c)) -EXT_LIBS_X=$(foreach lib,$(EXT_LIBS),base/lib/libtoaru_$(lib).so) -EXT_LIBS_Y=$(foreach lib,$(EXT_LIBS),.make/$(lib).elmak) - -.make/%.elmak: ext/%.c util/auto-dep.krk | dirs util/kuroko - util/kuroko util/auto-dep.krk --makelib $< > $@ - -ifeq (,$(findstring clean,$(MAKECMDGOALS))) --include ${EXT_LIBS_Y} -endif - -# Freetype: Terminal text rendering backend -ext-freetype: base/lib/libtoaru_ext_freetype_fonts.so - -# Cairo: Compositor rendering backend -ext-cairo: base/lib/libtoaru_ext_cairo_renderer.so - -# Other extra stuff -util/ungz: util/ungz.c - $(CC) -o $@ $< -lz +SOURCE_FILES = $(wildcard kernel/*.c kernel/*/*.c kernel/*/*/*.c kernel/*/*/*/*.c) +SOURCE_FILES += $(wildcard apps/*.c linker/*.c libc/*.c libc/*/*.c lib/*.c lib/kuroko/*.c) +SOURCE_FILES += $(wildcard kuroko/src/*.c kuroko/src/*.h kuroko/src/*/*.c kuroko/src/*/*.h) +SOURCE_FILES += $(wildcard $(BASE)/usr/include/*.h $(BASE)/usr/include/*/*.h $(BASE)/usr/include/*/*/*.h) +tags: $(SOURCE_FILES) + ctags -f tags $(SOURCE_FILES) diff --git a/apps/about.c b/apps/about.c index bef8e8be..102d5096 100644 --- a/apps/about.c +++ b/apps/about.c @@ -171,7 +171,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win) { win->focused = wf->focused; redraw(); diff --git a/apps/compositor.c b/apps/compositor.c index 6478c89d..d65f3b11 100644 --- a/apps/compositor.c +++ b/apps/compositor.c @@ -46,7 +46,7 @@ #include #include -//#define _DEBUG_YUTANI +#define _DEBUG_YUTANI #ifdef _DEBUG_YUTANI #include #define TRACE_APP_NAME "yutani" @@ -175,7 +175,7 @@ static int next_wid(void) { return _next++; } -uint32_t yutani_current_time(yutani_globals_t * yg) { +uint64_t yutani_current_time(yutani_globals_t * yg) { struct timeval t; gettimeofday(&t, NULL); @@ -187,13 +187,13 @@ uint32_t yutani_current_time(yutani_globals_t * yg) { usec_diff = (1000000 + t.tv_usec) - yg->start_subtime; } - return (uint32_t)(sec_diff * 1000 + usec_diff / 1000); + return (uint64_t)(sec_diff * 1000 + usec_diff / 1000); } -uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time) { +uint64_t yutani_time_since(yutani_globals_t * yg, uint64_t start_time) { - uint32_t now = yutani_current_time(yg); - uint32_t diff = now - start_time; /* Milliseconds */ + uint64_t now = yutani_current_time(yg); + uint64_t diff = now - start_time; /* Milliseconds */ return diff; } @@ -390,13 +390,13 @@ static int yutani_pick_animation(uint32_t flags, int direction) { * * Initializes a window of the particular size for a given client. */ -static yutani_server_window_t * server_window_create(yutani_globals_t * yg, int width, int height, uint32_t owner, uint32_t flags) { +static yutani_server_window_t * server_window_create(yutani_globals_t * yg, int width, int height, uintptr_t owner, uint32_t flags) { yutani_server_window_t * win = malloc(sizeof(yutani_server_window_t)); win->wid = next_wid(); win->owner = owner; list_insert(yg->windows, win); - hashmap_set(yg->wids_to_windows, (void*)win->wid, win); + hashmap_set(yg->wids_to_windows, (void*)(uintptr_t)win->wid, win); list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)owner); list_insert(client_list, win); @@ -733,7 +733,7 @@ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * wi case YUTANI_EFFECT_FADE_OUT: { frame = yutani_animation_lengths[window->anim_mode] - frame; - } + } /* fallthrough */ case YUTANI_EFFECT_SQUEEZE_IN: case YUTANI_EFFECT_FADE_IN: { @@ -1018,7 +1018,7 @@ static void redraw_windows(yutani_globals_t * yg) { if ((!yg->bottom_z || yg->bottom_z->anim_mode) && renderer_blit_screen) { /* TODO: Need to clear with Cairo backend */ - draw_fill(yg->backend_ctx, rgb(110,110,110)); + draw_fill(yg->backend_ctx, rgb(5,5,5)); } if (renderer_set_clip) renderer_set_clip(yg); @@ -1252,7 +1252,7 @@ static void window_mark_for_close(yutani_globals_t * yg, yutani_server_window_t * Remove a window from its owner's child set. */ static void window_remove_from_client(yutani_globals_t * yg, yutani_server_window_t * w) { - list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)w->owner); + list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)(uintptr_t)w->owner); if (client_list) { node_t * n = list_find(client_list, w); if (n) { @@ -1267,7 +1267,7 @@ static void window_remove_from_client(yutani_globals_t * yg, yutani_server_windo */ static void window_actually_close(yutani_globals_t * yg, yutani_server_window_t * w) { /* Remove from the wid -> window mapping */ - hashmap_remove(yg->wids_to_windows, (void *)w->wid); + hashmap_remove(yg->wids_to_windows, (void *)(uintptr_t)w->wid); /* Remove from the general list of windows. */ list_remove(yg->windows, list_index_of(yg->windows, w)); @@ -1319,7 +1319,7 @@ static uint32_t ad_flags(yutani_globals_t * yg, yutani_server_window_t * win) { /** * Send a result for a window query. */ -static void yutani_query_result(yutani_globals_t * yg, uint32_t dest, yutani_server_window_t * win) { +static void yutani_query_result(yutani_globals_t * yg, uintptr_t dest, yutani_server_window_t * win) { if (win && win->client_length) { yutani_msg_buildx_window_advertise_alloc(response, win->client_length); yutani_msg_buildx_window_advertise(response, win->wid, ad_flags(yg, win), win->client_offsets, win->client_length, win->client_strings); @@ -1335,7 +1335,7 @@ static void notify_subscribers(yutani_globals_t * yg) { yutani_msg_buildx_notify(response); list_t * remove = NULL; foreach(node, yg->window_subscribers) { - uint32_t subscriber = (uint32_t)node->value; + uintptr_t subscriber = (uintptr_t)node->value; if (!hashmap_has(yg->clients_to_windows, (void *)subscriber)) { if (!remove) { remove = list_create(); @@ -1601,8 +1601,8 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event * External bindings registered by clients. */ uint32_t key_code = ((ke->event.modifiers << 24) | (ke->event.keycode)); - if (hashmap_has(yg->key_binds, (void*)key_code)) { - struct key_bind * bind = hashmap_get(yg->key_binds, (void*)key_code); + if (hashmap_has(yg->key_binds, (void*)(uintptr_t)key_code)) { + struct key_bind * bind = hashmap_get(yg->key_binds, (void*)(uintptr_t)key_code); yutani_msg_buildx_key_event_alloc(response); yutani_msg_buildx_key_event(response,focused ? focused->wid : UINT32_MAX, &ke->event, &ke->state); @@ -1630,9 +1630,9 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event * req - bind message * owner - client to assign the binding to */ -static void add_key_bind(yutani_globals_t * yg, struct yutani_msg_key_bind * req, unsigned int owner) { +static void add_key_bind(yutani_globals_t * yg, struct yutani_msg_key_bind * req, uintptr_t owner) { uint32_t key_code = (((uint8_t)req->modifiers << 24) | ((uint32_t)req->key & 0xFFFFFF)); - struct key_bind * bind = hashmap_get(yg->key_binds, (void*)key_code); + struct key_bind * bind = hashmap_get(yg->key_binds, (void*)(uintptr_t)key_code); if (!bind) { bind = malloc(sizeof(struct key_bind)); @@ -1640,7 +1640,7 @@ static void add_key_bind(yutani_globals_t * yg, struct yutani_msg_key_bind * req bind->owner = owner; bind->response = req->response; - hashmap_set(yg->key_binds, (void*)key_code, bind); + hashmap_set(yg->key_binds, (void*)(uintptr_t)key_code, bind); } else { bind->owner = owner; bind->response = req->response; @@ -2103,7 +2103,7 @@ int main(int argc, char * argv[]) { yg->width = yg->backend_ctx->width; yg->height = yg->backend_ctx->height; - draw_fill(yg->backend_ctx, rgb(110,110,110)); + draw_fill(yg->backend_ctx, rgb(5,5,5)); flip(yg->backend_ctx); yg->backend_framebuffer = yg->backend_ctx->backbuffer; @@ -2388,10 +2388,10 @@ int main(int argc, char * argv[]) { switch(m->type) { case YUTANI_MSG_HELLO: { - TRACE("And hello to you, %08x!", p->source); + TRACE("And hello to you, %p!", p->source); list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)p->source); if (!client_list) { - TRACE("Client is new: %x", p->source); + TRACE("Client is new: %p", p->source); client_list = list_create(); hashmap_set(yg->clients_to_windows, (void *)p->source, client_list); } @@ -2404,7 +2404,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_NEW_FLAGS: { struct yutani_msg_window_new_flags * wn = (void *)m->data; - TRACE("Client %08x requested a new window (%dx%d).", p->source, wn->width, wn->height); + TRACE("Client %p requested a new window (%dx%d).", p->source, wn->width, wn->height); yutani_server_window_t * w = server_window_create(yg, wn->width, wn->height, p->source, m->type != YUTANI_MSG_WINDOW_NEW ? wn->flags : 0); yutani_msg_buildx_window_init_alloc(response); yutani_msg_buildx_window_init(response,w->wid, w->width, w->height, w->bufid); @@ -2420,7 +2420,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_FLIP: { struct yutani_msg_flip * wf = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wf->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wf->wid); if (w) { mark_window(yg, w); } @@ -2429,7 +2429,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_FLIP_REGION: { struct yutani_msg_flip_region * wf = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wf->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wf->wid); if (w) { mark_window_relative(yg, w, wf->x, wf->y, wf->width, wf->height); } @@ -2457,7 +2457,7 @@ int main(int argc, char * argv[]) { TRACE("Refusing to move window to these coordinates."); break; } - yutani_server_window_t * win = hashmap_get(yg->wids_to_windows, (void*)wm->wid); + yutani_server_window_t * win = hashmap_get(yg->wids_to_windows, (void*)(uintptr_t)wm->wid); if (win) { window_move(yg, win, wm->x, wm->y); } else { @@ -2468,7 +2468,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_CLOSE: { struct yutani_msg_window_close * wc = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wc->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wc->wid); if (w) { window_mark_for_close(yg, w); window_remove_from_client(yg, w); @@ -2478,7 +2478,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_STACK: { struct yutani_msg_window_stack * ws = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)ws->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)ws->wid); if (w) { reorder_window(yg, w, ws->z); } @@ -2487,7 +2487,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_RESIZE_REQUEST: { struct yutani_msg_window_resize * wr = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid); if (w) { yutani_msg_buildx_window_resize_alloc(response); yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0, w->tiled); @@ -2498,7 +2498,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_RESIZE_OFFER: { struct yutani_msg_window_resize * wr = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid); if (w) { yutani_msg_buildx_window_resize_alloc(response); yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0, w->tiled); @@ -2509,7 +2509,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_RESIZE_ACCEPT: { struct yutani_msg_window_resize * wr = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid); if (w) { uint32_t newbufid = server_window_resize(yg, w, wr->width, wr->height); yutani_msg_buildx_window_resize_alloc(response); @@ -2521,7 +2521,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_RESIZE_DONE: { struct yutani_msg_window_resize * wr = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid); if (w) { server_window_resize_finish(yg, w, wr->width, wr->height); } @@ -2542,7 +2542,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_SUBSCRIBE: { foreach(node, yg->window_subscribers) { - if ((uint32_t)node->value == p->source) { + if ((uintptr_t)node->value == p->source) { break; } } @@ -2560,7 +2560,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_ADVERTISE: { struct yutani_msg_window_advertise * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { if (w->client_strings) free(w->client_strings); @@ -2587,7 +2587,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS: { struct yutani_msg_window_focus * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { set_focused_window(yg, w); } @@ -2602,7 +2602,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_DRAG_START: { struct yutani_msg_window_drag_start * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { /* Start dragging */ mouse_start_drag(yg, w); @@ -2612,7 +2612,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_UPDATE_SHAPE: { struct yutani_msg_window_update_shape * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { /* Set shape parameter */ server_window_update_shape(yg, w, wa->set_shape); @@ -2622,7 +2622,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_WARP_MOUSE: { struct yutani_msg_window_warp_mouse * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { if (yg->focused_window == w) { int32_t x, y; @@ -2643,7 +2643,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_SHOW_MOUSE: { struct yutani_msg_window_show_mouse * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { if (wa->show_mouse == -1) { w->show_mouse = w->default_mouse; @@ -2662,7 +2662,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_RESIZE_START: { struct yutani_msg_window_resize_start * wa = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid); if (w) { if (yg->focused_window == w && !yg->resizing_window) { yg->resizing_window = w; @@ -2675,7 +2675,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_SPECIAL_REQUEST: { struct yutani_msg_special_request * sr = (void *)m->data; - yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)sr->wid); + yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)sr->wid); switch (sr->request) { case YUTANI_SPECIAL_REQUEST_MAXIMIZE: if (w) { diff --git a/apps/demo.c b/apps/demo.c new file mode 100644 index 00000000..19f141f8 --- /dev/null +++ b/apps/demo.c @@ -0,0 +1,6 @@ +#include + +int main(int argc, char * argv[]) { + printf("Hello, world! I am %s! I was called with '%s'\n", argv[0], argv[1]); + return 0; +} diff --git a/apps/demo.krk b/apps/demo.krk new file mode 100644 index 00000000..fd9b6ac9 --- /dev/null +++ b/apps/demo.krk @@ -0,0 +1,4 @@ +import os, kuroko + +print('Kuroko',kuroko.version, kuroko.buildenv, kuroko.builddate) +print('Running on:',os.uname()) diff --git a/apps/dhcp_bitbanger.c b/apps/dhcp_bitbanger.c new file mode 100644 index 00000000..cf722b4e --- /dev/null +++ b/apps/dhcp_bitbanger.c @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct ethernet_packet { + uint8_t destination[6]; + uint8_t source[6]; + uint16_t type; + uint8_t payload[]; +} __attribute__((packed)) __attribute__((aligned(2))); + +struct ipv4_packet { + uint8_t version_ihl; + uint8_t dscp_ecn; + uint16_t length; + uint16_t ident; + uint16_t flags_fragment; + uint8_t ttl; + uint8_t protocol; + uint16_t checksum; + uint32_t source; + uint32_t destination; + uint8_t payload[]; +} __attribute__ ((packed)) __attribute__((aligned(2))); + +struct udp_packet { + uint16_t source_port; + uint16_t destination_port; + uint16_t length; + uint16_t checksum; + uint8_t payload[]; +} __attribute__ ((packed)) __attribute__((aligned(2))); + +struct dhcp_packet { + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + + uint32_t xid; + + uint16_t secs; + uint16_t flags; + + uint32_t ciaddr; + uint32_t yiaddr; + uint32_t siaddr; + uint32_t giaddr; + + uint8_t chaddr[16]; + + uint8_t sname[64]; + uint8_t file[128]; + + uint32_t magic; + + uint8_t options[]; +} __attribute__ ((packed)) __attribute__((aligned(2))); + +struct dns_packet { + uint16_t qid; + uint16_t flags; + uint16_t questions; + uint16_t answers; + uint16_t authorities; + uint16_t additional; + uint8_t data[]; +} __attribute__ ((packed)) __attribute__((aligned(2))); + +struct tcp_header { + uint16_t source_port; + uint16_t destination_port; + + uint32_t seq_number; + uint32_t ack_number; + + uint16_t flags; + uint16_t window_size; + uint16_t checksum; + uint16_t urgent; + + uint8_t payload[]; +} __attribute__((packed)) __attribute__((aligned(2))); + +struct tcp_check_header { + uint32_t source; + uint32_t destination; + uint8_t zeros; + uint8_t protocol; + uint16_t tcp_len; + uint8_t tcp_header[]; +}; + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +// Note: Data offset is in upper 4 bits of flags field. Shift and subtract 5 since that is the min TCP size. +// If the value is more than 5, multiply by 4 because this field is specified in number of words +#define TCP_OPTIONS_LENGTH(tcp) (((((tcp)->flags) >> 12) - 5) * 4) +#define TCP_HEADER_LENGTH(tcp) ((((tcp)->flags) >> 12) * 4) +#define TCP_HEADER_LENGTH_FLIPPED(tcp) (((htons((tcp)->flags)) >> 12) * 4) + +#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) +#define htons(s) ( (((s) & 0xFF) << 8) | (((s) & 0xFF00) >> 8) ) +#define ntohl(l) htonl((l)) +#define ntohs(s) htons((s)) + +#define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} +#define IPV4_PROT_UDP 17 +#define IPV4_PROT_TCP 6 +#define DHCP_MAGIC 0x63825363 + +#define TCP_FLAGS_FIN (1 << 0) +#define TCP_FLAGS_SYN (1 << 1) +#define TCP_FLAGS_RES (1 << 2) +#define TCP_FLAGS_PSH (1 << 3) +#define TCP_FLAGS_ACK (1 << 4) +#define TCP_FLAGS_URG (1 << 5) +#define TCP_FLAGS_ECE (1 << 6) +#define TCP_FLAGS_CWR (1 << 7) +#define TCP_FLAGS_NS (1 << 8) +#define DATA_OFFSET_5 (0x5 << 12) + +#define ETHERNET_TYPE_IPV4 0x0800 +#define ETHERNET_TYPE_ARP 0x0806 + +struct payload { + struct ethernet_packet eth_header; + struct ipv4_packet ip_header; + struct udp_packet udp_header; + struct dhcp_packet dhcp_header; + uint8_t payload[32]; +}; + +static void eth_ntoa(const uint8_t addr[6], char * out) { + /* XX:XX:XX:XX:XX:XX */ + snprintf(out, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); +} + +static void ip_ntoa(const uint32_t src_addr, char * out) { + snprintf(out, 16, "%d.%d.%d.%d", + (src_addr & 0xFF000000) >> 24, + (src_addr & 0xFF0000) >> 16, + (src_addr & 0xFF00) >> 8, + (src_addr & 0xFF)); +} + +static const char * eth_type_str(uint16_t type) { + switch(type) { + case ETHERNET_TYPE_IPV4: return "IPv4"; + case ETHERNET_TYPE_ARP: return "ARP"; + default: return "unknown"; + } +} + +static void print_ipv4_header(struct ipv4_packet * packet) { + /* get addresses, type... */ + char dest_addr[16]; + char src_addr[16]; + ip_ntoa(ntohl(packet->destination), dest_addr); + ip_ntoa(ntohl(packet->source), src_addr); + fprintf(stderr, "%s -> %s %d (%s) ", + src_addr, dest_addr, packet->protocol, + packet->protocol == IPV4_PROT_UDP ? "udp" : + packet->protocol == IPV4_PROT_TCP ? "tcp" : "?"); +} + +void print_header(const struct payload * header) { + /* Assume it's at least an Ethernet frame */ + char dest_addr[18]; + char src_addr[18]; + eth_ntoa(header->eth_header.destination, dest_addr); + eth_ntoa(header->eth_header.source, src_addr); + fprintf(stderr, "%s -> %s %d (%s) ", + src_addr, dest_addr, ntohs(header->eth_header.type), eth_type_str(ntohs(header->eth_header.type))); + switch (ntohs(header->eth_header.type)) { + case ETHERNET_TYPE_IPV4: + print_ipv4_header((void*)&header->eth_header.payload); + break; + case ETHERNET_TYPE_ARP: + //print_arp_header(&header->eth_header.payload); + break; + } + fprintf(stderr, "\n"); +} + +uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) { + uint32_t sum = 0; + uint16_t * s = (uint16_t *)p; + + /* TODO: Checksums for options? */ + for (int i = 0; i < 10; ++i) { + sum += ntohs(s[i]); + } + + if (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return ~(sum & 0xFFFF) & 0xFFFF; +} + +uint8_t mac_addr[6]; + +void fill(struct payload *it, size_t payload_size) { + + it->eth_header.source[0] = mac_addr[0]; + it->eth_header.source[1] = mac_addr[1]; + it->eth_header.source[2] = mac_addr[2]; + it->eth_header.source[3] = mac_addr[3]; + it->eth_header.source[4] = mac_addr[4]; + it->eth_header.source[5] = mac_addr[5]; + + it->eth_header.destination[0] = 0xFF; + it->eth_header.destination[1] = 0xFF; + it->eth_header.destination[2] = 0xFF; + it->eth_header.destination[3] = 0xFF; + it->eth_header.destination[4] = 0xFF; + it->eth_header.destination[5] = 0xFF; + + it->eth_header.type = htons(0x0800); + + it->ip_header.version_ihl = ((0x4 << 4) | (0x5 << 0)); + it->ip_header.dscp_ecn = 0; + it->ip_header.length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + sizeof(struct dhcp_packet) + payload_size); + it->ip_header.ident = htons(1); + it->ip_header.flags_fragment = 0; + it->ip_header.ttl = 0x40; + it->ip_header.protocol = IPV4_PROT_UDP; + it->ip_header.checksum = 0; + it->ip_header.source = htonl(0); + it->ip_header.destination = htonl(0xFFFFFFFF); + + it->ip_header.checksum = htons(calculate_ipv4_checksum(&it->ip_header)); + + it->udp_header.source_port = htons(68); + it->udp_header.destination_port = htons(67); + it->udp_header.length = htons(sizeof(struct udp_packet) + sizeof(struct dhcp_packet) + payload_size); + it->udp_header.checksum = 0; /* uh */ + + it->dhcp_header.op = 1; + it->dhcp_header.htype = 1; + it->dhcp_header.hlen = 6; + it->dhcp_header.hops = 0; + it->dhcp_header.xid = htons(0x1337); /* transaction id... */ + it->dhcp_header.secs = 0; + it->dhcp_header.flags = 0; + + it->dhcp_header.ciaddr = 0; + it->dhcp_header.yiaddr = 0; + it->dhcp_header.siaddr = 0; + it->dhcp_header.giaddr = 0; + it->dhcp_header.chaddr[0] = mac_addr[0]; + it->dhcp_header.chaddr[1] = mac_addr[1]; + it->dhcp_header.chaddr[2] = mac_addr[2]; + it->dhcp_header.chaddr[3] = mac_addr[3]; + it->dhcp_header.chaddr[4] = mac_addr[4]; + it->dhcp_header.chaddr[5] = mac_addr[5]; + + it->dhcp_header.magic = htonl(DHCP_MAGIC); +} + +int main(int argc, char * argv[]) { + +#if 0 + /* Let's make a socket. */ + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { perror("socket"); return 1; } + + /* Bind the socket to the requested device. */ + //if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, +#endif + + char * if_name = "enp0s4"; + char if_path[100]; + + if (argc > 1) { + if_name = argv[1]; + } + + snprintf(if_path, 100, "/dev/net/%s", if_name); + + int netdev = open(if_path, O_RDWR); + + fprintf(stderr, "Configuring %s\n", if_name); + + if (ioctl(netdev, 0x12340001, &mac_addr)) { + fprintf(stderr, "could not get mac address\n"); + return 1; + } + + fprintf(stderr, "mac address: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + /* Try to frob the whatsit */ + { + struct payload thething = { + .payload = {53,1,1,55,2,3,6,255,0} + }; + + fill(&thething, 8); + + write(netdev, &thething, sizeof(struct payload)); + } + + uint32_t yiaddr; + int stage = 1; + + do { + char buf[8092] = {0}; + + struct pollfd fds[1]; + fds[0].fd = netdev; + fds[0].events = POLLIN; + int ret = poll(fds,1,2000); + if (ret <= 0) { + printf("...\n"); + continue; + } + ssize_t rsize = read(netdev, &buf, 8092); + + if (rsize <= 0) { + printf("bad size? %zd\n", rsize); + continue; + } + + struct payload * response = (void*)buf; + + print_header(response); + + if (ntohs(response->udp_header.destination_port) != 68) { + continue; + } + + if (stage == 1) { + yiaddr = response->dhcp_header.yiaddr; + char yiaddr_ip[16]; + ip_ntoa(ntohl(yiaddr), yiaddr_ip); + + printf("Response from DHCP Discover: %s\n", yiaddr_ip); + struct payload thething = { + .payload = {53,1,3,50,4, + (yiaddr) & 0xFF, + (yiaddr >> 8) & 0xFF, + (yiaddr >> 16) & 0xFF, + (yiaddr >> 24) & 0xFF, + 55,2,3,6,255,0} + }; + + fill(&thething, 14); + write(netdev, &thething, sizeof(struct payload)); + + stage = 2; + } else if (stage == 2) { + yiaddr = response->dhcp_header.yiaddr; + char yiaddr_ip[16]; + ip_ntoa(ntohl(yiaddr), yiaddr_ip); + + printf("ACK returns: %s\n", yiaddr_ip); + printf("Address is configured, continuing trace mode.\n"); + + stage = 3; + } + } while (1); + return 0; +} diff --git a/apps/du.c b/apps/du.c index 09399488..8df2c5e4 100644 --- a/apps/du.c +++ b/apps/du.c @@ -38,7 +38,7 @@ static int print_human_readable_size(char * _out, size_t s) { } static void print_size(uint64_t size, char * name) { - char sizes[8]; + char sizes[30]; if (!human) { sprintf(sizes, "%-7llu", size/1024LLU); } else { diff --git a/apps/fetch.c b/apps/fetch.c index 0140dab2..afac1b37 100644 --- a/apps/fetch.c +++ b/apps/fetch.c @@ -289,7 +289,7 @@ int main(int argc, char * argv[]) { struct http_req my_req; parse_url(argv[optind], &my_req); - char file[100]; + char file[600]; sprintf(file, "/dev/net/%s", my_req.domain); if (fetch_options.calculate_output) { diff --git a/apps/file-browser.c b/apps/file-browser.c index 658ad722..d3df6854 100644 --- a/apps/file-browser.c +++ b/apps/file-browser.c @@ -85,7 +85,7 @@ static int nav_bar_cursor_x = 0; static int nav_bar_focused = 0; /* Status bar displayed at the bottom of the window */ -static char window_status[512] = {0}; +static char window_status[1024] = {0}; /* Button row visibility statuses */ static int _button_hilights[4] = {3,3,3,3}; @@ -435,7 +435,7 @@ static void update_status(void) { char tmp_size[50]; if (selected_count == 0) { print_human_readable_size(tmp_size, total_size); - sprintf(window_status, "%d item%s (%s)", file_pointers_len, file_pointers_len == 1 ? "" : "s", tmp_size); + sprintf(window_status, "%zd item%s (%s)", file_pointers_len, file_pointers_len == 1 ? "" : "s", tmp_size); } else if (selected_count == 1) { print_human_readable_size(tmp_size, selected->size); sprintf(window_status, "\"%s\" (%s) %s", selected->name, tmp_size, selected->filetype); @@ -1955,7 +1955,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win == main_window) { win->focused = wf->focused; redraw_files(); @@ -1994,7 +1994,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_MOUSE_EVENT: { struct yutani_msg_window_mouse_event * me = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid); struct decor_bounds bounds; _decor_get_bounds(win, &bounds); diff --git a/apps/go-video.sh b/apps/go-video.sh deleted file mode 100644 index c5feeba5..00000000 --- a/apps/go-video.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# Start font server if freetype is available -if stat -Lq /usr/lib/libfreetype.so then font-server - -if empty? "$1" then export WIDTH=1024 else export WIDTH="$1" -if empty? "$2" then export HEIGHT=768 else export HEIGHT="$2" - -# Switch to graphics mode -if not set-resolution --initialize auto $WIDTH $HEIGHT then exec sh -c "echo 'Failed to set video mode, bailing.'; exit 1" - -# Tell the terminal to pause input -killall -s USR2 terminal-vga - -# Start the compositor -compositor diff --git a/apps/help-browser.c b/apps/help-browser.c index 04525c2e..896748b5 100644 --- a/apps/help-browser.c +++ b/apps/help-browser.c @@ -118,13 +118,13 @@ static void write_buffer(void) { static int parser_open(struct markup_state * self, void * user, struct markup_tag * tag) { if (!strcmp(tag->name, "b")) { - list_insert(state, (void*)current_state); + list_insert(state, (void*)(uintptr_t)current_state); current_state |= (1 << 0); } else if (!strcmp(tag->name, "i")) { - list_insert(state, (void*)current_state); + list_insert(state, (void*)(uintptr_t)current_state); current_state |= (1 << 1); } else if (!strcmp(tag->name, "h1")) { - list_insert(state, (void*)current_state); + list_insert(state, (void*)(uintptr_t)current_state); current_state |= (1 << 2); } else if (!strcmp(tag->name, "br")) { write_buffer(); @@ -138,18 +138,18 @@ static int parser_open(struct markup_state * self, void * user, struct markup_ta static int parser_close(struct markup_state * self, void * user, char * tag_name) { if (!strcmp(tag_name, "b")) { node_t * nstate = list_pop(state); - current_state = (int)nstate->value; + current_state = (int)(uintptr_t)nstate->value; free(nstate); } else if (!strcmp(tag_name, "i")) { node_t * nstate = list_pop(state); - current_state = (int)nstate->value; + current_state = (int)(uintptr_t)nstate->value; free(nstate); } else if (!strcmp(tag_name, "h1")) { write_buffer(); cursor_x = BASE_X; cursor_y += current_line_height(); node_t * nstate = list_pop(state); - current_state = (int)nstate->value; + current_state = (int)(uintptr_t)nstate->value; free(nstate); } return 0; @@ -413,7 +413,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win == main_window) { win->focused = wf->focused; redraw_window(); @@ -431,7 +431,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_MOUSE_EVENT: { struct yutani_msg_window_mouse_event * me = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid); if (win == main_window) { int result = decor_handle_event(yctx, m); diff --git a/apps/ifconfig.c b/apps/ifconfig.c new file mode 100644 index 00000000..9ddbc00e --- /dev/null +++ b/apps/ifconfig.c @@ -0,0 +1,11 @@ +/** + * @file apps/ifconfig.c + * @brief Network interface configuration tool. + * + * Manipulates and enumerates network interfaces. + */ +#include + +int main(int argc, char * argv[]) { + /* I have no idea how this works on Linux or BSD, but based on some manpages... */ +} diff --git a/apps/imgviewer.c b/apps/imgviewer.c index 0a251eb8..6c2f2f5b 100644 --- a/apps/imgviewer.c +++ b/apps/imgviewer.c @@ -190,7 +190,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win && win == window) { win->focused = wf->focused; decors(); diff --git a/apps/json-test.c b/apps/json-test.c index 6939299e..473adc15 100644 --- a/apps/json-test.c +++ b/apps/json-test.c @@ -24,19 +24,19 @@ int main(int argc, char * argv[]) { { Value * result = json_parse("-123"); assert(result && result->type == JSON_TYPE_NUMBER); - assert(fabs(result->number - (-123.0) < 0.0001)); + assert(fabs(result->number - (-123.0)) < 0.0001); } { Value * result = json_parse("2e3"); assert(result && result->type == JSON_TYPE_NUMBER); - assert(fabs(result->number - (2000.0) < 0.0001)); + assert(fabs(result->number - (2000.0)) < 0.0001); } { Value * result = json_parse("0.124"); assert(result && result->type == JSON_TYPE_NUMBER); - assert(fabs(result->number - (0.124) < 0.0001)); + assert(fabs(result->number - (0.124)) < 0.0001); } { diff --git a/apps/julia.c b/apps/julia.c index 92f29ba6..fd04c654 100644 --- a/apps/julia.c +++ b/apps/julia.c @@ -299,7 +299,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win && win == window) { win->focused = wf->focused; decors(); diff --git a/apps/killall.c b/apps/killall.c index 7a00518a..cd086003 100644 --- a/apps/killall.c +++ b/apps/killall.c @@ -31,7 +31,7 @@ typedef struct process { #define LINE_LEN 4096 p_t * build_entry(struct dirent * dent) { - char tmp[256]; + char tmp[300]; FILE * f; char line[LINE_LEN]; diff --git a/apps/kuroko.c b/apps/kuroko.c deleted file mode 100644 index b0e1a4d0..00000000 --- a/apps/kuroko.c +++ /dev/null @@ -1,1166 +0,0 @@ -/** - * Kuroko interpreter main executable. - * - * Reads lines from stdin with the `rline` library and executes them, - * or executes scripts from the argument list. - */ -#define _DEFAULT_SOURCE -#include -#include -#include -#include -#include -#include -#include - -#ifdef __toaru__ -#include -#else -#ifndef NO_RLINE -#include "vendor/rline.h" -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#define PROMPT_MAIN ">>> " -#define PROMPT_BLOCK " > " - -#define CALLGRIND_TMP_FILE "/tmp/kuroko.callgrind.tmp" - -static int enableRline = 1; -static int exitRepl = 0; -static int pasteEnabled = 0; - -KRK_FUNC(exit,{ - FUNCTION_TAKES_NONE(); - exitRepl = 1; -}) - -KRK_FUNC(paste,{ - FUNCTION_TAKES_AT_MOST(1); - if (argc) { - CHECK_ARG(0,bool,int,enabled); - pasteEnabled = enabled; - } else { - pasteEnabled = !pasteEnabled; - } - fprintf(stderr, "Pasting is %s.\n", pasteEnabled ? "enabled" : "disabled"); -}) - -static int doRead(char * buf, size_t bufSize) { -#ifndef NO_RLINE - if (enableRline) - return rline(buf, bufSize); - else -#endif - return read(STDIN_FILENO, buf, bufSize); -} - -static KrkValue readLine(char * prompt, int promptWidth, char * syntaxHighlighter) { - struct StringBuilder sb = {0}; - -#ifndef NO_RLINE - if (enableRline) { - rline_exit_string = ""; - rline_exp_set_prompts(prompt, "", promptWidth, 0); - rline_exp_set_syntax(syntaxHighlighter); - rline_exp_set_tab_complete_func(NULL); - } else -#endif - { - fprintf(stdout, "%s", prompt); - fflush(stdout); - } - - /* Read a line of input using a method that we can guarantee will be - * interrupted by signal delivery. */ - while (1) { - char buf[4096]; - ssize_t bytesRead = doRead(buf, 4096); - if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) goto _exit; - if (bytesRead < 0) { - krk_runtimeError(vm.exceptions->ioError, "%s", strerror(errno)); - goto _exit; - } else if (bytesRead == 0 && !sb.length) { - krk_runtimeError(vm.exceptions->baseException, "EOF"); - goto _exit; - } else { - pushStringBuilderStr(&sb, buf, bytesRead); - } - /* Was there a linefeed? Then we can exit. */ - if (sb.length && sb.bytes[sb.length-1] == '\n') { - sb.length--; - break; - } - } - - return finishStringBuilder(&sb); - -_exit: - discardStringBuilder(&sb); - return NONE_VAL(); -} - -/** - * @brief Read a line of input. - * - * In an interactive session, presents the configured prompt without - * a trailing linefeed. - */ -KRK_FUNC(input,{ - FUNCTION_TAKES_AT_MOST(1); - - char * prompt = ""; - int promptLength = 0; - char * syntaxHighlighter = NULL; - - if (argc) { - CHECK_ARG(0,str,KrkString*,_prompt); - prompt = _prompt->chars; - promptLength = _prompt->codesLength; - } - - if (hasKw) { - KrkValue promptwidth; - if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("promptwidth")), &promptwidth)) { - if (!IS_INTEGER(promptwidth)) return TYPE_ERROR(int,promptwidth); - promptLength = AS_INTEGER(promptwidth); - } - - KrkValue syntax; - if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("syntax")), &syntax)) { - if (!IS_STRING(syntax)) return TYPE_ERROR(str,syntax); - syntaxHighlighter = AS_CSTRING(syntax); - } - } - - return readLine(prompt, promptLength, syntaxHighlighter); -}) - -#ifndef NO_RLINE -/** - * Given an object, find a property with the same name as a scanner token. - * This can be either a field of an instance, or a method of the type of - * the of the object. If we can't find anything by that name, return None. - * - * We can probably also use valueGetProperty which does correct binding - * for native dynamic fields... - */ -static KrkValue findFromProperty(KrkValue current, KrkToken next) { - KrkValue member = OBJECT_VAL(krk_copyString(next.start, next.literalWidth)); - krk_push(member); - KrkValue value = krk_valueGetAttribute_default(current, AS_CSTRING(member), NONE_VAL()); - krk_pop(); - return value; -} - -static void tab_complete_func(rline_context_t * c) { - /* Figure out where the cursor is and if we should be completing anything. */ - if (c->offset) { - /* Copy up to the cursor... */ - char * tmp = malloc(c->offset + 1); - memcpy(tmp, c->buffer, c->offset); - tmp[c->offset] = '\0'; - /* and pass it to the scanner... */ - krk_initScanner(tmp); - /* Logically, there can be at most (offset) tokens, plus some wiggle room. */ - KrkToken * space = malloc(sizeof(KrkToken) * (c->offset + 2)); - int count = 0; - do { - space[count++] = krk_scanToken(); - } while (space[count-1].type != TOKEN_EOF && space[count-1].type != TOKEN_ERROR); - - /* If count == 1, it was EOF or an error and we have nothing to complete. */ - if (count == 1) { - goto _cleanup; - } - - /* Otherwise we want to see if we're on an identifier or a dot. */ - int base = 2; - int n = base; - if (space[count-base].type == TOKEN_DOT) { - /* Dots we need to look back at the previous tokens for */ - n--; - base--; - } else if (space[count-base].type >= TOKEN_IDENTIFIER && space[count-base].type <= TOKEN_WITH) { - /* Something alphanumeric; only for the last element */ - } else { - /* Some other symbol */ - goto _cleanup; - } - - /* Work backwards to find the start of this chain of identifiers */ - while (n < count) { - if (space[count-n-1].type != TOKEN_DOT) break; - n++; - if (n == count) break; - if (space[count-n-1].type != TOKEN_IDENTIFIER) break; - n++; - } - - if (n <= count) { - /* Now work forwards, starting from the current globals. */ - KrkValue root = OBJECT_VAL(krk_currentThread.module); - int isGlobal = 1; - while (n > base) { - /* And look at the potential fields for instances/classes */ - KrkValue next = findFromProperty(root, space[count-n]); - if (IS_NONE(next)) { - /* If we hit None, we found something invalid (or literally hit a None - * object, but really the difference is minimal in this case: Nothing - * useful to tab complete from here. */ - if (!isGlobal) goto _cleanup; - /* Does this match a builtin? */ - if (!krk_tableGet_fast(&vm.builtins->fields, - krk_copyString(space[count-n].start,space[count-n].literalWidth), &next) || IS_NONE(next)) { - goto _cleanup; - } - } - isGlobal = 0; - root = next; - n -= 2; /* To skip every other dot. */ - } - - /* Now figure out what we're completing - did we already have a partial symbol name? */ - int length = (space[count-base].type == TOKEN_DOT) ? 0 : (space[count-base].length); - isGlobal = isGlobal && (length != 0); - - /* Collect up to 256 of those that match */ - char * matches[256]; - int matchCount = 0; - - /* Take the last symbol name from the chain and get its member list from dir() */ - - for (;;) { - KrkValue dirList = krk_dirObject(1,(KrkValue[]){root},0); - krk_push(dirList); - if (!IS_INSTANCE(dirList)) { - fprintf(stderr,"\nInternal error while tab completting.\n"); - goto _cleanup; - } - - for (size_t i = 0; i < AS_LIST(dirList)->count; ++i) { - KrkString * s = AS_STRING(AS_LIST(dirList)->values[i]); - krk_push(OBJECT_VAL(s)); - KrkToken asToken = {.start = s->chars, .literalWidth = s->length}; - KrkValue thisValue = findFromProperty(root, asToken); - krk_push(thisValue); - if (IS_CLOSURE(thisValue) || IS_BOUND_METHOD(thisValue) || - (IS_NATIVE(thisValue) && !(((KrkNative*)AS_OBJECT(thisValue))->flags & KRK_NATIVE_FLAGS_IS_DYNAMIC_PROPERTY))) { - size_t allocSize = s->length + 2; - char * tmp = malloc(allocSize); - size_t len = snprintf(tmp, allocSize, "%s(", s->chars); - s = krk_takeString(tmp, len); - krk_pop(); - krk_push(OBJECT_VAL(s)); - } - - /* If this symbol is shorter than the current submatch, skip it. */ - if (length && (int)s->length < length) continue; - - /* See if it's already in the matches */ - int found = 0; - for (int i = 0; i < matchCount; ++i) { - if (!strcmp(matches[i], s->chars)) { - found = 1; - break; - } - } - if (found) continue; - - if (!memcmp(s->chars, space[count-base].start, length)) { - matches[matchCount] = s->chars; - matchCount++; - if (matchCount == 255) goto _toomany; - } - } - - /* - * If the object we were scanning was the current module, - * then we should also throw the builtins into the ring. - */ - if (isGlobal && AS_OBJECT(root) == (KrkObj*)krk_currentThread.module) { - root = OBJECT_VAL(vm.builtins); - continue; - } else if (isGlobal && AS_OBJECT(root) == (KrkObj*)vm.builtins) { - extern char * syn_krk_keywords[]; - KrkInstance * fakeKeywordsObject = krk_newInstance(vm.baseClasses->objectClass); - root = OBJECT_VAL(fakeKeywordsObject); - krk_push(root); - for (char ** keyword = syn_krk_keywords; *keyword; keyword++) { - krk_attachNamedValue(&fakeKeywordsObject->fields, *keyword, NONE_VAL()); - } - continue; - } else { - break; - } - } -_toomany: - - /* Now we can do things with the matches. */ - if (matchCount == 1) { - /* If there was only one, just fill it. */ - rline_insert(c, matches[0] + length); - rline_place_cursor(); - } else if (matchCount) { - /* Otherwise, try to find a common substring among them... */ - int j = length; - while (1) { - char m = matches[0][j]; - if (!m) break; - int diff = 0; - for (int i = 1; i < matchCount; ++i) { - if (matches[i][j] != m) { - diff = 1; - break; - } - } - if (diff) break; - j++; - } - /* If no common sub string could be filled in, we print the list. */ - if (j == length) { - /* First find the maximum width of an entry */ - int maxWidth = 0; - for (int i = 0; i < matchCount; ++i) { - if ((int)strlen(matches[i]) > maxWidth) maxWidth = strlen(matches[i]); - } - /* Now how many can we fit in a screen */ - int colsPerLine = rline_terminal_width / (maxWidth + 2); /* +2 for the spaces */ - fprintf(stderr, "\n"); - int column = 0; - for (int i = 0; i < matchCount; ++i) { - fprintf(stderr, "%-*s ", maxWidth, matches[i]); - column += 1; - if (column >= colsPerLine) { - fprintf(stderr, "\n"); - column = 0; - } - } - if (column != 0) fprintf(stderr, "\n"); - } else { - /* If we do have a common sub string, fill in those characters. */ - for (int i = length; i < j; ++i) { - char tmp[2] = {matches[0][i], '\0'}; - rline_insert(c, tmp); - } - } - } - } -_cleanup: - free(tmp); - free(space); - krk_resetStack(); - return; - } -} -#endif - -#ifndef KRK_DISABLE_DEBUG -static char * lastDebugCommand = NULL; -static int debuggerHook(KrkCallFrame * frame) { - - /* File information */ - fprintf(stderr, "At offset 0x%04lx of function '%s' from '%s' on line %lu:\n", - (unsigned long)(frame->ip - frame->closure->function->chunk.code), - frame->closure->function->name->chars, - frame->closure->function->chunk.filename->chars, - (unsigned long)krk_lineNumber(&frame->closure->function->chunk, - (unsigned long)(frame->ip - frame->closure->function->chunk.code))); - - /* Opcode trace */ - krk_disassembleInstruction( - stderr, - frame->closure->function, - (size_t)(frame->ip - frame->closure->function->chunk.code)); - - krk_debug_dumpStack(stderr, frame); - - while (1) { - char buf[4096] = {0}; -#ifndef NO_RLINE - if (enableRline) { - rline_exit_string=""; - rline_exp_set_prompts("(dbg) ", "", 6, 0); - rline_exp_set_syntax("krk-dbg"); - rline_exp_set_tab_complete_func(NULL); - if (rline(buf, 4096) == 0) goto _dbgQuit; - } else { -#endif - fprintf(stderr, "(dbg) "); - fflush(stderr); - char * out = fgets(buf, 4096, stdin); - if (!out || !strlen(buf)) { - fprintf(stdout, "^D\n"); - goto _dbgQuit; - } -#ifndef NO_RLINE - } -#endif - - char * nl = strstr(buf,"\n"); - if (nl) *nl = '\0'; - - if (!strlen(buf)) { - if (lastDebugCommand) { - strcpy(buf, lastDebugCommand); - } else { - continue; - } - } else { -#ifndef NO_RLINE - if (enableRline) { - rline_history_insert(strdup(buf)); - rline_scroll = 0; - } -#endif - if (lastDebugCommand) free(lastDebugCommand); - lastDebugCommand = strdup(buf); - } - - /* Try to tokenize the first bit */ - char * arg = NULL; - char * sp = strstr(buf," "); - if (sp) { - *sp = '\0'; - arg = sp + 1; - } - /* Now check commands */ - if (!strcmp(buf, "c") || !strcmp(buf,"continue")) { - return KRK_DEBUGGER_CONTINUE; - } else if (!strcmp(buf, "s") || !strcmp(buf, "step")) { - return KRK_DEBUGGER_STEP; - } else if (!strcmp(buf, "abort")) { - return KRK_DEBUGGER_ABORT; - } else if (!strcmp(buf, "q") || !strcmp(buf, "quit")) { - return KRK_DEBUGGER_QUIT; - } else if (!strcmp(buf, "bt") || !strcmp(buf, "backtrace")) { - krk_debug_dumpTraceback(); - } else if (!strcmp(buf, "p") || !strcmp(buf, "print")) { - if (!arg) { - fprintf(stderr, "print requires an argument\n"); - } else { - size_t frameCount = krk_currentThread.frameCount; - /* Compile statement */ - KrkCodeObject * expression = krk_compile(arg,""); - if (expression) { - /* Make sure stepping is disabled first. */ - krk_debug_disableSingleStep(); - /* Turn our compiled expression into a callable. */ - krk_push(OBJECT_VAL(expression)); - krk_push(OBJECT_VAL(krk_newClosure(expression))); - krk_swap(1); - krk_pop(); - /* Stack silliness, don't ask. */ - krk_push(NONE_VAL()); - krk_pop(); - /* Call the compiled expression with no args. */ - krk_push(krk_callStack(0)); - fprintf(stderr, "\033[1;30m=> "); - krk_printValue(stderr, krk_peek(0)); - fprintf(stderr, "\033[0m\n"); - krk_pop(); - } - if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { - krk_dumpTraceback(); - krk_currentThread.flags &= ~(KRK_THREAD_HAS_EXCEPTION); - } - krk_currentThread.frameCount = frameCount; - } - } else if (!strcmp(buf, "break") || !strcmp(buf, "b")) { - char * filename = arg; - if (!filename) { - fprintf(stderr, "usage: break FILE LINE [type]\n"); - continue; - } - - char * lineno = strstr(filename, " "); - if (!lineno) { - fprintf(stderr, "usage: break FILE LINE [type]\n"); - continue; - } - - /* Advance whitespace */ - *lineno = '\0'; - lineno++; - - /* collect optional type */ - int flags = KRK_BREAKPOINT_NORMAL; - char * type = strstr(lineno, " "); - if (type) { - *type = '\0'; type++; - if (!strcmp(type, "repeat") || !strcmp(type,"r")) { - flags = KRK_BREAKPOINT_REPEAT; - } else if (!strcmp(type, "once") || !strcmp(type,"o")) { - flags = KRK_BREAKPOINT_ONCE; - } else { - fprintf(stderr, "Unrecognized breakpoint type: %s\n", type); - continue; - } - } - - int lineInt = atoi(lineno); - int result = krk_debug_addBreakpointFileLine(krk_copyString(filename, strlen(filename)), lineInt, flags); - - if (result == -1) { - fprintf(stderr, "Sorry, couldn't add breakpoint.\n"); - } else { - fprintf(stderr, "Breakpoint %d enabled.\n", result); - } - - } else if (!strcmp(buf, "i") || !strcmp(buf, "info")) { - if (!arg) { - fprintf(stderr, " info breakpoints - Show breakpoints.\n"); - continue; - } - - if (!strcmp(arg,"breakpoints")) { - KrkCodeObject * codeObject = NULL; - size_t offset = 0; - int flags = 0; - int enabled = 0; - int breakIndex = 0; - while (1) { - int result = krk_debug_examineBreakpoint(breakIndex, &codeObject, &offset, &flags, &enabled); - if (result == -1) break; - if (result == -2) continue; - - fprintf(stderr, "%-4d in %s+%d %s %s\n", - breakIndex, - codeObject->name->chars, - (int)offset, - flags == KRK_BREAKPOINT_NORMAL ? "normal": - flags == KRK_BREAKPOINT_REPEAT ? "repeat" : - flags == KRK_BREAKPOINT_ONCE ? "once" : "?", - enabled ? "enabled" : "disabled"); - - breakIndex++; - } - } else { - fprintf(stderr, "Unrecognized info object: %s\n", arg); - } - - } else if (!strcmp(buf, "e") || !strcmp(buf, "enable")) { - if (!arg) { - fprintf(stderr, "enable requires an argument\n"); - continue; - } - - int breakIndex = atoi(arg); - - if (krk_debug_enableBreakpoint(breakIndex)) { - fprintf(stderr, "Invalid breakpoint handle.\n"); - } else { - fprintf(stderr, "Breakpoint %d enabled.\n", breakIndex); - } - } else if (!strcmp(buf, "d") || !strcmp(buf, "disable")) { - if (!arg) { - fprintf(stderr, "disable requires an argument\n"); - continue; - } - - int breakIndex = atoi(arg); - - if (krk_debug_disableBreakpoint(breakIndex)) { - fprintf(stderr, "Invalid breakpoint handle.\n"); - } else { - fprintf(stderr, "Breakpoint %d disabled.\n", breakIndex); - } - } else if (!strcmp(buf, "r") || !strcmp(buf, "remove")) { - if (!arg) { - fprintf(stderr, "remove requires an argument\n"); - continue; - } - - int breakIndex = atoi(arg); - - if (krk_debug_removeBreakpoint(breakIndex)) { - fprintf(stderr, "Invalid breakpoint handle.\n"); - } else { - fprintf(stderr, "Breakpoint %d removed.\n", breakIndex); - } - } else if (!strcmp(buf, "help")) { - fprintf(stderr, - "Kuroko Interactive Debugger\n" - " c continue - Continue until the next breakpoint.\n" - " s step - Execute this instruction and return to the debugger.\n" - " bt backtrace - Print a backtrace.\n" - " q quit - Exit the interpreter.\n" - " abort - Abort the interpreter (may create a core dump).\n" - " b break ... - Set a breakpoint.\n" - " e enable N - Enable breakpoint 'N'.\n" - " d disable N - Disable breakpoint 'N'.\n" - " r remove N - Remove breakpoint 'N'.\n" - " i info ... - See information about breakpoints.\n" - "\n" - "Empty input lines will repeat the last command.\n" - ); - } else { - fprintf(stderr, "Unrecognized command: %s\n", buf); - } - - } - - return KRK_DEBUGGER_CONTINUE; -_dbgQuit: - return KRK_DEBUGGER_QUIT; -} -#endif - -static void handleSigint(int sigNum) { - /* Don't set the signal flag if the VM is not running */ - if (!krk_currentThread.frameCount) return; - krk_currentThread.flags |= KRK_THREAD_SIGNALLED; -} - -#ifndef _WIN32 -static void handleSigtrap(int sigNum) { - if (!krk_currentThread.frameCount) return; - krk_currentThread.flags |= KRK_THREAD_SINGLE_STEP; -} -#endif - -static void bindSignalHandlers(void) { -#if !defined(_WIN32) && !defined(__toaru__) - struct sigaction sigIntAction; - sigIntAction.sa_handler = handleSigint; - sigemptyset(&sigIntAction.sa_mask); - sigIntAction.sa_flags = 0; /* Do not restore the default, do not restart syscalls, do not pass go, do not collect $500 */ - sigaction( - SIGINT, /* ^C for keyboard interrupts */ - &sigIntAction, - NULL); - - struct sigaction sigTrapAction; - sigTrapAction.sa_handler = handleSigtrap; - sigemptyset(&sigTrapAction.sa_mask); - sigTrapAction.sa_flags = 0; - sigaction( - SIGTRAP, - &sigTrapAction, - NULL); -#else - signal(SIGINT, handleSigint); -# ifndef _WIN32 - signal(SIGTRAP, handleSigtrap); - /* No SIGTRAP on windows? */ -# endif -#endif -} - -static void findInterpreter(char * argv[]) { -#ifdef _WIN32 - vm.binpath = strdup(_pgmptr); -#else - /* Try asking /proc */ - char tmp[4096]; - char * binpath = realpath("/proc/self/exe", tmp); - if (!binpath || (access(binpath, X_OK) != 0)) { - if (strchr(argv[0], '/')) { - binpath = realpath(argv[0], tmp); - } else { - /* Search PATH for argv[0] */ - char * _path = strdup(getenv("PATH")); - char * path = _path; - while (path) { - char * next = strchr(path,':'); - if (next) *next++ = '\0'; - - snprintf(tmp, 4096, "%s/%s", path, argv[0]); - if (access(tmp, X_OK) == 0) { - binpath = tmp; - break; - } - path = next; - } - free(_path); - } - } - if (binpath) { - vm.binpath = strdup(binpath); - } /* Else, give up at this point and just don't attach it at all. */ -#endif -} - -static int runString(char * argv[], int flags, char * string) { - findInterpreter(argv); - krk_initVM(flags); - krk_startModule("__main__"); - krk_attachNamedValue(&krk_currentThread.module->fields,"__doc__", NONE_VAL()); - krk_interpret(string, ""); - krk_freeVM(); - return 0; -} - -static int compileFile(char * argv[], int flags, char * fileName) { - findInterpreter(argv); - krk_initVM(flags); - - /* Open the file. */ - FILE * f = fopen(fileName,"r"); - if (!f) { - fprintf(stderr, "%s: could not read file '%s': %s\n", argv[0], fileName, strerror(errno)); - return 1; - } - - /* Read it like we normally do... */ - fseek(f, 0, SEEK_END); - size_t size = ftell(f); - fseek(f, 0, SEEK_SET); - char * buf = malloc(size+1); - if (fread(buf, 1, size, f) != size) return 2; - fclose(f); - buf[size] = '\0'; - - /* Set up a module scope */ - krk_startModule("__main__"); - - /* Call the compiler directly. */ - KrkCodeObject * func = krk_compile(buf, fileName); - - /* See if there was an exception. */ - if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { - krk_dumpTraceback(); - } - - /* Free the source string */ - free(buf); - - /* Close out the compiler */ - krk_freeVM(); - - return func == NULL; -} - -#ifdef BUNDLE_LIBS -#define BUNDLED(name) do { \ - extern KrkValue krk_module_onload_ ## name (); \ - KrkValue moduleOut = krk_module_onload_ ## name (); \ - krk_attachNamedValue(&vm.modules, # name, moduleOut); \ - krk_attachNamedObject(&AS_INSTANCE(moduleOut)->fields, "__name__", (KrkObj*)krk_copyString(#name, sizeof(#name)-1)); \ - krk_attachNamedValue(&AS_INSTANCE(moduleOut)->fields, "__file__", NONE_VAL()); \ -} while (0) -#endif - -int main(int argc, char * argv[]) { -#ifdef _WIN32 - SetConsoleOutputCP(65001); - SetConsoleCP(65001); -#endif - char * runCmd = NULL; - int flags = 0; - int moduleAsMain = 0; - int inspectAfter = 0; - int opt; - while ((opt = getopt(argc, argv, "+:c:C:dgGim:rstTMSV-:")) != -1) { - switch (opt) { - case 'c': - runCmd = optarg; - goto _finishArgs; - case 'd': - /* Disassemble code blocks after compilation. */ - flags |= KRK_THREAD_ENABLE_DISASSEMBLY; - break; - case 'g': - /* Always garbage collect during an allocation. */ - flags |= KRK_GLOBAL_ENABLE_STRESS_GC; - break; - case 'G': - flags |= KRK_GLOBAL_REPORT_GC_COLLECTS; - break; - case 's': - /* Print debug information during compilation. */ - flags |= KRK_THREAD_ENABLE_SCAN_TRACING; - break; - case 'S': - flags |= KRK_THREAD_SINGLE_STEP; - break; - case 't': - /* Disassemble instructions as they are executed. */ - flags |= KRK_THREAD_ENABLE_TRACING; - break; - case 'T': { - flags |= KRK_GLOBAL_CALLGRIND; - vm.callgrindFile = fopen(CALLGRIND_TMP_FILE,"w"); - break; - } - case 'i': - inspectAfter = 1; - break; - case 'm': - moduleAsMain = 1; - optind--; /* to get us back to optarg */ - goto _finishArgs; - case 'r': - enableRline = 0; - break; - case 'M': - return runString(argv,0,"import kuroko; print(kuroko.module_paths)\n"); - case 'V': - return runString(argv,0,"import kuroko; print('Kuroko',kuroko.version)\n"); - case 'C': - return compileFile(argv,flags,optarg); - case ':': - fprintf(stderr, "%s: option '%c' requires an argument\n", argv[0], optopt); - return 1; - case '?': - if (optopt != '-') { - fprintf(stderr, "%s: unrecognized option '%c'\n", argv[0], optopt); - return 1; - } - optarg = argv[optind]+2; - /* fall through */ - case '-': - if (!strcmp(optarg,"version")) { - return runString(argv,0,"import kuroko; print('Kuroko',kuroko.version)\n"); - } else if (!strcmp(optarg,"help")) { -#ifndef KRK_NO_DOCUMENTATION - fprintf(stderr,"usage: %s [flags] [FILE...]\n" - "\n" - "Interpreter options:\n" - " -d Debug output from the bytecode compiler.\n" - " -g Collect garbage on every allocation.\n" - " -G Report GC collections.\n" - " -i Enter repl after a running -c, -m, or FILE.\n" - " -m mod Run a module as a script.\n" - " -r Disable complex line editing in the REPL.\n" - " -s Debug output from the scanner/tokenizer.\n" - " -t Disassemble instructions as they are exceuted.\n" - " -T Write call trace file.\n" - " -C file Compile 'file', but do not execute it.\n" - " -M Print the default module import paths.\n" - " -S Enable single-step debugging.\n" - " -V Print version information.\n" - "\n" - " --version Print version information.\n" - " --help Show this help text.\n" - "\n" - "If no files are provided, the interactive REPL will run.\n", - argv[0]); -#endif - return 0; - } else { - fprintf(stderr,"%s: unrecognized option '--%s'\n", - argv[0], optarg); - return 1; - } - } - } - -_finishArgs: - findInterpreter(argv); - krk_initVM(flags); - -#ifndef KRK_DISABLE_DEBUG - krk_debug_registerCallback(debuggerHook); -#endif - - /* Attach kuroko.argv - argv[0] will be set to an empty string for the repl */ - if (argc == optind) krk_push(OBJECT_VAL(krk_copyString("",0))); - for (int arg = optind; arg < argc; ++arg) { - krk_push(OBJECT_VAL(krk_copyString(argv[arg],strlen(argv[arg])))); - } - KrkValue argList = krk_list_of(argc - optind + (optind == argc), &krk_currentThread.stackTop[-(argc - optind + (optind == argc))],0); - krk_push(argList); - krk_attachNamedValue(&vm.system->fields, "argv", argList); - krk_pop(); - for (int arg = optind; arg < argc + (optind == argc); ++arg) krk_pop(); - - /* Bind interrupt signal */ - bindSignalHandlers(); - -#ifdef BUNDLE_LIBS - /* Add any other modules you want to include that are normally built as shared objects. */ - BUNDLED(math); - BUNDLED(socket); -#endif - - KrkValue result = INTEGER_VAL(0); - - /** - * Add general builtins that aren't part of the core VM. - * This is where we provide @c input in particular. - */ - KRK_DOC(BIND_FUNC(vm.builtins,input), "@brief Read a line of input.\n" - "@arguments [prompt], promptwidth=None, syntax=None\n\n" - "Read a line of input from @c stdin. If the @c rline library is available, " - "it will be used to gather input. Input reading stops on end-of file or when " - "a read ends with a line feed, which will be removed from the returned string. " - "If a prompt is provided, it will be printed without a line feed before requesting " - "input. If @c rline is available, the prompt will be passed to the library as the " - "left-hand prompt string. If not provided, @p promptwidth will default to the width " - "of @p prompt in codepoints; if you are providing a prompt with escape characters or " - "characters with multi-column East-Asian Character Width be sure to pass a value " - "for @p promptwidth that reflects the display width of your prompt. " - "If provided, @p syntax specifies the name of an @c rline syntax module to " - "provide color highlighting of the input line."); - - if (moduleAsMain) { - krk_push(OBJECT_VAL(krk_copyString("__main__",8))); - int out = !krk_importModule( - AS_STRING(AS_LIST(argList)->values[0]), - AS_STRING(krk_peek(0))); - if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { - krk_dumpTraceback(); - krk_resetStack(); - } - if (!inspectAfter) return out; - if (IS_INSTANCE(krk_peek(0))) { - krk_currentThread.module = AS_INSTANCE(krk_peek(0)); - } - } else if (optind != argc) { - krk_startModule("__main__"); - result = krk_runfile(argv[optind],argv[optind]); - if (IS_NONE(result) && krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) result = INTEGER_VAL(1); - } - - if (!krk_currentThread.module) { - /* The repl runs in the context of a top-level module so each input - * line can share a globals state with the others. */ - krk_startModule("__main__"); - krk_attachNamedValue(&krk_currentThread.module->fields,"__doc__", NONE_VAL()); - } - - if (runCmd) { - result = krk_interpret(runCmd, ""); - } - - if ((!moduleAsMain && !runCmd && optind == argc) || inspectAfter) { - /* Add builtins for the repl, but hide them from the globals() list. */ - KRK_DOC(BIND_FUNC(vm.builtins,exit), "@brief Exit the interactive repl.\n\n" - "Only available from the interactive interpreter; exits the repl."); - KRK_DOC(BIND_FUNC(vm.builtins,paste), "@brief Toggle paste mode.\n" - "@arguments enabled=None\n\n" - "Toggles paste-safe mode, disabling automatic indentation in the repl. " - "If @p enabled is specified, the mode can be directly specified, otherwise " - "it will be set to the opposite of the current mode. The new mode will be " - "printed to stderr."); - - /** - * Python stores version info in a built-in module called `sys`. - * We are not Python, we'll use `sys` to pretend to be Python - * in emulation mode, so we use a different module to store - * this sort of thing: kuroko - * - * This module won't be imported by default, but it's still in - * the modules list, so we can look for it there. - */ - KrkValue systemModule; - if (krk_tableGet(&vm.modules, OBJECT_VAL(krk_copyString("kuroko",6)), &systemModule)) { - KrkValue version, buildenv, builddate; - krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("version",7)), &version); - krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("buildenv",8)), &buildenv); - krk_tableGet(&AS_INSTANCE(systemModule)->fields, OBJECT_VAL(krk_copyString("builddate",9)), &builddate); - - fprintf(stdout, "Kuroko %s (%s) with %s\n", - AS_CSTRING(version), AS_CSTRING(builddate), AS_CSTRING(buildenv)); - } - - fprintf(stdout, "Type `help` for guidance, `paste()` to toggle automatic indentation, `license` for copyright information.\n"); - - while (!exitRepl) { - size_t lineCapacity = 8; - size_t lineCount = 0; - char ** lines = ALLOCATE(char *, lineCapacity); - size_t totalData = 0; - int valid = 1; - char * allData = NULL; - int inBlock = 0; - int blockWidth = 0; - -#ifndef NO_RLINE - /* Main prompt is >>> like in Python */ - rline_exp_set_prompts(PROMPT_MAIN, "", 4, 0); - /* Set ^D to send EOF */ - rline_exit_string=""; - /* Enable syntax highlight for Kuroko */ - rline_exp_set_syntax("krk"); - /* Bind a callback for \t */ - rline_exp_set_tab_complete_func(tab_complete_func); -#endif - - while (1) { - /* This would be a nice place for line editing */ - char buf[4096] = {0}; - -#ifndef NO_RLINE - if (inBlock) { - /* When entering multiple lines, the additional lines - * will show a single > (and keep the left side aligned) */ - rline_exp_set_prompts(PROMPT_BLOCK, "", 4, 0); - /* Also add indentation as necessary */ - if (!pasteEnabled) { - rline_preload = malloc(blockWidth + 1); - for (int i = 0; i < blockWidth; ++i) { - rline_preload[i] = ' '; - } - rline_preload[blockWidth] = '\0'; - } - } - - if (!enableRline) { -#else - if (1) { -#endif - fprintf(stdout, "%s", inBlock ? PROMPT_BLOCK : PROMPT_MAIN); - fflush(stdout); - } - -#ifndef NO_RLINE - rline_scroll = 0; - if (enableRline) { - if (rline(buf, 4096) == 0) { - valid = 0; - exitRepl = 1; - break; - } - } else { -#endif - char * out = fgets(buf, 4096, stdin); - if (!out || !strlen(buf)) { - fprintf(stdout, "^D\n"); - valid = 0; - exitRepl = 1; - break; - } -#ifndef NO_RLINE - } -#endif - - if (buf[strlen(buf)-1] != '\n') { - /* rline shouldn't allow this as it doesn't accept ^D to submit input - * unless the line is empty, but just in case... */ - fprintf(stderr, "Expected end of line in repl input. Did you ^D early?\n"); - valid = 0; - break; - } - - if (lineCapacity < lineCount + 1) { - /* If we need more space, grow as needed... */ - size_t old = lineCapacity; - lineCapacity = GROW_CAPACITY(old); - lines = GROW_ARRAY(char *,lines,old,lineCapacity); - } - - int i = lineCount++; - lines[i] = strdup(buf); - - size_t lineLength = strlen(lines[i]); - totalData += lineLength; - - /* Figure out indentation */ - int isSpaces = 1; - int countSpaces = 0; - for (size_t j = 0; j < lineLength; ++j) { - if (lines[i][j] != ' ' && lines[i][j] != '\n') { - isSpaces = 0; - break; - } - countSpaces += 1; - } - - /* Naively detect the start of a new block so we can - * continue to accept input. Our compiler isn't really - * set up to let us compile "on the fly" so we can't just - * run lines through it and see if it wants more... */ - if (lineLength > 1 && lines[i][lineLength-2] == ':') { - inBlock = 1; - blockWidth = countSpaces + 4; - continue; - } else if (lineLength > 1 && lines[i][lineLength-2] == '\\') { - inBlock = 1; - continue; - } else if (inBlock && lineLength != 1) { - if (isSpaces) { - free(lines[i]); - totalData -= lineLength; - lineCount--; - break; - } - blockWidth = countSpaces; - continue; - } else if (lineLength > 1 && lines[i][countSpaces] == '@') { - inBlock = 1; - blockWidth = countSpaces; - continue; - } - - /* Ignore blank lines. */ - if (isSpaces && !i) valid = 0; - - /* If we're not in a block, or have entered a blank line, - * we can stop reading new lines and jump to execution. */ - break; - } - - if (valid) { - allData = malloc(totalData + 1); - allData[0] = '\0'; - } - - for (size_t i = 0; i < lineCount; ++i) { - if (valid) strcat(allData, lines[i]); -#ifndef NO_RLINE - if (enableRline) { - rline_history_insert(strdup(lines[i])); - rline_scroll = 0; - } -#endif - free(lines[i]); - } - FREE_ARRAY(char *, lines, lineCapacity); - - if (valid) { - KrkValue result = krk_interpret(allData, ""); - if (!IS_NONE(result)) { - KrkClass * type = krk_getType(result); - const char * formatStr = " \033[1;30m=> %s\033[0m\n"; - if (type->_reprer) { - krk_push(result); - result = krk_callDirect(type->_reprer, 1); - } else if (type->_tostr) { - krk_push(result); - result = krk_callDirect(type->_tostr, 1); - } - if (!IS_STRING(result)) { - fprintf(stdout, " \033[1;31m=> Unable to produce representation for value.\033[0m\n"); - } else { - fprintf(stdout, formatStr, AS_CSTRING(result)); - } - } - krk_resetStack(); - free(allData); - } - - (void)blockWidth; - } - } - - if (vm.globalFlags & KRK_GLOBAL_CALLGRIND) { - fclose(vm.callgrindFile); - vm.globalFlags &= ~(KRK_GLOBAL_CALLGRIND); - - krk_resetStack(); - krk_startModule(""); - krk_attachNamedObject(&krk_currentThread.module->fields, "filename", (KrkObj*)S(CALLGRIND_TMP_FILE)); - krk_interpret( - "from callgrind import processFile\n" - "import kuroko\n" - "import os\n" - "processFile(filename, os.getpid(), ' '.join(kuroko.argv))",""); - } - - krk_freeVM(); - - if (IS_INTEGER(result)) return AS_INTEGER(result); - - return 0; -} diff --git a/apps/lspci.c b/apps/lspci.c index c27731a1..8d9c33c1 100644 --- a/apps/lspci.c +++ b/apps/lspci.c @@ -63,10 +63,16 @@ struct { {0x15ad, 0x0405, "SVGA II Adapter"}, {0x15ad, 0x0790, "PCI bridge"}, {0x15ad, 0x07a0, "PCI Express Root Port"}, - {0x8086, 0x100e, "Gigabit Ethernet Controller (e1000)"}, - {0x8086, 0x100f, "Gigabit Ethernet Controller (e1000)"}, + {0x8086, 0x1004, "82543GC Gigabit Ethernet Controller (e1000)"}, + {0x8086, 0x100e, "82540EM Gigabit Ethernet Controller (e1000)"}, + {0x8086, 0x100f, "82545EM Gigabit Ethernet Controller (e1000)"}, + {0x8086, 0x10ea, "82577LM Gigabit Ethernet Controller (e1000)"}, {0x8086, 0x1237, "PCI & Memory"}, - {0x8086, 0x2415, "AC'97 Audio Chipset"}, + {0x8086, 0x2415, "82801AA AC'97 Audio Controller"}, + {0x8086, 0x29c0, "DRAM Controller"}, + {0x8086, 0x2918, "ICH9 LPC Interface Controller"}, + {0x8086, 0x2922, "ICH9 6-port SATA Controller"}, + {0x8086, 0x2930, "ICH9 SMBus Controller"}, {0x8086, 0x7000, "PCI-to-ISA Bridge"}, {0x8086, 0x7010, "IDE Interface"}, {0x8086, 0x7110, "PIIX4 ISA"}, diff --git a/apps/migrate.c b/apps/migrate.c index fc60f4c9..0fdace1a 100644 --- a/apps/migrate.c +++ b/apps/migrate.c @@ -217,7 +217,7 @@ int main(int argc, char * argv[]) { } char * root_type = hashmap_get(cmdline,"root_type"); if (!root_type) { - root_type = "ext2"; + root_type = "tar"; } char tmp[1024]; diff --git a/apps/misaka-test.c b/apps/misaka-test.c new file mode 100644 index 00000000..9293da3d --- /dev/null +++ b/apps/misaka-test.c @@ -0,0 +1,66 @@ +/** + * @file misaka-test.c + * @brief Test app for Misaka with a bunch of random stuff. + */ +#include +#include +#include +#include + +#include + +#include +#include + +static void demo_runKurokoSnippet(void) { + krk_initVM(0); + krk_startModule("__main__"); + krk_interpret("import kuroko\nprint('Kuroko',kuroko.version)\n", ""); + krk_freeVM(); +} + +static void demo_drawWallpaper(void) { + /* Set up a wrapper context for the framebuffer */ + gfx_context_t * ctx = init_graphics_fullscreen(); + + /* Load the wallpaper. */ + sprite_t wallpaper = { 0 }; + load_sprite(&wallpaper, "/usr/share/wallpaper.jpg"); + wallpaper.alpha = ALPHA_EMBEDDED; + + printf("wallpaper sprite info: %d x %d\n", wallpaper.width, wallpaper.height); + + draw_sprite_scaled(ctx, &wallpaper, 0, 0, 1440, 900); + flip(ctx); + //blur_context_box(&ctx, 10); +} + +int main(int argc, char * argv[]) { + demo_drawWallpaper(); + demo_runKurokoSnippet(); + + //execve("/bin/kuroko",(char*[]){"kuroko",NULL},(char*[]){NULL}); + char * args[] = { + "/bin/sh", + "-c", + "sleep 2; echo hi; echo glorp", + NULL, + }; + pid_t pid = fork(); + if (!pid) { + printf("returned from fork in child\n"); + execvp(args[0], args); + exit(1); + } else { + printf("returned from fork with pid = %d\n", pid); + int status; + waitpid(pid, &status, 0); + printf("done with waitpid, looping\n"); + while (1) { + sched_yield(); + } + return WEXITSTATUS(status); + } + + return 0; +} diff --git a/apps/msk.c b/apps/msk.c index 49d16099..a7ae3227 100644 --- a/apps/msk.c +++ b/apps/msk.c @@ -423,8 +423,8 @@ static int install_packages(int argc, char * argv[]) { } fprintf(stderr, "\nContinue? [Y/n] "); fflush(stderr); - char resp[4]; - fgets(resp, 4, stdin); + char resp[5]; + fgets(resp, 5, stdin); if (!(!strcmp(resp,"\n") || !strcmp(resp,"y\n") || !strcmp(resp,"Y\n") || !strcmp(resp,"yes\n"))) { fprintf(stderr, "Aborting.\n"); return 1; diff --git a/apps/package-manager.c b/apps/package-manager.c index b3ea908f..7cd83cbb 100644 --- a/apps/package-manager.c +++ b/apps/package-manager.c @@ -552,7 +552,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win == main_window) { win->focused = wf->focused; redraw_packages(); @@ -571,7 +571,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_MOUSE_EVENT: { struct yutani_msg_window_mouse_event * me = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid); if (win == main_window) { int result = decor_handle_event(yctx, m); diff --git a/apps/pidof.c b/apps/pidof.c index 90122923..1ef80864 100644 --- a/apps/pidof.c +++ b/apps/pidof.c @@ -26,7 +26,7 @@ typedef struct process { #define LINE_LEN 4096 p_t * build_entry(struct dirent * dent) { - char tmp[256]; + char tmp[300]; FILE * f; char line[LINE_LEN]; diff --git a/apps/plasma.c b/apps/plasma.c index 047b6cdc..dc00dabf 100644 --- a/apps/plasma.c +++ b/apps/plasma.c @@ -163,7 +163,7 @@ int main (int argc, char ** argv) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win && win == wina) { win->focused = wf->focused; } diff --git a/apps/pong.c b/apps/pong.c index 03e1a6ed..d52aa371 100644 --- a/apps/pong.c +++ b/apps/pong.c @@ -177,7 +177,7 @@ void update_stuff(void) { if (colliding(&ball, &left)) { ball.x = left.x + left.width + 2; - ball.vel_x = (abs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x; + ball.vel_x = (fabs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x; double intersect = ((ball.y + ball.height/2) - (left.y)) / ((double)left.height) - 0.5; ball.vel_y = intersect * 8.0; @@ -186,7 +186,7 @@ void update_stuff(void) { if (colliding(&ball, &right)) { ball.x = right.x - ball.width - 2; - ball.vel_x = (abs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x; + ball.vel_x = (fabs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x; double intersect = ((ball.y + ball.height/2) - (right.y)) / ((double)right.height/2.0); ball.vel_y = intersect * 3.0; diff --git a/apps/ps.c b/apps/ps.c index f07acc72..d4cadb57 100644 --- a/apps/ps.c +++ b/apps/ps.c @@ -55,7 +55,7 @@ void print_username(int uid) { } struct process * process_entry(struct dirent *dent) { - char tmp[256]; + char tmp[300]; FILE * f; char line[LINE_LEN]; diff --git a/apps/pstree.c b/apps/pstree.c index 69461c4f..e3cb667e 100644 --- a/apps/pstree.c +++ b/apps/pstree.c @@ -29,7 +29,7 @@ typedef struct process { #define LINE_LEN 4096 p_t * build_entry(struct dirent * dent) { - char tmp[256]; + char tmp[300]; FILE * f; char line[LINE_LEN]; @@ -87,7 +87,7 @@ p_t * build_entry(struct dirent * dent) { uint8_t find_pid(void * proc_v, void * pid_v) { p_t * p = proc_v; - pid_t i = (pid_t)pid_v; + pid_t i = (pid_t)(uintptr_t)pid_v; return (uint8_t)(p->pid == i); } @@ -161,7 +161,7 @@ int main (int argc, char * argv[]) { if (proc->ppid == 0 && proc->pid == 1) { tree_set_root(procs, proc); } else { - tree_node_t * parent = tree_find(procs,(void *)proc->ppid,find_pid); + tree_node_t * parent = tree_find(procs,(void *)(uintptr_t)proc->ppid,find_pid); if (parent) { tree_node_insert_child(procs, parent, proc); } diff --git a/apps/readelf.c b/apps/readelf.c index fdda7522..fa33c85e 100644 --- a/apps/readelf.c +++ b/apps/readelf.c @@ -1,256 +1,688 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2018 K Lange +/** + * @file readelf.c + * @brief Display information about a 64-bit Elf binary or object. * - * readelf - Show information about ELF objects - * - * This is a very custom implementation and nothing remotely - * like the version that comes with binutils. Making it more - * like that version might be worthwhile. + * Implementation of a `readelf` utility. */ #include -#include -#include #include +#include #include #include -/** - * Show usage for the readelf application. - * @param argc Argument count (unused) - * @param argv Arguments to binary - */ -void usage(int argc, char ** argv) { - /* Show usage */ - printf("%s [filename]\n", argv[0]); - printf("\tDisplays information on ELF binaries such as section names,\n"); - printf("\tlocations, sizes, and loading positions in memory.\n"); - exit(1); + +static const char * elf_classToStr(unsigned char ei_class) { + static char buf[64]; + switch (ei_class) { + case ELFCLASS32: return "ELF32"; + case ELFCLASS64: return "ELF64"; + default: + sprintf(buf, "unknown (%d)", ei_class); + return buf; + } } -/** - * Application entry point. - * @returns 0 on sucess, 1 on failure - */ -int main(int argc, char ** argv) { - /* Process arguments */ - if (argc < 2) usage(argc,argv); +static const char * elf_dataToStr(unsigned char ei_data) { + static char buf[64]; + switch (ei_data) { + case ELFDATA2LSB: return "2's complement, little endian"; + case ELFDATA2MSB: return "2's complement, big endian"; + default: + sprintf(buf, "unknown (%d)", ei_data); + return buf; + } +} - FILE * binary; /**< File pointer for requested executable */ - size_t binary_size; /**< Size of the file */ - char * binary_buf; /**< Buffer to store the binary in memory */ - Elf32_Header * header; /**< ELF header */ - char * string_table = NULL; /**< The section header string table */ - char * sym_string_table = NULL; /**< The symbol string table */ +static char * elf_versionToStr(unsigned char ei_version) { + static char buf[64]; + switch (ei_version) { + case 1: return "1 (current)"; + default: + sprintf(buf, "unknown (%d)", ei_version); + return buf; + } +} - /* Open the requested binary */ - binary = fopen(argv[1], "r"); +static char * elf_osabiToStr(unsigned char ei_osabi) { + static char buf[64]; + switch (ei_osabi) { + case 0: return "UNIX - System V"; + case 1: return "HP-UX"; + case 255: return "Standalone"; + default: + sprintf(buf, "unknown (%d)", ei_osabi); + return buf; + } +} - if (!binary) { +static char * elf_typeToStr(Elf64_Half type) { + static char buf[64]; + switch (type) { + case ET_NONE: return "NONE (No file type)"; + case ET_REL: return "REL (Relocatable object file)"; + case ET_EXEC: return "EXEC (Executable file)"; + case ET_DYN: return "DYN (Shared object file)"; + case ET_CORE: return "CORE (Core file)"; + default: + sprintf(buf, "unknown (%d)", type); + return buf; + } +} + +static char * elf_machineToStr(Elf64_Half machine) { + static char buf[64]; + switch (machine) { + case EM_X86_64: return "Advanced Micro Devices X86-64"; + default: + sprintf(buf, "unknown (%d)", machine); + return buf; + } +} + +static char * sectionHeaderTypeToStr(Elf64_Word type) { + static char buf[64]; + switch (type) { + case SHT_NULL: return "NULL"; + case SHT_PROGBITS: return "PROGBITS"; + case SHT_SYMTAB: return "SYMTAB"; + case SHT_STRTAB: return "STRTAB"; + case SHT_RELA: return "RELA"; + case SHT_HASH: return "HASH"; + case SHT_DYNAMIC: return "DYNAMIC"; + case SHT_NOTE: return "NOTE"; + case SHT_NOBITS: return "NOBITS"; + case SHT_REL: return "REL"; + case SHT_SHLIB: return "SHLIB"; + case SHT_DYNSYM: return "DYNSYM"; + + case 0xE: return "INIT_ARRAY"; + case 0xF: return "FINI_ARRAY"; + case 0x6ffffff6: return "GNU_HASH"; + case 0x6ffffffe: return "VERNEED"; + case 0x6fffffff: return "VERSYM"; + default: + sprintf(buf, "(%x)", type); + return buf; + } +} + +static char * programHeaderTypeToStr(Elf64_Word type) { + static char buf[64]; + switch (type) { + case PT_NULL: return "NULL"; + case PT_LOAD: return "LOAD"; + case PT_DYNAMIC: return "DYNAMIC"; + case PT_INTERP: return "INTERP"; + case PT_NOTE: return "NOTE"; + case PT_PHDR: return "PHDR"; + case PT_GNU_EH_FRAME: return "GNU_EH_FRAME"; + + case 0x6474e553: return "GNU_PROPERTY"; + case 0x6474e551: return "GNU_STACK"; + case 0x6474e552: return "GNU_RELRO"; + + default: + sprintf(buf, "(%x)", type); + return buf; + } +} + +static char * programHeaderFlagsToStr(Elf64_Word flags) { + static char buf[10]; + + snprintf(buf, 10, "%c%c%c ", + (flags & PF_R) ? 'R' : ' ', + (flags & PF_W) ? 'W' : ' ', + (flags & PF_X) ? 'E' : ' '); /* yes, E, not X... */ + + return buf; +} + +static char * dynamicTagToStr(Elf64_Dyn * dynEntry, char * dynstr) { + static char buf[1024]; + static char extra[500]; + char * name = NULL; + sprintf(extra, "0x%lx", dynEntry->d_un.d_val); + + switch (dynEntry->d_tag) { + case DT_NULL: + name = "(NULL)"; + break; + case DT_NEEDED: + name = "(NEEDED)"; + sprintf(extra, "[shared lib = %s]", dynstr + dynEntry->d_un.d_val); + break; + case DT_PLTRELSZ: + name = "(PLTRELSZ)"; + break; + case DT_PLTGOT: + name = "(PLTGOT)"; + break; + case DT_HASH: + name = "(HASH)"; + break; + case DT_STRTAB: + name = "(STRTAB)"; + break; + case DT_SYMTAB: + name = "(SYMTAB)"; + break; + case DT_RELA: + name = "(RELA)"; + break; + case DT_RELASZ: + name = "(RELASZ)"; + break; + case DT_RELAENT: + name = "(RELAENT)"; + break; + case DT_STRSZ: + name = "(STRSZ)"; + sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val); + break; + case DT_SYMENT: + name = "(SYMENT)"; + sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val); + break; + case DT_INIT: + name = "(INIT)"; + break; + case DT_FINI: + name = "(FINI)"; + break; + case DT_SONAME: + name = "(SONAME)"; + break; + case DT_RPATH: + name = "(RPATH)"; + break; + case DT_SYMBOLIC: + name = "(SYMBOLIC)"; + break; + case DT_REL: + name = "(REL)"; + break; + case DT_RELSZ: + name = "(RELSZ)"; + sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val); + break; + case DT_RELENT: + name = "(RELENT)"; + break; + case DT_PLTREL: + name = "(PLTREL)"; + sprintf(extra, "%s", + dynEntry->d_un.d_val == DT_REL ? "REL" : "RELA"); + break; + case DT_DEBUG: + name = "(DEBUG)"; + break; + case DT_TEXTREL: + name = "(TEXTREL)"; + break; + case DT_JMPREL: + name = "(JMPREL)"; + break; + case DT_BIND_NOW: + name = "(BIND_NOW)"; + break; + case DT_INIT_ARRAY: + name = "(INIT_ARRAY)"; + break; + case DT_FINI_ARRAY: + name = "(FINI_ARRAY)"; + break; + case DT_INIT_ARRAYSZ: + name = "(INIT_ARRAYSZ)"; + sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val); + break; + case DT_FINI_ARRAYSZ: + name = "(FINI_ARRASZ)"; + sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val); + break; + case 0x1E: + name = "(FLAGS)"; + break; + case 0x6ffffef5: + name = "(GNU_HASH)"; + break; + case 0x6ffffffb: + name = "(FLAGS_1)"; + break; + case 0x6ffffffe: + name = "(VERNEED)"; + break; + case 0x6fffffff: + name = "(VERNEEDNUM)"; + sprintf(extra, "%ld", dynEntry->d_un.d_val); + break; + case 0x6ffffff0: + name = "(VERSYM)"; + break; + case 0x6ffffff9: + name = "(RELACOUNT)"; + sprintf(extra, "%ld", dynEntry->d_un.d_val); + break; + default: + name = "(unknown)"; + break; + } + + sprintf(buf,"%-15s %s", name, extra); + return buf; +} + +static char * relocationInfoToStr(Elf64_Xword info) { +#define CASE(o) case o: return #o; + switch (info) { + CASE(R_X86_64_NONE) + CASE(R_X86_64_64) + CASE(R_X86_64_PC32) + CASE(R_X86_64_GOT32) + CASE(R_X86_64_PLT32) + CASE(R_X86_64_COPY) + CASE(R_X86_64_GLOB_DAT) + CASE(R_X86_64_JUMP_SLOT) + CASE(R_X86_64_RELATIVE) + CASE(R_X86_64_GOTPCREL) + CASE(R_X86_64_32) + CASE(R_X86_64_32S) + CASE(R_X86_64_DTPMOD64) + CASE(R_X86_64_DTPOFF64) + CASE(R_X86_64_TPOFF64) + CASE(R_X86_64_TLSGD) + CASE(R_X86_64_TLSLD) + CASE(R_X86_64_DTPOFF32) + CASE(R_X86_64_GOTTPOFF) + CASE(R_X86_64_TPOFF32) + CASE(R_X86_64_PC64) + CASE(R_X86_64_GOTOFF64) + CASE(R_X86_64_GOTPC32) + CASE(R_X86_64_GOT64) + CASE(R_X86_64_GOTPCREL64) + CASE(R_X86_64_GOTPC64) + CASE(R_X86_64_GOTPLT64) + CASE(R_X86_64_PLTOFF64) + CASE(R_X86_64_SIZE32) + CASE(R_X86_64_SIZE64) + CASE(R_X86_64_GOTPC32_TLSDESC) + CASE(R_X86_64_TLSDESC_CALL) + CASE(R_X86_64_TLSDESC) + CASE(R_X86_64_IRELATIVE) + default: + return "unknown"; + } +#undef CASE +} + +static int sizeOfRelocationValue(int type) { + switch (type) { + case R_X86_64_TLSDESC: + return 16; + case R_X86_64_64: + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + case R_X86_64_RELATIVE: + case R_X86_64_DTPMOD64: + case R_X86_64_DTPOFF64: + case R_X86_64_TPOFF64: + case R_X86_64_PC64: + case R_X86_64_GOTOFF64: + case R_X86_64_GOT64: + case R_X86_64_GOTPCREL64: + case R_X86_64_GOTPC64: + case R_X86_64_GOTPLT64: + case R_X86_64_PLTOFF64: + case R_X86_64_SIZE64: + case R_X86_64_IRELATIVE: + return 8; + case R_X86_64_PC32: + case R_X86_64_GOT32: + case R_X86_64_PLT32: + case R_X86_64_GOTPCREL: + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_TLSGD: + case R_X86_64_TLSLD: + case R_X86_64_DTPOFF32: + case R_X86_64_GOTTPOFF: + case R_X86_64_TPOFF32: + case R_X86_64_GOTPC32: + case R_X86_64_SIZE32: + case R_X86_64_GOTPC32_TLSDESC: + return 4; + case R_X86_64_16: + case R_X86_64_PC16: + return 2; + case R_X86_64_8: + case R_X86_64_PC8: + return 1; + case R_X86_64_NONE: + case R_X86_64_COPY: + case R_X86_64_TLSDESC_CALL: + default: + return 0; + } +} + +static char * symbolTypeToStr(int type) { + static char buf[10]; + switch (type) { + case STT_NOTYPE: return "NOTYPE"; + case STT_OBJECT: return "OBJECT"; + case STT_FUNC: return "FUNC"; + case STT_SECTION: return "SECTION"; + case STT_FILE: return "FILE"; + default: + sprintf(buf, "%x", type); + return buf; + } +} + +static char * symbolBindToStr(int bind) { + static char buf[10]; + switch (bind) { + case STB_LOCAL: return "LOCAL"; + case STB_GLOBAL: return "GLOBAL"; + case STB_WEAK: return "WEAK"; + default: + sprintf(buf, "%x", bind); + return buf; + } +} + +int main(int argc, char * argv[]) { + if (argc < 2) { + fprintf(stderr, "%s: expected filename\n", argv[0]); + return 1; + } + + FILE * f = fopen(argv[1],"r"); + + if (!f) { fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno)); return 1; } - /* Jump to the end so we can get the size */ - fseek(binary, 0, SEEK_END); - binary_size = ftell(binary); - fseek(binary, 0, SEEK_SET); + /** + * Validate header. + */ + Elf64_Header header; + fread(&header, sizeof(Elf64_Header), 1, f); - /* Some sanity checks */ - if (binary_size < 4 || binary_size > 0xFFFFFFF) { - printf("Oh no! I don't quite like the size of this binary.\n"); - return 1; - } - printf("Binary is %u bytes.\n", (unsigned int)binary_size); - - /* Read the binary into a buffer */ - binary_buf = malloc(binary_size); - fread((void *)binary_buf, binary_size, 1, binary); - - /* Let's start considering this guy an elf, 'eh? */ - header = (Elf32_Header *)binary_buf; - - /* Verify the magic */ - if ( header->e_ident[0] != ELFMAG0 || - header->e_ident[1] != ELFMAG1 || - header->e_ident[2] != ELFMAG2 || - header->e_ident[3] != ELFMAG3) { - printf("Header magic is wrong!\n"); - printf("Are you sure this is a 32-bit ELF binary or object file?\n"); + if (memcmp("\x7F" "ELF",&header,4)) { + fprintf(stderr, "%s: %s: not an elf\n", argv[0], argv[1]); return 1; } - /* Let's print out some of the header information, shall we? */ - printf("\033[1mELF Header\033[0m\n"); + printf("ELF Header:\n"); + printf(" Magic: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3], + header.e_ident[4], header.e_ident[5], header.e_ident[6], header.e_ident[7], + header.e_ident[8], header.e_ident[9], header.e_ident[10], header.e_ident[11], + header.e_ident[12], header.e_ident[13], header.e_ident[14], header.e_ident[15]); + printf(" Class: %s\n", elf_classToStr(header.e_ident[EI_CLASS])); + printf(" Data: %s\n", elf_dataToStr(header.e_ident[EI_DATA])); + printf(" Version: %s\n", elf_versionToStr(header.e_ident[EI_VERSION])); + printf(" OS/ABI: %s\n", elf_osabiToStr(header.e_ident[EI_OSABI])); + printf(" ABI Version: %u\n", header.e_ident[EI_ABIVERSION]); - /* File type */ - printf("[Type %d] ", header->e_type); - switch (header->e_type) { - case ET_NONE: - printf("No file type.\n"); - break; - case ET_REL: - printf("Relocatable file.\n"); - break; - case ET_EXEC: - printf("Executable file.\n"); - break; - case ET_DYN: - printf("Shared object file.\n"); - break; - case ET_CORE: - printf("Core file.\n"); - break; - default: - printf("(Unknown file type)\n"); - break; + if (header.e_ident[EI_CLASS] != ELFCLASS64) { + return 0; } - /* Machine Type */ - switch (header->e_machine) { - case EM_386: - printf("Intel x86\n"); - break; - default: - printf("Unknown machine: %d\n", header->e_machine); - break; + /* Byte-order dependent from here on out... */ + printf(" Type: %s\n", elf_typeToStr(header.e_type)); + printf(" Machine: %s\n", elf_machineToStr(header.e_machine)); + printf(" Version: 0x%x\n", header.e_version); + printf(" Entry point address: 0x%lx\n", header.e_entry); + printf(" Start of program headers: %lu (bytes into file)\n", header.e_phoff); + printf(" Start of section headers: %lu (bytes into file)\n", header.e_shoff); + printf(" Flags: 0x%x\n", header.e_flags); + printf(" Size of this header: %u (bytes)\n", header.e_ehsize); + printf(" Size of program headers: %u (bytes)\n", header.e_phentsize); + printf(" Number of program headers: %u\n", header.e_phnum); + printf(" Size of section headers: %u (bytes)\n", header.e_shentsize); + printf(" Number of section headers: %u\n", header.e_shnum); + printf(" Section header string table index: %u\n", header.e_shstrndx); + + /* Get the section header string table */ + Elf64_Shdr shstr_hdr; + fseek(f, header.e_shoff + header.e_shentsize * header.e_shstrndx, SEEK_SET); + fread(&shstr_hdr, sizeof(Elf64_Shdr), 1, f); + + char * stringTable = malloc(shstr_hdr.sh_size); + fseek(f, shstr_hdr.sh_offset, SEEK_SET); + fread(stringTable, shstr_hdr.sh_size, 1, f); + + /** + * Section Headers + */ + printf("\nSection Headers:\n"); + printf(" [Nr] Name Type Address Offset\n"); + printf(" Size EntSize Flags Link Info Align\n"); + for (unsigned int i = 0; i < header.e_shnum; ++i) { + fseek(f, header.e_shoff + header.e_shentsize * i, SEEK_SET); + Elf64_Shdr sectionHeader; + fread(§ionHeader, sizeof(Elf64_Shdr), 1, f); + + printf(" [%2d] %-17.17s %-16.16s %016lx %08lx\n", + i, stringTable + sectionHeader.sh_name, sectionHeaderTypeToStr(sectionHeader.sh_type), + sectionHeader.sh_addr, sectionHeader.sh_offset); + printf(" %016lx %016lx %4ld %6d %5d %5ld\n", + sectionHeader.sh_size, sectionHeader.sh_entsize, sectionHeader.sh_flags, + sectionHeader.sh_link, sectionHeader.sh_info, sectionHeader.sh_addralign); } - /* Version == EV_CURRENT? */ - if (header->e_version == EV_CURRENT) { - printf("ELF version is 1, as it should be.\n"); - } + /** + * Program Headers + */ + if (header.e_phoff && header.e_phnum) { + printf("\nProgram Headers:\n"); + printf(" Type Offset VirtAddr PhysAddr\n"); + printf(" FileSiz MemSiz Flags Align\n"); + for (unsigned int i = 0; i < header.e_phnum; ++i) { + fseek(f, header.e_phoff + header.e_phentsize * i, SEEK_SET); + Elf64_Phdr programHeader; + fread(&programHeader, sizeof(Elf64_Phdr), 1, f); - /* Entry point in memory */ - printf("Binary entry point in virtual memory is at 0x%x\n", (unsigned int)header->e_entry); + printf(" %-14.14s 0x%016lx 0x%016lx 0x%016lx\n", + programHeaderTypeToStr(programHeader.p_type), + programHeader.p_offset, programHeader.p_vaddr, programHeader.p_paddr); + printf(" 0x%016lx 0x%016lx %s 0x%lx\n", + programHeader.p_filesz, programHeader.p_memsz, + programHeaderFlagsToStr(programHeader.p_flags), programHeader.p_align); - /* Program header table offset */ - printf("Program header table is at +0x%x and one entry is 0x%x bytes.\n" - "There are %d total program headers.\n", - (unsigned int)header->e_phoff, (unsigned int)header->e_phentsize, (unsigned int)header->e_phnum); - - /* Section header table offset */ - printf("Section header table is at +0x%x and one entry is 0x%x bytes.\n" - "There are %d total section headers.\n", - (unsigned int)header->e_shoff, (unsigned int)header->e_shentsize, (unsigned int)header->e_shnum); - - /* Read the program headers */ - printf("\033[1mProgram Headers\033[0m\n"); - for (uint32_t x = 0; x < header->e_phentsize * header->e_phnum; x += header->e_phentsize) { - if (header->e_phoff + x > binary_size) { - printf("Tried to read beyond the end of the file.\n"); - return 1; + if (programHeader.p_type == PT_INTERP) { + /* Read interpreter string */ + char * tmp = malloc(programHeader.p_filesz); + fseek(f, programHeader.p_offset, SEEK_SET); + fread(tmp, programHeader.p_filesz, 1, f); + printf(" [Requesting program interpreter: %.*s]\n", + (int)programHeader.p_filesz, tmp); + free(tmp); + } } - /* Grab the program header */ - Elf32_Phdr * phdr = (Elf32_Phdr *)((uintptr_t)binary_buf + (header->e_phoff + x)); + } - /* Print the header type */ - switch (phdr->p_type) { - case PT_LOAD: - printf("[Loadable Segment]\n"); + /* TODO Section to segment mapping? */ + + /** + * Dump section information. + */ + for (unsigned int i = 0; i < header.e_shnum; ++i) { + fseek(f, header.e_shoff + header.e_shentsize * i, SEEK_SET); + Elf64_Shdr sectionHeader; + fread(§ionHeader, sizeof(Elf64_Shdr), 1, f); + + /* I think there should only be one of these... */ + switch (sectionHeader.sh_type) { + case SHT_DYNAMIC: + { + printf("\nDynamic section at offset 0x%lx contains (up to) %ld entries:\n", + sectionHeader.sh_offset, sectionHeader.sh_size / sectionHeader.sh_entsize); + printf(" Tag Type Name/Value\n"); + + /* Read the linked string table */ + Elf64_Shdr dynstr; + fseek(f, header.e_shoff + header.e_shentsize * sectionHeader.sh_link, SEEK_SET); + fread(&dynstr, sizeof(Elf64_Shdr), 1, f); + char * dynStr = malloc(dynstr.sh_size); + fseek(f, dynstr.sh_offset, SEEK_SET); + fread(dynStr, dynstr.sh_size, 1, f); + + char * dynTable = malloc(sectionHeader.sh_size); + fseek(f, sectionHeader.sh_offset, SEEK_SET); + fread(dynTable, sectionHeader.sh_size, 1, f); + + for (unsigned int i = 0; i < sectionHeader.sh_size / sectionHeader.sh_entsize; i++) { + Elf64_Dyn * dynEntry = (Elf64_Dyn *)(dynTable + sectionHeader.sh_entsize * i); + + printf(" 0x%016lx %s\n", + dynEntry->d_tag, + dynamicTagToStr(dynEntry, dynStr)); + + if (dynEntry->d_tag == DT_NULL) break; + } + + free(dynStr); + free(dynTable); + } break; - case PT_DYNAMIC: - printf("[Dynamic Loading Information]\n"); + case SHT_RELA: + { + printf("\nRelocation section '%s' at offset 0x%lx contains %ld entries.\n", + stringTable + sectionHeader.sh_name, sectionHeader.sh_offset, + sectionHeader.sh_size / sizeof(Elf64_Rela)); + printf(" Offset Info Type Sym. Value Sym. Name + Addend\n"); + + /* Section this relocation is in */ + Elf64_Shdr shdr_this; + fseek(f, header.e_shoff + header.e_shentsize * sectionHeader.sh_info, SEEK_SET); + fread(&shdr_this, sizeof(Elf64_Shdr), 1, f); + + /* Symbol table link */ + Elf64_Shdr shdr_symtab; + fseek(f, header.e_shoff + header.e_shentsize * sectionHeader.sh_link, SEEK_SET); + fread(&shdr_symtab, sizeof(Elf64_Shdr), 1, f); + Elf64_Sym * symtab = malloc(shdr_symtab.sh_size); + fseek(f, shdr_symtab.sh_offset, SEEK_SET); + fread(symtab, shdr_symtab.sh_size, 1, f); + + /* Symbol table's string table link */ + Elf64_Shdr shdr_strtab; + fseek(f, header.e_shoff + header.e_shentsize * shdr_symtab.sh_link, SEEK_SET); + fread(&shdr_strtab, sizeof(Elf64_Shdr), 1, f); + char * strtab = malloc(shdr_strtab.sh_size); + fseek(f, shdr_strtab.sh_offset, SEEK_SET); + fread(strtab, shdr_strtab.sh_size, 1, f); + + /* Load relocations from file */ + Elf64_Rela * relocations = malloc(sectionHeader.sh_size); + fseek(f, sectionHeader.sh_offset, SEEK_SET); + fread((void*)relocations, sectionHeader.sh_size, 1, f); + + for (unsigned int i = 0; i < sectionHeader.sh_size / sizeof(Elf64_Rela); ++i) { + Elf64_Shdr shdr; + Elf64_Sym * this = &symtab[ELF64_R_SYM(relocations[i].r_info)]; + char * symName; + + /* Get symbol name for this relocation */ + if ((this->st_info & 0xF) == STT_SECTION) { + fseek(f, header.e_shoff + header.e_shentsize * this->st_shndx, SEEK_SET); + fread(&shdr, sizeof(Elf64_Shdr), 1, f); + symName = stringTable + shdr.sh_name; + } else { + symName = strtab + this->st_name; + } + + /* Get the value currently in the section data */ + Elf64_Xword value = 0; + int valueSize = sizeOfRelocationValue(ELF64_R_TYPE(relocations[i].r_info)); + fseek(f, shdr_this.sh_offset + relocations[i].r_offset, SEEK_SET); + switch (valueSize) { + case 8: + { + uint64_t val; + fread(&val, valueSize, 1, f); + value = val; + break; + } + case 4: + { + uint32_t val; + fread(&val, valueSize, 1, f); + value = val; + break; + } + case 2: + { + uint16_t val; + fread(&val, valueSize, 1, f); + value = val; + break; + } + case 1: + { + uint8_t val; + fread(&val, valueSize, 1, f); + value = val; + break; + } + default: + break; + } + + printf("%012lx %012lx %-15.15s %016lx %s + %lx\n", + relocations[i].r_offset, relocations[i].r_info, + relocationInfoToStr(ELF64_R_TYPE(relocations[i].r_info)), + value, + symName, + relocations[i].r_addend); + } + + free(relocations); + free(strtab); + free(symtab); + } break; - case PT_INTERP: - printf("[Interpreter Path]\n"); + case SHT_SYMTAB: + { + printf("\nSymbol table '%s' contains %ld entries.\n", + stringTable + sectionHeader.sh_name, + sectionHeader.sh_size / sizeof(Elf64_Sym)); + printf(" Num: Value Size Type Bind Vis Ndx Name\n"); + + Elf64_Sym * symtab = malloc(sectionHeader.sh_size); + fseek(f, sectionHeader.sh_offset, SEEK_SET); + fread(symtab, sectionHeader.sh_size, 1, f); + + Elf64_Shdr shdr_strtab; + fseek(f, header.e_shoff + header.e_shentsize * sectionHeader.sh_link, SEEK_SET); + fread(&shdr_strtab, sizeof(Elf64_Shdr), 1, f); + char * strtab = malloc(shdr_strtab.sh_size); + fseek(f, shdr_strtab.sh_offset, SEEK_SET); + fread(strtab, shdr_strtab.sh_size, 1, f); + + for (unsigned int i = 0; i < sectionHeader.sh_size / sizeof(Elf64_Sym); ++i) { + printf("%6u: %016lx %6lu %-7.7s %-6.6s %-4d %6d %s\n", + i, symtab[i].st_value, symtab[i].st_size, + symbolTypeToStr(symtab[i].st_info & 0xF), + symbolBindToStr(symtab[i].st_info >> 4), + symtab[i].st_other, + symtab[i].st_shndx, + strtab + symtab[i].st_name); + } + + free(strtab); + free(symtab); + } break; default: - printf("[Unused Segement]\n"); break; + } } - uint32_t i = 0; - for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) { - if (header->e_shoff + x > binary_size) { - printf("Tried to read beyond the end of the file.\n"); - return 1; - } - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x)); - if (shdr->sh_type == SHT_STRTAB) { - if (i == header->e_shstrndx) { - string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset); - printf("Found the section string table at 0x%x\n", (unsigned int)shdr->sh_offset); - } - } - i++; - } - - if (!string_table) { - printf("No string table, skipping rest of output.\n"); - return 1; - } - - /* Find the (hopefully two) string tables */ - printf("\033[1mString Tables\033[0m\n"); - for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) { - if (header->e_shoff + x > binary_size) { - printf("Tried to read beyond the end of the file.\n"); - return 1; - } - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x)); - if (shdr->sh_type == SHT_STRTAB) { - if (!strcmp((char *)((uintptr_t)string_table + shdr->sh_name), ".strtab")) { - sym_string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset); - printf("Found the symbol string table at 0x%x\n", (unsigned int)shdr->sh_offset); - } - printf("Displaying string table at 0x%x\n", (unsigned int)shdr->sh_offset); - char * _string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset); - unsigned int j = 1; - int k = 0; - printf("%d\n", (unsigned int)shdr->sh_size); - while (j < shdr->sh_size) { - int t = strlen((char *)((uintptr_t)_string_table + j)); - if (t) { - printf("%d [%d] %s\n", k, j, (char *)((uintptr_t)_string_table + j)); - k++; - j += t; - } else { - j += 1; - } - } - } - } - - /* Read the section headers */ - printf("\033[1mSection Headers\033[0m\n"); - for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) { - if (header->e_shoff + x > binary_size) { - printf("Tried to read beyond the end of the file.\n"); - return 1; - } - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x)); - - printf("[%d] %s\n", (unsigned int)shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name)); - printf("Section starts at 0x%x and is 0x%x bytes long.\n", (unsigned int)shdr->sh_offset, (unsigned int)shdr->sh_size); - if (shdr->sh_addr) { - printf("It should be loaded at 0x%x.\n", (unsigned int)shdr->sh_addr); - } - } - -#if 1 - printf("\033[1mSymbol Tables\033[0m\n"); - for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) { - if (header->e_shoff + x > binary_size) { - printf("Tried to read beyond the end of the file.\n"); - return 1; - } - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x)); - - if (shdr->sh_type == SHT_SYMTAB) { - printf("Found symbol table: %s\n", (char *)((uintptr_t)string_table + shdr->sh_name)); - - Elf32_Sym * table = (Elf32_Sym *)((uintptr_t)binary_buf + (shdr->sh_offset)); - while ((uintptr_t)table - ((uintptr_t)binary_buf + shdr->sh_offset) < shdr->sh_size) { - printf("%s: 0x%x [0x%x]\n", (char *)((uintptr_t)sym_string_table + table->st_name), (unsigned int)table->st_value, (unsigned int)table->st_size); - table++; - } - } - } -#endif - return 0; } - diff --git a/apps/reload_desktop.sh b/apps/reload_desktop.sh deleted file mode 100644 index 55e30850..00000000 --- a/apps/reload_desktop.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -export-cmd DESKTOP cat /var/run/.wallpaper.pid - -if not empty? "$DESKTOP" then kill -SIGUSR2 $DESKTOP diff --git a/apps/sdf-demo.c b/apps/sdf-demo.c index c05cbefa..adb7f639 100644 --- a/apps/sdf-demo.c +++ b/apps/sdf-demo.c @@ -121,7 +121,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win) { win->focused = wf->focused; decors(); diff --git a/apps/set-resolution.c b/apps/set-resolution.c index c1a4938f..ee0ab7e6 100644 --- a/apps/set-resolution.c +++ b/apps/set-resolution.c @@ -52,7 +52,7 @@ int main(int argc, char * argv[]) { /* Send ioctl */ if (init) { char tmp[100]; - sprintf(tmp, "%s,%lu,%lu", driver, s.width, s.height); + sprintf(tmp, "%s,%u,%u", driver, s.width, s.height); if (ioctl(fd, IO_VID_REINIT, tmp) < 0) { perror("ioctl"); return 1; diff --git a/apps/set_wallpaper.sh b/apps/set_wallpaper.sh deleted file mode 100644 index ddf4a8e8..00000000 --- a/apps/set_wallpaper.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -if empty? "$1" then exec sh -c "echo 'usage: $0 WALLPAPER'" -if not stat -Lq "$1" then exec sh -c "echo '$0: $1 does not exist'" - -export-cmd DESKTOP cat /var/run/.wallpaper.pid -if empty? "$DESKTOP" then sh -c "echo '$0: No wallpaper running?'" - -echo "wallpaper=$1" > $HOME/.wallpaper.conf - -kill -SIGUSR1 $DESKTOP - diff --git a/apps/sh.c b/apps/sh.c index cdc0963b..2c040d44 100644 --- a/apps/sh.c +++ b/apps/sh.c @@ -1109,6 +1109,7 @@ int shell_exec(char * buffer, size_t size, FILE * file, char ** out_buffer) { *out_buffer = ++p; goto _done; } + goto _just_add; case '#': if (!quoted && !backtick) { goto _done; /* Support comments; must not be part of an existing arg */ @@ -1782,7 +1783,7 @@ uint32_t shell_cmd_cd(int argc, char * argv[]) { goto cd_error; } } else { - char home_path[512]; + char home_path[1200]; sprintf(home_path, "/home/%s", username); if (chdir(home_path)) { goto cd_error; diff --git a/apps/showdialog.c b/apps/showdialog.c index e9acd6ba..f2c2c92c 100644 --- a/apps/showdialog.c +++ b/apps/showdialog.c @@ -208,7 +208,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win) { win->focused = wf->focused; redraw(); diff --git a/apps/sleep.c b/apps/sleep.c index d4f64737..8433763f 100644 --- a/apps/sleep.c +++ b/apps/sleep.c @@ -25,7 +25,7 @@ int main(int argc, char ** argv) { unsigned int seconds = (unsigned int)time; unsigned int subsecs = (unsigned int)((time - (float)seconds) * 100); - ret = syscall_nanosleep(seconds, subsecs); + ret = syscall_sleep(seconds, subsecs); return ret; } diff --git a/apps/splash-log.c b/apps/splash-log.c index e5fcab14..8377ff68 100644 --- a/apps/splash-log.c +++ b/apps/splash-log.c @@ -18,24 +18,11 @@ #include "terminal-font.h" -/** - * For legacy backwards-compatibility reasons, the VGA - * text-mode window is normalled mapped 1:1. If this - * ever changes, a few applications will need to be updated. - */ -static unsigned short * textmemptr = (unsigned short *)0xB8000; -static void placech(unsigned char c, int x, int y, int attr) { - unsigned short *where; - unsigned att = attr << 8; - where = textmemptr + (y * 80 + x); - *where = c | att; -} - /** * Graphical framebuffer is a bit more straightforward. */ static int framebuffer_fd = -1; -static int width, height, depth; +static long width, height, depth; static char * framebuffer; static void set_point(int x, int y, uint32_t value) { @@ -65,62 +52,39 @@ static void write_char(int x, int y, int val, uint32_t color) { } static void update_message(char * c, int line) { - if (framebuffer_fd != -1) { - int x = 20; - int y = 20 + char_height * line; - while (*c) { - write_char(x, y, *c, FG_COLOR); - c++; - x += char_width; - } - while (x < width - char_width) { - write_char(x, y, ' ', FG_COLOR); - x += char_width; - } - } else { - int x = 2; - int y = 2 + line; - while (*c) { - placech(*c, x, y, 0x7); - c++; - x++; - } - while (x < 80) { - placech(' ', x, y, 0x7); - x++; - } + if (framebuffer_fd < 0) return; + int x = 20; + int y = 20 + char_height * line; + while (*c) { + write_char(x, y, *c, FG_COLOR); + c++; + x += char_width; + } + while (x < width - char_width) { + write_char(x, y, ' ', FG_COLOR); + x += char_width; } } static void clear_screen(void) { - if (framebuffer_fd != -1) { - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - set_point(x,y,BG_COLOR); - } - } + if (framebuffer_fd < 0) return; - } else { - for (int y = 0; y < 24; ++y) { - for (int x = 0; x < 80; ++x) { - placech(' ', x, y, 0); /* Clear */ - } + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + set_point(x,y,BG_COLOR); } } } static void check_framebuffer(void) { - int tmpfd = open("/proc/framebuffer", O_RDONLY); - if (tmpfd > 0) { - framebuffer_fd = open("/dev/fb0", O_RDONLY); - ioctl(framebuffer_fd, IO_VID_WIDTH, &width); - ioctl(framebuffer_fd, IO_VID_HEIGHT, &height); - ioctl(framebuffer_fd, IO_VID_DEPTH, &depth); - ioctl(framebuffer_fd, IO_VID_ADDR, &framebuffer); - ioctl(framebuffer_fd, IO_VID_SIGNAL, NULL); - } else { - framebuffer_fd = -1; - } + framebuffer_fd = open("/dev/fb0", O_RDONLY); + if (framebuffer_fd < 0) return; + + ioctl(framebuffer_fd, IO_VID_WIDTH, &width); + ioctl(framebuffer_fd, IO_VID_HEIGHT, &height); + ioctl(framebuffer_fd, IO_VID_DEPTH, &depth); + ioctl(framebuffer_fd, IO_VID_ADDR, &framebuffer); + ioctl(framebuffer_fd, IO_VID_SIGNAL, NULL); } static FILE * pex_endpoint = NULL; @@ -139,6 +103,7 @@ int main(int argc, char * argv[]) { if (!fork()) { check_framebuffer(); + //printf("splash daemon is running, framebuffer (%ldx%ld) is at %p\n", width, height, framebuffer); clear_screen(); update_message("ToaruOS is starting up...", 0); diff --git a/apps/tar.c b/apps/tar.c index a7d4b653..9e1029fb 100644 --- a/apps/tar.c +++ b/apps/tar.c @@ -299,13 +299,13 @@ int main(int argc, char * argv[]) { if (verbose) { fprintf(stdout, "%.155s%.100s\n", file->prefix, file->filename); } - char name[1024] = {0}; + char name[1025] = {0}; if (last_was_long) { - strncat(name, tmpname, 1023); + strncat(name, tmpname, 1024); last_was_long = 0; } else { - strncat(name, file->prefix, 155); - strncat(name, file->filename, 100); + strncat(name, file->prefix, 167); + strncat(name, file->filename, 512); } if (file->type[0] == '0' || file->type[0] == 0) { @@ -335,8 +335,8 @@ int main(int argc, char * argv[]) { } } else if (file->type[0] == '1') { if (!to_stdout && (!only_matches || matches_files(argc,argv,optind,name))) { - char tmp[101] = {0}; - strncat(tmp, file->link, 100); + char tmp[356] = {0}; + strncat(tmp, file->link, 355); FILE * mf = fopen(name,"w"); if (!mf) { fprintf(stderr, "%s: %s: %s: %s\n", argv[0], fname, name, strerror(errno)); @@ -359,8 +359,8 @@ int main(int argc, char * argv[]) { _seek_forward(f, interpret_size(file)); } else if (file->type[0] == '2') { if (!to_stdout && (!only_matches || matches_files(argc,argv,optind,name))) { - char tmp[101] = {0}; - strncat(tmp, file->link, 100); + char tmp[356] = {0}; + strncat(tmp, file->link, 355); if (symlink(tmp, name) < 0) { fprintf(stderr, "%s: %s: %s: %s: %s\n", argv[0], fname, name, tmp, strerror(errno)); } diff --git a/apps/terminal-font.h b/apps/terminal-font.h index 27030e87c6dc919053cf8cb4c96c4f00aa40ff26..62bb509e1b4390a098f52a1bf825c01897744160 100644 GIT binary patch delta 164 zcmcb2lWX%WE=PSWEiMHu1&6fEoK%JE)S|r99Q~5iqTI~9#2nqU{Javq44^zni5rlk zP+FXtqL7wfq>z%DRGOZinU_8}kFksoY(#Q?L1j^9dPd1aT_-LDIGC7ckIY-+g3NpG ZjKrI4$mr7igt7ezBjffbj7+~)0RU!*FjoKo delta 87 zcmdmdi|gJ^E?s>sg|f_CD}|E8q~enN0$US>;*89+lJd-yk_;dxFF&=SATcimD9xpy pHSws^WFbbo$= term_width || y >= term_height) return; /* Draw the image data */ - uint32_t * data = (uint32_t *)cell->fg; + uint32_t * data = (uint32_t *)((uintptr_t)cell->bg << 32 | cell->fg); for (uint32_t yy = 0; yy < char_height; ++yy) { for (uint32_t xx = 0; xx < char_width; ++xx) { term_set_point(x * char_width + xx, y * char_height + yy, *data); @@ -1066,7 +1066,8 @@ static void flush_unused_images(void) { for (int x = 0; x < term_width; ++x) { term_cell_t * cell = (term_cell_t *)((uintptr_t)term_buffer + (y * term_width + x) * sizeof(term_cell_t)); if (cell->flags & ANSI_EXT_IMG) { - list_insert(tmp, (void *)cell->fg); + uint32_t * data = (uint32_t *)((uintptr_t)cell->bg << 32 | cell->fg); + list_insert(tmp, data); } } } @@ -1364,7 +1365,10 @@ static void term_set_cell_contents(int x, int y, char * data) { char * cell_data = malloc(char_width * char_height * sizeof(uint32_t)); memcpy(cell_data, data, char_width * char_height * sizeof(uint32_t)); list_insert(images_list, cell_data); - cell_set(x, y, ' ', (uint32_t)cell_data, 0, ANSI_EXT_IMG); + cell_set(x, y, ' ', + (uintptr_t)(cell_data) & 0xFFFFFFFF, + (uintptr_t)(cell_data) >> 32, + ANSI_EXT_IMG); } /* ANSI callback to get character cell width */ @@ -1945,7 +1949,7 @@ static void * handle_incoming(void) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win == window) { win->focused = wf->focused; render_decors(); @@ -2461,8 +2465,8 @@ int main(int argc, char ** argv) { if (res[1]) { /* Read from PTY */ - int r = read(fd_master, buf, 4096); - for (int i = 0; i < r; ++i) { + ssize_t r = read(fd_master, buf, 4096); + for (ssize_t i = 0; i < r; ++i) { ansi_put(ansi_state, buf[i]); } display_flip(); diff --git a/apps/test-cxx.c++ b/apps/test-cxx.c++ new file mode 100644 index 00000000..d8687fe8 --- /dev/null +++ b/apps/test-cxx.c++ @@ -0,0 +1,6 @@ +#include + +int main() { + std::cout << "Hello, world!"; + return 0; +} diff --git a/apps/test-tls.c b/apps/test-tls.c index c8733471..9680833c 100644 --- a/apps/test-tls.c +++ b/apps/test-tls.c @@ -2,7 +2,7 @@ #include #include -__thread int myvalue; +__thread volatile int myvalue; void * getaddressinthread(void * _unused) { fprintf(stderr, "in thread before:\n"); diff --git a/apps/test.sh b/apps/test.sh deleted file mode 100644 index aea03646..00000000 --- a/apps/test.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -export-cmd UNAME uname -export-cmd DATE date -echo "This is a test shell script." -echo "This is $UNAME and it is $DATE" diff --git a/apps/tutorial.c b/apps/tutorial.c index f8d8cbc3..e6576b69 100644 --- a/apps/tutorial.c +++ b/apps/tutorial.c @@ -325,6 +325,9 @@ int main(int argc, char * argv[]) { decor_get_bounds(NULL, &bounds); window = yutani_window_create(yctx, width + bounds.width, height + bounds.height); + req_center_x = yctx->display_width / 2; + req_center_y = yctx->display_height / 2; + yutani_window_move(yctx, window, req_center_x - window->width / 2, req_center_y - window->height / 2); /* Load icons */ load_sprite(&logo, "/usr/share/logo_login.png"); @@ -335,9 +338,6 @@ int main(int argc, char * argv[]) { load_page(0); - req_center_x = yctx->display_width / 2; - req_center_y = yctx->display_height / 2; - yutani_window_move(yctx, window, req_center_x - window->width / 2, req_center_y - window->height / 2); yutani_window_advertise_icon(yctx, window, title_str, "star"); ctx = init_graphics_yutani_double_buffer(window); @@ -371,7 +371,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (wf->wid == background->wid) { yutani_focus_window(yctx, window->wid); } else if (win) { diff --git a/apps/wallpaper-picker.c b/apps/wallpaper-picker.c index abe55c89..558fbede 100644 --- a/apps/wallpaper-picker.c +++ b/apps/wallpaper-picker.c @@ -327,7 +327,7 @@ int main(int argc, char * argv[]) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid); if (win) { win->focused = wf->focused; redraw(); diff --git a/apps/weather-tool.c b/apps/weather-tool.c index 88954b67..367414b8 100644 --- a/apps/weather-tool.c +++ b/apps/weather-tool.c @@ -11,6 +11,7 @@ typedef struct JSON_Value Value; int main(int argc, char * argv[]) { + return 1; Value * config = json_parse_file("/etc/weather.json"); if (!config) { diff --git a/base/etc/msk.conf b/base/etc/msk.conf index 58a77515..3c671173 100644 --- a/base/etc/msk.conf +++ b/base/etc/msk.conf @@ -2,4 +2,4 @@ remote_order=local,remote [remotes] local=/cdrom/extra -remote=http://toaruos.org/msk/1.10.x +remote=http://toaruos.org/msk/2.0.x diff --git a/base/usr/bin/.dummy b/base/lib/.dummy similarity index 100% rename from base/usr/bin/.dummy rename to base/lib/.dummy diff --git a/base/opt/asm-demo.s b/base/opt/asm-demo.s deleted file mode 100644 index a607e44b..00000000 --- a/base/opt/asm-demo.s +++ /dev/null @@ -1,23 +0,0 @@ -# x86 Assembly w/ libc -.global fprintf # libc export -.global stdout # libc export - -.global main # our exported main function, called by C runtime - -main: - push $world - push $hello - push stdout - call fprintf # fprintf(stdout, "Hello, %s!\n", "world"); - pop %eax - pop %eax - pop %eax - - mov $0, %eax - ret - -hello: - .asciz "Hello, %s!\n" - -world: - .asciz "world" diff --git a/base/opt/bochsrc.txt b/base/opt/bochsrc.txt deleted file mode 100644 index 5d456fca..00000000 --- a/base/opt/bochsrc.txt +++ /dev/null @@ -1,54 +0,0 @@ -# configuration file generated by Bochs -plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1 -config_interface: textconfig -display_library: sdl -memory: host=256, guest=256 -romimage: file="/usr/local/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none -vgaromimage: file="/usr/local/share/bochs/VGABIOS-lgpl-latest" -boot: cdrom -floppy_bootsig_check: disabled=0 -# no floppya -# no floppyb -ata0: enabled=1, ioaddr1=0x000001f0, ioaddr2=0x000003f0, irq=14 -ata0-master: type=cdrom, path="/dev/cdrom0", status=inserted, model="Generic 1234", biosdetect=auto -ata0-slave: type=none -ata1: enabled=1, ioaddr1=0x00000170, ioaddr2=0x00000370, irq=15 -ata1-master: type=none -ata1-slave: type=none -ata2: enabled=0 -ata3: enabled=0 -optromimage1: file=none -optromimage2: file=none -optromimage3: file=none -optromimage4: file=none -optramimage1: file=none -optramimage2: file=none -optramimage3: file=none -optramimage4: file=none -pci: enabled=1, chipset=i440fx, slot1=pcivga -vga: extension=vbe, update_freq=5, realtime=1 -cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 -cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string=" Intel(R) Pentium(R) 4 CPU " -cpuid: mmx=1, apic=xapic, simd=sse2, sse4a=0, misaligned_sse=0, sep=1, movbe=0, adx=0 -cpuid: aes=0, sha=0, xsave=0, xsaveopt=0, smep=0, smap=0, mwait=1 -print_timestamps: enabled=0 -port_e9_hack: enabled=0 -private_colormap: enabled=0 -clock: sync=realtime, time0=local, rtc_sync=1 -# no cmosimage -# no loader -log: - -logprefix: %t%e%d -debug: action=ignore -info: action=report -error: action=report -panic: action=fatal -keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none -mouse: type=ps2, enabled=0, toggle=ctrl+mbutton -speaker: enabled=1, mode=gui -parport1: enabled=1, file=none -parport2: enabled=0 -com1: enabled=1, mode=null -com2: enabled=0 -com3: enabled=0 -com4: enabled=0 diff --git a/base/opt/build.sh b/base/opt/build.sh deleted file mode 100755 index 49771277..00000000 --- a/base/opt/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -export CRTBEG="/lib/crt0.o /lib/crti.o /usr/lib/crtbegin.o" -export CRTEND="/usr/lib/crtend.o /lib/crtn.o" - -/usr/i686-pc-toaru/bin/as -o /tmp/asm-demo.o asm-demo.s -/usr/i686-pc-toaru/bin/ld -o /tmp/asm-demo $CRTBEG -lc /tmp/asm-demo.o $CRTEND diff --git a/base/opt/test.c b/base/opt/test.c deleted file mode 100644 index c3e8d5c6..00000000 --- a/base/opt/test.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char * argv[]) { - fprintf(stdout, "Hello, %s!\n", "world"); - return 0; -} diff --git a/base/usr/include/ctype.h b/base/usr/include/ctype.h index 8ff3b77a..8b7187c6 100644 --- a/base/usr/include/ctype.h +++ b/base/usr/include/ctype.h @@ -32,6 +32,6 @@ extern int toupper(int c); #define _X 0100 #define _B 0200 -extern char _ctype_[256]; +extern unsigned char _ctype_[256]; _End_C_Header diff --git a/base/usr/include/errno.h b/base/usr/include/errno.h index b9c8b4ed..4fbc98db 100644 --- a/base/usr/include/errno.h +++ b/base/usr/include/errno.h @@ -135,7 +135,7 @@ _Begin_C_Header #ifndef _KERNEL_ extern int errno; -#define __sets_errno(...) int ret = __VA_ARGS__; if (ret < 0) { errno = -ret; ret = -1; } return ret +#define __sets_errno(...) long ret = __VA_ARGS__; if (ret < 0) { errno = -ret; ret = -1; } return ret #endif _End_C_Header diff --git a/base/usr/include/inttypes.h b/base/usr/include/inttypes.h index db27a77b..bcd8a555 100644 --- a/base/usr/include/inttypes.h +++ b/base/usr/include/inttypes.h @@ -5,12 +5,23 @@ #include _Begin_C_Header -#define PRIi8 "i" +#define PRIi8 "i" #define PRIi16 "i" #define PRIi32 "i" -#define PRIi64 "lli" +#define PRIi64 "li" -#define PRIx64 "llx" -#define PRIu64 "llu" -#define PRId64 "lld" +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 "lx" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 "lu" + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 "ld" _End_C_Header diff --git a/base/usr/include/kernel/arch/x86_64/acpi.h b/base/usr/include/kernel/arch/x86_64/acpi.h new file mode 100644 index 00000000..beee3aa5 --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/acpi.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +struct rsdp_descriptor { + char signature[8]; + uint8_t checksum; + char oemid[6]; + uint8_t revision; + uint32_t rsdt_address; +} __attribute__((packed)); + +struct rsdp_descriptor_20 { + struct rsdp_descriptor base; + + uint32_t length; + uint64_t xsdt_address; + uint8_t ext_checksum; + uint8_t _reserved[3]; +} __attribute((packed)); + +struct acpi_sdt_header { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oemid[6]; + char oem_tableid[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; +} __attribute__((packed)); + +struct rsdt { + struct acpi_sdt_header header; + uint32_t pointers[]; +}; + +struct madt { + struct acpi_sdt_header header; + uint32_t lapic_addr; + uint32_t flags; + uint8_t entries[]; +}; + +static inline int acpi_checksum(struct acpi_sdt_header * header) { + uint8_t check = 0; + for (size_t i = 0; i < header->length; ++i) { + check += ((uint8_t *)header)[i]; + } + return check == 0; +} + diff --git a/base/usr/include/kernel/arch/x86_64/cmos.h b/base/usr/include/kernel/arch/x86_64/cmos.h new file mode 100644 index 00000000..334bcf3e --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/cmos.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +uint32_t read_cmos(void); diff --git a/base/usr/include/kernel/arch/x86_64/irq.h b/base/usr/include/kernel/arch/x86_64/irq.h new file mode 100644 index 00000000..0db2d5b8 --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/irq.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +extern struct regs * _isr0(struct regs*); +extern struct regs * _isr1(struct regs*); +extern struct regs * _isr2(struct regs*); +extern struct regs * _isr3(struct regs*); +extern struct regs * _isr4(struct regs*); +extern struct regs * _isr5(struct regs*); +extern struct regs * _isr6(struct regs*); +extern struct regs * _isr7(struct regs*); +extern struct regs * _isr8(struct regs*); +extern struct regs * _isr9(struct regs*); +extern struct regs * _isr10(struct regs*); +extern struct regs * _isr11(struct regs*); +extern struct regs * _isr12(struct regs*); +extern struct regs * _isr13(struct regs*); +extern struct regs * _isr14(struct regs*); +extern struct regs * _isr15(struct regs*); +extern struct regs * _isr16(struct regs*); +extern struct regs * _isr17(struct regs*); +extern struct regs * _isr18(struct regs*); +extern struct regs * _isr19(struct regs*); +extern struct regs * _isr20(struct regs*); +extern struct regs * _isr21(struct regs*); +extern struct regs * _isr22(struct regs*); +extern struct regs * _isr23(struct regs*); +extern struct regs * _isr24(struct regs*); +extern struct regs * _isr25(struct regs*); +extern struct regs * _isr26(struct regs*); +extern struct regs * _isr27(struct regs*); +extern struct regs * _isr28(struct regs*); +extern struct regs * _isr29(struct regs*); +extern struct regs * _isr30(struct regs*); +extern struct regs * _isr31(struct regs*); +extern struct regs * _irq0(struct regs*); +extern struct regs * _irq1(struct regs*); +extern struct regs * _irq2(struct regs*); +extern struct regs * _irq3(struct regs*); +extern struct regs * _irq4(struct regs*); +extern struct regs * _irq5(struct regs*); +extern struct regs * _irq6(struct regs*); +extern struct regs * _irq7(struct regs*); +extern struct regs * _irq8(struct regs*); +extern struct regs * _irq9(struct regs*); +extern struct regs * _irq10(struct regs*); +extern struct regs * _irq11(struct regs*); +extern struct regs * _irq12(struct regs*); +extern struct regs * _irq13(struct regs*); +extern struct regs * _irq14(struct regs*); +extern struct regs * _irq15(struct regs*); +extern struct regs * _isr125(struct regs*); /* Does not actually take regs */ +extern struct regs * _isr126(struct regs*); /* Does not actually take regs */ +extern struct regs * _isr127(struct regs*); /* Syscall entry point */ + +typedef struct regs * (*interrupt_handler_t)(struct regs *); + + +/** + * Interrupt descriptor table + */ +typedef struct { + uint16_t base_low; + uint16_t selector; + + uint8_t zero; + uint8_t flags; + + uint16_t base_mid; + uint32_t base_high; + uint32_t pad; +} __attribute__((packed)) idt_entry_t; + +struct idt_pointer { + uint16_t limit; + uintptr_t base; +} __attribute__((packed)); + + +extern void irq_ack(size_t irq_no); + +typedef int (*irq_handler_chain_t) (struct regs *); +extern void irq_install_handler(size_t irq, irq_handler_chain_t handler, const char * desc); +extern const char * get_irq_handler(int irq, int chain); + +extern void idt_load(void *); diff --git a/base/usr/include/kernel/arch/x86_64/mmu.h b/base/usr/include/kernel/arch/x86_64/mmu.h new file mode 100644 index 00000000..a37537de --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/mmu.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include +#define MMU_FLAG_KERNEL 0x01 +#define MMU_FLAG_WRITABLE 0x02 +#define MMU_FLAG_NOCACHE 0x04 +#define MMU_FLAG_WRITETHROUGH 0x08 +#define MMU_FLAG_SPEC 0x10 +#define MMU_FLAG_WC (MMU_FLAG_NOCACHE | MMU_FLAG_WRITETHROUGH | MMU_FLAG_SPEC) +#define MMU_FLAG_NOEXECUTE 0x20 + +#define MMU_GET_MAKE 0x01 + + +void mmu_frame_set(uintptr_t frame_addr); +void mmu_frame_clear(uintptr_t frame_addr); +int mmu_frame_test(uintptr_t frame_addr); +uintptr_t mmu_first_n_frames(int n); +uintptr_t mmu_first_frame(void); +void mmu_frame_allocate(union PML * page, unsigned int flags); +void mmu_frame_map_address(union PML * page, unsigned int flags, uintptr_t physAddr); +void mmu_frame_free(union PML * page); +uintptr_t mmu_map_to_physical(uintptr_t virtAddr); +union PML * mmu_get_page(uintptr_t virtAddr, int flags); +void mmu_set_directory(union PML * new_pml); +void mmu_free(union PML * from); +union PML * mmu_clone(union PML * from); +void mmu_init(size_t memsize, uintptr_t firstFreePage); +void mmu_invalidate(uintptr_t addr); +uintptr_t mmu_allocate_a_frame(void); +uintptr_t mmu_allocate_n_frames(int n); +union PML * mmu_get_kernel_directory(void); +void * mmu_map_from_physical(uintptr_t frameaddress); +void * mmu_map_mmio_region(uintptr_t physical_address, size_t size); + +size_t mmu_count_user(union PML * from); +size_t mmu_count_shm(union PML * from); +size_t mmu_total_memory(void); +size_t mmu_used_memory(void); + +void * sbrk(size_t); diff --git a/base/usr/include/kernel/arch/x86_64/pml.h b/base/usr/include/kernel/arch/x86_64/pml.h new file mode 100644 index 00000000..4bd14149 --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/pml.h @@ -0,0 +1,23 @@ +#pragma once +#include + +union PML { + struct { + uint64_t present:1; + uint64_t writable:1; + uint64_t user:1; + uint64_t writethrough:1; + uint64_t nocache:1; + uint64_t accessed:1; + uint64_t _available1:1; + uint64_t size:1; + uint64_t global:1; + uint64_t _available2:3; + uint64_t page:28; + uint64_t reserved:12; + uint64_t _available3:11; + uint64_t nx:1; + } bits; + uint64_t raw; +}; + diff --git a/base/usr/include/kernel/arch/x86_64/ports.h b/base/usr/include/kernel/arch/x86_64/ports.h new file mode 100644 index 00000000..daeea755 --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/ports.h @@ -0,0 +1,12 @@ +#pragma once + +#include +extern unsigned short inports(unsigned short _port); +extern void outports(unsigned short _port, unsigned short _data); +extern unsigned int inportl(unsigned short _port); +extern void outportl(unsigned short _port, unsigned int _data); +extern unsigned char inportb(unsigned short _port); +extern void outportb(unsigned short _port, unsigned char _data); +extern void outportsm(unsigned short port, unsigned char * data, unsigned long size); +extern void inportsm(unsigned short port, unsigned char * data, unsigned long size); + diff --git a/base/usr/include/kernel/arch/x86_64/regs.h b/base/usr/include/kernel/arch/x86_64/regs.h new file mode 100644 index 00000000..2a2455e6 --- /dev/null +++ b/base/usr/include/kernel/arch/x86_64/regs.h @@ -0,0 +1,18 @@ +#pragma once +#include + +/** + * Register layout for interrupt context. + */ +struct regs { + /* Pushed by common stub */ + uintptr_t r15, r14, r13, r12; + uintptr_t r11, r10, r9, r8; + uintptr_t rbp, rdi, rsi, rdx, rcx, rbx, rax; + + /* Pushed by wrapper */ + uintptr_t int_no, err_code; + + /* Pushed by interrupt */ + uintptr_t rip, cs, rflags, rsp, ss; +}; diff --git a/base/usr/include/kernel/args.h b/base/usr/include/kernel/args.h index 0bc5fa08..f5529ea0 100644 --- a/base/usr/include/kernel/args.h +++ b/base/usr/include/kernel/args.h @@ -1,9 +1,6 @@ #pragma once -int args_present(char * karg); -char * args_value(char * karg); -void args_parse(char * _arg); - -void early_stage_args(void); -void late_stage_args(void); +int args_present(const char * karg); +char * args_value(const char * karg); +void args_parse(const char * arg); diff --git a/base/usr/include/kernel/ata.h b/base/usr/include/kernel/ata.h deleted file mode 100644 index 05edb5ce..00000000 --- a/base/usr/include/kernel/ata.h +++ /dev/null @@ -1,141 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * Values for ATA / PATA devices - */ - -#pragma once - -#define ATA_SR_BSY 0x80 -#define ATA_SR_DRDY 0x40 -#define ATA_SR_DF 0x20 -#define ATA_SR_DSC 0x10 -#define ATA_SR_DRQ 0x08 -#define ATA_SR_CORR 0x04 -#define ATA_SR_IDX 0x02 -#define ATA_SR_ERR 0x01 - -#define ATA_ER_BBK 0x80 -#define ATA_ER_UNC 0x40 -#define ATA_ER_MC 0x20 -#define ATA_ER_IDNF 0x10 -#define ATA_ER_MCR 0x08 -#define ATA_ER_ABRT 0x04 -#define ATA_ER_TK0NF 0x02 -#define ATA_ER_AMNF 0x01 - -#define ATA_CMD_READ_PIO 0x20 -#define ATA_CMD_READ_PIO_EXT 0x24 -#define ATA_CMD_READ_DMA 0xC8 -#define ATA_CMD_READ_DMA_EXT 0x25 -#define ATA_CMD_WRITE_PIO 0x30 -#define ATA_CMD_WRITE_PIO_EXT 0x34 -#define ATA_CMD_WRITE_DMA 0xCA -#define ATA_CMD_WRITE_DMA_EXT 0x35 -#define ATA_CMD_CACHE_FLUSH 0xE7 -#define ATA_CMD_CACHE_FLUSH_EXT 0xEA -#define ATA_CMD_PACKET 0xA0 -#define ATA_CMD_IDENTIFY_PACKET 0xA1 -#define ATA_CMD_IDENTIFY 0xEC - -#define ATAPI_CMD_READ 0xA8 -#define ATAPI_CMD_EJECT 0x1B - -#define ATA_IDENT_DEVICETYPE 0 -#define ATA_IDENT_CYLINDERS 2 -#define ATA_IDENT_HEADS 6 -#define ATA_IDENT_SECTORS 12 -#define ATA_IDENT_SERIAL 20 -#define ATA_IDENT_MODEL 54 -#define ATA_IDENT_CAPABILITIES 98 -#define ATA_IDENT_FIELDVALID 106 -#define ATA_IDENT_MAX_LBA 120 -#define ATA_IDENT_COMMANDSETS 164 -#define ATA_IDENT_MAX_LBA_EXT 200 - -#define IDE_ATA 0x00 -#define IDE_ATAPI 0x01 - -#define ATA_MASTER 0x00 -#define ATA_SLAVE 0x01 - -#define ATA_REG_DATA 0x00 -#define ATA_REG_ERROR 0x01 -#define ATA_REG_FEATURES 0x01 -#define ATA_REG_SECCOUNT0 0x02 -#define ATA_REG_LBA0 0x03 -#define ATA_REG_LBA1 0x04 -#define ATA_REG_LBA2 0x05 -#define ATA_REG_HDDEVSEL 0x06 -#define ATA_REG_COMMAND 0x07 -#define ATA_REG_STATUS 0x07 -#define ATA_REG_SECCOUNT1 0x08 -#define ATA_REG_LBA3 0x09 -#define ATA_REG_LBA4 0x0A -#define ATA_REG_LBA5 0x0B -#define ATA_REG_CONTROL 0x0C -#define ATA_REG_ALTSTATUS 0x0C -#define ATA_REG_DEVADDRESS 0x0D - -// Channels: -#define ATA_PRIMARY 0x00 -#define ATA_SECONDARY 0x01 - -// Directions: -#define ATA_READ 0x00 -#define ATA_WRITE 0x01 - -typedef struct { - uint16_t base; - uint16_t ctrl; - uint16_t bmide; - uint16_t nien; -} ide_channel_regs_t; - -typedef struct { - uint8_t reserved; - uint8_t channel; - uint8_t drive; - uint16_t type; - uint16_t signature; - uint16_t capabilities; - uint32_t command_sets; - uint32_t size; - uint8_t model[41]; -} ide_device_t; - -typedef struct { - uint8_t status; - uint8_t chs_first_sector[3]; - uint8_t type; - uint8_t chs_last_sector[3]; - uint32_t lba_first_sector; - uint32_t sector_count; -} partition_t; - -typedef struct { - uint16_t flags; - uint16_t unused1[9]; - char serial[20]; - uint16_t unused2[3]; - char firmware[8]; - char model[40]; - uint16_t sectors_per_int; - uint16_t unused3; - uint16_t capabilities[2]; - uint16_t unused4[2]; - uint16_t valid_ext_data; - uint16_t unused5[5]; - uint16_t size_of_rw_mult; - uint32_t sectors_28; - uint16_t unused6[38]; - uint64_t sectors_48; - uint16_t unused7[152]; -} __attribute__((packed)) ata_identify_t; - -typedef struct { - uint8_t boostrap[446]; - partition_t partitions[4]; - uint8_t signature[2]; -} __attribute__((packed)) mbr_t; - - diff --git a/base/usr/include/kernel/bitset.h b/base/usr/include/kernel/bitset.h deleted file mode 100644 index ccd3efb7..00000000 --- a/base/usr/include/kernel/bitset.h +++ /dev/null @@ -1,19 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ -#pragma once - -#include - -typedef struct { - unsigned char *data; - size_t size; -} bitset_t; - -void bitset_init(bitset_t *set, size_t size); -void bitset_free(bitset_t *set); -void bitset_set(bitset_t *set, size_t bit); -void bitset_clear(bitset_t *set, size_t bit); -int bitset_test(bitset_t *set, size_t bit); -/* Find first unset bit */ -int bitset_ffub(bitset_t *set); - diff --git a/base/usr/include/kernel/boot.h b/base/usr/include/kernel/boot.h deleted file mode 100644 index 34683981..00000000 --- a/base/usr/include/kernel/boot.h +++ /dev/null @@ -1,20 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ -#pragma once -/* - * Boot Information Types - * Used in the kernel boot process to determine - * how we booted and where we can get BIOS - * information from that bootloader. - * - */ -#include - -/* - * Multiboot - * A format managed by GNU and used in GRUB. - * Also supported natively by QEMU and a few - * other emulators. - */ -#include - diff --git a/base/usr/include/kernel/elf.h b/base/usr/include/kernel/elf.h index 75204398..06ec6408 100644 --- a/base/usr/include/kernel/elf.h +++ b/base/usr/include/kernel/elf.h @@ -1,185 +1,353 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file elf.h + * @author K. Lange * - * ELF Binary Executable headers + * @copyright Copyright in this work is disclaimed under the assertion + * that its contents are purely factual and no rights may be reserved + * for its use. * + * @brief Structures for Elf binary files. + * + * Based primarily on the Elf and SysV ABI specification documents. + * + * @see https://uclibc.org/docs/elf-64-gen.pdf + * @see https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf */ - #pragma once +#include -/* - * Different bits of our build environment - * require different header files for definitions +/** + * @typedef Elf64_Addr + * @brief Unsigned program address. (uintptr_t) + * @typedef Elf64_Off + * @brief Unsigned file offset. (size_t) + * @typedef Elf64_Half + * @brief Unsigned medium integer. (unsigned short) + * @typedef Elf64_Word + * @brief Unsigned integer. (unsigned int) + * @typedef Elf64_Sword + * @brief Signed integer. (int) + * @typedef Elf64_Xword + * @brief Unsigned long integer. (unsigned long long) + * @typedef Elf64_Sxword + * @brief Signed long integer. (long long) */ -#ifdef _KERNEL_ -# include -#else -# include -#endif +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; -/* - * Unless otherwise stated, the definitions herein - * are sourced from the Portable Formats Specification, - * version 1.1 - ELF: Executable and Linkable Format - */ - -/* - * ELF Magic Signature +/** + * Values for e_ident[EI_MAGn] */ #define ELFMAG0 0x7f #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' -#define EI_NIDENT 16 -/* - * ELF Datatypes +/** + * Values for e_ident[EI_CLASS] */ -typedef uint32_t Elf32_Word; -typedef uint32_t Elf32_Addr; -typedef uint32_t Elf32_Off; -typedef uint32_t Elf32_Sword; -typedef uint16_t Elf32_Half; +#define ELFCLASS32 1 +#define ELFCLASS64 2 -/* - * ELF Header +/** + * Values for e_ident[EI_DATA] */ -typedef struct { - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -} Elf32_Header; +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 -/* - * e_type +/** + * Values for e_type */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* Relocatable file */ -#define ET_EXEC 2 /* Executable file */ -#define ET_DYN 3 /* Shared object file */ -#define ET_CORE 4 /* Core file */ -#define ET_LOPROC 0xff0 /* [Processor Specific] */ -#define ET_HIPROC 0xfff /* [Processor Specific] */ - -/* - * Machine types +/** + * e_ident fields */ -#define EM_NONE 0 -#define EM_386 3 +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 -#define EV_NONE 0 -#define EV_CURRENT 1 +#define EM_X86_64 62 -/** Program Header */ -typedef struct { - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; +/** + * @brief Elf object file header. + */ +typedef struct Elf64_Header { + uint8_t e_ident[EI_NIDENT]; /**< @brief Identifies the layout of the rest of the file. */ + Elf64_Half e_type; /**< @brief What kind of file this is, eg. object or executable... */ + Elf64_Half e_machine; /**< @brief The architecture this file is for. */ + Elf64_Word e_version; /**< @brief The version of the standard this file confirms to. */ + Elf64_Addr e_entry; /**< @brief The entry point of an executable. */ + Elf64_Off e_phoff; /**< @brief The offset of the program headers. */ + Elf64_Off e_shoff; /**< @brief The offset of the section headers. */ + Elf64_Word e_flags; /**< @brief Various flags. */ + Elf64_Half e_ehsize; /**< @brief Size of this header. */ + Elf64_Half e_phentsize; /**< @brief Size of one program header table entry. */ + Elf64_Half e_phnum; /**< @brief The number of entries in the program header table. */ + Elf64_Half e_shentsize; /**< @brief Size of one section header table entry. */ + Elf64_Half e_shnum; /**< @brief The number of entries in the section header table. */ + Elf64_Half e_shstrndx; +} Elf64_Header; -/* p_type values */ -#define PT_NULL 0 /* Unused, skip me */ -#define PT_LOAD 1 /* Loadable segment */ -#define PT_DYNAMIC 2 /* Dynamic linking information */ -#define PT_INTERP 3 /* Interpreter (null-terminated string, pathname) */ -#define PT_NOTE 4 /* Auxillary information */ -#define PT_SHLIB 5 /* Reserved. */ -#define PT_PHDR 6 /* Oh, it's me. Hello! Back-reference to the header table itself */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7FFFFFFF +/** + * Special section indices + */ +#define SHN_UNDEF 0 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_LOOS 0xFF20 +#define SHN_HIOS 0xFF3F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +/** + * Values for sh_type, sh_link, sh_info + */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6FFFFFFF +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF -/** Section Header */ -typedef struct { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -} Elf32_Shdr; +/** + * Values for sh_flags + */ +#define SHF_WRITE 0x00000001 +#define SHF_ALLOC 0x00000002 +#define SHF_EXECINSTR 0x00000004 +#define SHF_MASKOS 0x0F000000 +#define SHF_MASKPROC 0xF0000000 +/* From the SysV x86-64 ABI */ +#define SHF_X86_64_LARGE 0x10000000 +#define SHF_X86_64_UNWIND 0x70000001 -typedef struct { - uint32_t id; - uintptr_t ptr; -} Elf32_auxv; +typedef struct Elf64_Shdr { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; -typedef struct { - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -} Elf32_Sym; - -typedef struct { - Elf32_Addr r_offset; - Elf32_Word r_info; -} Elf32_Rel; - -typedef struct { - Elf32_Sword d_tag; - union { - Elf32_Word d_val; - Elf32_Addr d_ptr; - Elf32_Off d_off; - } d_un; -} Elf32_Dyn; - -/* sh_type values */ -#define SHT_NONE 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_NOBITS 8 -#define SHT_REL 9 - -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) - -#define ELF32_ST_BIND(i) ((i) >> 4) -#define ELF32_ST_TYPE(i) ((i) & 0xf) -#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) - -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 -#define STB_NUM 3 - -#define STB_LOPROC 13 -#define STB_HIPROC 15 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 -#define STT_NUM 7 +/** + * Binding types. + * Contained in the high four bits of @p st_info + */ +#define STB_LOCAL 0 /**< @brief Not visible outside the object file. */ +#define STB_GLOBAL 1 /**< @brief Global symbol, visible to all object files. */ +#define STB_WEAK 2 /**< @brief Global scope, but with lower precedence than global symbols. */ +#define STB_LOOS 10 +#define STB_HIOS 12 +#define STB_LOPROC 13 +#define STB_HIPROC 15 +/** + * Symbol types. + * Contained in the low four bits of @p st_info + */ +#define STT_NOTYPE 0 /**< @brief No type specified (e.g., an absolute symbol) */ +#define STT_OBJECT 1 /**< @brief Data object */ +#define STT_FUNC 2 /**< @brief Function entry point */ +#define STT_SECTION 3 /**< @brief Symbol is associated with a section */ +#define STT_FILE 4 /**< @brief Source file associated with the object */ +#define STT_LOOS 10 +#define STT_HIOS 12 #define STT_LOPROC 13 #define STT_HIPROC 15 +typedef struct Elf64_Sym { + Elf64_Word st_name; /**< @brief Symbol name */ + unsigned char st_info; /**< @brief Type and binding attributes */ + unsigned char st_other; /**< @brief Reserved */ + Elf64_Half st_shndx; /**< @brief Section table index */ + Elf64_Addr st_value; /**< @brief Symbol value */ + Elf64_Xword st_size; /**< @brief Size of object (e.g., common) */ +} Elf64_Sym; + +/** + * Relocations + */ + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xFFFFFFFFL) +#define ELF64_R_INFO(s,t) (((s) << 32) + ((t) & 0xFFFFFFFFL)) + +typedef struct Elf64_Rel { + Elf64_Addr r_offset; /**< @brief Address of reference */ + Elf64_Xword r_info; /**< @brief Symbol index and type of relocation */ +} Elf64_Rel; + +typedef struct Elf64_Rela { + Elf64_Addr r_offset; /**< @brief Address of reference */ + Elf64_Xword r_info; /**< @brief Symbol index and type of relocation */ + Elf64_Sxword r_addend; /**< @brief Constant part of expression */ +} Elf64_Rela; + +/** + * x86-64 SysV Relocation types + */ +#define R_X86_64_NONE 0 /**< @brief @p none none */ +#define R_X86_64_64 1 /**< @brief @p word64 S + A */ +#define R_X86_64_PC32 2 /**< @brief @p word32 S + A - P */ +#define R_X86_64_GOT32 3 /**< @brief @p word32 G + A */ +#define R_X86_64_PLT32 4 /**< @brief @p word32 L + A - P */ +#define R_X86_64_COPY 5 /**< @brief @p none none */ +#define R_X86_64_GLOB_DAT 6 /**< @brief @p word64 S */ +#define R_X86_64_JUMP_SLOT 7 /**< @brief @p word64 S */ +#define R_X86_64_RELATIVE 8 /**< @brief @p word64 B + A */ +#define R_X86_64_GOTPCREL 9 /**< @brief @p word32 G + GOT + A - P */ +#define R_X86_64_32 10 /**< @brief @p word32 S + A */ +#define R_X86_64_32S 11 /**< @brief @p word32 S + A */ +/* vvv These should not appear in a valid file */ +#define R_X86_64_16 12 /**< @brief @p word16 S + A */ +#define R_X86_64_PC16 13 /**< @brief @p word16 S + A - P */ +#define R_X86_64_8 14 /**< @brief @p word8 S + A */ +#define R_X86_64_PC8 15 /**< @brief @p word8 S + A - P */ +/* ^^^ These should not appear in a valid file */ +#define R_X86_64_DTPMOD64 16 /**< @brief @p word64 */ +#define R_X86_64_DTPOFF64 17 /**< @brief @p word64 */ +#define R_X86_64_TPOFF64 18 /**< @brief @p word64 */ +#define R_X86_64_TLSGD 19 /**< @brief @p word32 */ +#define R_X86_64_TLSLD 20 /**< @brief @p word32 */ +#define R_X86_64_DTPOFF32 21 /**< @brief @p word32 */ +#define R_X86_64_GOTTPOFF 22 /**< @brief @p word32 */ +#define R_X86_64_TPOFF32 23 /**< @brief @p word32 */ +#define R_X86_64_PC64 24 /**< @brief @p word64 S + A - P */ +#define R_X86_64_GOTOFF64 25 /**< @brief @p word64 S + A - GOT */ +#define R_X86_64_GOTPC32 26 /**< @brief @p word32 GOT + A - P */ +/* Large model */ +#define R_X86_64_GOT64 27 /**< @brief @p word64 G + A */ +#define R_X86_64_GOTPCREL64 28 /**< @brief @p word64 G + GOT - P + A */ +#define R_X86_64_GOTPC64 29 /**< @brief @p word64 GOT - P + A */ +#define R_X86_64_GOTPLT64 30 /**< @brief @p word64 G + A */ +#define R_X86_64_PLTOFF64 31 /**< @brief @p word64 L - GOT + A */ +/* ... */ +#define R_X86_64_SIZE32 32 /**< @brief @p word32 Z + A */ +#define R_X86_64_SIZE64 33 /**< @brief @p word64 Z + A */ +#define R_X86_64_GOTPC32_TLSDESC 34 /**< @brief @p word32 */ +#define R_X86_64_TLSDESC_CALL 35 /**< @brief @p none */ +#define R_X86_64_TLSDESC 36 /**< @brief @p word64*2 */ +#define R_X86_64_IRELATIVE 37 /**< @brief @p word64 indirect (B + A) */ + + +/** + * Program header types + */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6FFFFFFF +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF +/* From the SysV x86-64 ABI */ +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_SUNW_EH_FRAME 0x6474e550 +#define PT_SUNW_UNWIND 0x6464e550 + + +/** + * Program header flags + */ +#define PF_X 0x01 +#define PF_W 0x02 +#define PF_R 0x04 +#define PF_MASKOS 0x00FF0000 +#define PF_MAKSPROC 0xFF000000 + +typedef struct Elf64_Phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +/** + * Dynamic table + */ + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_LOOS 0x60000000 +#define DT_HIOS 0x6FFFFFFF +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +typedef struct Elf64_Dyn { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + + diff --git a/base/usr/include/kernel/ext2.h b/base/usr/include/kernel/ext2.h deleted file mode 100644 index 965af6cc..00000000 --- a/base/usr/include/kernel/ext2.h +++ /dev/null @@ -1,174 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ -#pragma once - -#ifdef _KERNEL_ -# include -#else -# ifdef BOOTLOADER -# include -# else -# include -# endif -#endif - -#define EXT2_SUPER_MAGIC 0xEF53 - -#define EXT2_DIRECT_BLOCKS 12 - -/* Super block struct. */ -struct ext2_superblock { - uint32_t inodes_count; - uint32_t blocks_count; - uint32_t r_blocks_count; - uint32_t free_blocks_count; - uint32_t free_inodes_count; - uint32_t first_data_block; - uint32_t log_block_size; - uint32_t log_frag_size; - uint32_t blocks_per_group; - uint32_t frags_per_group; - uint32_t inodes_per_group; - uint32_t mtime; - uint32_t wtime; - - uint16_t mnt_count; - uint16_t max_mnt_count; - uint16_t magic; - uint16_t state; - uint16_t errors; - uint16_t minor_rev_level; - - uint32_t lastcheck; - uint32_t checkinterval; - uint32_t creator_os; - uint32_t rev_level; - - uint16_t def_resuid; - uint16_t def_resgid; - - /* EXT2_DYNAMIC_REV */ - uint32_t first_ino; - uint16_t inode_size; - uint16_t block_group_nr; - uint32_t feature_compat; - uint32_t feature_incompat; - uint32_t feature_ro_compat; - - uint8_t uuid[16]; - uint8_t volume_name[16]; - - uint8_t last_mounted[64]; - - uint32_t algo_bitmap; - - /* Performance Hints */ - uint8_t prealloc_blocks; - uint8_t prealloc_dir_blocks; - uint16_t _padding; - - /* Journaling Support */ - uint8_t journal_uuid[16]; - uint32_t journal_inum; - uint32_t jounral_dev; - uint32_t last_orphan; - - /* Directory Indexing Support */ - uint32_t hash_seed[4]; - uint8_t def_hash_version; - uint16_t _padding_a; - uint8_t _padding_b; - - /* Other Options */ - uint32_t default_mount_options; - uint32_t first_meta_bg; - uint8_t _unused[760]; - -} __attribute__ ((packed)); - -typedef struct ext2_superblock ext2_superblock_t; - -/* Block group descriptor. */ -struct ext2_bgdescriptor { - uint32_t block_bitmap; - uint32_t inode_bitmap; // block no. of inode bitmap - uint32_t inode_table; - uint16_t free_blocks_count; - uint16_t free_inodes_count; - uint16_t used_dirs_count; - uint16_t pad; - uint8_t reserved[12]; -} __attribute__ ((packed)); - -typedef struct ext2_bgdescriptor ext2_bgdescriptor_t; - -/* File Types */ -#define EXT2_S_IFSOCK 0xC000 -#define EXT2_S_IFLNK 0xA000 -#define EXT2_S_IFREG 0x8000 -#define EXT2_S_IFBLK 0x6000 -#define EXT2_S_IFDIR 0x4000 -#define EXT2_S_IFCHR 0x2000 -#define EXT2_S_IFIFO 0x1000 - -/* setuid, etc. */ -#define EXT2_S_ISUID 0x0800 -#define EXT2_S_ISGID 0x0400 -#define EXT2_S_ISVTX 0x0200 - -/* rights */ -#define EXT2_S_IRUSR 0x0100 -#define EXT2_S_IWUSR 0x0080 -#define EXT2_S_IXUSR 0x0040 -#define EXT2_S_IRGRP 0x0020 -#define EXT2_S_IWGRP 0x0010 -#define EXT2_S_IXGRP 0x0008 -#define EXT2_S_IROTH 0x0004 -#define EXT2_S_IWOTH 0x0002 -#define EXT2_S_IXOTH 0x0001 - -/* This is not actually the inode table. - * It represents an inode in an inode table on disk. */ -struct ext2_inodetable { - uint16_t mode; - uint16_t uid; - uint32_t size; // file length in byte. - uint32_t atime; - uint32_t ctime; - uint32_t mtime; - uint32_t dtime; - uint16_t gid; - uint16_t links_count; - uint32_t blocks; - uint32_t flags; - uint32_t osd1; - uint32_t block[15]; - uint32_t generation; - uint32_t file_acl; - uint32_t dir_acl; - uint32_t faddr; - uint8_t osd2[12]; -} __attribute__ ((packed)); - -typedef struct ext2_inodetable ext2_inodetable_t; - -/* Represents directory entry on disk. */ -struct ext2_dir { - uint32_t inode; - uint16_t rec_len; - uint8_t name_len; - uint8_t file_type; - char name[]; /* Actually a set of characters, at most 255 bytes */ -} __attribute__ ((packed)); - -typedef struct ext2_dir ext2_dir_t; - -typedef struct { - uint32_t block_no; - uint32_t last_use; - uint8_t dirty; - uint8_t *block; -} ext2_disk_cache_entry_t; - -typedef int (*ext2_block_io_t) (void *, uint32_t, uint8_t *); - diff --git a/base/usr/include/kernel/generic.h b/base/usr/include/kernel/generic.h new file mode 100644 index 00000000..72443349 --- /dev/null +++ b/base/usr/include/kernel/generic.h @@ -0,0 +1,22 @@ +#pragma once + +/** + * @brief Initialize early subsystems. + * + * Should be called after the architecture-specific startup routine has + * enabled all hardware required for tasking switching and memory management. + * + * Initializes the scheduler, shared memory subsystem, and virtual file system; + * mounts generic device drivers, sets up the virtual /dev directory, parses + * the architecture-provided kernel arguments, and enables scheduling by + * launching the idle task and converting the current context to 'init'. + */ +void generic_startup(void); + +/** + * @brief Starts init. + * + * Should be called after all architecture-specific initialization is completed. + * Parses the boot arguments and executes /bin/init. + */ +int generic_main(void); diff --git a/base/usr/include/kernel/gzip.h b/base/usr/include/kernel/gzip.h new file mode 100644 index 00000000..56433d9b --- /dev/null +++ b/base/usr/include/kernel/gzip.h @@ -0,0 +1,16 @@ +/** + * @brief Kernel gzip decompressor + * + * This is a slimmed down version of libtoaru_inflate; it's an implementation + * of the tinf algorithm for decompressing gzip/DEFLATE payloads, with a + * very straightforward API: Point @c gzip_inputPtr at your gzip data, + * point @c gzip_outputPtr where you want the output to go, and then + * run @c gzip_decompress(). + */ +#pragma once + +#include + +extern int gzip_decompress(void); +extern uint8_t * gzip_inputPtr; +extern uint8_t * gzip_outputPtr; diff --git a/base/usr/include/kernel/hashmap.h b/base/usr/include/kernel/hashmap.h new file mode 100644 index 00000000..1ce0ff03 --- /dev/null +++ b/base/usr/include/kernel/hashmap.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +typedef unsigned int (*hashmap_hash_t) (const void * key); +typedef int (*hashmap_comp_t) (const void * a, const void * b); +typedef void (*hashmap_free_t) (void *); +typedef void * (*hashmap_dupe_t) (const void *); + +typedef struct hashmap_entry { + char * key; + void * value; + struct hashmap_entry * next; +} hashmap_entry_t; + +typedef struct hashmap { + hashmap_hash_t hash_func; + hashmap_comp_t hash_comp; + hashmap_dupe_t hash_key_dup; + hashmap_free_t hash_key_free; + hashmap_free_t hash_val_free; + size_t size; + hashmap_entry_t ** entries; +} hashmap_t; + +extern hashmap_t * hashmap_create(int size); +extern hashmap_t * hashmap_create_int(int size); +extern void * hashmap_set(hashmap_t * map, const void * key, void * value); +extern void * hashmap_get(hashmap_t * map, const void * key); +extern void * hashmap_remove(hashmap_t * map, const void * key); +extern int hashmap_has(hashmap_t * map, const void * key); +extern list_t * hashmap_keys(hashmap_t * map); +extern list_t * hashmap_values(hashmap_t * map); +extern void hashmap_free(hashmap_t * map); + +extern unsigned int hashmap_string_hash(const void * key); +extern int hashmap_string_comp(const void * a, const void * b); +extern void * hashmap_string_dupe(const void * key); +extern int hashmap_is_empty(hashmap_t * map); + diff --git a/base/usr/include/kernel/ipv4.h b/base/usr/include/kernel/ipv4.h deleted file mode 100644 index 078f0b5b..00000000 --- a/base/usr/include/kernel/ipv4.h +++ /dev/null @@ -1,188 +0,0 @@ -#pragma once - -#include - -struct ethernet_packet { - uint8_t destination[6]; - uint8_t source[6]; - uint16_t type; - uint8_t payload[]; -} __attribute__((packed)); - -struct ipv4_packet { - uint8_t version_ihl; - uint8_t dscp_ecn; - uint16_t length; - uint16_t ident; - uint16_t flags_fragment; - uint8_t ttl; - uint8_t protocol; - uint16_t checksum; - uint32_t source; - uint32_t destination; - uint8_t payload[]; -} __attribute__ ((packed)); - -struct udp_packet { - uint16_t source_port; - uint16_t destination_port; - uint16_t length; - uint16_t checksum; - uint8_t payload[]; -} __attribute__ ((packed)); - -struct dhcp_packet { - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - - uint32_t xid; - - uint16_t secs; - uint16_t flags; - - uint32_t ciaddr; - uint32_t yiaddr; - uint32_t siaddr; - uint32_t giaddr; - - uint8_t chaddr[16]; - - uint8_t sname[64]; - uint8_t file[128]; - - uint32_t magic; - - uint8_t options[]; -} __attribute__ ((packed)); - -struct dns_packet { - uint16_t qid; - uint16_t flags; - uint16_t questions; - uint16_t answers; - uint16_t authorities; - uint16_t additional; - uint8_t data[]; -} __attribute__ ((packed)); - -struct tcp_header { - uint16_t source_port; - uint16_t destination_port; - - uint32_t seq_number; - uint32_t ack_number; - - uint16_t flags; - uint16_t window_size; - uint16_t checksum; - uint16_t urgent; - - uint8_t payload[]; -} __attribute__((packed)); - -struct tcp_check_header { - uint32_t source; - uint32_t destination; - uint8_t zeros; - uint8_t protocol; - uint16_t tcp_len; - uint8_t tcp_header[]; -}; - -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 - -// Note: Data offset is in upper 4 bits of flags field. Shift and subtract 5 since that is the min TCP size. -// If the value is more than 5, multiply by 4 because this field is specified in number of words -#define TCP_OPTIONS_LENGTH(tcp) (((((tcp)->flags) >> 12) - 5) * 4) -#define TCP_HEADER_LENGTH(tcp) ((((tcp)->flags) >> 12) * 4) -#define TCP_HEADER_LENGTH_FLIPPED(tcp) (((htons((tcp)->flags)) >> 12) * 4) - -#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) -#define htons(s) ( (((s) & 0xFF) << 8) | (((s) & 0xFF00) >> 8) ) -#define ntohl(l) htonl((l)) -#define ntohs(s) htons((s)) - -#define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} -#define IPV4_PROT_UDP 17 -#define IPV4_PROT_TCP 6 -#define DHCP_MAGIC 0x63825363 - -#define TCP_FLAGS_FIN (1 << 0) -#define TCP_FLAGS_SYN (1 << 1) -#define TCP_FLAGS_RES (1 << 2) -#define TCP_FLAGS_PSH (1 << 3) -#define TCP_FLAGS_ACK (1 << 4) -#define TCP_FLAGS_URG (1 << 5) -#define TCP_FLAGS_ECE (1 << 6) -#define TCP_FLAGS_CWR (1 << 7) -#define TCP_FLAGS_NS (1 << 8) -#define DATA_OFFSET_5 (0x5 << 12) - -#define ETHERNET_TYPE_IPV4 0x0800 -#define ETHERNET_TYPE_ARP 0x0806 - -extern uint32_t ip_aton(const char * in); -extern void ip_ntoa(uint32_t src_addr, char * out); -extern uint16_t calculate_ipv4_checksum(struct ipv4_packet * p); -uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header * h, void * d, size_t d_words); - -struct tcp_socket { - list_t* is_connected; - uint32_t seq_no; - uint32_t ack_no; - int status; -}; - -// Note: for now, not sure what to put in here, so removing from the union to get rid of compiler warnings about empty struct -// struct udp_socket { -// }; - -struct socket { - uint32_t ip; - uint8_t mac[6]; - uint32_t port_dest; - uint32_t port_recv; - list_t* packet_queue; - spin_lock_t packet_queue_lock; - list_t* packet_wait; - int32_t status; - size_t bytes_available; - size_t bytes_read; - void * current_packet; - uint32_t sock_type; - union { - struct tcp_socket tcp_socket; - // struct udp_socket udp_socket; - } proto_sock; - list_t * alert_waiters; -}; - -struct sized_blob { - size_t size; - uint8_t blob[]; -}; - -struct in_addr { - unsigned long s_addr; // load with inet_pton() -}; - -struct sockaddr { - uint16_t sa_family; - char sa_data[14]; -}; - -struct sockaddr_in { - short sin_family; // e.g. AF_INET, AF_INET6 - unsigned short sin_port; // e.g. htons(3490) - struct in_addr sin_addr; // see struct in_addr, below - char sin_zero[8]; // zero this if you want to -}; - -typedef struct { - uint8_t *payload; - size_t payload_size; -} tcpdata_t; - diff --git a/base/usr/include/kernel/list.h b/base/usr/include/kernel/list.h new file mode 100644 index 00000000..8842fbd1 --- /dev/null +++ b/base/usr/include/kernel/list.h @@ -0,0 +1,50 @@ +/** + * @brief General-purpose doubly-linked list. + */ +#pragma once + +#include +#include + +typedef struct node { + struct node * next; + struct node * prev; + void * value; + struct ListHeader * owner; +} __attribute__((packed)) node_t; + +typedef struct ListHeader { + node_t * head; + node_t * tail; + size_t length; + const char * name; + const void * metadata; +} __attribute__((packed)) list_t; + +extern void list_destroy(list_t * list); +extern void list_free(list_t * list); +extern void list_append(list_t * list, node_t * item); +extern node_t * list_insert(list_t * list, void * item); +extern list_t * list_create(const char * name, const void * metadata); +extern node_t * list_find(list_t * list, void * value); +extern int list_index_of(list_t * list, void * value); +extern void list_remove(list_t * list, size_t index); +extern void list_delete(list_t * list, node_t * node); +extern node_t * list_pop(list_t * list); +extern node_t * list_dequeue(list_t * list); +extern list_t * list_copy(list_t * original); +extern void list_merge(list_t * target, list_t * source); +extern void * list_index(list_t * list, int index); + +extern void list_append_after(list_t * list, node_t * before, node_t * node); +extern node_t * list_insert_after(list_t * list, node_t * before, void * item); + +extern void list_append_before(list_t * list, node_t * after, node_t * node); +extern node_t * list_insert_before(list_t * list, node_t * after, void * item); + +/* Known to conflict with some popular third-party libraries. */ +#ifndef TOARU_LIST_NO_FOREACH +# define foreach(i, list) for (node_t * i = (list)->head; i != NULL; i = i->next) +# define foreachr(i, list) for (node_t * i = (list)->tail; i != NULL; i = i->prev) +#endif + diff --git a/base/usr/include/kernel/logging.h b/base/usr/include/kernel/logging.h deleted file mode 100644 index 5576e68a..00000000 --- a/base/usr/include/kernel/logging.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -typedef enum { - INFO = 0, /* Unimportant */ - NOTICE, /* Important, but not bad */ - WARNING, /* Not what was expected, but still okay */ - ERROR, /* This is bad... */ - CRITICAL, /* Shit */ - INSANE -} log_type_t; - -extern log_type_t debug_level; -extern void * debug_file; -extern void _debug_print(char * title, int line_no, log_type_t level, char *fmt, ...); -extern void (*debug_hook)(void *, char *); -extern void (*debug_video_crash)(char **); - -#ifndef MODULE_NAME -#define MODULE_NAME __FILE__ -#endif - -#ifndef QUIET -#define debug_print(level, ...) _debug_print(MODULE_NAME, __LINE__, level, __VA_ARGS__) -#else -#define debug_print(level, ...) -#endif - diff --git a/base/usr/include/kernel/mem.h b/base/usr/include/kernel/mem.h deleted file mode 100644 index 5e5ca4a9..00000000 --- a/base/usr/include/kernel/mem.h +++ /dev/null @@ -1,16 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ - -#pragma once - -#include - -extern uintptr_t heap_end; - -extern void set_frame(uintptr_t frame_addr); -extern void clear_frame(uintptr_t frame_addr); -extern uint32_t test_frame(uintptr_t frame_addr); -extern uint32_t first_frame(void); - -extern uintptr_t map_to_physical(uintptr_t virtual); - diff --git a/base/usr/include/kernel/misc.h b/base/usr/include/kernel/misc.h new file mode 100644 index 00000000..260fedcc --- /dev/null +++ b/base/usr/include/kernel/misc.h @@ -0,0 +1,14 @@ +#pragma once +#include + +size_t arch_cpu_mhz(void); + +const char * arch_get_cmdline(void); +const char * arch_get_loader(void); + +void arch_pause(void); + +void arch_fatal(void); + +void arch_set_tls_base(uintptr_t tlsbase); +long arch_reboot(void); diff --git a/base/usr/include/kernel/mmu.h b/base/usr/include/kernel/mmu.h new file mode 100644 index 00000000..f41ef833 --- /dev/null +++ b/base/usr/include/kernel/mmu.h @@ -0,0 +1,2 @@ +#pragma once +#include diff --git a/base/usr/include/kernel/mod/net.h b/base/usr/include/kernel/mod/net.h index ec674385..abc246a0 100644 --- a/base/usr/include/kernel/mod/net.h +++ b/base/usr/include/kernel/mod/net.h @@ -1,6 +1,8 @@ #ifndef KERNEL_MOD_NET_H #define KERNEL_MOD_NET_H +#include + typedef uint8_t* (*get_mac_func)(void); typedef struct ethernet_packet* (*get_packet_func)(void); typedef void (*send_packet_func)(uint8_t*, size_t); diff --git a/base/usr/include/kernel/mod/snd.h b/base/usr/include/kernel/mod/snd.h index 115314a5..a7925753 100644 --- a/base/usr/include/kernel/mod/snd.h +++ b/base/usr/include/kernel/mod/snd.h @@ -4,9 +4,8 @@ /* The format isn't really used for anything right now */ #define SND_FORMAT_L16SLE 0 /* Linear 16-bit signed little endian */ +#include #include -#include -#include #define SND_KNOB_VENDOR 1024 diff --git a/base/usr/include/kernel/module.h b/base/usr/include/kernel/module.h deleted file mode 100644 index 7012d305..00000000 --- a/base/usr/include/kernel/module.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include - -typedef struct { - char * name; - int (* initialize)(void); - int (* finalize)(void); -} module_defs; - -typedef struct { - module_defs * mod_info; - void * bin_data; - hashmap_t * symbols; - uintptr_t end; - size_t deps_length; - char * deps; - uintptr_t text_addr; -} module_data_t; - -void (* symbol_find(const char * name))(void); - -extern int module_quickcheck(void * blob); -extern void * module_load_direct(void * blob, size_t size); -extern void * module_load(char * filename); -extern void module_unload(char * name); -extern void modules_install(void); - -#define MODULE_DEF(n,init,fini) \ - module_defs module_info_ ## n = { \ - .name = #n, \ - .initialize = &init, \ - .finalize = &fini \ - } - -extern hashmap_t * modules_get_list(void); -extern hashmap_t * modules_get_symbols(void); - -#define MODULE_DEPENDS(n) \ - static char _mod_dependency_ ## n [] __attribute__((section("moddeps"), used)) = #n - diff --git a/base/usr/include/kernel/mouse.h b/base/usr/include/kernel/mouse.h index 45138390..04fc5500 100644 --- a/base/usr/include/kernel/mouse.h +++ b/base/usr/include/kernel/mouse.h @@ -1,5 +1,7 @@ #pragma once +#include + typedef enum { LEFT_CLICK = 0x01, RIGHT_CLICK = 0x02, diff --git a/base/usr/include/kernel/multiboot.h b/base/usr/include/kernel/multiboot.h index a9ee78ca..e98d9be2 100644 --- a/base/usr/include/kernel/multiboot.h +++ b/base/usr/include/kernel/multiboot.h @@ -1,8 +1,6 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ #pragma once -#include +#include #define MULTIBOOT_MAGIC 0x1BADB002 #define MULTIBOOT_EAX_MAGIC 0x2BADB002 @@ -13,7 +11,7 @@ #define MULTIBOOT_FLAG_AOUT 0x010 #define MULTIBOOT_FLAG_ELF 0x020 #define MULTIBOOT_FLAG_MMAP 0x040 -#define MULTIBOOT_FLAG_DRIVE 0x080 +#define MULTIBOOT_FLAG_DRIVER 0x080 #define MULTIBOOT_FLAG_CONFIG 0x100 #define MULTIBOOT_FLAG_LOADER 0x200 #define MULTIBOOT_FLAG_APM 0x400 @@ -22,37 +20,44 @@ struct multiboot { - uintptr_t flags; - uintptr_t mem_lower; - uintptr_t mem_upper; - uintptr_t boot_device; - uintptr_t cmdline; - uintptr_t mods_count; - uintptr_t mods_addr; - uintptr_t num; - uintptr_t size; - uintptr_t addr; - uintptr_t shndx; - uintptr_t mmap_length; - uintptr_t mmap_addr; - uintptr_t drives_length; - uintptr_t drives_addr; - uintptr_t config_table; - uintptr_t boot_loader_name; - uintptr_t apm_table; - uintptr_t vbe_control_info; - uintptr_t vbe_mode_info; - uintptr_t vbe_mode; - uintptr_t vbe_interface_seg; - uintptr_t vbe_interface_off; - uintptr_t vbe_interface_len; - uintptr_t framebuffer_addr; - uintptr_t framebuffer_pitch; - uintptr_t framebuffer_width; - uintptr_t framebuffer_height; - uint8_t framebuffer_bpp; - uint8_t framebuffer_type; - /* Palette stuff goes here but we don't use it */ + uint32_t flags; + uint32_t mem_lower; + uint32_t mem_upper; + uint32_t boot_device; + uint32_t cmdline; + uint32_t mods_count; + uint32_t mods_addr; + + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; + + uint32_t mmap_length; + uint32_t mmap_addr; + + uint32_t drives_length; + uint32_t drives_addr; + + uint32_t config_table; + + uint32_t boot_loader_name; + + uint32_t apm_table; + + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; + + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; } __attribute__ ((packed)); typedef struct { @@ -81,10 +86,10 @@ typedef struct { } __attribute__ ((packed)) vbe_info_t; typedef struct { - uintptr_t mod_start; - uintptr_t mod_end; - uintptr_t cmdline; - uintptr_t reserved; + uint32_t mod_start; + uint32_t mod_end; + uint32_t cmdline; + uint32_t reserved; } __attribute__ ((packed)) mboot_mod_t; typedef struct { @@ -94,8 +99,3 @@ typedef struct { uint32_t type; } __attribute__ ((packed)) mboot_memmap_t; -extern struct multiboot *copy_multiboot(struct multiboot *mboot_ptr); -extern void dump_multiboot(struct multiboot *mboot_ptr); -extern char * ramdisk; -extern struct multiboot * mboot_ptr; - diff --git a/base/usr/include/kernel/net/e1000.h b/base/usr/include/kernel/net/e1000.h new file mode 100644 index 00000000..f4b58fbc --- /dev/null +++ b/base/usr/include/kernel/net/e1000.h @@ -0,0 +1,102 @@ +#pragma once + +#include + +#define E1000_REG_CTRL 0x0000 +#define E1000_REG_STATUS 0x0008 +#define E1000_REG_EEPROM 0x0014 +#define E1000_REG_CTRL_EXT 0x0018 +#define E1000_REG_ICR 0x00C0 + +#define E1000_REG_RCTRL 0x0100 +#define E1000_REG_RXDESCLO 0x2800 +#define E1000_REG_RXDESCHI 0x2804 +#define E1000_REG_RXDESCLEN 0x2808 +#define E1000_REG_RXDESCHEAD 0x2810 +#define E1000_REG_RXDESCTAIL 0x2818 + +#define E1000_REG_TCTRL 0x0400 +#define E1000_REG_TXDESCLO 0x3800 +#define E1000_REG_TXDESCHI 0x3804 +#define E1000_REG_TXDESCLEN 0x3808 +#define E1000_REG_TXDESCHEAD 0x3810 +#define E1000_REG_TXDESCTAIL 0x3818 + +#define E1000_REG_RXADDR 0x5400 + +#define E1000_NUM_RX_DESC 32 +#define E1000_NUM_TX_DESC 8 + +#define RCTL_EN (1 << 1) /* Receiver Enable */ +#define RCTL_SBP (1 << 2) /* Store Bad Packets */ +#define RCTL_UPE (1 << 3) /* Unicast Promiscuous Enabled */ +#define RCTL_MPE (1 << 4) /* Multicast Promiscuous Enabled */ +#define RCTL_LPE (1 << 5) /* Long Packet Reception Enable */ +#define RCTL_LBM_NONE (0 << 6) /* No Loopback */ +#define RCTL_LBM_PHY (3 << 6) /* PHY or external SerDesc loopback */ +#define RCTL_RDMTS_HALF (0 << 8) /* Free Buffer Threshold is 1/2 of RDLEN */ +#define RCTL_RDMTS_QUARTER (1 << 8) /* Free Buffer Threshold is 1/4 of RDLEN */ +#define RCTL_RDMTS_EIGHTH (2 << 8) /* Free Buffer Threshold is 1/8 of RDLEN */ +#define RCTL_MO_36 (0 << 12) /* Multicast Offset - bits 47:36 */ +#define RCTL_MO_35 (1 << 12) /* Multicast Offset - bits 46:35 */ +#define RCTL_MO_34 (2 << 12) /* Multicast Offset - bits 45:34 */ +#define RCTL_MO_32 (3 << 12) /* Multicast Offset - bits 43:32 */ +#define RCTL_BAM (1 << 15) /* Broadcast Accept Mode */ +#define RCTL_VFE (1 << 18) /* VLAN Filter Enable */ +#define RCTL_CFIEN (1 << 19) /* Canonical Form Indicator Enable */ +#define RCTL_CFI (1 << 20) /* Canonical Form Indicator Bit Value */ +#define RCTL_DPF (1 << 22) /* Discard Pause Frames */ +#define RCTL_PMCF (1 << 23) /* Pass MAC Control Frames */ +#define RCTL_SECRC (1 << 26) /* Strip Ethernet CRC */ + +#define RCTL_BSIZE_256 (3 << 16) +#define RCTL_BSIZE_512 (2 << 16) +#define RCTL_BSIZE_1024 (1 << 16) +#define RCTL_BSIZE_2048 (0 << 16) +#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) +#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) +#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) + +#define TCTL_EN (1 << 1) /* Transmit Enable */ +#define TCTL_PSP (1 << 3) /* Pad Short Packets */ +#define TCTL_CT_SHIFT 4 /* Collision Threshold */ +#define TCTL_COLD_SHIFT 12 /* Collision Distance */ +#define TCTL_SWXOFF (1 << 22) /* Software XOFF Transmission */ +#define TCTL_RTLC (1 << 24) /* Re-transmit on Late Collision */ + +#define CMD_EOP (1 << 0) /* End of Packet */ +#define CMD_IFCS (1 << 1) /* Insert FCS */ +#define CMD_IC (1 << 2) /* Insert Checksum */ +#define CMD_RS (1 << 3) /* Report Status */ +#define CMD_RPS (1 << 4) /* Report Packet Sent */ +#define CMD_VLE (1 << 6) /* VLAN Packet Enable */ +#define CMD_IDE (1 << 7) /* Interrupt Delay Enable */ + +#define ICR_TXDW (1 << 0) +#define ICR_TXQE (1 << 1) /* Transmit queue is empty */ +#define ICR_LSC (1 << 2) /* Link status changed */ +#define ICR_RXSEQ (1 << 3) /* Receive sequence count error */ +#define ICR_RXDMT0 (1 << 4) /* Receive descriptor minimum threshold */ +/* what's 5 (0x20)? */ +#define ICR_RXO (1 << 6) /* Receive overrun */ +#define ICR_RXT0 (1 << 7) /* Receive timer interrupt? */ + +struct e1000_rx_desc { + volatile uint64_t addr; + volatile uint16_t length; + volatile uint16_t checksum; + volatile uint8_t status; + volatile uint8_t errors; + volatile uint16_t special; +} __attribute__((packed)); /* this looks like it should pack fine as-is */ + +struct e1000_tx_desc { + volatile uint64_t addr; + volatile uint16_t length; + volatile uint8_t cso; + volatile uint8_t cmd; + volatile uint8_t status; + volatile uint8_t css; + volatile uint16_t special; +} __attribute__((packed)); + diff --git a/base/usr/include/kernel/pci.h b/base/usr/include/kernel/pci.h index 0a3ad199..655c6c7c 100644 --- a/base/usr/include/kernel/pci.h +++ b/base/usr/include/kernel/pci.h @@ -1,5 +1,7 @@ #pragma once +#include + #define PCI_VENDOR_ID 0x00 // 2 #define PCI_DEVICE_ID 0x02 // 2 #define PCI_COMMAND 0x04 // 2 @@ -59,10 +61,10 @@ static inline uint32_t pci_box_device(int bus, int slot, int func) { uint32_t pci_read_field(uint32_t device, int field, int size); void pci_write_field(uint32_t device, int field, int size, uint32_t value); uint16_t pci_find_type(uint32_t dev); -void pci_scan_hit(pci_func_t f, uint32_t dev, void * extra); void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void * extra); void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void * extra); void pci_scan_bus(pci_func_t f, int type, int bus, void * extra); void pci_scan(pci_func_t f, int type, void * extra); void pci_remap(void); int pci_get_interrupt(uint32_t device); + diff --git a/base/usr/include/kernel/pipe.h b/base/usr/include/kernel/pipe.h index 1b7a1f87..1571c631 100644 --- a/base/usr/include/kernel/pipe.h +++ b/base/usr/include/kernel/pipe.h @@ -5,7 +5,10 @@ #pragma once -#include +#include +#include +#include +#include typedef struct _pipe_device { uint8_t * buffer; @@ -13,12 +16,16 @@ typedef struct _pipe_device { size_t read_ptr; size_t size; size_t refcount; - volatile int lock_read[2]; - volatile int lock_write[2]; list_t * wait_queue_readers; list_t * wait_queue_writers; int dead; list_t * alert_waiters; + + spin_lock_t lock_read; + spin_lock_t lock_write; + spin_lock_t alert_lock; + spin_lock_t wait_lock; + spin_lock_t ptr_lock; } pipe_device_t; fs_node_t * make_pipe(size_t size); diff --git a/base/usr/include/kernel/printf.h b/base/usr/include/kernel/printf.h index 9182c4de..c52becb0 100644 --- a/base/usr/include/kernel/printf.h +++ b/base/usr/include/kernel/printf.h @@ -1,10 +1,9 @@ #pragma once -#include - -#include - -extern size_t vasprintf(char * buf, const char *fmt, va_list args); -extern int sprintf(char *buf, const char *fmt, ...); -extern int fprintf(fs_node_t * device, char *fmt, ...); +#include +__attribute__((format(__printf__,1,2))) +extern int printf(const char *fmt, ...); +extern size_t (*printf_output)(size_t, uint8_t *); +__attribute__((format(__printf__,3,4))) +extern int snprintf(char * str, size_t size, const char * format, ...); diff --git a/base/usr/include/kernel/process.h b/base/usr/include/kernel/process.h index 215f3e7d..a7823b2e 100644 --- a/base/usr/include/kernel/process.h +++ b/base/usr/include/kernel/process.h @@ -1,162 +1,220 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ - #pragma once -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include +#define PROC_REUSE_FDS 0x0001 +#define KERNEL_STACK_SIZE 0x9000 +#define USER_ROOT_UID 0 -#define KERNEL_STACK_SIZE 0x8000 +typedef struct { + intptr_t refcount; + union PML * directory; + spin_lock_t lock; +} page_directory_t; -typedef signed int pid_t; -typedef unsigned int user_t; -typedef unsigned int status_t; +typedef struct { + uintptr_t sp; /* 0 */ + uintptr_t bp; /* 8 */ + uintptr_t ip; /* 16 */ + uintptr_t tls_base; /* 24 */ + uintptr_t saved[5]; /* XXX Arch dependent */ + /** + * 32: rbx + * 40: r12 + * 48: r13 + * 56: r14 + * 64: r15 + */ +} kthread_context_t; -#define USER_ROOT_UID (user_t)0 - -/* Unix waitpid() options */ -enum wait_option{ - WCONTINUED, - WNOHANG, - WUNTRACED -}; - -/* x86 task */ typedef struct thread { - uintptr_t esp; /* Stack Pointer */ - uintptr_t ebp; /* Base Pointer */ - uintptr_t eip; /* Instruction Pointer */ - - uint8_t fpu_enabled; - uint8_t fp_regs[512]; - - uint8_t padding[32]; /* I don't know */ - - page_directory_t * page_directory; /* Page Directory */ - uintptr_t gsbase; - + kthread_context_t context; + uint8_t fp_regs[512]; + page_directory_t * page_directory; } thread_t; -/* Portable image struct */ typedef struct image { - size_t size; /* Image size */ - uintptr_t entry; /* Binary entry point */ - uintptr_t heap; /* Heap pointer */ - uintptr_t heap_actual; /* Actual heap location */ - uintptr_t stack; /* Process kernel stack */ - uintptr_t user_stack; /* User stack */ - uintptr_t start; + uintptr_t entry; + uintptr_t heap; + uintptr_t stack; uintptr_t shm_heap; - volatile int lock[2]; + spin_lock_t lock; } image_t; -/* Resizable descriptor table */ -typedef struct descriptor_table { +typedef struct file_descriptors { fs_node_t ** entries; - uint64_t * offsets; - int * modes; - size_t length; - size_t capacity; - size_t refs; + uint64_t * offsets; + int * modes; + size_t length; + size_t capacity; + size_t refs; + spin_lock_t lock; } fd_table_t; -/* XXX */ -#define SIG_COUNT 10 +#define PROC_FLAG_IS_TASKLET 0x01 +#define PROC_FLAG_FINISHED 0x02 +#define PROC_FLAG_STARTED 0x04 +#define PROC_FLAG_RUNNING 0x08 +#define PROC_FLAG_SLEEP_INT 0x10 +#define PROC_FLAG_SUSPENDED 0x20 -/* Signal Table */ -typedef struct signal_table { - uintptr_t functions[NUMSIGNALS+1]; -} sig_table_t; - -/* Portable process struct */ typedef struct process { - pid_t id; /* Process ID (pid) */ - char * name; /* Process Name */ - char * description; /* Process description */ - user_t user; /* Effective user */ - user_t real_user; /* Real user ID */ - int mask; /* Umask */ + pid_t id; /* PID */ + pid_t group; /* thread group */ + pid_t job; /* tty job */ + pid_t session; /* tty session */ + int status; /* status code */ + unsigned int flags; /* finished, started, running, isTasklet */ + int owner; - char ** cmdline; + uid_t user; + uid_t real_user; + unsigned int mask; - pid_t group; /* Process thread group */ - pid_t job; /* Process job group */ - pid_t session; /* Session group */ + char * name; + char * description; + char ** cmdline; - thread_t thread; /* Associated task information */ - tree_node_t * tree_entry; /* Process Tree Entry */ - image_t image; /* Binary image information */ - fs_node_t * wd_node; /* Working directory VFS node */ - char * wd_name; /* Working directory path name */ + char * wd_name; + fs_node_t * wd_node; fd_table_t * fds; /* File descriptor table */ - status_t status; /* Process status */ - sig_table_t signals; /* Signal table */ - uint8_t finished; /* Status indicator */ - uint8_t started; - uint8_t running; - struct regs * syscall_registers; /* Registers at interrupt */ - list_t * wait_queue; - list_t * shm_mappings; /* Shared memory chunk mappings */ - list_t * signal_queue; /* Queued signals */ - thread_t signal_state; - char * signal_kstack; - node_t sched_node; - node_t sleep_node; - node_t * timed_sleep_node; - uint8_t is_tasklet; - volatile uint8_t sleep_interrupted; - list_t * node_waits; - int awoken_index; - node_t * timeout_node; + + tree_node_t * tree_entry; + struct regs * syscall_registers; + struct regs * interrupt_registers; + list_t * wait_queue; + list_t * shm_mappings; + list_t * node_waits; + list_t * signal_queue; + char * signal_kstack; + + node_t sched_node; + node_t sleep_node; + node_t * timed_sleep_node; + node_t * timeout_node; + struct timeval start; - uint8_t suspended; + int awoken_index; + + thread_t thread; + thread_t signal_state; + image_t image; + + spin_lock_t sched_lock; + + uintptr_t signals[NUMSIGNALS+1]; } process_t; typedef struct { - unsigned long end_tick; - unsigned long end_subtick; + uint64_t end_tick; + uint64_t end_subtick; process_t * process; int is_fswait; } sleeper_t; +struct ProcessorLocal { + /** + * @brief The running process on this core. + * + * The current_process is a pointer to the process struct for + * the process, userspace-thread, or kernel tasklet currently + * executing. Once the scheduler is active, this should always + * be set. If a core is not currently doing, its current_process + * should be the core's idle task. + * + * Because a process's data can be modified by nested interrupt + * contexts, we mark them as volatile to avoid making assumptions + * based on register-stored cached values. + */ + volatile process_t * current_process; + /** + * @brief Idle loop. + * + * This is a special kernel tasklet that sits in a loop + * waiting for an interrupt from a preemption source or hardware + * device. Its context should never be saved, it should never + * be added to a sleep queue, and it should be scheduled whenever + * there is nothing else to do. + */ + process_t * kernel_idle_task; + /** + * @brief Process this core was last scheduled to run. + */ + volatile process_t * previous_process; + + int cpu_id; + union PML * current_pml; +#ifdef __x86_64__ + int lapic_id; + /* Processor information loaded at startup. */ + int cpu_model; + int cpu_family; + char cpu_model_name[48]; + const char * cpu_manufacturer; +#endif +}; + +extern struct ProcessorLocal processor_local_data[32]; +extern int processor_count; + +/** + * @brief Core-local kernel data. + * + * x86-64: Marking this as __seg_gs makes it %gs-base-relative. + */ +static struct ProcessorLocal __seg_gs * const this_core = 0; + +extern unsigned long process_append_fd(process_t * proc, fs_node_t * node); +extern long process_move_fd(process_t * proc, long src, long dest); extern void initialize_process_tree(void); -extern process_t * spawn_process(volatile process_t * parent, int reuse_fds); -extern void debug_print_process_tree(void); -extern process_t * spawn_init(void); -extern process_t * spawn_kidle(void); -extern void set_process_environment(process_t * proc, page_directory_t * directory); -extern void make_process_ready(process_t * proc); -extern uint8_t process_available(void); -extern process_t * next_ready_process(void); -extern uint32_t process_append_fd(process_t * proc, fs_node_t * node); extern process_t * process_from_pid(pid_t pid); -extern void delete_process(process_t * proc); -process_t * process_get_parent(process_t * process); -extern uint32_t process_move_fd(process_t * proc, int src, int dest); -extern int process_is_ready(process_t * proc); -extern void wakeup_sleepers(unsigned long seconds, unsigned long subseconds); -extern void sleep_until(process_t * process, unsigned long seconds, unsigned long subseconds); - -extern volatile process_t * current_process; -extern process_t * kernel_idle_task; -extern list_t * process_list; - -extern int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout); +extern void process_delete(process_t * proc); +extern void make_process_ready(volatile process_t * proc); +extern volatile process_t * next_ready_process(void); +extern int wakeup_queue(list_t * queue); +extern int wakeup_queue_interrupted(list_t * queue); +extern int sleep_on(list_t * queue); extern int process_alert_node(process_t * process, void * value); +extern void sleep_until(process_t * process, unsigned long seconds, unsigned long subseconds); +extern void switch_task(uint8_t reschedule); +extern int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout); +extern process_t * process_get_parent(process_t * process); +extern int process_is_ready(process_t * proc); +extern void wakeup_sleepers(unsigned long seconds, unsigned long subseconds); +extern void task_exit(int retval); +extern __attribute__((noreturn)) void switch_next(void); extern int process_awaken_from_fswait(process_t * process, int index); - -typedef void (*tasklet_t) (void *, char *); -extern int create_kernel_tasklet(tasklet_t tasklet, char * name, void * argp); - -extern void release_directory(page_directory_t * dir); -extern void release_directory_for_exec(page_directory_t * dir); - -extern void cleanup_process(process_t * proc, int retval); -extern void reap_process(process_t * proc); +extern void process_release_directory(page_directory_t * dir); +extern process_t * spawn_worker_thread(void (*entrypoint)(void * argp), const char * name, void * argp); +extern pid_t fork(void); +extern pid_t clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg); extern int waitpid(int pid, int * status, int options); +extern int exec(const char * path, int argc, char *const argv[], char *const env[], int interp_depth); -extern int is_valid_process(process_t * process); +extern tree_t * process_tree; /* Parent->Children tree */ +extern list_t * process_list; /* Flat storage */ +extern list_t * process_queue; /* Ready queue */ +extern list_t * sleep_queue; + +extern void arch_enter_tasklet(void); +extern __attribute__((noreturn)) void arch_resume_user(void); +extern __attribute__((noreturn)) void arch_restore_context(volatile thread_t * buf); +extern __attribute__((returns_twice)) int arch_save_context(volatile thread_t * buf); +extern void arch_restore_floating(process_t * proc); +extern void arch_save_floating(process_t * proc); +extern void arch_set_kernel_stack(uintptr_t); +extern void arch_enter_user(uintptr_t entrypoint, int argc, char * argv[], char * envp[], uintptr_t stack); +__attribute__((noreturn)) +extern void arch_enter_signal_handler(uintptr_t,int); +extern void arch_wakeup_others(void); diff --git a/base/usr/include/kernel/procfs.h b/base/usr/include/kernel/procfs.h new file mode 100644 index 00000000..6bc09ae6 --- /dev/null +++ b/base/usr/include/kernel/procfs.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct procfs_entry { + intptr_t id; + const char * name; + read_type_t func; +}; + +extern int procfs_install(struct procfs_entry * entry); +extern void procfs_initialize(void); diff --git a/base/usr/include/kernel/pty.h b/base/usr/include/kernel/pty.h index 5990752d..0854c0d7 100644 --- a/base/usr/include/kernel/pty.h +++ b/base/usr/include/kernel/pty.h @@ -1,13 +1,14 @@ #pragma once -#include +#include #include +#include #include #include typedef struct pty { /* the PTY number */ - int name; + intptr_t name; /* Master and slave endpoints */ fs_node_t * master; diff --git a/base/usr/include/kernel/ramdisk.h b/base/usr/include/kernel/ramdisk.h new file mode 100644 index 00000000..c8a8bf52 --- /dev/null +++ b/base/usr/include/kernel/ramdisk.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include +#include + +extern fs_node_t * ramdisk_mount(uintptr_t, size_t); diff --git a/base/usr/include/kernel/ringbuffer.h b/base/usr/include/kernel/ringbuffer.h index a062a7c0..ee957abd 100644 --- a/base/usr/include/kernel/ringbuffer.h +++ b/base/usr/include/kernel/ringbuffer.h @@ -1,11 +1,16 @@ #pragma once +#include +#include +#include +#include + typedef struct { unsigned char * buffer; size_t write_ptr; size_t read_ptr; size_t size; - volatile int lock[2]; + spin_lock_t lock; list_t * wait_queue_readers; list_t * wait_queue_writers; int internal_stop; diff --git a/base/usr/include/kernel/shm.h b/base/usr/include/kernel/shm.h index 7c8f32f5..66294d8a 100644 --- a/base/usr/include/kernel/shm.h +++ b/base/usr/include/kernel/shm.h @@ -2,7 +2,8 @@ */ #pragma once -#include +#include +#include #include #define SHM_PATH_SEPARATOR "." @@ -13,9 +14,8 @@ struct shm_node; typedef struct { struct shm_node * parent; volatile uint8_t lock; - int32_t ref_count; - - uint32_t num_frames; + ssize_t ref_count; + size_t num_frames; uintptr_t *frames; } shm_chunk_t; @@ -27,8 +27,7 @@ typedef struct shm_node { typedef struct { shm_chunk_t * chunk; uint8_t volatile lock; - - uint32_t num_vaddrs; + size_t num_vaddrs; uintptr_t *vaddrs; } shm_mapping_t; diff --git a/base/usr/include/kernel/signal.h b/base/usr/include/kernel/signal.h index 126100d3..57e91127 100644 --- a/base/usr/include/kernel/signal.h +++ b/base/usr/include/kernel/signal.h @@ -1,11 +1,20 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ - #pragma once -#include -void return_from_signal_handler(void); -void fix_signal_stacks(void); +#include +#include +#include -#include +typedef struct { + int signum; + uintptr_t handler; + struct regs registers_before; +} signal_t; + +extern void fix_signal_stacks(void); +extern int send_signal(pid_t process, int signal, int force_root); +extern int group_send_signal(pid_t group, int signal, int force_root); +extern void handle_signal(process_t * proc, signal_t * sig); + +__attribute__((noreturn)) +extern void return_from_signal_handler(void); diff --git a/base/usr/include/kernel/spinlock.h b/base/usr/include/kernel/spinlock.h new file mode 100644 index 00000000..4b622d63 --- /dev/null +++ b/base/usr/include/kernel/spinlock.h @@ -0,0 +1,19 @@ +#pragma once + +typedef volatile struct { + volatile int latch[1]; + int owner; + const char * func; +} spin_lock_t; +#define spin_init(lock) do { (lock).owner = 0; (lock).latch[0] = 0; (lock).func = NULL; } while (0) + +#define DEBUG_LOCKS +#ifdef DEBUG_LOCKS +#define spin_lock(lock) do { while (__sync_lock_test_and_set((lock).latch, 0x01)); (lock).owner = this_core->cpu_id+1; (lock).func = __func__; } while (0) +#define spin_unlock(lock) do { (lock).func = NULL; (lock).owner = -1; __sync_lock_release((lock).latch); } while (0) +#else +#define spin_lock(lock) do { while (__sync_lock_test_and_set((lock).latch, 0x01)); } while(0) +#define spin_unlock(lock) __sync_lock_release((lock).latch); +#endif + +#include diff --git a/base/usr/include/kernel/libc.h b/base/usr/include/kernel/string.h similarity index 71% rename from base/usr/include/kernel/libc.h rename to base/usr/include/kernel/string.h index e2fa14d9..f79c639d 100644 --- a/base/usr/include/kernel/libc.h +++ b/base/usr/include/kernel/string.h @@ -1,14 +1,10 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ #pragma once #include -#define MIN(A, B) ((A) < (B) ? (A) : (B)) -#define MAX(A, B) ((A) > (B) ? (A) : (B)) - extern void * memcpy(void * restrict dest, const void * restrict src, size_t n); extern void * memset(void * dest, int c, size_t n); +extern unsigned short * memsetw(unsigned short * dest, unsigned short val, int count); extern void * memchr(const void * src, int c, size_t n); extern void * memrchr(const void * m, int c, size_t n); extern void * memmove(void *dest, const void *src, size_t n); @@ -32,6 +28,11 @@ extern size_t strlen(const char * s); extern int atoi(const char * s); -/* Non-standard broken strtok_r */ extern char * strtok_r(char * str, const char * delim, char ** saveptr); +extern void * __attribute__ ((malloc)) malloc(uintptr_t size); +extern void * __attribute__ ((malloc)) realloc(void * ptr, uintptr_t size); +extern void * __attribute__ ((malloc)) calloc(uintptr_t nmemb, uintptr_t size); +extern void * __attribute__ ((malloc)) valloc(uintptr_t size); +extern void free(void * ptr); +extern uint8_t startswith(const char * str, const char * accept); diff --git a/base/usr/include/kernel/symboltable.h b/base/usr/include/kernel/symboltable.h new file mode 100644 index 00000000..e106333e --- /dev/null +++ b/base/usr/include/kernel/symboltable.h @@ -0,0 +1,11 @@ +#pragma once + +extern char kernel_symbols_start[]; +extern char kernel_symbols_end[]; + +typedef struct { + uintptr_t addr; + char name[]; +} kernel_symbol_t; + + diff --git a/base/usr/include/kernel/syscall.h b/base/usr/include/kernel/syscall.h new file mode 100644 index 00000000..511b3cc8 --- /dev/null +++ b/base/usr/include/kernel/syscall.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +#define FD_INRANGE(FD) \ + ((FD) < (int)this_core->current_process->fds->length && (FD) >= 0) +#define FD_ENTRY(FD) \ + (this_core->current_process->fds->entries[(FD)]) +#define FD_CHECK(FD) \ + (FD_INRANGE(FD) && FD_ENTRY(FD)) +#define FD_OFFSET(FD) \ + (this_core->current_process->fds->offsets[(FD)]) +#define FD_MODE(FD) \ + (this_core->current_process->fds->modes[(FD)]) + +#define PTR_INRANGE(PTR) \ + ((uintptr_t)(PTR) > this_core->current_process->image.entry && ((uintptr_t)(PTR) < 0x8000000000000000)) +#define PTR_VALIDATE(PTR) \ + ptr_validate((void *)(PTR), __func__) +extern void ptr_validate(void * ptr, const char * syscall); + +extern long arch_syscall_number(struct regs * r); +extern long arch_syscall_arg0(struct regs * r); +extern long arch_syscall_arg1(struct regs * r); +extern long arch_syscall_arg2(struct regs * r); +extern long arch_syscall_arg3(struct regs * r); +extern long arch_syscall_arg4(struct regs * r); + +extern long arch_stack_pointer(struct regs * r); +extern long arch_user_ip(struct regs * r); + +extern void arch_syscall_return(struct regs * r, long retval); diff --git a/base/usr/include/kernel/system.h b/base/usr/include/kernel/system.h deleted file mode 100644 index 140dfa58..00000000 --- a/base/usr/include/kernel/system.h +++ /dev/null @@ -1,239 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include - -#define ASSUME(cond) __extension__ ({ if (!(cond)) { __builtin_unreachable(); } }) - -#define STR(x) #x -#define STRSTR(x) STR(x) - -#define asm __asm__ -#define volatile __volatile__ - -void int_disable(void); -void int_resume(void); -void int_enable(void); - -#define IRQ_OFF int_disable() -#define IRQ_RES int_resume() -#define IRQ_ON int_enable() -#define PAUSE { asm volatile ("hlt"); } - -#define STOP while (1) { PAUSE; } - -#define SYSCALL_VECTOR 0x7F -#define SIGNAL_RETURN 0xFFFFDEAF -#define THREAD_RETURN 0xFFFFB00F - -extern void * code; -extern void * end; - -extern char * boot_arg; /* Argument to pass to init */ -extern char * boot_arg_extra; /* Extra data to pass to init */ - -extern void *sbrk(uintptr_t increment); - -/* spin.c */ -typedef volatile int spin_lock_t[2]; -extern void spin_init(spin_lock_t lock); -extern void spin_lock(spin_lock_t lock); -extern void spin_unlock(spin_lock_t lock); - -extern void return_to_userspace(void); - -/* Kernel Main */ -extern unsigned short *memsetw(unsigned short *dest, unsigned short val, int count); - -extern unsigned char inportb(unsigned short _port); -extern void outportb(unsigned short _port, unsigned char _data); -extern unsigned short inports(unsigned short _port); -extern void outports(unsigned short _port, unsigned short _data); -extern unsigned int inportl(unsigned short _port); -extern void outportl(unsigned short _port, unsigned int _data); -extern void outportsm(unsigned short port, unsigned char * data, unsigned long size); -extern void inportsm(unsigned short port, unsigned char * data, unsigned long size); - - -extern size_t lfind(const char * str, const char accept); -extern size_t rfind(const char * str, const char accept); - -extern uint32_t krand(void); - -extern uint8_t startswith(const char * str, const char * accept); - -/* GDT */ -extern void gdt_install(void); -extern void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran); -extern void set_kernel_stack(uintptr_t stack); -extern void gdt_set_gsbase(uintptr_t base); -extern uintptr_t gdt_get_gsbase(void); - -/* IDT */ -extern void idt_install(void); -extern void idt_set_gate(uint8_t num, void (*base)(void), uint16_t sel, uint8_t flags); - -/* Registers - * - * Note: if the order of these changes, sys/task.S must be changed to use - * the correct offsets as well. - */ -struct regs { - unsigned int _unused, fs, es, ds; - unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; - unsigned int int_no, err_code; - unsigned int eip, cs, eflags, useresp, ss; -}; - -typedef struct regs regs_t; - -typedef void (*irq_handler_t) (struct regs *); -typedef int (*irq_handler_chain_t) (struct regs *); - -/* Panic */ -#define HALT_AND_CATCH_FIRE(mesg, regs) halt_and_catch_fire(mesg, __FILE__, __LINE__, regs) -#define assert(statement) ((statement) ? (void)0 : assert_failed(__FILE__, __LINE__, #statement)) -void halt_and_catch_fire(char *error_message, const char *file, int line, struct regs * regs); -void assert_failed(const char *file, uint32_t line, const char *desc); - -/* ISRS */ -extern void isrs_install(void); -extern void isrs_install_handler(size_t isrs, irq_handler_t); -extern void isrs_uninstall_handler(size_t isrs); - -/* Interrupt Handlers */ -extern void irq_install(void); -extern void irq_install_handler(size_t irq, irq_handler_chain_t, char * desc); -extern void irq_uninstall_handler(size_t irq); -extern int irq_is_handler_free(size_t irq); -extern void irq_gates(void); -extern void irq_ack(size_t); - -/* Timer */ -extern void timer_install(void); -extern unsigned long timer_ticks; -extern unsigned long timer_subticks; -extern signed long timer_drift; -extern void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds); - -/* Memory Management */ -extern uintptr_t placement_pointer; -extern void kmalloc_startat(uintptr_t address); -extern uintptr_t kmalloc_real(size_t size, int align, uintptr_t * phys); -extern uintptr_t kmalloc(size_t size); -extern uintptr_t kvmalloc(size_t size); -extern uintptr_t kmalloc_p(size_t size, uintptr_t * phys); -extern uintptr_t kvmalloc_p(size_t size, uintptr_t * phys); - -// Page types moved to task.h - -extern page_directory_t *kernel_directory; -extern page_directory_t *current_directory; - -extern void paging_install(uint32_t memsize); -extern void paging_prestart(void); -extern void paging_finalize(void); -extern void paging_mark_system(uint64_t addr); -extern void switch_page_directory(page_directory_t * new); -extern void invalidate_page_tables(void); -extern void invalidate_tables_at(uintptr_t addr); -extern page_t *get_page(uintptr_t address, int make, page_directory_t * dir); -extern void page_fault(struct regs *r); -extern void dma_frame(page_t * page, int, int, uintptr_t); -extern void debug_print_directory(page_directory_t *); - -int debug_shell_start(void); - -void heap_install(void); - -void alloc_frame(page_t *page, int is_kernel, int is_writeable); -void free_frame(page_t *page); -uintptr_t memory_use(void); -uintptr_t memory_total(void); - -/* klmalloc */ -void * __attribute__ ((malloc)) malloc(uintptr_t size); -void * __attribute__ ((malloc)) realloc(void *ptr, uintptr_t size); -void * __attribute__ ((malloc)) calloc(uintptr_t nmemb, uintptr_t size); -void * __attribute__ ((malloc)) valloc(uintptr_t size); -void free(void *ptr); - -/* Tasks */ -extern uintptr_t read_eip(void); -extern void copy_page_physical(uint32_t, uint32_t); -extern page_directory_t * clone_directory(page_directory_t * src); -extern page_table_t * clone_table(page_table_t * src, uintptr_t * physAddr); -extern void move_stack(void *new_stack_start, size_t size); -extern void kexit(int retval); -extern void task_exit(int retval); -extern uint32_t next_pid; - -extern void tasking_install(void); -extern void switch_task(uint8_t reschedule); -extern void switch_next(void); -extern uint32_t fork(void); -extern uint32_t clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg); -extern uint32_t getpid(void); -extern void enter_user_jmp(uintptr_t location, int argc, char ** argv, uintptr_t stack); - -extern uintptr_t initial_esp; - -/* Kernel Argument Parser */ -extern void parse_args(char * argv); - -/* CMOS */ -extern void get_time(uint16_t * hours, uint16_t * minutes, uint16_t * seconds); -extern void get_date(uint16_t * month, uint16_t * day); -extern uint32_t boot_time; -extern uint32_t read_cmos(void); - -extern int gettimeofday(struct timeval * t, void * z); -extern uint32_t now(void); - - -/* Floating Point Unit */ -extern void switch_fpu(void); -extern void unswitch_fpu(void); -extern void fpu_install(void); - -/* ELF */ -extern int exec( char *, int, char **, char **, int); -extern int system( char *, int, char **, char **); - -/* Sytem Calls */ -extern void syscalls_install(void); - -/* wakeup queue */ -extern int wakeup_queue(list_t * queue); -extern int wakeup_queue_interrupted(list_t * queue); -extern int sleep_on(list_t * queue); - -typedef struct { - uint32_t signum; - uintptr_t handler; - regs_t registers_before; -} signal_t; - -extern void handle_signal(process_t *, signal_t *); - -extern int send_signal(pid_t process, uint32_t signal, int force); -extern int group_send_signal(int group, uint32_t signal, int force_root); - -#define USER_STACK_BOTTOM 0xAFF00000 -#define USER_STACK_TOP 0xB0000000 -#define SHM_START 0xB0000000 - -extern void validate(void * ptr); -extern int validate_safe(void * ptr); - -#include - diff --git a/base/usr/include/kernel/task.h b/base/usr/include/kernel/task.h deleted file mode 100644 index a5639ae9..00000000 --- a/base/usr/include/kernel/task.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -typedef struct page { - unsigned int present:1; - unsigned int rw:1; - unsigned int user:1; - unsigned int writethrough:1; - unsigned int cachedisable:1; - unsigned int accessed:1; - unsigned int dirty:1; - unsigned int pat:1; - unsigned int global:1; - unsigned int unused:3; - unsigned int frame:20; -} __attribute__((packed)) page_t; - -typedef struct page_table { - page_t pages[1024]; -} page_table_t; - -typedef struct page_directory { - uintptr_t physical_tables[1024]; /* Physical addresses of the tables */ - page_table_t *tables[1024]; /* 1024 pointers to page tables... */ - uintptr_t physical_address; /* The physical address of physical_tables */ - int32_t ref_count; -} page_directory_t; - diff --git a/base/usr/include/kernel/time.h b/base/usr/include/kernel/time.h new file mode 100644 index 00000000..e136da6c --- /dev/null +++ b/base/usr/include/kernel/time.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +extern void relative_time(unsigned long, unsigned long, unsigned long *, unsigned long *); +extern uint64_t now(void); diff --git a/base/usr/include/kernel/mod/tmpfs.h b/base/usr/include/kernel/tmpfs.h similarity index 77% rename from base/usr/include/kernel/mod/tmpfs.h rename to base/usr/include/kernel/tmpfs.h index ea606d66..6e5722aa 100644 --- a/base/usr/include/kernel/mod/tmpfs.h +++ b/base/usr/include/kernel/tmpfs.h @@ -1,6 +1,7 @@ -#ifndef _TMPFS_H__ -#define _TMPFS_H__ -#include +#pragma once +#include +#include +#include fs_node_t * tmpfs_create(char * name); @@ -8,15 +9,15 @@ struct tmpfs_file { char * name; int type; int mask; - int uid; - int gid; + uid_t uid; + uid_t gid; unsigned int atime; unsigned int mtime; unsigned int ctime; size_t length; size_t block_count; size_t pointers; - char ** blocks; + uintptr_t * blocks; char * target; }; @@ -35,4 +36,3 @@ struct tmpfs_dir { struct tmpfs_dir * parent; }; -#endif /* _TMPFS_H__ */ diff --git a/base/usr/include/kernel/tokenize.h b/base/usr/include/kernel/tokenize.h index a9d3ba0c..9ac39c59 100644 --- a/base/usr/include/kernel/tokenize.h +++ b/base/usr/include/kernel/tokenize.h @@ -1,4 +1,3 @@ #pragma once -int tokenize(char *, char *, char **); - +int tokenize(char * str, const char * sep, char **buf); diff --git a/base/usr/include/kernel/tree.h b/base/usr/include/kernel/tree.h new file mode 100644 index 00000000..2207f84a --- /dev/null +++ b/base/usr/include/kernel/tree.h @@ -0,0 +1,36 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose tree implementation + */ +#pragma once + +#include + +typedef struct tree_node { + void * value; + list_t * children; + struct tree_node * parent; +} tree_node_t; + +typedef struct { + size_t nodes; + tree_node_t * root; +} tree_t; + +typedef uint8_t (*tree_comparator_t) (void *, void *); + +extern tree_t * tree_create(void); +extern void tree_set_root(tree_t * tree, void * value); +extern void tree_node_destroy(tree_node_t * node); +extern void tree_destroy(tree_t * tree); +extern void tree_free(tree_t * tree); +extern tree_node_t * tree_node_create(void * value); +extern void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node); +extern tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value); +extern tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle); +extern void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node); +extern void tree_node_remove(tree_t * tree, tree_node_t * node); +extern void tree_remove(tree_t * tree, tree_node_t * node); +extern tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator); +extern void tree_break_off(tree_t * tree, tree_node_t * node); + diff --git a/base/usr/include/kernel/tss.h b/base/usr/include/kernel/tss.h deleted file mode 100644 index 4fe22565..00000000 --- a/base/usr/include/kernel/tss.h +++ /dev/null @@ -1,37 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ -#pragma once - -extern void tss_flush(void); - -typedef struct tss_entry { - uint32_t prev_tss; - uint32_t esp0; - uint32_t ss0; - uint32_t esp1; - uint32_t ss1; - uint32_t esp2; - uint32_t ss2; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t es; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t fs; - uint32_t gs; - uint32_t ldt; - uint16_t trap; - uint16_t iomap_base; -} __attribute__ ((packed)) tss_entry_t; - - diff --git a/base/usr/include/kernel/types.h b/base/usr/include/kernel/types.h index 79716fe8..133b62f0 100644 --- a/base/usr/include/kernel/types.h +++ b/base/usr/include/kernel/types.h @@ -1,19 +1,15 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ #pragma once -/* Types */ - -#define NULL ((void *)0UL) - +#include #include +#include -typedef int wchar_t; -typedef unsigned long size_t; -#define CHAR_BIT 8 +#define asm __asm__ +#define volatile __volatile__ -struct timeval { - uint32_t tv_sec; - uint32_t tv_usec; -}; +#define ALIGN (sizeof(size_t)) + +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(X) (((X)-ONES) & ~(X) & HIGHS) diff --git a/base/usr/include/kernel/ubsan.h b/base/usr/include/kernel/ubsan.h deleted file mode 100644 index c8be5939..00000000 --- a/base/usr/include/kernel/ubsan.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include - -struct TypeDescriptor { - uint16_t type_kind; - uint16_t type_info; - char type_name[1]; -}; - -struct SourceLocation { - const char *file_name; - uint32_t line; - uint32_t column; -}; - -struct OverflowData { - struct SourceLocation location; - struct TypeDescriptor *type; -}; - -struct TypeMismatchData { - struct SourceLocation location; - struct TypeDescriptor *type; - unsigned long alignment; - unsigned char type_check_kind; -}; - -struct NonnullArgData { - struct SourceLocation location; - struct SourceLocation attr_location; - int arg_index; -}; - -struct NonnullReturnData { - struct SourceLocation location; - struct SourceLocation attr_location; -}; - -struct VLABoundData { - struct SourceLocation location; - struct TypeDescriptor *type; -}; - -struct OutOfBoundsData { - struct SourceLocation location; - struct TypeDescriptor *array_type; - struct TypeDescriptor *index_type; -}; - -struct ShiftOutOfBoundsData { - struct SourceLocation location; - struct TypeDescriptor *lhs_type; - struct TypeDescriptor *rhs_type; -}; - -struct UnreachableData { - struct SourceLocation location; -}; - -struct InvalidValueData { - struct SourceLocation location; - struct TypeDescriptor *type; -}; - -typedef int64_t s_max; -typedef uint64_t u_max; - diff --git a/base/usr/include/kernel/version.h b/base/usr/include/kernel/version.h index a19664be..4ecbe175 100644 --- a/base/usr/include/kernel/version.h +++ b/base/usr/include/kernel/version.h @@ -1,19 +1,19 @@ #pragma once -extern char * __kernel_name; -extern char * __kernel_version_format; +extern const char * __kernel_name; +extern const char * __kernel_version_format; extern int __kernel_version_major; extern int __kernel_version_minor; extern int __kernel_version_lower; -extern char * __kernel_version_suffix; -extern char * __kernel_version_codename; +extern const char * __kernel_version_suffix; +extern const char * __kernel_version_codename; -extern char * __kernel_arch; +extern const char * __kernel_arch; -extern char * __kernel_build_date; -extern char * __kernel_build_time; +extern const char * __kernel_build_date; +extern const char * __kernel_build_time; -extern char * __kernel_compiler_version; +extern const char * __kernel_compiler_version; diff --git a/base/usr/include/kernel/fs.h b/base/usr/include/kernel/vfs.h similarity index 73% rename from base/usr/include/kernel/fs.h rename to base/usr/include/kernel/vfs.h index a211da52..a2f2a28a 100644 --- a/base/usr/include/kernel/fs.h +++ b/base/usr/include/kernel/vfs.h @@ -1,8 +1,9 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - */ - #pragma once +#include +#include +#include + #define PATH_SEPARATOR '/' #define PATH_SEPARATOR_STRING "/" #define PATH_UP ".." @@ -39,11 +40,11 @@ struct fs_node; -typedef uint32_t (*read_type_t) (struct fs_node *, uint64_t, uint32_t, uint8_t *); -typedef uint32_t (*write_type_t) (struct fs_node *, uint64_t, uint32_t, uint8_t *); +typedef uint64_t (*read_type_t) (struct fs_node *, uint64_t, uint64_t, uint8_t *); +typedef uint64_t (*write_type_t) (struct fs_node *, uint64_t, uint64_t, uint8_t *); typedef void (*open_type_t) (struct fs_node *, unsigned int flags); typedef void (*close_type_t) (struct fs_node *); -typedef struct dirent *(*readdir_type_t) (struct fs_node *, uint32_t); +typedef struct dirent *(*readdir_type_t) (struct fs_node *, uint64_t); typedef struct fs_node *(*finddir_type_t) (struct fs_node *, char *name); typedef int (*create_type_t) (struct fs_node *, char *name, uint16_t permission); typedef int (*unlink_type_t) (struct fs_node *, char *name); @@ -61,19 +62,19 @@ typedef void (*truncate_type_t) (struct fs_node *); typedef struct fs_node { char name[256]; /* The filename. */ void * device; /* Device object (optional) */ - uint32_t mask; /* The permissions mask. */ - uint32_t uid; /* The owning user. */ - uint32_t gid; /* The owning group. */ - uint32_t flags; /* Flags (node type, etc). */ - uint32_t inode; /* Inode number. */ - uint32_t length; /* Size of the file, in byte. */ - uint32_t impl; /* Used to keep track which fs it belongs to. */ - uint32_t open_flags; /* Flags passed to open (read/write/append, etc.) */ + uint64_t mask; /* The permissions mask. */ + uid_t uid; /* The owning user. */ + uid_t gid; /* The owning group. */ + uint64_t flags; /* Flags (node type, etc). */ + uint64_t inode; /* Inode number. */ + uint64_t length; /* Size of the file, in byte. */ + uint64_t impl; /* Used to keep track which fs it belongs to. */ + uint64_t open_flags; /* Flags passed to open (read/write/append, etc.) */ /* times */ - uint32_t atime; /* Accessed */ - uint32_t mtime; /* Modified */ - uint32_t ctime; /* Created */ + uint64_t atime; /* Accessed */ + uint64_t mtime; /* Modified */ + uint64_t ctime; /* Created */ /* File operations */ read_type_t read; @@ -93,8 +94,8 @@ typedef struct fs_node { truncate_type_t truncate; struct fs_node *ptr; /* Alias pointer, for symlinks. */ - int32_t refcount; - uint32_t nlink; + int64_t refcount; + uint64_t nlink; selectcheck_type_t selectcheck; selectwait_type_t selectwait; @@ -116,12 +117,9 @@ struct stat { uint16_t st_gid; uint16_t st_rdev; uint32_t st_size; - uint32_t st_atime; - uint32_t __unused1; - uint32_t st_mtime; - uint32_t __unused2; - uint32_t st_ctime; - uint32_t __unused3; + uint64_t st_atime; + uint64_t st_mtime; + uint64_t st_ctime; uint32_t st_blksize; uint32_t st_blocks; }; @@ -137,16 +135,16 @@ extern fs_node_t *fs_root; extern int pty_create(void *size, fs_node_t ** fs_master, fs_node_t ** fs_slave); int has_permission(fs_node_t *node, int permission_bit); -uint32_t read_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer); -uint32_t write_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer); +uint64_t read_fs(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer); +uint64_t write_fs(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer); void open_fs(fs_node_t *node, unsigned int flags); void close_fs(fs_node_t *node); -struct dirent *readdir_fs(fs_node_t *node, uint32_t index); +struct dirent *readdir_fs(fs_node_t *node, uint64_t index); fs_node_t *finddir_fs(fs_node_t *node, char *name); int mkdir_fs(char *name, uint16_t permission); int create_file_fs(char *name, uint16_t permission); -fs_node_t *kopen(char *filename, uint32_t flags); -char *canonicalize_path(char *cwd, char *input); +fs_node_t *kopen(const char *filename, uint64_t flags); +char *canonicalize_path(const char *cwd, const char *input); fs_node_t *clone_fs(fs_node_t * source); int ioctl_fs(fs_node_t *node, int request, void * argp); int chmod_fs(fs_node_t *node, int mode); @@ -159,16 +157,16 @@ int selectwait_fs(fs_node_t * node, void * process); void truncate_fs(fs_node_t * node); void vfs_install(void); -void * vfs_mount(char * path, fs_node_t * local_root); -typedef fs_node_t * (*vfs_mount_callback)(char * arg, char * mount_point); -int vfs_register(char * name, vfs_mount_callback callback); -int vfs_mount_type(char * type, char * arg, char * mountpoint); +void * vfs_mount(const char * path, fs_node_t * local_root); +typedef fs_node_t * (*vfs_mount_callback)(const char * arg, const char * mount_point); +int vfs_register(const char * name, vfs_mount_callback callback); +int vfs_mount_type(const char * type, const char * arg, const char * mountpoint); void vfs_lock(fs_node_t * node); /* Debug purposes only, please */ void debug_print_vfs_tree(void); -void map_vfs_directory(char *); +void map_vfs_directory(const char *); int make_unix_pipe(fs_node_t ** pipes); diff --git a/base/usr/include/kernel/video.h b/base/usr/include/kernel/video.h index a3116a29..9aeef539 100644 --- a/base/usr/include/kernel/video.h +++ b/base/usr/include/kernel/video.h @@ -22,5 +22,5 @@ extern uint16_t lfb_resolution_y; extern uint16_t lfb_resolution_b; extern uint8_t * lfb_vid_memory; extern const char * lfb_driver_name; +extern int framebuffer_initialize(void); #endif - diff --git a/base/usr/include/kuroko b/base/usr/include/kuroko deleted file mode 120000 index 9432f989..00000000 --- a/base/usr/include/kuroko +++ /dev/null @@ -1 +0,0 @@ -../../../kuroko/src/kuroko \ No newline at end of file diff --git a/base/usr/include/memory.h b/base/usr/include/memory.h new file mode 100644 index 00000000..3e144e1f --- /dev/null +++ b/base/usr/include/memory.h @@ -0,0 +1,2 @@ +#pragma once +#include diff --git a/base/usr/include/setjmp.h b/base/usr/include/setjmp.h index 6f41a76c..87686076 100644 --- a/base/usr/include/setjmp.h +++ b/base/usr/include/setjmp.h @@ -7,7 +7,7 @@ _Begin_C_Header /* i386 */ #define _JBLEN 9 -typedef int jmp_buf[_JBLEN]; +typedef long long jmp_buf[_JBLEN]; extern void longjmp(jmp_buf j, int r); extern int setjmp(jmp_buf j); diff --git a/base/usr/include/sys/socket.h b/base/usr/include/sys/socket.h index 9e90de95..ddc3c95f 100644 --- a/base/usr/include/sys/socket.h +++ b/base/usr/include/sys/socket.h @@ -99,6 +99,7 @@ extern uint16_t ntohs(uint16_t netshort); extern int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); extern int accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen); +extern int accept4(int sockfd, struct sockaddr * addr, socklen_t * addrlen, int flags); extern int listen(int sockfd, int backlog); extern int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); extern int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); diff --git a/base/usr/include/sys/stat.h b/base/usr/include/sys/stat.h index 17c7d53e..23f357c9 100644 --- a/base/usr/include/sys/stat.h +++ b/base/usr/include/sys/stat.h @@ -16,13 +16,10 @@ struct stat { uint16_t st_uid; uint16_t st_gid; uint16_t st_rdev; - int32_t st_size; - uint32_t st_atime; - uint32_t __unused1; - int32_t st_mtime; - uint32_t __unused2; - uint32_t st_ctime; - uint32_t __unused3; + uint32_t st_size; + uint64_t st_atime; + uint64_t st_mtime; + uint64_t st_ctime; uint32_t st_blksize; uint32_t st_blocks; }; diff --git a/base/usr/include/sys/termios.h b/base/usr/include/sys/termios.h index 8b66dd9f..464445ea 100644 --- a/base/usr/include/sys/termios.h +++ b/base/usr/include/sys/termios.h @@ -2,11 +2,7 @@ #include <_cheader.h> -#ifndef _KERNEL_ #include -#else -#include -#endif _Begin_C_Header diff --git a/base/usr/include/sys/types.h b/base/usr/include/sys/types.h index 832974aa..f2684fe6 100644 --- a/base/usr/include/sys/types.h +++ b/base/usr/include/sys/types.h @@ -17,20 +17,16 @@ typedef unsigned short nlink_t; typedef long off_t; typedef long time_t; -#if defined(__INT_MAX__) && __INT_MAX__ == 2147483647 -typedef int ssize_t; -#else typedef long ssize_t; -#endif typedef unsigned long useconds_t; typedef long suseconds_t; typedef int pid_t; #define FD_SETSIZE 64 /* compatibility with newlib */ -typedef long fd_mask; +typedef unsigned int fd_mask; typedef struct _fd_set { - fd_mask fds_bits[2]; /* should be 64 bits */ + fd_mask fds_bits[1]; /* should be 64 bits */ } fd_set; _End_C_Header diff --git a/base/usr/include/syscall.h b/base/usr/include/syscall.h index d32f99c3..8ab0e1da 100644 --- a/base/usr/include/syscall.h +++ b/base/usr/include/syscall.h @@ -6,86 +6,85 @@ _Begin_C_Header -#define DECL_SYSCALL0(fn) int syscall_##fn() -#define DECL_SYSCALL1(fn,p1) int syscall_##fn(p1) -#define DECL_SYSCALL2(fn,p1,p2) int syscall_##fn(p1,p2) -#define DECL_SYSCALL3(fn,p1,p2,p3) int syscall_##fn(p1,p2,p3) -#define DECL_SYSCALL4(fn,p1,p2,p3,p4) int syscall_##fn(p1,p2,p3,p4) -#define DECL_SYSCALL5(fn,p1,p2,p3,p4,p5) int syscall_##fn(p1,p2,p3,p4,p5) +#define DECL_SYSCALL0(fn) long syscall_##fn() +#define DECL_SYSCALL1(fn,p1) long syscall_##fn(p1) +#define DECL_SYSCALL2(fn,p1,p2) long syscall_##fn(p1,p2) +#define DECL_SYSCALL3(fn,p1,p2,p3) long syscall_##fn(p1,p2,p3) +#define DECL_SYSCALL4(fn,p1,p2,p3,p4) long syscall_##fn(p1,p2,p3,p4) +#define DECL_SYSCALL5(fn,p1,p2,p3,p4,p5) long syscall_##fn(p1,p2,p3,p4,p5) #define DEFN_SYSCALL0(fn, num) \ - int syscall_##fn() { \ - int a = num; __asm__ __volatile__("int $0x7F" : "=a" (a) : "a" (a)); \ + long syscall_##fn() { \ + long a = num; __asm__ __volatile__("int $0x7F" : "=a" (a) : "a" ((long)a)); \ return a; \ } #define DEFN_SYSCALL1(fn, num, P1) \ - int syscall_##fn(P1 p1) { \ - int __res = num; __asm__ __volatile__("int $0x7F" \ + long syscall_##fn(P1 p1) { \ + long __res = num; __asm__ __volatile__("int $0x7F" \ : "=a" (__res) \ - : "a" (__res), "b" ((int)(p1))); \ + : "a" (__res), "b" ((long)(p1))); \ return __res; \ } #define DEFN_SYSCALL2(fn, num, P1, P2) \ - int syscall_##fn(P1 p1, P2 p2) { \ - int __res = num; __asm__ __volatile__("int $0x7F" \ + long syscall_##fn(P1 p1, P2 p2) { \ + long __res = num; __asm__ __volatile__("int $0x7F" \ : "=a" (__res) \ - : "a" (__res), "b" ((int)(p1)), "c"((int)(p2))); \ + : "a" (__res), "b" ((long)(p1)), "c"((long)(p2))); \ return __res; \ } #define DEFN_SYSCALL3(fn, num, P1, P2, P3) \ - int syscall_##fn(P1 p1, P2 p2, P3 p3) { \ - int __res = num; __asm__ __volatile__("int $0x7F" \ + long syscall_##fn(P1 p1, P2 p2, P3 p3) { \ + long __res = num; __asm__ __volatile__("int $0x7F" \ : "=a" (__res) \ - : "a" (__res), "b" ((int)(p1)), "c"((int)(p2)), "d"((int)(p3))); \ + : "a" (__res), "b" ((long)(p1)), "c"((long)(p2)), "d"((long)(p3))); \ return __res; \ } #define DEFN_SYSCALL4(fn, num, P1, P2, P3, P4) \ - int syscall_##fn(P1 p1, P2 p2, P3 p3, P4 p4) { \ - int __res = num; __asm__ __volatile__("int $0x7F" \ + long syscall_##fn(P1 p1, P2 p2, P3 p3, P4 p4) { \ + long __res = num; __asm__ __volatile__("int $0x7F" \ : "=a" (__res) \ - : "a" (__res), "b" ((int)(p1)), "c"((int)(p2)), "d"((int)(p3)), "S"((int)(p4))); \ + : "a" (__res), "b" ((long)(p1)), "c"((long)(p2)), "d"((long)(p3)), "S"((long)(p4))); \ return __res; \ } #define DEFN_SYSCALL5(fn, num, P1, P2, P3, P4, P5) \ - int syscall_##fn(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { \ - int __res = num; __asm__ __volatile__("int $0x7F" \ + long syscall_##fn(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { \ + long __res = num; __asm__ __volatile__("int $0x7F" \ : "=a" (__res) \ - : "a" (__res), "b" ((int)(p1)), "c"((int)(p2)), "d"((int)(p3)), "S"((int)(p4)), "D"((int)(p5))); \ + : "a" (__res), "b" ((long)(p1)), "c"((long)(p2)), "d"((long)(p3)), "S"((long)(p4)), "D"((long)(p5))); \ return __res; \ } DECL_SYSCALL1(exit, int); -DECL_SYSCALL1(print, const char *); +DECL_SYSCALL0(geteuid); DECL_SYSCALL3(open, const char *, int, int); -DECL_SYSCALL3(read, int, char *, int); -DECL_SYSCALL3(write, int, char *, int); +DECL_SYSCALL3(read, int, char *, size_t); +DECL_SYSCALL3(write, int, char *, size_t); DECL_SYSCALL1(close, int); DECL_SYSCALL2(gettimeofday, void *, void *); DECL_SYSCALL3(execve, char *, char **, char **); DECL_SYSCALL0(fork); DECL_SYSCALL0(getpid); DECL_SYSCALL1(sbrk, int); -DECL_SYSCALL0(getgraphicsaddress); +DECL_SYSCALL3(socket, int, int, int); DECL_SYSCALL1(uname, void *); DECL_SYSCALL5(openpty, int *, int *, char *, void *, void *); -DECL_SYSCALL3(lseek, int, int, int); -DECL_SYSCALL2(fstat, int, void *); -DECL_SYSCALL1(setgraphicsoffset, int); -DECL_SYSCALL1(wait, unsigned int); -DECL_SYSCALL0(getgraphicswidth); -DECL_SYSCALL0(getgraphicsheight); -DECL_SYSCALL0(getgraphicsdepth); -DECL_SYSCALL0(mkpipe); +DECL_SYSCALL3(seek, int, long, int); +DECL_SYSCALL2(stat, int, void *); +DECL_SYSCALL5(setsockopt,int,int,int,const void*,size_t); +DECL_SYSCALL3(bind,int,const void*,size_t); +DECL_SYSCALL4(accept,int,void*,size_t*,int); +DECL_SYSCALL2(listen,int,int); +DECL_SYSCALL3(connect,int,const void*,size_t); DECL_SYSCALL2(dup2, int, int); DECL_SYSCALL0(getuid); DECL_SYSCALL1(setuid, unsigned int); -DECL_SYSCALL1(kernel_string_XXX, char *); +DECL_SYSCALL5(getsockopt,int,int,int,void*,size_t*); DECL_SYSCALL0(reboot); DECL_SYSCALL3(readdir, int, int, void *); DECL_SYSCALL1(chdir, char *); @@ -93,35 +92,37 @@ DECL_SYSCALL2(getcwd, char *, size_t); DECL_SYSCALL3(clone, uintptr_t, uintptr_t, void *); DECL_SYSCALL1(sethostname, char *); DECL_SYSCALL1(gethostname, char *); -DECL_SYSCALL0(mousedevice); DECL_SYSCALL2(mkdir, char *, unsigned int); DECL_SYSCALL2(shm_obtain, char *, size_t *); DECL_SYSCALL1(shm_release, char *); -DECL_SYSCALL2(send_signal, uint32_t, uint32_t); -DECL_SYSCALL2(signal, uint32_t, void *); -DECL_SYSCALL2(share_fd, int, int); -DECL_SYSCALL1(get_fd, int); +DECL_SYSCALL2(kill, int, int); +DECL_SYSCALL2(signal, int, void *); +DECL_SYSCALL3(recv,int,void*,int); +DECL_SYSCALL3(send,int,const void*,int); DECL_SYSCALL0(gettid); DECL_SYSCALL0(yield); -DECL_SYSCALL2(system_function, int, char **); -DECL_SYSCALL1(open_serial, int); +DECL_SYSCALL2(sysfunc, int, char **); +DECL_SYSCALL2(shutdown, int, int); DECL_SYSCALL2(sleepabs, unsigned long, unsigned long); -DECL_SYSCALL2(nanosleep, unsigned long, unsigned long); +DECL_SYSCALL2(sleep, unsigned long, unsigned long); DECL_SYSCALL3(ioctl, int, int, void *); DECL_SYSCALL2(access, char *, int); -DECL_SYSCALL2(stat, char *, void *); +DECL_SYSCALL2(statf, char *, void *); +DECL_SYSCALL2(chmod, char *, int); +DECL_SYSCALL1(umask, int); +DECL_SYSCALL1(unlink, char *); +DECL_SYSCALL3(waitpid, int, int *, int); +DECL_SYSCALL1(pipe, int *); +DECL_SYSCALL5(mount, char *, char *, char *, unsigned long, void *); +DECL_SYSCALL2(symlink, const char *, const char *); +DECL_SYSCALL3(readlink, char *, char *, int); +DECL_SYSCALL2(lstat, char *, void *); DECL_SYSCALL2(fswait,int,int*); DECL_SYSCALL3(fswait2,int,int*,int); DECL_SYSCALL3(chown,char*,int,int); -DECL_SYSCALL3(waitpid, int, int *, int); -DECL_SYSCALL5(mount, char *, char *, char *, unsigned long, void *); -DECL_SYSCALL1(pipe, int *); -DECL_SYSCALL3(readlink, char *, char *, int); DECL_SYSCALL0(setsid); DECL_SYSCALL2(setpgid,int,int); DECL_SYSCALL1(getpgid,int); -DECL_SYSCALL0(geteuid); -DECL_SYSCALL2(lstat, char *, void *); DECL_SYSCALL4(fswait3, int, int*, int, int*); _End_C_Header diff --git a/base/usr/include/syscall_nums.h b/base/usr/include/syscall_nums.h index 714efaff..5532a54c 100644 --- a/base/usr/include/syscall_nums.h +++ b/base/usr/include/syscall_nums.h @@ -11,14 +11,21 @@ #define SYS_FORK 8 #define SYS_GETPID 9 #define SYS_SBRK 10 +#define SYS_SOCKET 11 #define SYS_UNAME 12 #define SYS_OPENPTY 13 #define SYS_SEEK 14 #define SYS_STAT 15 +#define SYS_SETSOCKOPT 16 +#define SYS_BIND 17 +#define SYS_ACCEPT 18 +#define SYS_LISTEN 19 +#define SYS_CONNECT 20 #define SYS_MKPIPE 21 #define SYS_DUP2 22 #define SYS_GETUID 23 #define SYS_SETUID 24 +#define SYS_GETSOCKOPT 25 #define SYS_REBOOT 26 #define SYS_READDIR 27 #define SYS_CHDIR 28 @@ -31,9 +38,12 @@ #define SYS_SHM_RELEASE 36 #define SYS_KILL 37 #define SYS_SIGNAL 38 +#define SYS_RECV 39 +#define SYS_SEND 40 #define SYS_GETTID 41 #define SYS_YIELD 42 #define SYS_SYSFUNC 43 +#define SYS_SHUTDOWN 44 #define SYS_SLEEPABS 45 #define SYS_SLEEP 46 #define SYS_IOCTL 47 diff --git a/base/usr/include/termio.h b/base/usr/include/termio.h new file mode 100644 index 00000000..aa30393c --- /dev/null +++ b/base/usr/include/termio.h @@ -0,0 +1,3 @@ +#pragma once +#include +#include diff --git a/base/usr/include/toaru/pex.h b/base/usr/include/toaru/pex.h index 7ba5d2c9..13bbf012 100644 --- a/base/usr/include/toaru/pex.h +++ b/base/usr/include/toaru/pex.h @@ -19,7 +19,7 @@ typedef struct pex_header { uint8_t data[]; } pex_header_t; -extern size_t pex_send(FILE * sock, unsigned int rcpt, size_t size, char * blob); +extern size_t pex_send(FILE * sock, uintptr_t rcpt, size_t size, char * blob); extern size_t pex_broadcast(FILE * sock, size_t size, char * blob); extern size_t pex_listen(FILE * sock, pex_packet_t * packet); diff --git a/base/usr/include/toaru/rline.h b/base/usr/include/toaru/rline.h index b6face56..1952ca0f 100644 --- a/base/usr/include/toaru/rline.h +++ b/base/usr/include/toaru/rline.h @@ -51,6 +51,8 @@ extern char * rline_history_get(int item); extern char * rline_history_prev(int item); extern void rline_place_cursor(void); extern void rline_set_colors(rline_style_t style); +extern void rline_redraw(rline_context_t * context); +extern void rline_insert(rline_context_t * context, const char * what); extern int rline_terminal_width; #define RLINE_HISTORY_ENTRIES 128 @@ -60,7 +62,3 @@ extern int rline_history_offset; extern int rline_scroll; extern char * rline_exit_string; extern char * rline_preload; - -/* Legacy stuff */ -extern void rline_redraw(rline_context_t * context); -extern void rline_insert(rline_context_t * context, const char * what); diff --git a/base/usr/include/toaru/termemu.h b/base/usr/include/toaru/termemu.h index ca78962d..8d9bd0a2 100644 --- a/base/usr/include/toaru/termemu.h +++ b/base/usr/include/toaru/termemu.h @@ -1,12 +1,7 @@ #pragma once #include <_cheader.h> - -#ifdef _KERNEL_ -# include -#else -# include -#endif +#include _Begin_C_Header diff --git a/base/usr/include/toaru/yutani-server.h b/base/usr/include/toaru/yutani-server.h index 63c750fe..4b5f2b01 100644 --- a/base/usr/include/toaru/yutani-server.h +++ b/base/usr/include/toaru/yutani-server.h @@ -115,7 +115,7 @@ typedef struct YutaniServerWindow { uint8_t * newbuffer; /* Connection that owns this window */ - uint32_t owner; + uintptr_t owner; /* Rotation of windows XXX */ int16_t rotation; @@ -127,8 +127,8 @@ typedef struct YutaniServerWindow { char * client_strings; /* Window animations */ - int anim_mode; - uint32_t anim_start; + uint64_t anim_mode; + uint64_t anim_start; /* Alpha shaping threshold */ int alpha_threshold; @@ -304,14 +304,14 @@ typedef struct YutaniGlobals { } yutani_globals_t; struct key_bind { - unsigned int owner; + uintptr_t owner; int response; }; /* Exported functions for plugins */ extern int yutani_window_is_top(yutani_globals_t * yg, yutani_server_window_t * window); extern int yutani_window_is_bottom(yutani_globals_t * yg, yutani_server_window_t * window); -extern uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time); +extern uint64_t yutani_time_since(yutani_globals_t * yg, uint64_t start_time); extern void yutani_window_to_device(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y); extern void yutani_device_to_window(yutani_server_window_t * window, int32_t x, int32_t y, int32_t * out_x, int32_t * out_y); extern uint32_t yutani_color_for_wid(yutani_wid_t wid); diff --git a/base/usr/include/unistd.h b/base/usr/include/unistd.h index 3e15c436..97bef392 100644 --- a/base/usr/include/unistd.h +++ b/base/usr/include/unistd.h @@ -7,6 +7,8 @@ _Begin_C_Header +#define _POSIX_VERSION 200809L + extern char **environ; extern pid_t getpid(void); @@ -100,4 +102,7 @@ extern void *sbrk(intptr_t increment); extern void sync(void); extern int truncate(const char *, off_t); +#define _PC_PATH_MAX 1 +extern long pathconf(const char *path, int name); + _End_C_Header diff --git a/base/usr/lib/.dummy b/base/usr/lib/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/build/x86_64.mk b/build/x86_64.mk new file mode 100644 index 00000000..0135d4ba --- /dev/null +++ b/build/x86_64.mk @@ -0,0 +1,6 @@ +ARCH=x86_64 + +ARCH_KERNEL_CFLAGS = -mno-red-zone -fno-omit-frame-pointer -mfsgsbase +ARCH_KERNEL_CFLAGS += -mgeneral-regs-only -z max-page-size=0x1000 -nostdlib + +TARGET=x86_64-pc-toaru diff --git a/ext/ext_cairo_renderer.c b/ext/ext_cairo_renderer.c deleted file mode 100644 index d378605c..00000000 --- a/ext/ext_cairo_renderer.c +++ /dev/null @@ -1,257 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2018 K. Lange - * - * Compositor Cairo renderer backend - */ - -#include -#include -#include - -struct cairo_renderer { - cairo_t * framebuffer_ctx; - cairo_surface_t * framebuffer_surface; - cairo_t * real_ctx; - cairo_surface_t * real_surface; -}; - -int renderer_alloc(yutani_globals_t * yg) { - struct cairo_renderer * c = malloc(sizeof(struct cairo_renderer)); - c->framebuffer_ctx = NULL; - c->framebuffer_surface = NULL; - c->real_ctx = NULL; - c->real_surface = NULL; - yg->renderer_ctx = c; - return 0; -} - -int renderer_init(yutani_globals_t * yg) { - struct cairo_renderer * c = yg->renderer_ctx; - - int stride = yg->backend_ctx->stride; - c->framebuffer_surface = cairo_image_surface_create_for_data( - yg->backend_framebuffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride); - c->framebuffer_ctx = cairo_create(c->framebuffer_surface); - - c->real_surface = cairo_image_surface_create_for_data( - (unsigned char *)yg->backend_ctx->buffer, CAIRO_FORMAT_ARGB32, yg->width, yg->height, stride); - c->real_ctx = cairo_create(c->real_surface); - - return 0; -} - -int renderer_add_clip(yutani_globals_t * yg, double x, double y, double w, double h) { - struct cairo_renderer * c = yg->renderer_ctx; - cairo_rectangle(c->framebuffer_ctx, x, y, w, h); - if (yg->width > 2490) { - x = 0; - w = yg->width; - } - cairo_rectangle(c->real_ctx, x, y, w, h); - return 0; -} - -int renderer_set_clip(yutani_globals_t * yg) { - struct cairo_renderer * c = yg->renderer_ctx; - cairo_clip(c->framebuffer_ctx); - cairo_clip(c->real_ctx); - return 0; -} - -int renderer_push_state(yutani_globals_t * yg) { - struct cairo_renderer * c = yg->renderer_ctx; - cairo_save(c->framebuffer_ctx); - cairo_save(c->real_ctx); - return 0; -} - -int renderer_pop_state(yutani_globals_t * yg) { - struct cairo_renderer * c = yg->renderer_ctx; - cairo_restore(c->framebuffer_ctx); - cairo_restore(c->real_ctx); - return 0; -} - -int renderer_destroy(yutani_globals_t * yg) { - struct cairo_renderer * c = yg->renderer_ctx; - cairo_destroy(c->framebuffer_ctx); - cairo_surface_destroy(c->framebuffer_surface); - cairo_destroy(c->real_ctx); - cairo_surface_destroy(c->real_surface); - return 0; -} - -int renderer_blit_screen(yutani_globals_t * yg) { - struct cairo_renderer * c = yg->renderer_ctx; - cairo_set_operator(c->real_ctx, CAIRO_OPERATOR_SOURCE); - cairo_translate(c->real_ctx, 0, 0); - cairo_set_source_surface(c->real_ctx, c->framebuffer_surface, 0, 0); - cairo_paint(c->real_ctx); - return 0; -} - -int renderer_blit_window(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) { - /* Obtain the previously initialized cairo contexts */ - struct cairo_renderer * c = yg->renderer_ctx; - cairo_t * cr = c->framebuffer_ctx; - - /* Window stride is always 4 bytes per pixel... */ - int stride = window->width * 4; - - /* Initialize a cairo surface object for this window */ - cairo_surface_t * surf = cairo_image_surface_create_for_data( - window->buffer, CAIRO_FORMAT_ARGB32, window->width, window->height, stride); - - /* Save cairo context */ - cairo_save(cr); - - /* - * Offset the rendering context appropriately for the position of the window - * based on the modifier paramters - */ - cairo_identity_matrix(cr); - cairo_translate(cr, x, y); - - /* Top and bottom windows can not be rotated. */ - if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window)) { - /* Calcuate radians from degrees */ - - if (window->rotation != 0) { - double r = M_PI * (((double)window->rotation) / 180.0); - - /* Rotate the render context about the center of the window */ - cairo_translate(cr, (int)( window->width / 2), (int)( (int)window->height / 2)); - cairo_rotate(cr, r); - cairo_translate(cr, (int)(-window->width / 2), (int)(-window->height / 2)); - - /* Prefer faster filter when rendering rotated windows */ - cairo_pattern_t * p = cairo_get_source(cr); - cairo_pattern_set_filter(p, CAIRO_FILTER_FAST); - } - - if (window == yg->resizing_window) { - double x_scale = (double)yg->resizing_w / (double)yg->resizing_window->width; - double y_scale = (double)yg->resizing_h / (double)yg->resizing_window->height; - if (x_scale < 0.00001) { - x_scale = 0.00001; - } - if (y_scale < 0.00001) { - y_scale = 0.00001; - } - cairo_translate(cr, (int)yg->resizing_offset_x, (int)yg->resizing_offset_y); - cairo_scale(cr, x_scale, y_scale); - } - - } - if (window->anim_mode) { - int frame = yutani_time_since(yg, window->anim_start); - if (frame >= yutani_animation_lengths[window->anim_mode]) { - if (window->anim_mode == YUTANI_EFFECT_FADE_OUT || - window->anim_mode == YUTANI_EFFECT_SQUEEZE_OUT) { - list_insert(yg->windows_to_remove, window); - goto draw_finish; - } - window->anim_mode = 0; - window->anim_start = 0; - goto draw_window; - } else { - switch (window->anim_mode) { - case YUTANI_EFFECT_SQUEEZE_OUT: - case YUTANI_EFFECT_FADE_OUT: - { - frame = yutani_animation_lengths[window->anim_mode] - frame; - } - case YUTANI_EFFECT_SQUEEZE_IN: - case YUTANI_EFFECT_FADE_IN: - { - double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]); - - if (window->server_flags & YUTANI_WINDOW_FLAG_DIALOG_ANIMATION) { - double x = time_diff; - int t_y = (window->height * (1.0 -x)) / 2; - cairo_translate(cr, 0, t_y); - cairo_scale(cr, 1.0, x); - } else if (!yutani_window_is_top(yg, window) && !yutani_window_is_bottom(yg, window) && - !(window->server_flags & YUTANI_WINDOW_FLAG_ALT_ANIMATION)) { - double x = 0.75 + time_diff * 0.25; - int t_x = (window->width * (1.0 - x)) / 2; - int t_y = (window->height * (1.0 - x)) / 2; - cairo_translate(cr, t_x, t_y); - cairo_scale(cr, x, x); - } - - cairo_set_source_surface(cr, surf, 0, 0); - if (window->opacity != 255) { - cairo_paint_with_alpha(cr, time_diff * (double)(window->opacity) / 255.0); - } else { - cairo_paint_with_alpha(cr, time_diff); - } - } - break; - default: - goto draw_window; - break; - } - } - } else { -draw_window: - /* Paint window */ - cairo_set_source_surface(cr, surf, 0, 0); - - if (window->opacity != 255) { - cairo_paint_with_alpha(cr, (float)(window->opacity)/255.0); - } else { - cairo_paint(cr); - } - } - -draw_finish: - - /* Clean up */ - cairo_surface_destroy(surf); - - /* Restore context stack */ - cairo_restore(cr); - -#if YUTANI_DEBUG_WINDOW_BOUNDS - /* - * If window bound debugging is enabled, we also draw a box - * representing the rectangular (possibly rotated) boundary - * for a window texture. - */ - if (yg->debug_bounds) { - cairo_save(cr); - - int32_t t_x, t_y; - int32_t s_x, s_y; - int32_t r_x, r_y; - int32_t q_x, q_y; - - yutani_window_to_device(window, 0, 0, &t_x, &t_y); - yutani_window_to_device(window, window->width, window->height, &s_x, &s_y); - yutani_window_to_device(window, 0, window->height, &r_x, &r_y); - yutani_window_to_device(window, window->width, 0, &q_x, &q_y); - - uint32_t x = yutani_color_for_wid(window->wid); - cairo_set_source_rgba(cr, - _RED(x) / 255.0, - _GRE(x) / 255.0, - _BLU(x) / 255.0, - 0.7 - ); - - cairo_move_to(cr, t_x, t_y); - cairo_line_to(cr, r_x, r_y); - cairo_line_to(cr, s_x, s_y); - cairo_line_to(cr, q_x, q_y); - cairo_fill(cr); - - cairo_restore(cr); - } -#endif - - - return 0; -} diff --git a/ext/ext_freetype_fonts.c b/ext/ext_freetype_fonts.c deleted file mode 100644 index 91839e73..00000000 --- a/ext/ext_freetype_fonts.c +++ /dev/null @@ -1,329 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2018 K. Lange - * - * Extension library for freetype font rendering. - */ -#include -#include -#include -#include - -#include -#include FT_FREETYPE_H -#include FT_CACHE_H - -#define SERVER_NAME "fonts" - -#define FONT_SANS_SERIF 0 -#define FONT_SANS_SERIF_BOLD 1 -#define FONT_SANS_SERIF_ITALIC 2 -#define FONT_SANS_SERIF_BOLD_ITALIC 3 -#define FONT_MONOSPACE 4 -#define FONT_MONOSPACE_BOLD 5 -#define FONT_MONOSPACE_ITALIC 6 -#define FONT_MONOSPACE_BOLD_ITALIC 7 -#define FONT_JAPANESE 8 -#define FONT_SYMBOLA 9 -#define FONTS_TOTAL 10 - -#define FONT_SIZE 12 - -static FT_Library library; -static FT_Face faces[FONTS_TOTAL]; /* perhaps make this an array ? */ -static FT_GlyphSlot slot; -static int selected_face = 0; -static int _font_size = 12; -static int fallbacks[] = {FONT_JAPANESE, FONT_SYMBOLA, -1}; - -#define SGFX(CTX,x,y,WIDTH) *((uint32_t *)&CTX[((WIDTH) * (y) + (x)) * 4]) - -static void _load_font(int i, char * name) { - uint8_t * font; - size_t s = 0; - int error; - char tmp[100]; - snprintf(tmp, 100, "sys.%s%s", SERVER_NAME, name); - - font = (void*)syscall_shm_obtain(tmp, &s); - error = FT_New_Memory_Face(library, font, s, 0, &faces[i]); - if (error) { - fprintf(stderr, "[freetype backend] encountered error\n"); - } - error = FT_Set_Pixel_Sizes(faces[i], FONT_SIZE, FONT_SIZE); - if (error) { - fprintf(stderr, "[freetype backend] encountered error\n"); - } -} - -static void _load_font_f(int i, char * path) { - int error; - error = FT_New_Face(library, path, 0, &faces[i]); - if (error) { - fprintf(stderr, "[freetype backend] encountered error\n"); - } - error = FT_Set_Pixel_Sizes(faces[i], FONT_SIZE, FONT_SIZE); - if (error) { - fprintf(stderr, "[freetype backend] encountered error\n"); - } -} - -static void _load_fonts() { - _load_font(FONT_SANS_SERIF, ".fonts.sans-serif"); - _load_font(FONT_SANS_SERIF_BOLD, ".fonts.sans-serif.bold"); - _load_font(FONT_SANS_SERIF_ITALIC, ".fonts.sans-serif.italic"); - _load_font(FONT_SANS_SERIF_BOLD_ITALIC, ".fonts.sans-serif.bolditalic"); - _load_font(FONT_MONOSPACE, ".fonts.monospace"); - _load_font(FONT_MONOSPACE_BOLD, ".fonts.monospace.bold"); - _load_font(FONT_MONOSPACE_ITALIC, ".fonts.monospace.italic"); - _load_font(FONT_MONOSPACE_BOLD_ITALIC, ".fonts.monospace.bolditalic"); - _load_font_f(FONT_JAPANESE, "/usr/share/fonts/VLGothic.ttf"); - _load_font_f(FONT_SYMBOLA, "/usr/share/fonts/Symbola.ttf"); -} - -void freetype_set_font_face(int font) { - selected_face = font; -} - -void freetype_set_font_size(int size) { - _font_size = size; - for (int i = 0; i < FONTS_TOTAL; ++i) { - FT_Set_Pixel_Sizes(faces[i], size, size); - } -} - -static void draw_char(FT_Bitmap * bitmap, int x, int y, uint32_t fg, gfx_context_t * ctx) { - int i, j, p, q; - int x_max = x + bitmap->width; - int y_max = y + bitmap->rows; - for (j = y, q = 0; j < y_max; j++, q++) { - if (j < 0 || j >= ctx->height) continue; - for ( i = x, p = 0; i < x_max; i++, p++) { - uint32_t a = _ALP(fg); - a = (a * bitmap->buffer[q * bitmap->width + p]) / 255; - uint32_t tmp = premultiply(rgba(_RED(fg),_GRE(fg),_BLU(fg),a)); - if (i < 0 || i >= ctx->width) continue; - SGFX(ctx->backbuffer,i,j,ctx->width) = alpha_blend_rgba(SGFX(ctx->backbuffer,i,j,ctx->width),tmp); - } - } -} - -void freetype_draw_char(gfx_context_t * ctx, int x, int y, uint32_t fg, uint32_t o) { - int pen_x = x, pen_y = y; - int error; - slot = faces[selected_face]->glyph; - FT_UInt glyph_index; - - glyph_index = FT_Get_Char_Index( faces[selected_face], o); - if (glyph_index) { - error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%lu'\n", o); - return; - } - slot = (faces[selected_face])->glyph; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - error = FT_Render_Glyph((faces[selected_face])->glyph, FT_RENDER_MODE_NORMAL); - if (error) { - fprintf(stderr, "Error rendering glyph for '%lu'\n", o); - return; - } - } - } else { - int i = 0; - while (!glyph_index && fallbacks[i] != -1) { - int fallback = fallbacks[i++]; - glyph_index = FT_Get_Char_Index( faces[fallback], o); - error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%lu'\n", o); - return; - } - slot = (faces[fallback])->glyph; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - error = FT_Render_Glyph((faces[fallback])->glyph, FT_RENDER_MODE_NORMAL); - if (error) { - fprintf(stderr, "Error rendering glyph for '%lu'\n", o); - return; - } - } - } - - } - - draw_char(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, fg, ctx); - -} - -int freetype_draw_string(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string) { - slot = faces[selected_face]->glyph; - int pen_x = x, pen_y = y; - int error; - - uint8_t * s = (uint8_t *)string; - - uint32_t codepoint; - uint32_t state = 0; - - while (*s) { - uint32_t o = 0; - while (*s) { - if (!decode(&state, &codepoint, (uint8_t)*s)) { - o = (uint32_t)codepoint; - s++; - goto finished; - } else if (state == UTF8_REJECT) { - state = 0; - } - s++; - } - -finished: - if (!o) continue; - - FT_UInt glyph_index; - - glyph_index = FT_Get_Char_Index( faces[selected_face], o); - if (glyph_index) { - error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%lu'\n", o); - continue; - } - slot = (faces[selected_face])->glyph; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - error = FT_Render_Glyph((faces[selected_face])->glyph, FT_RENDER_MODE_NORMAL); - if (error) { - fprintf(stderr, "Error rendering glyph for '%lu'\n", o); - continue; - } - } - } else { - int i = 0; - while (!glyph_index && fallbacks[i] != -1) { - int fallback = fallbacks[i++]; - glyph_index = FT_Get_Char_Index( faces[fallback], o); - error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%lu'\n", o); - continue; - } - slot = (faces[fallback])->glyph; - if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { - error = FT_Render_Glyph((faces[fallback])->glyph, FT_RENDER_MODE_NORMAL); - if (error) { - fprintf(stderr, "Error rendering glyph for '%lu'\n", o); - continue; - } - } - } - - } - - draw_char(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, fg, ctx); - pen_x += slot->advance.x >> 6; - pen_y += slot->advance.y >> 6; - } - return pen_x - x; -} - -int freetype_draw_string_width(char * string) { - slot = faces[selected_face]->glyph; - int pen_x = 0; - int error; - - uint8_t * s = (uint8_t *)string; - - uint32_t codepoint; - uint32_t state = 0; - - while (*s) { - uint32_t o = 0; - while (*s) { - if (!decode(&state, &codepoint, (uint8_t)*s)) { - o = (uint32_t)codepoint; - s++; - goto finished_width; - } else if (state == UTF8_REJECT) { - state = 0; - } - s++; - } - -finished_width: - if (!o) continue; - - FT_UInt glyph_index; - - glyph_index = FT_Get_Char_Index( faces[selected_face], o); - if (glyph_index) { - error = FT_Load_Glyph(faces[selected_face], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%lu'\n", o); - continue; - } - slot = (faces[selected_face])->glyph; - } else { - int i = 0; - while (!glyph_index && fallbacks[i] != -1) { - int fallback = fallbacks[i++]; - glyph_index = FT_Get_Char_Index( faces[fallback], o); - error = FT_Load_Glyph(faces[fallback], glyph_index, FT_LOAD_DEFAULT); - if (error) { - fprintf(stderr, "Error loading glyph for '%lu'\n", o); - continue; - } - slot = (faces[fallback])->glyph; - } - } - pen_x += slot->advance.x >> 6; - } - return pen_x; -} - -__attribute__((constructor)) static void init_lib(void) { - FT_Init_FreeType(&library); - _load_fonts(); - selected_face = FONT_SANS_SERIF; -} - -char * freetype_font_name(int i) { - return ((FT_FaceRec *)faces[i])->family_name; -} - -FT_Face freetype_get_active_font_face(void) { - return faces[selected_face]; -} - -void freetype_draw_string_shadow(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string, uint32_t shadow_color, int darkness, int offset_x, int offset_y, double radius) { -#define OFFSET_X 5 -#define OFFSET_Y 5 -#define WIDTH_PAD 15 -#define HEIGHT_PAD 15 - - gfx_context_t * out_c; - sprite_t * out_s; - - size_t width = freetype_draw_string_width(string) + WIDTH_PAD; - size_t height = _font_size + HEIGHT_PAD; - - out_s = create_sprite(width, height, ALPHA_EMBEDDED); - out_c = init_graphics_sprite(out_s); - - draw_fill(out_c, rgba(0,0,0,0)); - freetype_draw_string(out_c, OFFSET_X + offset_x, OFFSET_Y + offset_y + _font_size, shadow_color, string); - - /* Two should work okay? */ - blur_context_box(out_c, radius); - blur_context_box(out_c, radius); - - freetype_draw_string(out_c, OFFSET_X, OFFSET_Y + _font_size, fg, string); - - for (int i = 0; i < darkness; ++i) { - draw_sprite(ctx, out_s, x - OFFSET_X, y - OFFSET_Y - _font_size); - } - - sprite_free(out_s); - free(out_c); -} diff --git a/kernel/arch/x86_64/bootstrap.S b/kernel/arch/x86_64/bootstrap.S new file mode 100644 index 00000000..943794d4 --- /dev/null +++ b/kernel/arch/x86_64/bootstrap.S @@ -0,0 +1,179 @@ +/* + This is primarily adapted from Toaru's 32-bit mulitboot bootstrap. + Instead of jumping straight to our C entry point, however, we need + to (obviously) get ourselves set up for long mode first by setting + up initial page tables, etc. + + We use a multiboot "1.0" header and build the whole kernel into an + elf32 binary so that we can safely load with qemu's -kernel mode. +*/ +.section .multiboot +.code32 +.align 4 + +.set MB_MAGIC, 0x1BADB002 +.set MB_FLAG_PAGE_ALIGN, 1 << 0 +.set MB_FLAG_MEMORY_INFO, 1 << 1 +.set MB_FLAG_GRAPHICS, 1 << 2 +.set MB_FLAG_AOUT, 1 << 12 +.set MB_FLAGS, MB_FLAG_PAGE_ALIGN | MB_FLAG_MEMORY_INFO | MB_FLAG_GRAPHICS +.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) + +.extern bss_start +.extern end + +/* Multiboot section */ +multiboot_header: +.long MB_MAGIC +.long MB_FLAGS +.long MB_CHECKSUM +.long 0 // 0x00100000 /* header_addr */ +.long 0 // 0x00100000 /* load_addr */ +.long 0 // bss_start /* load_end_addr */ +.long 0 // end /* bss_end_addr */ +.long 0 // start /* entry_addr */ + +/* Request linear graphics mode */ +.long 0x00000000 +.long 1024 +.long 768 +.long 32 + +/* .stack resides in .bss */ +.section .stack, "aw", @nobits +stack_bottom: +.skip 16384 /* 16KiB */ +.global stack_top +stack_top: + +.section .bootstrap +.code32 +.align 4 + +.extern jmp_to_long +.type jmp_to_long, @function + +.extern kmain +.type kmain, @function + +.global start +.type start, @function + +start: + /* Setup our stack */ + mov $stack_top, %esp + + /* Make sure our stack is 16-byte aligned */ + and $-16, %esp + + pushl $0 + pushl %esp + pushl $0 + pushl %eax /* Multiboot header magic */ + pushl $0 + pushl %ebx /* Multiboot header pointer */ + + jmp jmp_to_long + + +.align 4 + +jmp_to_long: + .extern init_page_region + + /* Set up initial page region, which was zero'd for us by the loader */ + mov $init_page_region, %edi + mov %edi, %cr3 + + /* PML4[0] = &PDP[0] | (PRESENT, WRITABLE, USER) */ + mov $0x1007, %eax + add %edi, %eax + mov %eax, (%edi) + + /* PDP[0] = &PD[0] | (PRESENT, WRITABLE, USER) */ + add $0x1000, %edi + mov $0x1003, %eax + add %edi, %eax + mov %eax, (%edi) + + /* Set 32 2MiB pages to map 64MiB of low memory temporarily, which should + be enough to get us through our C MMU initialization where we then + use 2MiB pages to map all of the 4GiB standard memory space and map + a much more restricted subset of the kernel in the lower address space. */ + add $0x1000, %edi + + mov $0x87, %ebx + mov $32, %ecx + +.set_entry: + mov %ebx, (%edi) + add $0x200000, %ebx + add $8, %edi + loop .set_entry + + /* Enable PAE */ + mov %cr4, %eax + or $32, %eax + mov %eax, %cr4 + + /* EFER */ + mov $0xC0000080, %ecx + rdmsr + or $256, %eax + wrmsr + + /* Set PG */ + mov %cr0, %eax + or $0x80000000, %eax + mov %eax, %cr0 + + lgdt gdtr + ljmp $0x08,$realm64 + +.align 8 +gdtr: + .word gdt_end-gdt_base + .quad gdt_base + +gdt_base: + /* Null */ + .quad 0 + /* Code */ + .word 0 + .word 0 + .byte 0 + .byte 0x9a + .byte 0x20 + .byte 0 + /* Data */ + .word 0xffff + .word 0 + .byte 0 + .byte 0x92 + .byte 0 + .byte 0 +gdt_end: + + +.code64 +.align 8 +.section .bootstrap + +realm64: + cli + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + pop %rdi + pop %rsi + pop %rdx + callq kmain + +halt: + cli + hlt + jmp halt diff --git a/kernel/arch/x86_64/cmos.c b/kernel/arch/x86_64/cmos.c new file mode 100644 index 00000000..d13980d6 --- /dev/null +++ b/kernel/arch/x86_64/cmos.c @@ -0,0 +1,248 @@ +/** + * @file kernel/arch/x86_64/cmos.c + * @author K. Lange + * @brief Real-time clock. + * + * Provides access to the CMOS RTC for initial boot time and + * calibrates the TSC to use as a general timing source. IRQ 0 + * handler is also in here because it updates the wall clock time + * and triggers timeout-based wakeups. + */ +#include +#include +#include +#include +#include +#include + +#define from_bcd(val) ((val / 16) * 10 + (val & 0xf)) +#define CMOS_ADDRESS 0x70 +#define CMOS_DATA 0x71 + +enum { + CMOS_SECOND = 0, + CMOS_MINUTE = 2, + CMOS_HOUR = 4, + CMOS_DAY = 7, + CMOS_MONTH = 8, + CMOS_YEAR = 9 +}; + +static void cmos_dump(uint16_t * values) { + for (uint16_t index = 0; index < 128; ++index) { + outportb(CMOS_ADDRESS, index); + values[index] = inportb(CMOS_DATA); + } +} + +static int is_update_in_progress(void) { + outportb(CMOS_ADDRESS, 0x0a); + return inportb(CMOS_DATA) & 0x80; +} + +static uint32_t secs_of_years(int years) { + uint32_t days = 0; + years += 2000; + while (years > 1969) { + days += 365; + if (years % 4 == 0) { + if (years % 100 == 0) { + if (years % 400 == 0) { + days++; + } + } else { + days++; + } + } + years--; + } + return days * 86400; +} + +static uint32_t secs_of_month(int months, int year) { + year += 2000; + + uint32_t days = 0; + switch(months) { + case 11: + days += 30; /* fallthrough */ + case 10: + days += 31; /* fallthrough */ + case 9: + days += 30; /* fallthrough */ + case 8: + days += 31; /* fallthrough */ + case 7: + days += 31; /* fallthrough */ + case 6: + days += 30; /* fallthrough */ + case 5: + days += 31; /* fallthrough */ + case 4: + days += 30; /* fallthrough */ + case 3: + days += 31; /* fallthrough */ + case 2: + days += 28; + if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) { + days++; + } /* fallthrough */ + case 1: + days += 31; /* fallthrough */ + default: + break; + } + return days * 86400; +} + +uint32_t read_cmos(void) { + uint16_t values[128]; + uint16_t old_values[128]; + + while (is_update_in_progress()); + cmos_dump(values); + + do { + memcpy(old_values, values, 128); + while (is_update_in_progress()); + cmos_dump(values); + } while ((old_values[CMOS_SECOND] != values[CMOS_SECOND]) || + (old_values[CMOS_MINUTE] != values[CMOS_MINUTE]) || + (old_values[CMOS_HOUR] != values[CMOS_HOUR]) || + (old_values[CMOS_DAY] != values[CMOS_DAY]) || + (old_values[CMOS_MONTH] != values[CMOS_MONTH]) || + (old_values[CMOS_YEAR] != values[CMOS_YEAR])); + + /* Math Time */ + uint32_t time = + secs_of_years(from_bcd(values[CMOS_YEAR]) - 1) + + secs_of_month(from_bcd(values[CMOS_MONTH]) - 1, + from_bcd(values[CMOS_YEAR])) + + (from_bcd(values[CMOS_DAY]) - 1) * 86400 + + (from_bcd(values[CMOS_HOUR])) * 3600 + + (from_bcd(values[CMOS_MINUTE])) * 60 + + from_bcd(values[CMOS_SECOND]) + 0; + + return time; +} + +static uint64_t boot_time = 0; +uint64_t timer_ticks = 0; +uint64_t timer_subticks = 0; + +unsigned long tsc_mhz = 3500; /* XXX */ + +static inline uint64_t read_tsc(void) { + uint32_t lo, hi; + asm volatile ( "rdtsc" : "=a"(lo), "=d"(hi) ); + return ((uint64_t)hi << 32) | (uint64_t)lo; +} + +size_t arch_cpu_mhz(void) { + return tsc_mhz; +} + +void arch_clock_initialize(void) { + boot_time = read_cmos(); + uintptr_t end_lo, end_hi; + uint32_t start_lo, start_hi; + asm volatile ( + /* Disables and sets gating for channel 2 */ + "inb $0x61, %%al\n" + "andb $0xDD, %%al\n" + "orb $0x01, %%al\n" + "outb %%al, $0x61\n" + /* Configure channel 2 to one-shot, next two bytes are low/high */ + "movb $0xB2, %%al\n" /* 0b10110010 */ + "outb %%al, $0x43\n" + /* 0x__9b */ + "movb $0x9B, %%al\n" + "outb %%al, $0x42\n" + "inb $0x60, %%al\n" + /* 0x2e__ */ + "movb $0x2E, %%al\n" + "outb %%al, $0x42\n" + /* Re-enable */ + "inb $0x61, %%al\n" + "andb $0xDE, %%al\n" + "outb %%al, $0x61\n" + /* Pulse high */ + "orb $0x01, %%al\n" + "outb %%al, $0x61\n" + /* Read TSC and store in vars */ + "rdtsc\n" + "movl %%eax, %2\n" + "movl %%edx, %3\n" + /* In QEMU and VirtualBox, this seems to flip low. + * On real hardware and VMware it flips high. */ + "inb $0x61, %%al\n" + "andb $0x20, %%al\n" + "jz 2f\n" + /* Loop until output goes low? */ + "1:\n" + "inb $0x61, %%al\n" + "andb $0x20, %%al\n" + "jnz 1b\n" + "rdtsc\n" + "jmp 3f\n" + /* Loop until output goes high */ + "2:\n" + "inb $0x61, %%al\n" + "andb $0x20, %%al\n" + "jz 2b\n" + "rdtsc\n" + "3:\n" + : "=a"(end_lo), "=d"(end_hi), "=r"(start_lo), "=r"(start_hi) + ); + + uintptr_t end = ((end_hi & 0xFFFFffff) << 32) | (end_lo & 0xFFFFffff); + uintptr_t start = ((uintptr_t)(start_hi & 0xFFFFffff) << 32) | (start_lo & 0xFFFFffff); + tsc_mhz = (end - start) / 10000; + if (tsc_mhz == 0) tsc_mhz = 2000; /* uh oh */ +} + +#define SUBTICKS_PER_TICK 1000000 +static void update_ticks(void) { + uint64_t tsc = read_tsc(); + timer_subticks = tsc / tsc_mhz; + timer_ticks = timer_subticks / SUBTICKS_PER_TICK; + timer_subticks = timer_subticks % SUBTICKS_PER_TICK; +} + +int gettimeofday(struct timeval * t, void *z) { + update_ticks(); + t->tv_sec = boot_time + timer_ticks; + t->tv_usec = timer_subticks; + return 0; +} + +uint64_t now(void) { + struct timeval t; + gettimeofday(&t, NULL); + return t.tv_sec; +} + + +void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds) { + update_ticks(); + if (subseconds + timer_subticks >= SUBTICKS_PER_TICK) { + *out_seconds = timer_ticks + seconds + (subseconds + timer_subticks) / SUBTICKS_PER_TICK; + *out_subseconds = (subseconds + timer_subticks) % SUBTICKS_PER_TICK; + } else { + *out_seconds = timer_ticks + seconds; + *out_subseconds = timer_subticks + subseconds; + } +} + +int cmos_time_stuff(struct regs *r) { + update_ticks(); + wakeup_sleepers(timer_ticks, timer_subticks); + irq_ack(0); + switch_task(1); + asm volatile ( + ".global _ret_from_preempt_source\n" + "_ret_from_preempt_source:" + ); + return 1; +} + diff --git a/kernel/arch/x86_64/gdt.c b/kernel/arch/x86_64/gdt.c new file mode 100644 index 00000000..951998c4 --- /dev/null +++ b/kernel/arch/x86_64/gdt.c @@ -0,0 +1,107 @@ +/** + * @file kernel/arch/x86_64/gdt.c + * @author K. Lange + * @brief x86-64 GDT + */ + +#include +#include +#include + +/** + * @brief 64-bit TSS + */ +typedef struct tss_entry { + uint32_t reserved_0; + uint64_t rsp[3]; + uint64_t reserved_1; + uint64_t ist[7]; + uint64_t reserved_2; + uint16_t reserved_3; + uint16_t iomap_base; +} __attribute__ ((packed)) tss_entry_t; + +typedef struct { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; +} __attribute__((packed)) gdt_entry_t; + +typedef struct { + uint32_t base_highest; + uint32_t reserved0; +} __attribute__((packed)) gdt_entry_high_t; + +typedef struct { + uint16_t limit; + uintptr_t base; +} __attribute__((packed)) gdt_pointer_t; + +typedef struct { + gdt_entry_t entries[6]; + gdt_entry_high_t tss_extra; + gdt_pointer_t pointer; + tss_entry_t tss; +} __attribute__((packed)) __attribute__((aligned(0x10))) FullGDT; + +FullGDT gdt[32] __attribute__((used)) = {{ + { + {0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00}, + {0xFFFF, 0x0000, 0x00, 0x9A, (1 << 5) | (1 << 7) | 0x0F, 0x00}, + {0xFFFF, 0x0000, 0x00, 0x92, (1 << 5) | (1 << 7) | 0x0F, 0x00}, + {0xFFFF, 0x0000, 0x00, 0xFA, (1 << 5) | (1 << 7) | 0x0F, 0x00}, + {0xFFFF, 0x0000, 0x00, 0xF2, (1 << 5) | (1 << 7) | 0x0F, 0x00}, + {0x0067, 0x0000, 0x00, 0xE9, 0x00, 0x00}, + }, + {0x00000000, 0x00000000}, + {0x0000, 0x0000000000000000}, + {0,{0,0,0},0,{0,0,0,0,0,0,0},0,0,0}, +}}; + +void gdt_install(void) { + for (int i = 1; i < 32; ++i) { + memcpy(&gdt[i], &gdt[0], sizeof(gdt)); + } + + for (int i = 0; i < 32; ++i) { + gdt[i].pointer.limit = sizeof(gdt[i].entries)+sizeof(gdt[i].tss_extra)-1; + gdt[i].pointer.base = (uintptr_t)&gdt[i].entries; + + uintptr_t addr = (uintptr_t)&gdt[i].tss; + gdt[i].entries[5].limit_low = sizeof(gdt[i].tss); + gdt[i].entries[5].base_low = (addr & 0xFFFF); + gdt[i].entries[5].base_middle = (addr >> 16) & 0xFF; + gdt[i].entries[5].base_high = (addr >> 24) & 0xFF; + gdt[i].tss_extra.base_highest = (addr >> 32) & 0xFFFFFFFF; + } + + extern void * stack_top; + gdt[0].tss.rsp[0] = (uintptr_t)&stack_top; + + asm volatile ( + "mov %0, %%rdi\n" + "lgdt (%%rdi)\n" + "mov $0x10, %%ax\n" + "mov %%ax, %%ds\n" + "mov %%ax, %%es\n" + "mov %%ax, %%ss\n" + "mov $0x2b, %%ax\n" + "ltr %%ax\n" + : : "r"(&gdt[0].pointer) + ); +} + +void gdt_copy_to_trampoline(int ap, char * trampoline) { + memcpy(trampoline, &gdt[ap].pointer, sizeof(gdt[ap].pointer)); +} + +void arch_set_kernel_stack(uintptr_t stack) { + gdt[this_core->cpu_id].tss.rsp[0] = stack; +} + +void arch_set_tls_base(uintptr_t tlsbase) { + asm volatile ("wrmsr" : : "c"(0xc0000100), "d"((uint32_t)(tlsbase >> 32)), "a"((uint32_t)(tlsbase & 0xFFFFFFFF))); +} diff --git a/kernel/arch/x86_64/idt.c b/kernel/arch/x86_64/idt.c new file mode 100644 index 00000000..0784ceb7 --- /dev/null +++ b/kernel/arch/x86_64/idt.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_FAULTS +#define LOUD_SEGFAULTS + +static struct idt_pointer idtp; +static idt_entry_t idt[256]; + +void idt_set_gate(uint8_t num, interrupt_handler_t handler, uint16_t selector, uint8_t flags, int userspace) { + uintptr_t base = (uintptr_t)handler; + idt[num].base_low = (base & 0xFFFF); + idt[num].base_mid = (base >> 16) & 0xFFFF; + idt[num].base_high = (base >> 32) & 0xFFFFFFFF; + idt[num].selector = selector; + idt[num].zero = 0; + idt[num].pad = 0; + idt[num].flags = flags | (userspace ? 0x60 : 0); +} + +void idt_install(void) { + idtp.limit = sizeof(idt); + idtp.base = (uintptr_t)&idt; + + /** ISRs */ + idt_set_gate(0, _isr0, 0x08, 0x8E, 0); + idt_set_gate(1, _isr1, 0x08, 0x8E, 0); + idt_set_gate(2, _isr2, 0x08, 0x8E, 0); + idt_set_gate(3, _isr3, 0x08, 0x8E, 0); + idt_set_gate(4, _isr4, 0x08, 0x8E, 0); + idt_set_gate(5, _isr5, 0x08, 0x8E, 0); + idt_set_gate(6, _isr6, 0x08, 0x8E, 0); + idt_set_gate(7, _isr7, 0x08, 0x8E, 0); + idt_set_gate(8, _isr8, 0x08, 0x8E, 0); + idt_set_gate(9, _isr9, 0x08, 0x8E, 0); + idt_set_gate(10, _isr10, 0x08, 0x8E, 0); + idt_set_gate(11, _isr11, 0x08, 0x8E, 0); + idt_set_gate(12, _isr12, 0x08, 0x8E, 0); + idt_set_gate(13, _isr13, 0x08, 0x8E, 0); + idt_set_gate(14, _isr14, 0x08, 0x8E, 0); + idt_set_gate(15, _isr15, 0x08, 0x8E, 0); + idt_set_gate(16, _isr16, 0x08, 0x8E, 0); + idt_set_gate(17, _isr17, 0x08, 0x8E, 0); + idt_set_gate(18, _isr18, 0x08, 0x8E, 0); + idt_set_gate(19, _isr19, 0x08, 0x8E, 0); + idt_set_gate(20, _isr20, 0x08, 0x8E, 0); + idt_set_gate(21, _isr21, 0x08, 0x8E, 0); + idt_set_gate(22, _isr22, 0x08, 0x8E, 0); + idt_set_gate(23, _isr23, 0x08, 0x8E, 0); + idt_set_gate(24, _isr24, 0x08, 0x8E, 0); + idt_set_gate(25, _isr25, 0x08, 0x8E, 0); + idt_set_gate(26, _isr26, 0x08, 0x8E, 0); + idt_set_gate(27, _isr27, 0x08, 0x8E, 0); + idt_set_gate(28, _isr28, 0x08, 0x8E, 0); + idt_set_gate(29, _isr29, 0x08, 0x8E, 0); + idt_set_gate(30, _isr30, 0x08, 0x8E, 0); + idt_set_gate(31, _isr31, 0x08, 0x8E, 0); + idt_set_gate(32, _irq0, 0x08, 0x8E, 0); + idt_set_gate(33, _irq1, 0x08, 0x8E, 0); + idt_set_gate(34, _irq2, 0x08, 0x8E, 0); + idt_set_gate(35, _irq3, 0x08, 0x8E, 0); + idt_set_gate(36, _irq4, 0x08, 0x8E, 0); + idt_set_gate(37, _irq5, 0x08, 0x8E, 0); + idt_set_gate(38, _irq6, 0x08, 0x8E, 0); + idt_set_gate(39, _irq7, 0x08, 0x8E, 0); + idt_set_gate(40, _irq8, 0x08, 0x8E, 0); + idt_set_gate(41, _irq9, 0x08, 0x8E, 0); + idt_set_gate(42, _irq10, 0x08, 0x8E, 0); + idt_set_gate(43, _irq11, 0x08, 0x8E, 0); + idt_set_gate(44, _irq12, 0x08, 0x8E, 0); + idt_set_gate(45, _irq13, 0x08, 0x8E, 0); + idt_set_gate(46, _irq14, 0x08, 0x8E, 0); + idt_set_gate(47, _irq15, 0x08, 0x8E, 0); + + idt_set_gate(125, _isr125, 0x08, 0x8E, 0); /* Halts everyone. */ + idt_set_gate(126, _isr126, 0x08, 0x8E, 0); /* Intentionally does nothing. */ + idt_set_gate(127, _isr127, 0x08, 0x8E, 1); + + asm volatile ( + "lidt %0" + : : "m"(idtp) + ); +} + +void idt_ap_install(void) { + idtp.limit = sizeof(idt); + idtp.base = (uintptr_t)&idt; + asm volatile ( + "lidt %0" + : : "m"(idtp) + ); +} + +static spin_lock_t dump_lock = {0}; +static void dump_regs(struct regs * r) { + spin_lock(dump_lock); + printf( + "Registers at interrupt:\n" + " $rip=0x%016lx\n" + " $rsi=0x%016lx,$rdi=0x%016lx,$rbp=0x%016lx,$rsp=0x%016lx\n" + " $rax=0x%016lx,$rbx=0x%016lx,$rcx=0x%016lx,$rdx=0x%016lx\n" + " $r8= 0x%016lx,$r9= 0x%016lx,$r10=0x%016lx,$r11=0x%016lx\n" + " $r12=0x%016lx,$r13=0x%016lx,$r14=0x%016lx,$r15=0x%016lx\n" + " cs=0x%016lx ss=0x%016lx rflags=0x%016lx int=0x%02lx err=0x%02lx\n", + r->rip, + r->rsi, r->rdi, r->rbp, r->rsp, + r->rax, r->rbx, r->rcx, r->rdx, + r->r8, r->r9, r->r10, r->r11, + r->r12, r->r13, r->r14, r->r15, + r->cs, r->ss, r->rflags, r->int_no, r->err_code + ); + spin_unlock(dump_lock); +} + +extern void syscall_handler(struct regs *); + +#define IRQ_CHAIN_SIZE 16 +#define IRQ_CHAIN_DEPTH 4 +static irq_handler_chain_t irq_routines[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; +static const char * _irq_handler_descriptions[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; + +const char * get_irq_handler(int irq, int chain) { + if (irq >= IRQ_CHAIN_SIZE) return NULL; + if (chain >= IRQ_CHAIN_DEPTH) return NULL; + return _irq_handler_descriptions[IRQ_CHAIN_SIZE * chain + irq]; +} + +void irq_install_handler(size_t irq, irq_handler_chain_t handler, const char * desc) { + for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { + if (irq_routines[i * IRQ_CHAIN_SIZE + irq]) + continue; + irq_routines[i * IRQ_CHAIN_SIZE + irq] = handler; + _irq_handler_descriptions[i * IRQ_CHAIN_SIZE + irq ] = desc; + break; + } +} + +void irq_uninstall_handler(size_t irq) { + for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) + irq_routines[i * IRQ_CHAIN_SIZE + irq] = NULL; +} + +struct regs * isr_handler(struct regs * r) { + switch (r->int_no) { + case 14: /* Page fault */ { + uintptr_t faulting_address; + asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); + if (!this_core->current_process || r->cs == 0x08) { + arch_fatal(); + } + if (faulting_address == 0xFFFFB00F) { + /* Thread exit */ + task_exit(0); + break; + } + if (faulting_address == 0x8DEADBEEF) { + return_from_signal_handler(); + break; + } +#ifdef DEBUG_FAULTS + arch_fatal(); +#else +# ifdef LOUD_SEGFAULTS + printf("Page fault in pid=%d (%s; cpu=%d) at %#zx\n", (int)this_core->current_process->id, this_core->current_process->name, this_core->cpu_id, faulting_address); + dump_regs(r); +# endif + send_signal(this_core->current_process->id, SIGSEGV, 1); +#endif + break; + } + case 13: /* GPF */ { +#ifdef DEBUG_FAULTS + arch_fatal(); +#else + if (!this_core->current_process || r->cs == 0x08) { + arch_fatal(); + } +# ifdef LOUD_SEGFAULTS + printf("GPF in userspace on CPU %d\n", this_core->cpu_id); + dump_regs(r); +# endif + send_signal(this_core->current_process->id, SIGSEGV, 1); +#endif + break; + } + case 8: /* Double fault */ { + arch_fatal(); + break; + } + case 127: /* syscall */ { + syscall_handler(r); + asm volatile("sti"); + return r; + } + case 39: { + /* Spurious interrupt */ + break; + } + default: { + if (r->int_no < 32) { +#ifdef DEBUG_FAULTS + arch_fatal(); +#else + if (!this_core->current_process || r->cs == 0x08) { + arch_fatal(); + } + send_signal(this_core->current_process->id, SIGILL, 1); +#endif + } else { + for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { + irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)]; + if (!handler) break; + if (handler(r)) { + goto done; + } + } + irq_ack(r->int_no - 32); + break; + } + } + } + +done: + + if (this_core->current_process == this_core->kernel_idle_task && process_queue && process_queue->head) { + /* If this is kidle and we got here, instead of finishing the interrupt + * we can just switch task and there will probably be something else + * to run that was awoken by the interrupt. */ + switch_next(); + } + + return r; +} + diff --git a/kernel/arch/x86_64/irq.S b/kernel/arch/x86_64/irq.S new file mode 100644 index 00000000..69b01fb5 --- /dev/null +++ b/kernel/arch/x86_64/irq.S @@ -0,0 +1,221 @@ +.section .text +.align 8 + +.macro IRQ index byte + .global _irq\index + .type _irq\index, @function + _irq\index: + pushq $0x00 + pushq $\byte + jmp isr_common +.endm + +.macro ISR_NOERR index + .global _isr\index + .type _isr\index, @function + _isr\index: + pushq $0x00 + pushq $\index + jmp isr_common +.endm + +.macro ISR_ERR index + .global _isr\index + .type _isr\index, @function + _isr\index: + pushq $\index + jmp isr_common +.endm + +/* Interrupt Requests */ +ISR_NOERR 0 +ISR_NOERR 1 +//ISR_NOERR 2 +ISR_NOERR 3 +ISR_NOERR 4 +ISR_NOERR 5 +ISR_NOERR 6 +ISR_NOERR 7 +ISR_ERR 8 +ISR_NOERR 9 +ISR_ERR 10 +ISR_ERR 11 +ISR_ERR 12 +ISR_ERR 13 +ISR_ERR 14 +ISR_NOERR 15 +ISR_NOERR 16 +ISR_NOERR 17 +ISR_NOERR 18 +ISR_NOERR 19 +ISR_NOERR 20 +ISR_NOERR 21 +ISR_NOERR 22 +ISR_NOERR 23 +ISR_NOERR 24 +ISR_NOERR 25 +ISR_NOERR 26 +ISR_NOERR 27 +ISR_NOERR 28 +ISR_NOERR 29 +ISR_NOERR 30 +ISR_NOERR 31 +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +/* syscall entry point */ +ISR_NOERR 127 + +/* No op, used to signal sleeping processor to wake and check the queue. */ +.extern lapic_final +.global _isr126 +.type _isr126, @function +_isr126: + pushq %r12 + mov (lapic_final), %r12 + movq $0, 0xb0(%r12) + popq %r12 + iretq + +/* Fatal signal, stop everything. */ +.global _isr125 +.type _isr125, @function +_isr125: + cli +1: + hlt + jmp 1b + +/* Fatal signal, stop everything. */ +.global _isr2 +.type _isr2, @function +_isr2: + cli +1: + hlt + jmp 1b + +.macro _swapgs + cmpq $8, 24(%rsp) + je 1f + swapgs +1: +.endm + +.extern isr_handler +.type isr_handler, @function + +isr_common: + /* Save all registers */ + _swapgs + push %rax + push %rbx + push %rcx + push %rdx + push %rsi + push %rdi + push %rbp + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + cld + + /* Call interrupt handler */ + mov %rsp, %rdi + call isr_handler + mov %rax, %rsp + + /* Restore all registers */ + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rbp + pop %rdi + pop %rsi + pop %rdx + pop %rcx + pop %rbx + pop %rax + + _swapgs + + /* Cleanup error code and interrupt # */ + add $16, %rsp + + /* Return from interrupt */ + iretq + + +.global arch_save_context +.type arch_save_context, @function +arch_save_context: + leaq 8(%rsp), %rax + movq %rax, 0(%rdi) + movq %rbp, 8(%rdi) + movq (%rsp), %rax + movq %rax, 16(%rdi) + movq $0xc0000100, %rcx + rdmsr + movl %eax, 24(%rdi) + movl %edx, 28(%rdi) + movq %rbx, 32(%rdi) + movq %r12, 40(%rdi) + movq %r13, 48(%rdi) + movq %r14, 56(%rdi) + movq %r15, 64(%rdi) + xor %rax, %rax + retq + +.global arch_restore_context +.type arch_restore_context, @function +arch_restore_context: + mov %gs:0x10,%rax + cmp %gs:0x0,%rax + je 1f + lock andl $0xFFFFfff7,0x14(%rax) +1: + movq 0(%rdi), %rsp + movq 8(%rdi), %rbp + movl 24(%rdi), %eax + movl 28(%rdi), %edx + movq $0xc0000100, %rcx + wrmsr + movq 32(%rdi), %rbx + movq 40(%rdi), %r12 + movq 48(%rdi), %r13 + movq 56(%rdi), %r14 + movq 64(%rdi), %r15 + movq $1, %rax + jmpq *16(%rdi) + +.global arch_enter_tasklet +.type arch_enter_tasklet, @function +arch_enter_tasklet: + popq %rdi + popq %rsi + jmpq *%rsi diff --git a/kernel/link.ld b/kernel/arch/x86_64/link.ld similarity index 82% rename from kernel/link.ld rename to kernel/arch/x86_64/link.ld index f3a72fc1..35ca823d 100644 --- a/kernel/link.ld +++ b/kernel/arch/x86_64/link.ld @@ -1,7 +1,4 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * Kernel linker script for x86 - */ -OUTPUT_FORMAT(elf32-i386) +OUTPUT_FORMAT(elf64-x86-64) ENTRY(start) SECTIONS @@ -11,8 +8,9 @@ SECTIONS .text BLOCK(4K) : ALIGN(4K) { - code = .; *(.multiboot) + *(.bootstrap) + code = .; *(.text) } @@ -28,6 +26,7 @@ SECTIONS *(.symbols) PROVIDE(kernel_symbols_start = .); PROVIDE(kernel_symbols_end = .); + PROVIDE(bss_start = .); } .bss BLOCK(4K) : ALIGN(4K) @@ -46,4 +45,5 @@ SECTIONS *(.eh_frame) *(.note.gnu.build-id) } + } diff --git a/kernel/arch/x86_64/main.c b/kernel/arch/x86_64/main.c new file mode 100644 index 00000000..4306a50c --- /dev/null +++ b/kernel/arch/x86_64/main.c @@ -0,0 +1,319 @@ +/** + * @file kernel/arch/x86_64/main.c + * @brief Intel/AMD x86-64 (IA64/amd64) architecture-specific startup. + * + * Parses multiboot data, sets up GDT/IDT/TSS, initializes PML4 paging, + * and sets up PC device drivers (PS/2, port I/O, serial). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +extern void arch_clock_initialize(void); + +extern char end[]; + +extern void gdt_install(void); +extern void idt_install(void); +extern void pic_initialize(void); +extern void pit_initialize(void); +extern void smp_initialize(void); +extern void portio_initialize(void); +extern void ps2hid_install(void); +extern void serial_initialize(void); +extern void fbterm_initialize(void); + +#define EARLY_LOG_DEVICE 0x3F8 +static size_t _early_log_write(size_t size, uint8_t * buffer) { + for (unsigned int i = 0; i < size; ++i) { + outportb(EARLY_LOG_DEVICE, buffer[i]); + } + return size; +} + +static void early_log_initialize(void) { + printf_output = &_early_log_write; +} + +static size_t memCount = 0; +static uintptr_t maxAddress = (uintptr_t)&end; +static void multiboot_initialize(struct multiboot * mboot) { + /* Set memCount to 1M + high mem */ + if (mboot->flags & MULTIBOOT_FLAG_MEM) { + /* mem_upper is in kibibytes and is one mebibyte less than + * actual available memory, so add that back in and multiply... */ + memCount = (uintptr_t)mboot->mem_upper * 0x400 + 0x100000; + } + + /** + * FIXME: + * The multiboot 0.6.96 spec actually says the upper_memory is at most + * the address of the first hole, minus 1MiB, so in theory there should + * not be any unavailable memory between 1MiB and mem_upper... that + * also technically means there might be even higher memory above that + * hole that we're missing... We should really be scanning the whole map + * to find the highest address of available memory, using that as our + * memory count, and then ensuring all of the holes are marked unavailable. + * but for now we'll just accept that there's a hole in lower memory and + * mem_upper is probably the total available physical RAM. That's probably + * good enough for 1GiB~4GiB cases... + */ +#if 0 + printf("mem_upper = %#zx\n", mboot->mem_upper); + if (mboot->flags & MULTIBOOT_FLAG_MMAP) { + mboot_memmap_t * mmap = (void *)(uintptr_t)mboot->mmap_addr; + while ((uintptr_t)mmap < mboot->mmap_addr + mboot->mmap_length) { + printf(" 0x%016zx:0x%016zx %d (%s)\n", mmap->base_addr, mmap->length, mmap->type, + mmap->type == 1 ? "available" : (mmap->type == 2 ? "reserved" : "unknown") + ); + mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uint32_t)); + } + } +#endif + + if (mboot->flags & MULTIBOOT_FLAG_MODS) { + mboot_mod_t * mods = (mboot_mod_t *)(uintptr_t)mboot->mods_addr; + for (unsigned int i = 0; i < mboot->mods_count; ++i) { + uintptr_t addr = (uintptr_t)mods[i].mod_start + mods[i].mod_end; + if (addr > maxAddress) maxAddress = addr; + } + } + + /* Round the max address up a page */ + maxAddress = (maxAddress + 0xFFF) & 0xFFFFffffFFFFf000; +} + +/** + * FIXME: We don't currently use the kernel symbol table, but when modules + * are implemented again we need it for linking... but also we could + * just build the kernel with a dynamic symbol table attached? + */ +static hashmap_t * kernelSymbols = NULL; + +static void symbols_install(void) { + kernelSymbols = hashmap_create(10); + kernel_symbol_t * k = (kernel_symbol_t *)&kernel_symbols_start; + while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { + hashmap_set(kernelSymbols, k->name, (void*)k->addr); + k = (kernel_symbol_t *)((uintptr_t)k + sizeof *k + strlen(k->name) + 1); + } +} + +/** + * @brief Initializes the page attribute table. + * FIXME: This seems to be assuming the lower entries are + * already sane - we should probably initialize all + * of the entries ourselves. + */ +void pat_initialize(void) { + asm volatile ( + "mov $0x277, %%ecx\n" /* IA32_MSR_PAT */ + "rdmsr\n" + "or $0x1000000, %%edx\n" /* set bit 56 */ + "and $0xf9ffffff, %%edx\n" /* unset bits 57, 58 */ + "wrmsr\n" + : : : "ecx", "edx", "eax" + ); +} + +/** + * @brief Turns on the floating-point unit. + * + * Enables a few bits so we can get SSE. + * + * We don't do any fancy lazy FPU reload as x86-64 assumes a wide + * variety of FPU-provided registers are available so most userspace + * code will be messing with the FPU anyway and we'd probably just + * waste time with all the interrupts turning it off and on... + */ +void fpu_initialize(void) { + asm volatile ( + "clts\n" + "mov %%cr0, %%rax\n" + "and $0xFFFD, %%ax\n" + "or $0x10, %%ax\n" + "mov %%rax, %%cr0\n" + "fninit\n" + "mov %%cr0, %%rax\n" + "and $0xfffb, %%ax\n" + "or $0x0002, %%ax\n" + "mov %%rax, %%cr0\n" + "mov %%cr4, %%rax\n" + "or $0x600, %%rax\n" + "mov %%rax, %%cr4\n" + "push $0x1F80\n" + "ldmxcsr (%%rsp)\n" + "addq $8, %%rsp\n" + : : : "rax"); +} + +struct multiboot * mboot_struct = NULL; + +/** + * @brief Decompress compressed ramdisks and hand them to the ramdisk driver. + * + * Reads through the list of modules passed by a multiboot-compatible loader + * and determines if they are gzip-compressed, decompresses if they are, and + * finally hands them to the VFS driver. The VFS ramdisk driver takes control + * of linear sets of physical pages, and handles mapping them somewhere to + * provide reads in userspace, as well as freeing them if requested. + */ +void mount_multiboot_ramdisks(struct multiboot * mboot) { + /* ramdisk_mount takes physical pages, it will map them itself. */ + mboot_mod_t * mods = mmu_map_from_physical(mboot->mods_addr); + + for (unsigned int i = 0; i < mboot->mods_count; ++i) { + /* Is this a gzipped data source? */ + uint8_t * data = mmu_map_from_physical(mods[i].mod_start); + if (data[0] == 0x1F && data[1] == 0x8B) { + /* Yes - decompress it first */ + uint32_t decompressedSize = *(uint32_t*)mmu_map_from_physical(mods[i].mod_end - sizeof(uint32_t)); + size_t pageCount = (((size_t)decompressedSize + 0xFFF) & ~(0xFFF)) >> 12; + uintptr_t physicalAddress = mmu_allocate_n_frames(pageCount) << 12; + if (physicalAddress == (uintptr_t)-1) { + printf("gzip: failed to allocate pages for decompressed payload, skipping\n"); + continue; + } + gzip_inputPtr = (void*)data; + gzip_outputPtr = mmu_map_from_physical(physicalAddress); + /* Do the deed */ + if (gzip_decompress()) { + printf("gzip: failed to decompress payload, skipping\n"); + continue; + } + ramdisk_mount(physicalAddress, decompressedSize); + /* Free the pages from the original mod */ + for (size_t j = mods[i].mod_start; j < mods[i].mod_end; j += 0x1000) { + mmu_frame_clear(j); + } + } else { + /* No, or it doesn't look like one - mount it directly */ + ramdisk_mount(mods[i].mod_start, mods[i].mod_end - mods[i].mod_start); + } + } +} + +/** + * x86-64: The kernel commandline is retrieved from the multiboot struct. + */ +const char * arch_get_cmdline(void) { + return mmu_map_from_physical(mboot_struct->cmdline); +} + +/** + * x86-64: The bootloader name is retrieved from the multiboot struct. + */ +const char * arch_get_loader(void) { + if (mboot_struct->flags & MULTIBOOT_FLAG_LOADER) { + return mmu_map_from_physical(mboot_struct->boot_loader_name); + } else { + return "(unknown)"; + } +} + +/** + * x86-64: The GS register, which is set by a pair of MSRs, tracks per-CPU kernel state. + */ +void arch_set_core_base(uintptr_t base) { + asm volatile ("wrmsr" : : "c"(0xc0000101), "d"((uint32_t)(base >> 32)), "a"((uint32_t)(base & 0xFFFFFFFF))); + asm volatile ("wrmsr" : : "c"(0xc0000102), "d"((uint32_t)(base >> 32)), "a"((uint32_t)(base & 0xFFFFFFFF))); + asm volatile ("swapgs"); +} + +/** + * @brief x86-64 multiboot C entrypoint. + * + * Called by the x86-64 longmode bootstrap. + */ +int kmain(struct multiboot * mboot, uint32_t mboot_mag, void* esp) { + /* The debug log is over /dev/ttyS0, but skips the PTY interface; it's available + * as soon as we can call printf(), which is as soon as we get to long mode. */ + early_log_initialize(); + + /* Initialize GS base */ + arch_set_core_base((uintptr_t)&processor_local_data[0]); + + /* Time the TSC and get the initial boot time from the RTC. */ + arch_clock_initialize(); + + /* Parse multiboot data so we can get memory map, modules, command line, etc. */ + multiboot_initialize(mboot); + + /* memCount and maxAddress come from multiboot data */ + mmu_init(memCount, maxAddress); + + /* multiboot memory is now mapped high, if you want it. */ + mboot_struct = mmu_map_from_physical((uintptr_t)mboot); + + /* With the MMU initialized, set up things required for the scheduler. */ + pat_initialize(); + symbols_install(); + gdt_install(); + idt_install(); + fpu_initialize(); + pic_initialize(); + + /* Early generic stuff */ + generic_startup(); + + /* Should we override the TSC timing? */ + if (args_present("tsc_mhz")) { + extern unsigned long tsc_mhz; + tsc_mhz = atoi(args_value("tsc_mhz")); + } + + /* Scheduler is running and we have parsed the kcmdline, initialize video. */ + framebuffer_initialize(); + fbterm_initialize(); + + smp_initialize(); + + /* Decompress and mount all initial ramdisks. */ + mount_multiboot_ramdisks(mboot); + + /* Set up preempt source */ + pit_initialize(); + + /* Install generic PC device drivers. */ + ps2hid_install(); + serial_initialize(); + portio_initialize(); + + /* Special drivers should probably be modules... */ + extern void ac97_install(void); + ac97_install(); + + if (!args_present("novmware")) { + extern void vmware_initialize(void); + vmware_initialize(); + } + + if (!args_present("novbox")) { + extern void vbox_initialize(void); + vbox_initialize(); + } + + extern void e1000_initialize(void); + e1000_initialize(); + + /* Yield to the generic main, which starts /bin/init */ + return generic_main(); +} diff --git a/kernel/arch/x86_64/mmu.c b/kernel/arch/x86_64/mmu.c new file mode 100644 index 00000000..01e627d3 --- /dev/null +++ b/kernel/arch/x86_64/mmu.c @@ -0,0 +1,801 @@ +/** + * @file kernel/arch/x86_64/mmu.c + * @brief Memory management facilities for x86-64 + * + * Frame allocation and mapping routines for x86-64. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * bitmap page allocator for 4KiB pages + */ +static uint32_t *frames; +static uint32_t nframes; + +#define PAGE_SHIFT 12 +#define PAGE_SIZE 0x1000UL +#define PAGE_SIZE_MASK 0xFFFFffffFFFFf000UL +#define PAGE_LOW_MASK 0x0000000000000FFFUL + +#define LARGE_PAGE_SIZE 0x200000UL + +#define KERNEL_HEAP_START 0xFFFFff0000000000UL +#define MMIO_BASE_START 0xffffff1fc0000000UL +#define HIGH_MAP_REGION 0xffffff8000000000UL + +/* These are actually defined in the shm layer... */ +#define USER_SHM_LOW 0x0000000200000000UL +#define USER_SHM_HIGH 0x0000000400000000UL +#define USER_DEVICE_MAP 0x0000000100000000UL + +#define USER_PML_ACCESS 0x07 +#define KERNEL_PML_ACCESS 0x03 +#define LARGE_PAGE_BIT 0x80 + +#define PDP_MASK 0x3fffffffUL +#define PD_MASK 0x1fffffUL +#define PT_MASK PAGE_LOW_MASK +#define ENTRY_MASK 0x1FF + +#define PHYS_MASK 0x7fffffffffUL +#define CANONICAL_MASK 0xFFFFffffFFFFUL + +#define INDEX_FROM_BIT(b) ((b) >> 5) +#define OFFSET_FROM_BIT(b) ((b) & 0x1F) + +void mmu_frame_set(uintptr_t frame_addr) { + /* If the frame is within bounds... */ + if (frame_addr < nframes * 4 * 0x400) { + uint64_t frame = frame_addr >> 12; + uint64_t index = INDEX_FROM_BIT(frame); + uint32_t offset = OFFSET_FROM_BIT(frame); + frames[index] |= ((uint32_t)1 << offset); + } +} + +void mmu_frame_clear(uintptr_t frame_addr) { + /* If the frame is within bounds... */ + if (frame_addr < nframes * 4 * 0x400) { + uint64_t frame = frame_addr >> PAGE_SHIFT; + uint64_t index = INDEX_FROM_BIT(frame); + uint32_t offset = OFFSET_FROM_BIT(frame); + frames[index] &= ~((uint32_t)1 << offset); + } +} + +int mmu_frame_test(uintptr_t frame_addr) { + if (!(frame_addr < nframes * 4 * 0x400)) return 0; + uint64_t frame = frame_addr >> PAGE_SHIFT; + uint64_t index = INDEX_FROM_BIT(frame); + uint32_t offset = OFFSET_FROM_BIT(frame); + return !!(frames[index] & ((uint32_t)1 << offset)); +} + +static spin_lock_t frame_alloc_lock = { 0 }; +static spin_lock_t kheap_lock = { 0 }; +static spin_lock_t mmio_space_lock = { 0 }; + +/** + * @brief Find the first range of @p n contiguous frames. + * + * If a large enough region could not be found, results are fatal. + */ +uintptr_t mmu_first_n_frames(int n) { + for (uint64_t i = 0; i < nframes * PAGE_SIZE; i += PAGE_SIZE) { + int bad = 0; + for (int j = 0; j < n; ++j) { + if (mmu_frame_test(i + PAGE_SIZE * j)) { + bad = j + 1; + } + } + if (!bad) { + return i / PAGE_SIZE; + } + } + + printf("failed to allocate %d contiguous frames\n", n); + arch_fatal(); + return (uintptr_t)-1; +} + +/** + * @brief Find the first available frame from the bitmap. + */ +uintptr_t mmu_first_frame(void) { + uintptr_t i, j; + for (i = 0; i < INDEX_FROM_BIT(nframes); ++i) { + if (frames[i] != (uint32_t)-1) { + for (j = 0; j < (sizeof(uint32_t)*8); ++j) { + uint32_t testFrame = (uint32_t)1 << j; + if (!(frames[i] & testFrame)) return (i << 5) + j; + } + } + } + + printf("error: out allocatable frames\n"); + arch_fatal(); + return (uintptr_t)-1; +} + +/** + * @brief Set the flags for a page, and allocate a frame for it if needed. + * + * Sets the page bits based on the the value of @p flags. + * If @p page->bits.page is unset, a new frame will be allocated. + */ +void mmu_frame_allocate(union PML * page, unsigned int flags) { + if (page->bits.page == 0) { + spin_lock(frame_alloc_lock); + uintptr_t index = mmu_first_frame(); + mmu_frame_set(index << PAGE_SHIFT); + page->bits.page = index; + spin_unlock(frame_alloc_lock); + } + page->bits.size = 0; + page->bits.present = 1; + page->bits.writable = (flags & MMU_FLAG_WRITABLE) ? 1 : 0; + page->bits.user = (flags & MMU_FLAG_KERNEL) ? 0 : 1; + page->bits.nocache = (flags & MMU_FLAG_NOCACHE) ? 1 : 0; + page->bits.writethrough = (flags & MMU_FLAG_WRITETHROUGH) ? 1 : 0; + page->bits.size = (flags & MMU_FLAG_SPEC) ? 1 : 0; + page->bits.nx = (flags & MMU_FLAG_NOEXECUTE) ? 1 : 0; +} + +/** + * @brief Map the given page to the requested physical address. + */ +void mmu_frame_map_address(union PML * page, unsigned int flags, uintptr_t physAddr) { + mmu_frame_set(physAddr); + page->bits.page = physAddr >> PAGE_SHIFT; + mmu_frame_allocate(page, flags); +} + +/* Initial memory maps loaded by boostrap */ +#define _pagemap __attribute__((aligned(PAGE_SIZE))) = {0} +union PML init_page_region[3][512] _pagemap; +union PML high_base_pml[512] _pagemap; +union PML heap_base_pml[512] _pagemap; +union PML heap_base_pd[512] _pagemap; +union PML heap_base_pt[512] _pagemap; +union PML low_base_pmls[34][512] _pagemap; +union PML twom_high_pds[4][512] _pagemap; + +/** + * @brief Maps a frame address to a virtual address. + * + * Returns the virtual address within the general-purpose + * identity mapping region for the given physical frame address. + * This address is not suitable for some operations, such as MMIO. + */ +void * mmu_map_from_physical(uintptr_t frameaddress) { + return (void*)(frameaddress | HIGH_MAP_REGION); +} + +/** + * @brief Find the physical address at a given virtual address. + * + * Calculates the physical address of the page backing the virtual + * address @p virtAddr. If no page is mapped, a negative value + * is returned indicating which level of the page directory is + * unmapped from -1 (no PDP) to -4 (page not present in table). + */ +uintptr_t mmu_map_to_physical(uintptr_t virtAddr) { + uintptr_t realBits = virtAddr & CANONICAL_MASK; + uintptr_t pageAddr = realBits >> PAGE_SHIFT; + unsigned int pml4_entry = (pageAddr >> 27) & ENTRY_MASK; + unsigned int pdp_entry = (pageAddr >> 18) & ENTRY_MASK; + unsigned int pd_entry = (pageAddr >> 9) & ENTRY_MASK; + unsigned int pt_entry = (pageAddr) & ENTRY_MASK; + + union PML * root = this_core->current_pml; + + /* Get the PML4 entry for this address */ + if (!root[pml4_entry].bits.present) return (uintptr_t)-1; + + union PML * pdp = mmu_map_from_physical((uintptr_t)root[pml4_entry].bits.page << PAGE_SHIFT); + + if (!pdp[pdp_entry].bits.present) return (uintptr_t)-2; + if (pdp[pdp_entry].bits.size) return ((uintptr_t)pdp[pdp_entry].bits.page << PAGE_SHIFT) | (virtAddr & PDP_MASK); + + union PML * pd = mmu_map_from_physical((uintptr_t)pdp[pdp_entry].bits.page << PAGE_SHIFT); + + if (!pd[pd_entry].bits.present) return (uintptr_t)-3; + if (pd[pd_entry].bits.size) return ((uintptr_t)pd[pd_entry].bits.page << PAGE_SHIFT) | (virtAddr & PD_MASK); + + union PML * pt = mmu_map_from_physical((uintptr_t)pd[pd_entry].bits.page << PAGE_SHIFT); + + if (!pt[pt_entry].bits.present) return (uintptr_t)-4; + return ((uintptr_t)pt[pt_entry].bits.page << PAGE_SHIFT) | (virtAddr & PT_MASK); +} + +/** + * @brief Obtain the page entry for a virtual address. + * + * Digs into the current page directory to obtain the page entry + * for a requested address @p virtAddr. If new intermediary directories + * need to be allocated and @p flags has @c MMU_GET_MAKE set, they + * will be allocated with the user access bits set. Otherwise, + * NULL will be returned. If the requested virtual address is within + * a large page, NULL will be returned. + * + * @param virtAddr Canonical virtual address offset. + * @param flags See @c MMU_GET_MAKE + * @returns the requested page entry, or NULL if doing so required allocating + * an intermediary paging level and @p flags did not have @c MMU_GET_MAKE set. + */ +union PML * mmu_get_page(uintptr_t virtAddr, int flags) { + uintptr_t realBits = virtAddr & CANONICAL_MASK; + uintptr_t pageAddr = realBits >> PAGE_SHIFT; + unsigned int pml4_entry = (pageAddr >> 27) & ENTRY_MASK; + unsigned int pdp_entry = (pageAddr >> 18) & ENTRY_MASK; + unsigned int pd_entry = (pageAddr >> 9) & ENTRY_MASK; + unsigned int pt_entry = (pageAddr) & ENTRY_MASK; + + union PML * root = this_core->current_pml; + + /* Get the PML4 entry for this address */ + if (!root[pml4_entry].bits.present) { + if (!(flags & MMU_GET_MAKE)) goto _noentry; + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + /* zero it */ + memset(mmu_map_from_physical(newPage), 0, PAGE_SIZE); + root[pml4_entry].raw = (newPage) | USER_PML_ACCESS; + } + + union PML * pdp = mmu_map_from_physical((uintptr_t)root[pml4_entry].bits.page << PAGE_SHIFT); + + if (!pdp[pdp_entry].bits.present) { + if (!(flags & MMU_GET_MAKE)) goto _noentry; + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + /* zero it */ + memset(mmu_map_from_physical(newPage), 0, PAGE_SIZE); + pdp[pdp_entry].raw = (newPage) | USER_PML_ACCESS; + } + + if (pdp[pdp_entry].bits.size) { + printf("Warning: Tried to get page for a 1GiB page!\n"); + return NULL; + } + + union PML * pd = mmu_map_from_physical((uintptr_t)pdp[pdp_entry].bits.page << PAGE_SHIFT); + + if (!pd[pd_entry].bits.present) { + if (!(flags & MMU_GET_MAKE)) goto _noentry; + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + /* zero it */ + memset(mmu_map_from_physical(newPage), 0, PAGE_SIZE); + pd[pd_entry].raw = (newPage) | USER_PML_ACCESS; + } + + if (pd[pd_entry].bits.size) { + printf("Warning: Tried to get page for a 2MiB page!\n"); + return NULL; + } + + union PML * pt = mmu_map_from_physical((uintptr_t)pd[pd_entry].bits.page << PAGE_SHIFT); + return (union PML *)&pt[pt_entry]; + +_noentry: + printf("no entry for requested page\n"); + return NULL; +} + +/** + * @brief Create a new address space with the same contents of an existing one. + * + * Allocates all of the necessary intermediary directory levels for a new address space + * and also copies data from the existing address space. + * + * TODO: This doesn't do any CoW and it's kinda complicated. + * + * @param from The directory to clone, or NULL to clone the kernel map. + * @returns a pointer to the new page directory, suitable for mapping to a physical address. + */ +union PML * mmu_clone(union PML * from) { + /* Clone the current PMLs... */ + if (!from) from = this_core->current_pml; + + /* First get a page for ourselves. */ + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + union PML * pml4_out = mmu_map_from_physical(newPage); + + /* Zero bottom half */ + memset(&pml4_out[0], 0, 256 * sizeof(union PML)); + + /* Copy top half */ + memcpy(&pml4_out[256], &from[256], 256 * sizeof(union PML)); + + /* Copy PDPs */ + for (size_t i = 0; i < 256; ++i) { + if (from[i].bits.present) { + union PML * pdp_in = mmu_map_from_physical((uintptr_t)from[i].bits.page << PAGE_SHIFT); + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + union PML * pdp_out = mmu_map_from_physical(newPage); + memset(pdp_out, 0, 512 * sizeof(union PML)); + pml4_out[i].raw = (newPage) | USER_PML_ACCESS; + + /* Copy the PDs */ + for (size_t j = 0; j < 512; ++j) { + if (pdp_in[j].bits.present) { + union PML * pd_in = mmu_map_from_physical((uintptr_t)pdp_in[j].bits.page << PAGE_SHIFT); + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + union PML * pd_out = mmu_map_from_physical(newPage); + memset(pd_out, 0, 512 * sizeof(union PML)); + pdp_out[j].raw = (newPage) | USER_PML_ACCESS; + + /* Now copy the PTs */ + for (size_t k = 0; k < 512; ++k) { + if (pd_in[k].bits.present) { + union PML * pt_in = mmu_map_from_physical((uintptr_t)pd_in[k].bits.page << PAGE_SHIFT); + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + union PML * pt_out = mmu_map_from_physical(newPage); + memset(pt_out, 0, 512 * sizeof(union PML)); + pd_out[k].raw = (newPage) | USER_PML_ACCESS; + + /* Now, finally, copy pages */ + for (size_t l = 0; l < 512; ++l) { + uintptr_t address = ((i << (9 * 3 + 12)) | (j << (9*2 + 12)) | (k << (9 + 12)) | (l << PAGE_SHIFT)); + if (address >= USER_DEVICE_MAP && address <= USER_SHM_HIGH) continue; + if (pt_in[l].bits.present) { + if (pt_in[l].bits.user) { + char * page_in = mmu_map_from_physical((uintptr_t)pt_in[l].bits.page << PAGE_SHIFT); + spin_lock(frame_alloc_lock); + uintptr_t newPage = mmu_first_frame() << PAGE_SHIFT; + mmu_frame_set(newPage); + spin_unlock(frame_alloc_lock); + char * page_out = mmu_map_from_physical(newPage); + memcpy(page_out,page_in,PAGE_SIZE); + pt_out[l].bits.page = newPage >> PAGE_SHIFT; + pt_out[l].bits.present = 1; + pt_out[l].bits.user = 1; + pt_out[l].bits.writable = pt_in[l].bits.writable; + pt_out[l].bits.writethrough = pt_out[l].bits.writethrough; + pt_out[l].bits.accessed = pt_out[l].bits.accessed; + pt_out[l].bits.size = pt_out[l].bits.size; + pt_out[l].bits.global = pt_out[l].bits.global; + pt_out[l].bits.nx = pt_out[l].bits.nx; + } else { + /* If it's not a user page, just copy directly */ + pt_out[l].raw = pt_in[l].raw; + } + } + } + } + } + } + } + } + } + + return pml4_out; +} + +/** + * @brief Allocate one physical page. + * + * @returns a frame index, not an address + */ +uintptr_t mmu_allocate_a_frame(void) { + spin_lock(frame_alloc_lock); + uintptr_t index = mmu_first_frame(); + mmu_frame_set(index << PAGE_SHIFT); + spin_unlock(frame_alloc_lock); + return index; +} + +/** + * @brief Allocate a number of contiguous physical pages. + * + * @returns a frame index, not an address + */ +uintptr_t mmu_allocate_n_frames(int n) { + spin_lock(frame_alloc_lock); + uintptr_t index = mmu_first_n_frames(n); + for (int i = 0; i < n; ++i) { + mmu_frame_set((index+i) << PAGE_SHIFT); + } + spin_unlock(frame_alloc_lock); + return index; +} + +/** + * @brief Scans a directory to calculate how many user pages are in use. + * + * Calculates how many pages a userspace application has mapped, between + * its general memory space and stack. Excludes shared mappings, such + * as SHM or mapped devices. + * + * TODO: This can probably be reduced to check a smaller range, but as we + * currently stick the user stack at the top of the low half of the + * address space we just scan everything and exclude shared memory... + * + * @param from Top-level page directory to scan. + */ +size_t mmu_count_user(union PML * from) { + size_t out = 0; + + for (size_t i = 0; i < 256; ++i) { + if (from[i].bits.present) { + union PML * pdp_in = mmu_map_from_physical((uintptr_t)from[i].bits.page << PAGE_SHIFT); + for (size_t j = 0; j < 512; ++j) { + if (pdp_in[j].bits.present) { + union PML * pd_in = mmu_map_from_physical((uintptr_t)pdp_in[j].bits.page << PAGE_SHIFT); + for (size_t k = 0; k < 512; ++k) { + if (pd_in[k].bits.present) { + union PML * pt_in = mmu_map_from_physical((uintptr_t)pd_in[k].bits.page << PAGE_SHIFT); + for (size_t l = 0; l < 512; ++l) { + /* Calculate final address to skip SHM */ + uintptr_t address = ((i << (9 * 3 + 12)) | (j << (9*2 + 12)) | (k << (9 + 12)) | (l << PAGE_SHIFT)); + if (address >= USER_DEVICE_MAP && address <= USER_SHM_HIGH) continue; + if (pt_in[l].bits.present) { + if (pt_in[l].bits.user) { + out++; + } + } + } + } + } + } + } + } + } + return out; +} + +/** + * @brief Scans a directory to calculate how many shared memory pages are in use. + * + * At the moment, we only ever map shared pages to a specific region, so we just figure + * out how many present pages are in that region and that's the answer. + * + * @param from Top-level page directory to scan. + */ +size_t mmu_count_shm(union PML * from) { + size_t out = 0; + + if (from[0].bits.present) { + union PML * pdp_in = mmu_map_from_physical((uintptr_t)from[0].bits.page << PAGE_SHIFT); + /* [0,8,0,0] through [0,15,511,511] map to our current SHM mapping region; + * if you change the bounds of that region, be sure to update this! */ + for (size_t j = 8; j < 16; ++j) { + if (pdp_in[j].bits.present) { + union PML * pd_in = mmu_map_from_physical((uintptr_t)pdp_in[j].bits.page << PAGE_SHIFT); + for (size_t k = 0; k < 512; ++k) { + if (pd_in[k].bits.present) { + union PML * pt_in = mmu_map_from_physical((uintptr_t)pd_in[k].bits.page << PAGE_SHIFT); + for (size_t l = 0; l < 512; ++l) { + if (pt_in[l].bits.present) { + if (pt_in[l].bits.user) { + out++; + } + } + } + } + } + } + } + } + return out; +} + +/** + * @brief Return the total amount of usable memory. + * + * Just returns the number of frames in the bitmap allocator, times 4. + * + * @returns the total amount of usable memory in KiB. + */ +size_t mmu_total_memory(void) { + return nframes * 4; +} + +/** + * @brief Return the amount of used memory. + * + * Calculates the number of pages currently marked as allocated. + * Multiplies it by 4 because pages are 4KiB. + * + * @returns the amount of memory in use in KiB. + */ +size_t mmu_used_memory(void) { + size_t ret = 0; + size_t i, j; + for (i = 0; i < INDEX_FROM_BIT(nframes); ++i) { + for (j = 0; j < 32; ++j) { + uint32_t testFrame = (uint32_t)0x1 << j; + if (frames[i] & testFrame) { + ret++; + } + } + } + return ret * 4; +} + +/** + * @brief Relinquish pages owned by a top-level directory. + * + * Frees the underlying pages for a page directory within the lower (user) region. + * Does not free kernel pages, as those are generally shared in the lower region. + * + * @param from Virtual pointer to top-level directory. + */ +void mmu_free(union PML * from) { + if (!from) { + printf("can't clear NULL directory\n"); + return; + } + + spin_lock(frame_alloc_lock); + for (size_t i = 0; i < 256; ++i) { + if (from[i].bits.present) { + union PML * pdp_in = mmu_map_from_physical((uintptr_t)from[i].bits.page << PAGE_SHIFT); + for (size_t j = 0; j < 512; ++j) { + if (pdp_in[j].bits.present) { + union PML * pd_in = mmu_map_from_physical((uintptr_t)pdp_in[j].bits.page << PAGE_SHIFT); + for (size_t k = 0; k < 512; ++k) { + if (pd_in[k].bits.present) { + union PML * pt_in = mmu_map_from_physical((uintptr_t)pd_in[k].bits.page << PAGE_SHIFT); + for (size_t l = 0; l < 512; ++l) { + uintptr_t address = ((i << (9 * 3 + 12)) | (j << (9*2 + 12)) | (k << (9 + 12)) | (l << PAGE_SHIFT)); + /* Do not free shared mappings; SHM subsystem does that for SHM, devices don't need it. */ + if (address >= USER_DEVICE_MAP && address <= USER_SHM_HIGH) continue; + if (pt_in[l].bits.present) { + /* Free only user pages */ + if (pt_in[l].bits.user) { + mmu_frame_clear((uintptr_t)pt_in[l].bits.page << PAGE_SHIFT); + } + } + } + mmu_frame_clear((uintptr_t)pd_in[k].bits.page << PAGE_SHIFT); + } + } + mmu_frame_clear((uintptr_t)pdp_in[j].bits.page << PAGE_SHIFT); + } + } + mmu_frame_clear((uintptr_t)from[i].bits.page << PAGE_SHIFT); + } + } + + mmu_frame_clear((((uintptr_t)from) & PHYS_MASK)); + spin_unlock(frame_alloc_lock); +} + +union PML * mmu_get_kernel_directory(void) { + return mmu_map_from_physical((uintptr_t)&init_page_region[0]); +} + +/** + * @brief Switch the active page directory for this core. + * + * Generally called during task creation and switching to change + * the active page directory of a core. Updates @c this_core->current_pml. + * + * x86-64: Loads a given PML into CR3. + * + * @param new_pml Either the physical address or the shadow mapping virtual address + * of the new PML4 directory to switch into, general obtained from + * a process struct; if NULL is passed, the initial kernel directory + * will be used and no userspace mappings will be present. + */ +void mmu_set_directory(union PML * new_pml) { + if (!new_pml) new_pml = mmu_map_from_physical((uintptr_t)&init_page_region[0]); + this_core->current_pml = new_pml; + + asm volatile ( + "movq %0, %%cr3" + : : "r"((uintptr_t)new_pml & PHYS_MASK)); +} + +/** + * @brief Mark a virtual address's mappings as invalid in the TLB. + * + * Generally should be called when a mapping is relinquished, as this is what + * the TLB caches, but is also called in a bunch of places where we're just mapping + * new pages... + * + * @param addr Virtual address in the current address space to invalidate. + */ +void mmu_invalidate(uintptr_t addr) { + asm volatile ( + "invlpg (%0)" + : : "r"(addr)); +} + +static char * heapStart = NULL; +extern char end[]; + +/** + * @brief Prepare virtual page mappings for use by the kernel. + * + * Called during early boot to switch from the loader/bootstrap mappings + * to ones suitable for general use. Sets up the bitmap allocator, high + * identity mapping, kernel heap, and various mid-level structures to + * ensure that future kernelspace mappings apply to all kernel threads. + * + * @param memsize The maximum accessible physical address. + * @param firstFreePage The address of the first frame the kernel may use for new allocations. + */ +void mmu_init(size_t memsize, uintptr_t firstFreePage) { + this_core->current_pml = (union PML *)&init_page_region[0]; + + /* Map the high base PDP */ + init_page_region[0][511].raw = (uintptr_t)&high_base_pml | KERNEL_PML_ACCESS; + init_page_region[0][510].raw = (uintptr_t)&heap_base_pml | KERNEL_PML_ACCESS; + + /* Identity map from -128GB in the boot PML using 2MiB pages */ + high_base_pml[0].raw = (uintptr_t)&twom_high_pds[0] | KERNEL_PML_ACCESS; + high_base_pml[1].raw = (uintptr_t)&twom_high_pds[1] | KERNEL_PML_ACCESS; + high_base_pml[2].raw = (uintptr_t)&twom_high_pds[2] | KERNEL_PML_ACCESS; + high_base_pml[3].raw = (uintptr_t)&twom_high_pds[3] | KERNEL_PML_ACCESS; + + for (uintptr_t i = 0; i < 512; i += 1) { + twom_high_pds[0][i].raw = (0x00000000 + i * LARGE_PAGE_SIZE) | LARGE_PAGE_BIT | KERNEL_PML_ACCESS; + twom_high_pds[1][i].raw = (0x40000000 + i * LARGE_PAGE_SIZE) | LARGE_PAGE_BIT | KERNEL_PML_ACCESS; + twom_high_pds[2][i].raw = (0x80000000 + i * LARGE_PAGE_SIZE) | LARGE_PAGE_BIT | KERNEL_PML_ACCESS; + twom_high_pds[3][i].raw = (0xC0000000 + i * LARGE_PAGE_SIZE) | LARGE_PAGE_BIT | KERNEL_PML_ACCESS; + } + + /* Map low base PDP */ + low_base_pmls[0][0].raw = (uintptr_t)&low_base_pmls[1] | USER_PML_ACCESS; + + /* How much memory do we need to map low for our *kernel* to fit? */ + uintptr_t endPtr = ((uintptr_t)&end + PAGE_LOW_MASK) & PAGE_SIZE_MASK; + + /* How many pages does that need? */ + size_t lowPages = endPtr >> PAGE_SHIFT; + + /* And how many 512-page blocks does that fit in? */ + size_t pdCount = (lowPages + ENTRY_MASK) >> 9; + + for (size_t j = 0; j < pdCount; ++j) { + low_base_pmls[1][j].raw = (uintptr_t)&low_base_pmls[2+j] | KERNEL_PML_ACCESS; + for (int i = 0; i < 512; ++i) { + low_base_pmls[2+j][i].raw = (uintptr_t)(LARGE_PAGE_SIZE * j + PAGE_SIZE * i) | KERNEL_PML_ACCESS; + } + } + + /* Unmap null */ + low_base_pmls[2][0].raw = 0; + + /* Now map our new low base */ + init_page_region[0][0].raw = (uintptr_t)&low_base_pmls[0] | USER_PML_ACCESS; + + /* Set up the page allocator bitmap... */ + nframes = (memsize >> 12); + size_t bytesOfFrames = INDEX_FROM_BIT(nframes * 8); + bytesOfFrames = (bytesOfFrames + PAGE_LOW_MASK) & PAGE_SIZE_MASK; + firstFreePage = (firstFreePage + PAGE_LOW_MASK) & PAGE_SIZE_MASK; + size_t pagesOfFrames = bytesOfFrames >> 12; + + /* Set up heap map for that... */ + heap_base_pml[0].raw = (uintptr_t)&heap_base_pd | KERNEL_PML_ACCESS; + heap_base_pd[0].raw = (uintptr_t)&heap_base_pt | KERNEL_PML_ACCESS; + + if (pagesOfFrames > 512) { + printf("Warning: Too much available memory for current setup. Need %zu pages to represent allocation bitmap.\n", pagesOfFrames); + } + + for (size_t i = 0; i < pagesOfFrames; i++) { + heap_base_pt[i].raw = (firstFreePage + (i << 12)) | KERNEL_PML_ACCESS; + } + + asm volatile ("" : : : "memory"); + this_core->current_pml = mmu_map_from_physical((uintptr_t)this_core->current_pml); + asm volatile ("" : : : "memory"); + + /* We are now in the new stuff. */ + frames = (void*)((uintptr_t)KERNEL_HEAP_START); + memset(frames, 0, bytesOfFrames); + + /* Now mark everything up to (firstFreePage + bytesOfFrames) as in use */ + for (uintptr_t i = 0; i < firstFreePage + bytesOfFrames; i += PAGE_SIZE) { + mmu_frame_set(i); + } + + heapStart = (char*)KERNEL_HEAP_START + bytesOfFrames; +} + +/** + * @brief Allocate space in the kernel virtual heap. + * + * Called by the kernel heap allocator to obtain space for new heap allocations. + * + * @warning Not to be confused with sys_sbrk + * + * @param bytes Bytes to allocate. Must be a multiple of PAGE_SIZE. + * @returns The previous address of the break point, after which @p bytes may now be used. + */ +void * sbrk(size_t bytes) { + if (!heapStart) { + printf("sbrk: Called before heap was ready.\n"); + arch_fatal(); + } + + if (!bytes) { + /* Skip lock acquisition if we just wanted to know where the break was. */ + return heapStart; + } + + if (bytes & PAGE_LOW_MASK) { + printf("sbrk: Size must be multiple of 4096, was %#zx\n", bytes); + arch_fatal(); + } + + if (bytes > 0xF00000) { + printf("sbrk: Size must be within a reasonable bound, was %#zx\n", bytes); + arch_fatal(); + } + + spin_lock(kheap_lock); + void * out = heapStart; + + for (uintptr_t p = (uintptr_t)out; p < (uintptr_t)out + bytes; p += PAGE_SIZE) { + union PML * page = mmu_get_page(p, MMU_GET_MAKE); + mmu_frame_allocate(page, MMU_FLAG_WRITABLE | MMU_FLAG_KERNEL); + mmu_invalidate(p); + } + + heapStart += bytes; + spin_unlock(kheap_lock); + return out; +} + +static uintptr_t mmio_base_address = MMIO_BASE_START; + +/** + * @brief Obtain a writethrough region mapped to the given physical address. + * + * For use by device drivers to obtain mappings suitable for MMIO accesses. Note that the + * virtual address space for these mappings can not be reclaimed, so drivers should keep + * them around or use the other MMU facilities to repurpose them. + * + * @param physical_address Physical memory offset of the destination MMIO space. + * @param size Size of the requested space, which must be a multiple of PAGE_SIZE. + * @returns a virtual address suitable for MMIO accesses. + */ +void * mmu_map_mmio_region(uintptr_t physical_address, size_t size) { + if (size & PAGE_LOW_MASK) { + printf("mmu_map_mmio_region: MMIO region size must be multiple of 4096 bytes, was %#zx.\n", size); + arch_fatal(); + } + + spin_lock(mmio_space_lock); + void * out = (void*)mmio_base_address; + for (size_t i = 0; i < size; i += PAGE_SIZE) { + union PML * p = mmu_get_page(mmio_base_address + i, MMU_GET_MAKE); + mmu_frame_map_address(p, MMU_FLAG_KERNEL | MMU_FLAG_WRITABLE | MMU_FLAG_NOCACHE | MMU_FLAG_WRITETHROUGH, physical_address + i); + mmu_invalidate(mmio_base_address + i); + } + mmio_base_address += size; + spin_unlock(mmio_space_lock); + + return out; +} diff --git a/kernel/arch/x86_64/pic.c b/kernel/arch/x86_64/pic.c new file mode 100644 index 00000000..910d9f10 --- /dev/null +++ b/kernel/arch/x86_64/pic.c @@ -0,0 +1,64 @@ +/** + * @file kernel/arch/x86_64/pic.c + * @brief Legacy PIC support. + */ +#include +#include +#include +#include +#include + +/* Programmable interrupt controller */ +#define PIC1 0x20 +#define PIC1_COMMAND PIC1 +#define PIC1_OFFSET 0x20 +#define PIC1_DATA (PIC1+1) + +#define PIC2 0xA0 +#define PIC2_COMMAND PIC2 +#define PIC2_OFFSET 0x28 +#define PIC2_DATA (PIC2+1) + +#define PIC_EOI 0x20 + +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 + +#define PIC_WAIT() \ + do { \ + /* May be fragile */ \ + asm volatile("jmp 1f\n\t" \ + "1:\n\t" \ + " jmp 2f\n\t" \ + "2:"); \ + } while (0) + +static void irq_remap(void) { + /* Cascade initialization */ + outportb(PIC1_COMMAND, ICW1_INIT|ICW1_ICW4); PIC_WAIT(); + outportb(PIC2_COMMAND, ICW1_INIT|ICW1_ICW4); PIC_WAIT(); + + /* Remap */ + outportb(PIC1_DATA, PIC1_OFFSET); PIC_WAIT(); + outportb(PIC2_DATA, PIC2_OFFSET); PIC_WAIT(); + + /* Cascade identity with slave PIC at IRQ2 */ + outportb(PIC1_DATA, 0x04); PIC_WAIT(); + outportb(PIC2_DATA, 0x02); PIC_WAIT(); + + /* Request 8086 mode on each PIC */ + outportb(PIC1_DATA, 0x01); PIC_WAIT(); + outportb(PIC2_DATA, 0x01); PIC_WAIT(); +} + +void irq_ack(size_t irq_no) { + if (irq_no >= 8) { + outportb(PIC2_COMMAND, PIC_EOI); + } + outportb(PIC1_COMMAND, PIC_EOI); +} + +void pic_initialize(void) { + irq_remap(); +} + diff --git a/kernel/arch/x86_64/pit.c b/kernel/arch/x86_64/pit.c new file mode 100644 index 00000000..d806ae2c --- /dev/null +++ b/kernel/arch/x86_64/pit.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +/* Programmable interval timer */ +#define PIT_A 0x40 +#define PIT_B 0x41 +#define PIT_C 0x42 +#define PIT_CONTROL 0x43 + +#define PIT_MASK 0xFF +#define PIT_SCALE 1193180 +#define PIT_SET 0x34 + +#define TIMER_IRQ 0 + +#define RESYNC_TIME 1 + +static void pit_set_timer_phase(long hz) { + long divisor = PIT_SCALE / hz; + outportb(PIT_CONTROL, PIT_SET); + outportb(PIT_A, divisor & PIT_MASK); + outportb(PIT_A, (divisor >> 8) & PIT_MASK); +} + +extern int cmos_time_stuff(struct regs *r); + +void pit_initialize(void) { + irq_install_handler(TIMER_IRQ, cmos_time_stuff, "pit timer"); + + /* ELCR? */ + uint8_t val = inportb(0x4D1); + outportb(0x4D1, val | (1 << (10-8)) | (1 << (11-8))); + + /* Enable PIT */ + pit_set_timer_phase(100); /* 1000 Hz */ +} diff --git a/kernel/sys/system.c b/kernel/arch/x86_64/ports.c similarity index 50% rename from kernel/sys/system.c rename to kernel/arch/x86_64/ports.c index 1bd2725d..72d227b9 100644 --- a/kernel/sys/system.c +++ b/kernel/arch/x86_64/ports.c @@ -1,40 +1,8 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * System Functions - * +/** + * @file kernel/arch/x86_64/ports.c + * @brief Port I/O methods for x86-64. */ -#include - -char * boot_arg = NULL; -char * boot_arg_extra = NULL; - -/* - * memsetw - * Set `count` shorts to `val`. - */ -unsigned short * memsetw(unsigned short * dest, unsigned short val, int count) { - int i = 0; - for ( ; i < count; ++i ) { - dest[i] = val; - } - return dest; -} - -uint32_t __attribute__ ((pure)) krand(void) { - static uint32_t x = 123456789; - static uint32_t y = 362436069; - static uint32_t z = 521288629; - static uint32_t w = 88675123; - - uint32_t t; - - t = x ^ (x << 11); - x = y; y = z; z = w; - return w = w ^ (w >> 19) ^ t ^ (t >> 8); -} +#include unsigned short inports(unsigned short _port) { unsigned short rv; @@ -73,16 +41,3 @@ void outportsm(unsigned short port, unsigned char * data, unsigned long size) { void inportsm(unsigned short port, unsigned char * data, unsigned long size) { asm volatile ("rep insw" : "+D" (data), "+c" (size) : "d" (port) : "memory"); } - -size_t lfind(const char * str, const char accept) { - return (size_t)strchr(str, accept); -} - -size_t rfind(const char * str, const char accept) { - return (size_t)strrchr(str, accept); -} - -uint8_t startswith(const char * str, const char * accept) { - return strstr(str, accept) == str; -} - diff --git a/kernel/arch/x86_64/ps2hid.c b/kernel/arch/x86_64/ps2hid.c new file mode 100644 index 00000000..9eb531bf --- /dev/null +++ b/kernel/arch/x86_64/ps2hid.c @@ -0,0 +1,366 @@ +/** + * @file kernel/arch/x86_64/ps2mouse.c + * @brief PC PS/2 input device driver + * + * This is the slightly less terrible merged PS/2 mouse+keyboard driver. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014-2021 K. Lange + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PACKETS_IN_PIPE 1024 +#define DISCARD_POINT 32 +#define KEYBOARD_IRQ 1 +#define MOUSE_IRQ 12 + +#define PS2_DATA 0x60 +#define PS2_STATUS 0x64 +#define PS2_COMMAND 0x64 +#define MOUSE_WRITE 0xD4 +#define MOUSE_V_BIT 0x08 + +#define PS2_PORT1_IRQ 0x01 +#define PS2_PORT2_IRQ 0x02 +#define PS2_PORT1_TLATE 0x40 + +#define PS2_READ_CONFIG 0x20 +#define PS2_WRITE_CONFIG 0x60 + +#define PS2_DISABLE_PORT2 0xA7 +#define PS2_ENABLE_PORT2 0xA8 +#define PS2_DISABLE_PORT1 0xAD +#define PS2_ENABLE_PORT1 0xAE + +#define MOUSE_SET_REMOTE 0xF0 +#define MOUSE_DEVICE_ID 0xF2 +#define MOUSE_SAMPLE_RATE 0xF3 +#define MOUSE_DATA_ON 0xF4 +#define MOUSE_DATA_OFF 0xF5 +#define MOUSE_SET_DEFAULTS 0xF6 + +#define MOUSE_DEFAULT 0 +#define MOUSE_SCROLLWHEEL 1 +#define MOUSE_BUTTONS 2 + +#define KBD_SET_SCANCODE 0xF0 + +static uint8_t mouse_cycle = 0; +static uint8_t mouse_byte[4]; +static int8_t mouse_mode = MOUSE_DEFAULT; +static fs_node_t * mouse_pipe; +static fs_node_t * keyboard_pipe; + +void (*ps2_mouse_alternate)(uint8_t) = NULL; + +/** + * @brief Wait until the PS/2 controller's input buffer is clear. + * + * Use this before WRITING to the controller. + */ +static int ps2_wait_input(void) { + uint64_t timeout = 100000UL; + while (--timeout) { + if (!(inportb(PS2_STATUS) & (1 << 1))) return 0; + } + return 1; +} + +/** + * @brief Wait until the PS/2 controller's output buffer is filled. + * + * Use this before READING from the controller. + */ +static int ps2_wait_output(void) { + uint64_t timeout = 100000UL; + while (--timeout) { + if (inportb(PS2_STATUS) & (1 << 0)) return 0; + } + return 1; +} + +/** + * @brief Send a command with no response or argument. + */ +static void ps2_command(uint8_t cmdbyte) { + ps2_wait_input(); + outportb(PS2_COMMAND, cmdbyte); +} + +/** + * @brief Send a command and get the reply. + */ +static uint8_t ps2_command_response(uint8_t cmdbyte) { + ps2_wait_input(); + outportb(PS2_COMMAND, cmdbyte); + ps2_wait_output(); + return inportb(PS2_DATA); +} + +/** + * @brief Send a command with an argument and no reply. + */ +static void ps2_command_arg(uint8_t cmdbyte, uint8_t arg) { + ps2_wait_input(); + outportb(PS2_COMMAND, cmdbyte); + ps2_wait_input(); + outportb(PS2_DATA, arg); +} + +/** + * @brief Write to the aux port. + */ +static void mouse_write(uint8_t write) { + ps2_command_arg(MOUSE_WRITE, write); +} + +/** + * @brief Write to the primary port. + */ +static void kbd_write(uint8_t write) { + ps2_wait_input(); + outportb(PS2_DATA, write); +} + +/** + * @brief Process a completed mouse packet. + * + * Assembles a mouse_device_packet_t from the data we got from + * the PS/2 device and forwards it to the pipe to be read by + * userspace; if the pipe is full we discard old bytes first. + */ +static void finish_packet(void) { + mouse_cycle = 0; + /* We now have a full mouse packet ready to use */ + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + int x = mouse_byte[1]; + int y = mouse_byte[2]; + if (x && mouse_byte[0] & (1 << 4)) { + /* Sign bit */ + x = x - 0x100; + } + if (y && mouse_byte[0] & (1 << 5)) { + /* Sign bit */ + y = y - 0x100; + } + if (mouse_byte[0] & (1 << 6) || mouse_byte[0] & (1 << 7)) { + /* Overflow */ + x = 0; + y = 0; + } + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + if (mouse_byte[0] & 0x01) { + packet.buttons |= LEFT_CLICK; + } + if (mouse_byte[0] & 0x02) { + packet.buttons |= RIGHT_CLICK; + } + if (mouse_byte[0] & 0x04) { + packet.buttons |= MIDDLE_CLICK; + } + + if (mouse_mode == MOUSE_SCROLLWHEEL && mouse_byte[3]) { + if ((int8_t)mouse_byte[3] > 0) { + packet.buttons |= MOUSE_SCROLL_DOWN; + } else if ((int8_t)mouse_byte[3] < 0) { + packet.buttons |= MOUSE_SCROLL_UP; + } + } + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); +} + +/** + * @brief Read one byte from the mouse. + */ +static void ps2_mouse_handle(uint8_t data_byte) { + if (ps2_mouse_alternate) { + ps2_mouse_alternate(data_byte); + } else { + int8_t mouse_in = data_byte; + switch (mouse_cycle) { + case 0: + mouse_byte[0] = mouse_in; + if (!(mouse_in & MOUSE_V_BIT)) break; + ++mouse_cycle; + break; + case 1: + mouse_byte[1] = mouse_in; + ++mouse_cycle; + break; + case 2: + mouse_byte[2] = mouse_in; + if (mouse_mode == MOUSE_SCROLLWHEEL || mouse_mode == MOUSE_BUTTONS) { + ++mouse_cycle; + break; + } + finish_packet(); + break; + case 3: + mouse_byte[3] = mouse_in; + finish_packet(); + break; + } + } +} + +static int ioctl_mouse(fs_node_t * node, int request, void * argp) { + if (request == 1) { + mouse_cycle = 0; + return 0; + } + return -1; +} + +/** + * @brief Read one byte from the keyboard. + * + * We give userspace the keyboard scancodes directly, and libtoaru_kbd + * handles translation to a more usable format. This is probably not + * the best way to do this... + */ +static void ps2_kbd_handle(uint8_t data_byte) { + write_fs(keyboard_pipe, 0, 1, (uint8_t []){data_byte}); +} + +/** + * @brief Shared handler that does some magic that probably only works in QEMU. + * + * The general idea behind this shared handler is that QEMU is "broken" + * and introduces a race that shouldn't be possible on real hardware? + * We can get an interrupt but the byte we get out of the port is + * for the other device. This makes playing Quake very hard because + * our keyboard our mouse devices get garbage when we're doing both + * at once! Thankfully, QEMU supports the status bit for checking + * if there is mouse data, and if we prevent any data from coming + * in from either port (by disabling both) while checking both + * the status and the data port, we can use that as a lock and get + * an "atomic" read that tells us which thing the data come from. + */ +static int shared_handler(struct regs * r) { + /* Disable both ports */ + ps2_command(PS2_DISABLE_PORT1); + ps2_command(PS2_DISABLE_PORT2); + /* Read the status and data */ + uint8_t status = inportb(PS2_STATUS); + uint8_t data_byte = inportb(PS2_DATA); + /* Re-enable both */ + ps2_command(PS2_ENABLE_PORT1); + ps2_command(PS2_ENABLE_PORT2); + + irq_ack(r->int_no-32); + + if (!(status & 0x01)) return 1; + + if (!(status & 0x20)) { + ps2_kbd_handle(data_byte); + } else if (status & 0x21) { + ps2_mouse_handle(data_byte); + } + return 1; +} + +/** + * @brief IRQ1 handler. + */ +static int keyboard_handler(struct regs *r) { + uint8_t data_byte = inportb(PS2_DATA); + irq_ack(KEYBOARD_IRQ); + ps2_kbd_handle(data_byte); + return 1; +} + +/** + * @brief IRQ12 handler. + */ +static int mouse_handler(struct regs *r) { + uint8_t data_byte = inportb(PS2_DATA); + irq_ack(MOUSE_IRQ); + ps2_mouse_handle(data_byte); + return 1; +} + + +/** + * @brief Initialze i8042/AIP PS/2 controller. + */ +void ps2hid_install(void) { + uint8_t status, result; + + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); + mouse_pipe->flags = FS_CHARDEVICE; + mouse_pipe->ioctl = ioctl_mouse; + vfs_mount("/dev/mouse", mouse_pipe); + + keyboard_pipe = make_pipe(128); + keyboard_pipe->flags = FS_CHARDEVICE; + vfs_mount("/dev/kbd", keyboard_pipe); + + /* Disable both ports. */ + ps2_command(PS2_DISABLE_PORT1); + ps2_command(PS2_DISABLE_PORT2); + + /* Clear the input buffer. */ + while ((inportb(PS2_STATUS) & 1)) inportb(PS2_DATA); + + /* Enable interrupt lines, enable translation. */ + status = ps2_command_response(PS2_READ_CONFIG); + status |= (PS2_PORT1_IRQ | PS2_PORT2_IRQ | PS2_PORT1_TLATE); + ps2_command_arg(PS2_WRITE_CONFIG, status); + + /* Re-enable ports */ + ps2_command(PS2_ENABLE_PORT1); + ps2_command(PS2_ENABLE_PORT2); + + /* Set scancode mode to 2... which then gives us 1 with translation... */ + kbd_write(KBD_SET_SCANCODE); + kbd_write(2); + + /* Now we'll configure the mouse... */ + mouse_write(MOUSE_SET_DEFAULTS); + mouse_write(MOUSE_DATA_ON); + + /* Try to enable scroll wheel (but not buttons) */ + if (!args_present("nomousescroll")) { + mouse_write(MOUSE_DEVICE_ID); + mouse_write(MOUSE_SAMPLE_RATE); + mouse_write(200); + mouse_write(MOUSE_SAMPLE_RATE); + mouse_write(100); + mouse_write(MOUSE_SAMPLE_RATE); + mouse_write(80); + mouse_write(MOUSE_DEVICE_ID); + result = inportb(PS2_STATUS); + if (result == 3) { + mouse_mode = MOUSE_SCROLLWHEEL; + } + } + + if (args_present("sharedps2")) { + irq_install_handler(KEYBOARD_IRQ, shared_handler, "ps2hid"); + irq_install_handler(MOUSE_IRQ, shared_handler, "ps2hid"); + } else { + irq_install_handler(KEYBOARD_IRQ, keyboard_handler, "ps2hid"); + irq_install_handler(MOUSE_IRQ, mouse_handler, "ps2hid"); + } +} + diff --git a/modules/serial.c b/kernel/arch/x86_64/serial.c similarity index 60% rename from modules/serial.c rename to kernel/arch/x86_64/serial.c index 2dbd70ed..1bf740db 100644 --- a/modules/serial.c +++ b/kernel/arch/x86_64/serial.c @@ -1,20 +1,26 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/arch/x86_64/serial.c + * @brief PC serial port driver. + * + * Attaches serial ports to TTY interfaces. Serial input processing + * happens in a kernel tasklet so that blocking is handled smoothly. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * Serial communication device - * + * Copyright (C) 2014-2021 K. Lange */ - -#include -#include +#include +#include +#include #include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include #define SERIAL_PORT_A 0x3F8 #define SERIAL_PORT_B 0x2F8 @@ -44,7 +50,7 @@ static int serial_rcvd(int device) { } static char serial_recv(int device) { - while (serial_rcvd(device) == 0) ; + while (serial_rcvd(device) == 0) switch_task(1); return inportb(device); } @@ -53,36 +59,49 @@ static int serial_transmit_empty(int device) { } static void serial_send(int device, char out) { - while (serial_transmit_empty(device) == 0); + while (serial_transmit_empty(device) == 0) switch_task(1); outportb(device, out); } -static int serial_handler_ac(struct regs *r) { - char serial; - int port = 0; - if (inportb(SERIAL_PORT_A+1) & 0x01) { - port = SERIAL_PORT_A; - } else { - port = SERIAL_PORT_C; +static list_t * sem_serial_ac = NULL; +static list_t * sem_serial_bd = NULL; +static process_t * serial_ac_handler = NULL; +static process_t * serial_bd_handler = NULL; + +static void process_serial(void * argp) { + int portBase = (argp == sem_serial_ac) ? SERIAL_PORT_A : SERIAL_PORT_B; + char ch; + pty_t * pty; + while (1) { + sleep_on((list_t*)argp); + int next = 0; + int port = 0; + if (inportb(portBase+1) & 0x01) { + port = portBase; + } else { + port = portBase - 0x100; + } + do { + ch = serial_recv(port); + pty = *pty_for_port(port); + tty_input_process(pty, ch); + next = serial_rcvd(port); + /* TODO: Can we handle more than one character here + * before yielding? Would that be helpful? */ + if (next) switch_task(1); + } while (next); } - serial = serial_recv(port); +} + +int serial_handler_ac(struct regs *r) { irq_ack(SERIAL_IRQ_AC); - tty_input_process(*pty_for_port(port), serial); + wakeup_queue(sem_serial_ac); return 1; } -static int serial_handler_bd(struct regs *r) { - char serial; - int port = 0; - debug_print(NOTICE, "Received something on secondary port"); - if (inportb(SERIAL_PORT_B+1) & 0x01) { - port = SERIAL_PORT_B; - } else { - port = SERIAL_PORT_D; - } - serial = serial_recv(port); +int serial_handler_bd(struct regs *r) { irq_ack(SERIAL_IRQ_BD); - tty_input_process(*pty_for_port(port), serial); + wakeup_queue(sem_serial_bd); return 1; } @@ -114,10 +133,10 @@ static void serial_write_out(pty_t * pty, uint8_t c) { #define TTY_D "ttyS3" static void serial_fill_name(pty_t * pty, char * name) { - if (pty == _serial_port_pty_a) sprintf(name, DEV_PATH TTY_A); - if (pty == _serial_port_pty_b) sprintf(name, DEV_PATH TTY_B); - if (pty == _serial_port_pty_c) sprintf(name, DEV_PATH TTY_C); - if (pty == _serial_port_pty_d) sprintf(name, DEV_PATH TTY_D); + if (pty == _serial_port_pty_a) snprintf(name, 100, DEV_PATH TTY_A); + if (pty == _serial_port_pty_b) snprintf(name, 100, DEV_PATH TTY_B); + if (pty == _serial_port_pty_c) snprintf(name, 100, DEV_PATH TTY_C); + if (pty == _serial_port_pty_d) snprintf(name, 100, DEV_PATH TTY_D); } static fs_node_t * serial_device_create(int port) { @@ -143,40 +162,15 @@ static fs_node_t * serial_device_create(int port) { return pty->slave; } -static int serial_mount_devices(void) { +void serial_initialize(void) { + sem_serial_ac = list_create("serial ac semaphore",NULL); + sem_serial_bd = list_create("serial bd semaphore",NULL); + + serial_ac_handler = spawn_worker_thread(process_serial, "[serial ac]", sem_serial_ac); + serial_bd_handler = spawn_worker_thread(process_serial, "[serial bd]", sem_serial_bd); fs_node_t * ttyS0 = serial_device_create(SERIAL_PORT_A); vfs_mount(DEV_PATH TTY_A, ttyS0); fs_node_t * ttyS1 = serial_device_create(SERIAL_PORT_B); vfs_mount(DEV_PATH TTY_B, ttyS1); fs_node_t * ttyS2 = serial_device_create(SERIAL_PORT_C); vfs_mount(DEV_PATH TTY_C, ttyS2); fs_node_t * ttyS3 = serial_device_create(SERIAL_PORT_D); vfs_mount(DEV_PATH TTY_D, ttyS3); - - char * c; - if ((c = args_value("logtoserial"))) { - debug_file = ttyS0; - if (!strcmp(c,"INFO") || !strcmp(c,"info")) { - debug_level = INFO; - } else if (!strcmp(c,"NOTICE") || !strcmp(c,"notice")) { - debug_level = NOTICE; - } else if (!strcmp(c,"WARNING") || !strcmp(c,"warning")) { - debug_level = WARNING; - } else if (!strcmp(c,"ERROR") || !strcmp(c,"error")) { - debug_level = ERROR; - } else if (!strcmp(c,"CRITICAL") || !strcmp(c,"critical")) { - debug_level = CRITICAL; - } else if (!strcmp(c,"INSANE") || !strcmp(c,"insane")) { - debug_level = INSANE; - } else { - debug_level = atoi(c); - } - debug_print(NOTICE, "Serial logging enabled at level %d.", debug_level); - } - - - return 0; } - -static int serial_finalize(void) { - return 0; -} - -MODULE_DEF(serial, serial_mount_devices, serial_finalize); diff --git a/kernel/arch/x86_64/smp.c b/kernel/arch/x86_64/smp.c new file mode 100644 index 00000000..d3cfd7a2 --- /dev/null +++ b/kernel/arch/x86_64/smp.c @@ -0,0 +1,299 @@ +/** + * @file kernel/arch/x86_64/smp.c + * @brief Multi-processor Support for x86-64. + * + * Locates and bootstraps APs using ACPI MADT tables. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +__attribute__((used)) +__attribute__((naked)) +static void __ap_bootstrap(void) { + asm volatile ( + ".code16\n" + ".org 0x0\n" + ".global _ap_bootstrap_start\n" + "_ap_bootstrap_start:\n" + + /* Enable PAE, paging */ + "mov $0xA0, %%eax\n" + "mov %%eax, %%cr4\n" + + /* Kernel base PML4 */ + ".global init_page_region\n" + "mov $init_page_region, %%edx\n" + "mov %%edx, %%cr3\n" + + /* Set LME */ + "mov $0xc0000080, %%ecx\n" + "rdmsr\n" + "or $0x100, %%eax\n" + "wrmsr\n" + + /* Enable long mode */ + "mov $0x80000011, %%ebx\n" + "mov %%ebx, %%cr0\n" + + /* Set up basic GDT */ + "addr32 lgdtl %%cs:_ap_bootstrap_gdtp-_ap_bootstrap_start\n" + + /* Jump... */ + "data32 jmp $0x08,$ap_premain\n" + + ".global _ap_bootstrap_gdtp\n" + ".align 16\n" + "_ap_bootstrap_gdtp:\n" + ".word 0\n" + ".quad 0\n" + + ".code64\n" + ".align 16\n" + "ap_premain:\n" + "mov $0x10, %%ax\n" + "mov %%ax, %%ds\n" + "mov %%ax, %%ss\n" + "mov $0x2b, %%ax\n" + "ltr %%ax\n" + ".extern _ap_stack_base\n" + "mov _ap_stack_base,%%rsp\n" + ".extern ap_main\n" + "callq ap_main\n" + + ".global _ap_bootstrap_end\n" + "_ap_bootstrap_end:\n" + : : : "memory" + ); +} + +extern char _ap_bootstrap_start[]; +extern char _ap_bootstrap_end[]; +extern char _ap_bootstrap_gdtp[]; +extern size_t arch_cpu_mhz(void); +extern void gdt_copy_to_trampoline(int ap, char * trampoline); +extern void arch_set_core_base(uintptr_t base); +extern void fpu_initialize(void); +extern void idt_ap_install(void); +extern void pat_initialize(void); +extern process_t * spawn_kidle(int); +extern union PML init_page_region[]; + +uintptr_t _ap_stack_base = 0; +static volatile int _ap_startup_flag = 0; +void load_processor_info(void); + +/* For timing delays on IPIs */ +static inline uint64_t read_tsc(void) { + uint32_t lo, hi; + asm volatile ( "rdtsc" : "=a"(lo), "=d"(hi) ); + return ((uint64_t)hi << 32) | (uint64_t)lo; +} + +static void short_delay(unsigned long amount) { + uint64_t clock = read_tsc(); + while (read_tsc() < clock + amount * arch_cpu_mhz()); +} + +static volatile int _ap_current = 0; +uintptr_t lapic_final = 0; + +#define cpuid(in,a,b,c,d) do { asm volatile ("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(in)); } while(0) + +/* C entrypoint for APs */ +void ap_main(void) { + arch_set_core_base((uintptr_t)&processor_local_data[_ap_current]); + + uint32_t ebx, _unused; + cpuid(0x1,_unused,ebx,_unused,_unused); + if (this_core->lapic_id != (int)(ebx >> 24)) { + printf("smp: lapic id does not match\n"); + } + + /* Load the IDT */ + idt_ap_install(); + fpu_initialize(); + pat_initialize(); + + /* Enable our spurious vector register */ + *((volatile uint32_t*)(lapic_final + 0x0F0)) = 0x127; + + /* Set our pml pointers */ + this_core->current_pml = &init_page_region[0]; + + /* Spawn our kidle, make it our current process. */ + this_core->kernel_idle_task = spawn_kidle(0); + this_core->current_process = this_core->kernel_idle_task; + + load_processor_info(); + + /* Inform BSP it can continue. */ + _ap_startup_flag = 1; + + switch_next(); +} + +void load_processor_info(void) { + unsigned long a, b, unused; + cpuid(0,unused,b,unused,unused); + + this_core->cpu_manufacturer = "Unknown"; + + if (b == 0x756e6547) { + cpuid(1, a, b, unused, unused); + this_core->cpu_manufacturer = "Intel"; + this_core->cpu_model = (a >> 4) & 0x0F; + this_core->cpu_family = (a >> 8) & 0x0F; + } else if (b == 0x68747541) { + cpuid(1, a, unused, unused, unused); + this_core->cpu_manufacturer = "AMD"; + this_core->cpu_model = (a >> 4) & 0x0F; + this_core->cpu_family = (a >> 8) & 0x0F; + } + + snprintf(processor_local_data[this_core->cpu_id].cpu_model_name, 20, "(unknown)"); + + /* See if we can get a long manufacturer strings */ + cpuid(0x80000000, a, unused, unused, unused); + if (a >= 0x80000004) { + uint32_t brand[12]; + cpuid(0x80000002, brand[0], brand[1], brand[2], brand[3]); + cpuid(0x80000003, brand[4], brand[5], brand[6], brand[7]); + cpuid(0x80000004, brand[8], brand[9], brand[10], brand[11]); + memcpy(processor_local_data[this_core->cpu_id].cpu_model_name, brand, 48); + } +} + +void lapic_write(size_t addr, uint32_t value) { + *((volatile uint32_t*)(lapic_final + addr)) = value; + asm volatile ("":::"memory"); +} + +uint32_t lapic_read(size_t addr) { + return *((volatile uint32_t*)(lapic_final + addr)); +} + +void lapic_send_ipi(int i, uint32_t val) { + lapic_write(0x310, i << 24); + lapic_write(0x300, val); + do { asm volatile ("pause" : : : "memory"); } while (lapic_read(0x300) & (1 << 12)); +} + +void smp_initialize(void) { + /* Locate ACPI tables */ + uintptr_t scan; + int good = 0; + for (scan = 0x000E0000; scan < 0x00100000; scan += 16) { + char * _scan = mmu_map_from_physical(scan); + if (_scan[0] == 'R' && + _scan[1] == 'S' && + _scan[2] == 'D' && + _scan[3] == ' ' && + _scan[4] == 'P' && + _scan[5] == 'T' && + _scan[6] == 'R') { + good = 1; + break; + } + } + + load_processor_info(); + + if (!good) { + printf("smp: No RSD PTR found\n"); + return; + } + + struct rsdp_descriptor * rsdp = (struct rsdp_descriptor *)scan; + uint8_t check = 0; + uint8_t * tmp; + for (tmp = (uint8_t *)scan; (uintptr_t)tmp < scan + sizeof(struct rsdp_descriptor); tmp++) { + check += *tmp; + } + if (check != 0) { + printf("smp: Bad checksum on RSDP\n"); + return; /* bad checksum */ + } + + /* Load information for the current CPU. */ + + if (args_present("nosmp")) return; + + struct rsdt * rsdt = mmu_map_from_physical(rsdp->rsdt_address); + + int cores = 0; + uintptr_t lapic_base = 0x0; + for (unsigned int i = 0; i < (rsdt->header.length - 36) / 4; ++i) { + uint8_t * table = mmu_map_from_physical(rsdt->pointers[i]); + if (table[0] == 'A' && table[1] == 'P' && table[2] == 'I' && table[3] == 'C') { + /* APIC table! Let's find some CPUs! */ + struct madt * madt = (void*)table; + lapic_base = madt->lapic_addr; + for (uint8_t * entry = madt->entries; entry < table + madt->header.length; entry += entry[1]) { + switch (entry[0]) { + case 0: + if (entry[4] & 0x01) { + processor_local_data[cores].cpu_id = cores; + processor_local_data[cores].lapic_id = entry[3]; + cores++; + if (cores == 33) { + printf("smp: too many cores\n"); + arch_fatal(); + } + } + break; + /* TODO: Other entries */ + } + } + } + } + + processor_count = cores; + + if (!lapic_base) return; + + /* Allocate a virtual address with which we can poke the lapic */ + lapic_final = (uintptr_t)mmu_map_mmio_region(lapic_base, 0x1000); + + if (cores <= 1) return; + + /* Map the bootstrap code */ + memcpy(mmu_map_from_physical(0x1000), &_ap_bootstrap_start, (uintptr_t)&_ap_bootstrap_end - (uintptr_t)&_ap_bootstrap_start); + + for (int i = 1; i < cores; ++i) { + _ap_startup_flag = 0; + + /* Set gdt pointer value */ + gdt_copy_to_trampoline(i, (char*)mmu_map_from_physical(0x1000) + ((uintptr_t)&_ap_bootstrap_gdtp - (uintptr_t)&_ap_bootstrap_start)); + + /* Make an initial stack for this AP */ + _ap_stack_base = (uintptr_t)valloc(KERNEL_STACK_SIZE)+ KERNEL_STACK_SIZE; + + _ap_current = i; + + /* Send INIT */ + lapic_send_ipi(processor_local_data[i].lapic_id, 0x4500); + short_delay(5000UL); + + /* Send SIPI */ + lapic_send_ipi(processor_local_data[i].lapic_id, 0x4601); + + /* Wait for AP to signal it is ready before starting next AP */ + do { asm volatile ("pause" : : : "memory"); } while (!_ap_startup_flag); + } +} + +void arch_wakeup_others(void) { + /* Never wake up BSP, don't hit ourselves, easy. */ + for (int i = 1; i < processor_count; ++i) { + if (i == this_core->cpu_id) continue; + if (processor_local_data[i].current_process == processor_local_data[i].kernel_idle_task) { + lapic_send_ipi(processor_local_data[i].lapic_id, 0x407E); + } + } +} diff --git a/kernel/arch/x86_64/user.c b/kernel/arch/x86_64/user.c new file mode 100644 index 00000000..7a7ecb78 --- /dev/null +++ b/kernel/arch/x86_64/user.c @@ -0,0 +1,137 @@ +/** + * @file kernel/arch/x86_64/user.c + * @brief Various assembly snippets for jumping to usermode and back. + */ +#include +#include +#include +#include +#include +#include + +void arch_enter_user(uintptr_t entrypoint, int argc, char * argv[], char * envp[], uintptr_t stack) { + struct regs ret; + ret.cs = 0x18 | 0x03; + ret.ss = 0x20 | 0x03; + ret.rip = entrypoint; + ret.rflags = (1 << 21) | (1 << 9); + ret.rsp = stack; + + asm volatile ( + "pushq %0\n" + "pushq %1\n" + "pushq %2\n" + "pushq %3\n" + "pushq %4\n" + "swapgs\n" + "iretq" + : : "m"(ret.ss), "m"(ret.rsp), "m"(ret.rflags), "m"(ret.cs), "m"(ret.rip), + "D"(argc), "S"(argv), "d"(envp)); +} + +void arch_enter_signal_handler(uintptr_t entrypoint, int signum) { + struct regs ret; + ret.cs = 0x18 | 0x03; + ret.ss = 0x20 | 0x03; + ret.rip = entrypoint; + ret.rflags = (1 << 21) | (1 << 9); + ret.rsp = (this_core->current_process->syscall_registers->rsp - 128 - 8) & 0xFFFFFFFFFFFFFFF0; /* ensure considerable alignment */ + *(uintptr_t*)ret.rsp = 0x00000008DEADBEEF; /* arbitrarily chosen stack return sentinel IP */ + + asm volatile( + "pushq %0\n" + "pushq %1\n" + "pushq %2\n" + "pushq %3\n" + "pushq %4\n" + "swapgs\n" + "iretq" + : : "m"(ret.ss), "m"(ret.rsp), "m"(ret.rflags), "m"(ret.cs), "m"(ret.rip), + "D"(signum)); + __builtin_unreachable(); +} + +__attribute__((naked)) +void arch_resume_user(void) { + asm volatile ( + "pop %r15\n" + "pop %r14\n" + "pop %r13\n" + "pop %r12\n" + "pop %r11\n" + "pop %r10\n" + "pop %r9\n" + "pop %r8\n" + "pop %rbp\n" + "pop %rdi\n" + "pop %rsi\n" + "pop %rdx\n" + "pop %rcx\n" + "pop %rbx\n" + "pop %rax\n" + "add $16, %rsp\n" + "swapgs\n" + "iretq\n" + ); + __builtin_unreachable(); +} + +static uint8_t saves[512] __attribute__((aligned(16))); +void arch_restore_floating(process_t * proc) { + memcpy(&saves,(uint8_t *)&proc->thread.fp_regs,512); + asm volatile ("fxrstor (%0)" :: "r"(saves)); +} + +void arch_save_floating(process_t * proc) { + asm volatile ("fxsave (%0)" :: "r"(saves)); + memcpy((uint8_t *)&proc->thread.fp_regs,&saves,512); +} + +void arch_pause(void) { + asm volatile ( + "sti\n" + "hlt\n" + "cli\n" + ); +} + +extern void lapic_send_ipi(int i, uint32_t val); +void arch_fatal(void) { + for (int i = 0; i < processor_count; ++i) { + if (i == this_core->cpu_id) continue; + lapic_send_ipi(processor_local_data[i].lapic_id, 0x447D); + } + while (1) { + asm volatile ( + "cli\n" + "hlt\n" + ); + } +} + +long arch_reboot(void) { + /* load a null page as an IDT */ + uintptr_t frame = mmu_allocate_a_frame(); + uintptr_t * idt = mmu_map_from_physical(frame << 12); + memset(idt, 0, 0x1000); + asm volatile ( + "lidt (%0)" + : : "r"(idt) + ); + uint8_t out = 0x02; + while ((out & 0x02) != 0) { + out = inportb(0x64); + } + outportb(0x64, 0xFE); /* Reset */ + return 0; +} + +void arch_syscall_return(struct regs * r, long retval) { r->rax = retval; } +long arch_syscall_number(struct regs * r) { return (unsigned long)r->rax; } +long arch_syscall_arg0(struct regs * r) { return r->rbx; } +long arch_syscall_arg1(struct regs * r) { return r->rcx; } +long arch_syscall_arg2(struct regs * r) { return r->rdx; } +long arch_syscall_arg3(struct regs * r) { return r->rsi; } +long arch_syscall_arg4(struct regs * r) { return r->rdi; } +long arch_stack_pointer(struct regs * r) { return r->rsp; } +long arch_user_ip(struct regs * r) { return r->rip; } diff --git a/modules/vbox.c b/kernel/arch/x86_64/vbox.c similarity index 85% rename from modules/vbox.c rename to kernel/arch/x86_64/vbox.c index 1e0e343c..2ddf09c8 100644 --- a/modules/vbox.c +++ b/kernel/arch/x86_64/vbox.c @@ -1,23 +1,35 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/arch/x86_64/vbox.c + * @brief VirtualBox Guest Additions driver + * + * Implements the following features: + * - Absolute mouse cursor positioning + * - "Hardware" cursor sprites + * - Automatic display modesetting + * - "Seamless" mode rectangle device + * - Log device + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016-2018 K. Lange - * - * VirtualBox Guest Additions driver + * Copyright (C) 2016-2021 K. Lange */ -#include -#include -#include #include -#include +#include +#include +#include #include -#include #include #include #include #include +#include +#include +#include +#include + #define VBOX_VENDOR_ID 0x80EE #define VBOX_DEVICE_ID 0xCAFE @@ -107,13 +119,17 @@ struct vbox_pointershape { #define EARLY_LOG_DEVICE 0x504 -static uint32_t _vbox_write(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static size_t _vbox_write(size_t size, uint8_t * buffer) { for (unsigned int i = 0; i < size; ++i) { outportb(EARLY_LOG_DEVICE, buffer[i]); } return size; } -static fs_node_t vb = { .write = &_vbox_write }; + +void vbox_set_log(void) { + printf_output = &_vbox_write; + printf("Hello world, using VBox machine log for kernel output\n"); +} static uint32_t vbox_device = 0; static uint32_t vbox_port = 0x0; @@ -183,10 +199,6 @@ static int vbox_irq_handler(struct regs *r) { return 1; } -void vbox_set_log(void) { - debug_file = &vb; -} - #define VBOX_MOUSE_ON (1 << 0) | (1 << 4) #define VBOX_MOUSE_OFF (0) @@ -222,8 +234,7 @@ static int ioctl_mouse(fs_node_t * node, int request, void * argp) { return -1; } -uint32_t write_pointer(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { - +uint64_t write_pointer(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { if (!mouse_state) { return -1; } @@ -234,7 +245,7 @@ uint32_t write_pointer(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t return size; } -uint32_t write_rectpipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t write_rectpipe(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { (void)node; (void)offset; @@ -246,23 +257,10 @@ uint32_t write_rectpipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t if (count > 254) count = 254; /* enforce maximum */ -#if 0 - fprintf(&vb, "Writing %d rectangles\n", count); -#endif - buffer += sizeof(uint32_t); for (unsigned int i = 0; i < count; ++i) { memcpy(&vbox_visibleregion->rect[i], buffer, sizeof(struct vbox_rtrect)); -#if 0 - fprintf(&vb, "Rectangle %d is [%d,%d,%d,%d]\n", - i, - vbox_visibleregion->rect[i].xLeft, - vbox_visibleregion->rect[i].yTop, - vbox_visibleregion->rect[i].xRight, - vbox_visibleregion->rect[i].yBottom); -#endif - buffer += sizeof(struct vbox_rtrect); } @@ -272,16 +270,19 @@ uint32_t write_rectpipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t return size; } -static int vbox_check(void) { +static void * kvmalloc_p(size_t size, uint32_t * outphys) { + uintptr_t index = mmu_allocate_n_frames(size / 0x1000) << 12; + *outphys = index; + return mmu_map_from_physical(index); +} + +void vbox_initialize(void) { pci_scan(vbox_scan_pci, -1, &vbox_device); if (vbox_device) { - fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n"); - - if (args_present("vboxdebug")) { + if (!args_present("novboxdebug")) { vbox_set_log(); } - fprintf(&vb, "HELLO WORLD\n"); uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4); if (t > 0) { @@ -289,9 +290,9 @@ static int vbox_check(void) { } uint16_t c = pci_read_field(vbox_device, PCI_COMMAND, 2); - fprintf(&vb, "Command register: 0x%4x\n", c); + //fprintf(&vb, "Command register: 0x%4x\n", c); if (!!(c & (1 << 10))) { - fprintf(&vb, "Interrupts are disabled\n"); + //fprintf(&vb, "Interrupts are disabled\n"); } @@ -302,8 +303,7 @@ static int vbox_check(void) { vfs_mount("/dev/absmouse", mouse_pipe); vbox_irq = pci_get_interrupt(vbox_device); - debug_print(WARNING, "(vbox) device IRQ is set to %d", vbox_irq); - fprintf(&vb, "irq line is %d\n", vbox_irq); + //fprintf(&vb, "irq line is %d\n", vbox_irq); irq_install_handler(vbox_irq, vbox_irq_handler, "vbox"); uint32_t vbox_phys = 0; @@ -315,7 +315,7 @@ static int vbox_check(void) { packet->header.reserved1 = 0; packet->header.reserved2 = 0; packet->version = VMMDEV_VERSION; - packet->ostype = 0; + packet->ostype = 0x00100; /* Unknown, x86-64 */ outportl(vbox_port, vbox_phys); @@ -367,7 +367,7 @@ static int vbox_check(void) { vbox_pointershape = (void*)kvmalloc_p(0x4000, &vbox_phys_pointershape); if (vbox_pointershape) { - fprintf(&vb, "Got a valid set of pages to load up a cursor.\n"); + //fprintf(&vb, "Got a valid set of pages to load up a cursor.\n"); vbox_pointershape->header.version = VBOX_REQUEST_HEADER_VERSION; vbox_pointershape->header.requestType = VMM_SetPointerShape; vbox_pointershape->header.rc = 0; @@ -389,7 +389,7 @@ static int vbox_check(void) { mask_bytes++; } int base = mask_bytes; - fprintf(&vb, "mask_bytes = %d\n", mask_bytes); + //fprintf(&vb, "mask_bytes = %d\n", mask_bytes); vbox_pointershape->header.size = sizeof(struct vbox_pointershape) + (48*48*4)+mask_bytes; /* update later */ @@ -402,10 +402,10 @@ static int vbox_check(void) { outportl(vbox_port, vbox_phys_pointershape); if (vbox_pointershape->header.rc < 0) { - fprintf(&vb, "Bad response code: -%d\n", -vbox_pointershape->header.rc); + //fprintf(&vb, "Bad response code: -%d\n", -vbox_pointershape->header.rc); } else { /* Success, let's install the device file */ - fprintf(&vb, "Successfully initialized cursor, going to allow compositor to set it.\n"); + //fprintf(&vb, "Successfully initialized cursor, going to allow compositor to set it.\n"); pointer_pipe = malloc(sizeof(fs_node_t)); memset(pointer_pipe, 0, sizeof(fs_node_t)); pointer_pipe->mask = 0666; @@ -444,25 +444,15 @@ static int vbox_check(void) { /* device memory region mapping? */ { uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4); - fprintf(&vb, "mapping vmm_dev = 0x%x\n", t); + //fprintf(&vb, "mapping vmm_dev = 0x%x\n", t); if (t > 0) { - vbox_vmmdev = (void *)(t & 0xFFFFFFF0); - } - uintptr_t fb_offset = (uintptr_t)vbox_vmmdev; - for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + vbox_vmmdev = mmu_map_from_physical(t & 0xFFFFFFF0); + printf("Setting vbox mem device at %p\n", (void*)vbox_vmmdev); } } vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */ } - return 0; } -static int fini(void) { - return 0; -} - -MODULE_DEF(vboxguest, vbox_check, fini); -MODULE_DEPENDS(lfbvideo); diff --git a/modules/vmware.c b/kernel/arch/x86_64/vmware.c similarity index 91% rename from modules/vmware.c rename to kernel/arch/x86_64/vmware.c index 65cb373c..4b4c7f67 100644 --- a/modules/vmware.c +++ b/kernel/arch/x86_64/vmware.c @@ -1,12 +1,11 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2017-2018 K. Lange - * - * VMWare backdoor driver. +/** + * @file kernel/arch/x86_64/vmware.c + * @brief VMware/QEMU mouse and VMWare backdoor driver. * * Supports absolute mouse cursor and resolution setting. * + * FIXME The vmware display size adjustment is currently disabled. + * * Mouse: * Toggle off / on with ioctl 1 and 2 respectively to /dev/vmmouse. * Supports mouse buttons, unlike the one in VirtualBox. @@ -15,18 +14,27 @@ * Resolution setting: * Enabled when the "vmware" LFB driver is active. Automatically * resizes the display when the window size changes. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2017-2021 K. Lange */ -#include -#include +#include +#include +#include +#include +#include #include #include -#include -#include #include #include +#include #include +#include #include +#include #define VMWARE_MAGIC 0x564D5868 /* hXMV */ #define VMWARE_PORT 0x5658 @@ -51,7 +59,7 @@ /* -Wpedantic complains about unnamed unions */ #pragma GCC diagnostic ignored "-Wpedantic" -extern void (*ps2_mouse_alternate)(void); /* modules/mouse.c */ +extern void (*ps2_mouse_alternate)(uint8_t); /* modules/mouse.c */ static fs_node_t * mouse_pipe; @@ -72,8 +80,8 @@ typedef struct { uint32_t dx; uint16_t port; }; - uint32_t si; - uint32_t di; + uintptr_t si; + uintptr_t di; } vmware_cmd; /** Low bandwidth backdoor */ @@ -142,9 +150,9 @@ static void mouse_absolute(void) { volatile int8_t vmware_mouse_byte = 0; -static void vmware_mouse(void) { +static void vmware_mouse(uint8_t byte) { /* unused, but we need to read the fake mouse event bytes from the PS/2 device. */ - vmware_mouse_byte = inportb(0x60); + vmware_mouse_byte = byte; /* Read status byte. */ vmware_cmd cmd; @@ -175,12 +183,9 @@ static void vmware_mouse(void) { * I guess the flags tell you if this was relative or absolute, so if we * actually used the relative mode, we'd want to check that, but... */ - int flags = (cmd.ax & 0xFFFF0000) >> 16; + //int flags = (cmd.ax & 0xFFFF0000) >> 16; int buttons = (cmd.ax & 0x0000FFFF); - debug_print(INFO, "flags=%4x buttons=%4x", flags, buttons); - debug_print(INFO, "x=%x y=%x z=%x", cmd.bx, cmd.cx, cmd.dx); - unsigned int x = 0; unsigned int y = 0; @@ -282,7 +287,7 @@ static int open_tclo_channel(void) { return tclo_channel; } -static int msg_send(int channel, char * msg, size_t size) { +static int msg_send(int channel, const char * msg, size_t size) { { vmware_cmd cmd = {0}; cmd.cx = CMD_MESSAGE | 0x00010000; /* CMD_MESSAGE size */ @@ -302,7 +307,7 @@ static int msg_send(int channel, char * msg, size_t size) { cmd.bx = 0x0010000; cmd.cx = size; cmd.dx = channel << 16; - cmd.si = (uint32_t)msg; + cmd.si = (uintptr_t)msg; vmware_send_hb(&cmd); if (!(cmd.bx & 0x0010000)) { @@ -334,7 +339,7 @@ static int msg_recv(int channel, char * buf, size_t bufsize) { cmd.bx = 0x00010000; cmd.cx = size; cmd.dx = channel << 16; - cmd.di = (uint32_t)buf; + cmd.di = (uintptr_t)buf; vmware_get_hb(&cmd); if (!(cmd.bx & 0x00010000)) { @@ -354,7 +359,7 @@ static int msg_recv(int channel, char * buf, size_t bufsize) { return size; } -static int rpci_string(char * request) { +static int rpci_string(const char * request) { /* Open channel */ int channel = open_rpci_channel(); if (channel < 0) return channel; @@ -400,8 +405,8 @@ static int attempt_scale(void) { resend = 0; } else { unsigned long s, ss; - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); + relative_time(0, 10000, &s, &ss); + sleep_until((process_t *)this_core->current_process, s, ss); switch_task(0); } if ((i = msg_send(c, buf, 0)) < 0) { return 1; } @@ -455,7 +460,7 @@ static void vmware_resize(void * data, char * name) { attempt_scale(); unsigned long s, ss; relative_time(1, 0, &s, &ss); - sleep_until((process_t *)current_process, s, ss); + sleep_until((process_t *)this_core->current_process, s, ss); switch_task(0); } } @@ -479,7 +484,7 @@ static int ioctl_mouse(fs_node_t * node, int request, void * argp) { } } -static int init(void) { +void vmware_initialize(void) { if (detect_device()) { mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); @@ -499,19 +504,12 @@ static int init(void) { mouse_absolute(); + #if 0 if (lfb_driver_name && !strcmp(lfb_driver_name, "vmware") && !args_present("novmwareresset")) { create_kernel_tasklet(vmware_resize, "[vmware]", NULL); } + #endif } - - return 0; } -static int fini(void) { - return 0; -} - -MODULE_DEF(vmmware, init, fini); -MODULE_DEPENDS(ps2mouse); /* For ps2_mouse_alternate */ -MODULE_DEPENDS(lfbvideo); /* For lfb resolution */ diff --git a/modules/ac97.c b/kernel/audio/ac97.c similarity index 80% rename from modules/ac97.c rename to kernel/audio/ac97.c index 042f7418..3997dd3e 100644 --- a/modules/ac97.c +++ b/kernel/audio/ac97.c @@ -1,21 +1,36 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/audio/ac97.c + * @brief Driver for the Intel AC'97. + * + * Simple PCM interface for the AC'97 codec when used with the + * ICH hardware interface. There are other hardware interfaces + * that use this codec and this driver could probably be ported + * to them. + * + * Note that the audio subsystem is intended to be non-blocking + * so that buffer filling can be done directly in interrupt handlers. + * + * @see http://www.intel.com/design/chipsets/manuals/29802801.pdf + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2015 Michael Gerow - * Copyright (C) 2015-2018 K. Lange - * - * Driver for the Intel AC'97. - * - * See . + * Copyright (C) 2015-2021 K. Lange */ -#include -#include -#include -#include +#include +#include #include #include -#include +#include +#include +#include +#include + +#include +#include +#include /* Utility macros */ #define N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -133,29 +148,22 @@ static void find_ac97(uint32_t device, uint16_t vendorid, uint16_t deviceid, voi } #define DIVISION 0x1000 -static int irq_handler(struct regs * regs) { +static int ac97_irq_handler(struct regs * regs) { uint16_t sr = inports(_device.nabmbar + AC97_PO_SR); - if (!sr) return 0; - if (sr & AC97_X_SR_BCIS) { - size_t f = (_device.lvi + 2) % AC97_BDL_LEN; - for (size_t i = 0; i < AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0]); i += DIVISION) { - snd_request_buf(&_snd, DIVISION, (uint8_t *)_device.bufs[f] + i); - //switch_task(1); - } - _device.lvi = (_device.lvi + 1) % AC97_BDL_LEN; - outportb(_device.nabmbar + AC97_PO_LVI, _device.lvi); + uint16_t current_buffer = inportb(_device.nabmbar + AC97_PO_CIV); + uint16_t last_valid = ((current_buffer+2) & (AC97_BDL_LEN-1)); + snd_request_buf(&_snd, 0x1000, (uint8_t *)_device.bufs[last_valid]); + outportb(_device.nabmbar + AC97_PO_LVI, last_valid); + snd_request_buf(&_snd, 0x1000, (uint8_t *)_device.bufs[last_valid]+0x1000); + outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_BCIS); } else if (sr & AC97_X_SR_LVBCI) { - debug_print(NOTICE, "ac97 irq is lvbci"); + outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_LVBCI); } else if (sr & AC97_X_SR_FIFOE) { - debug_print(NOTICE, "ac97 irq is fifoe"); + outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_FIFOE); } else { - /* don't handle it */ return 0; } - debug_print(NOTICE, "ac97 status register: 0x%4x", sr); - outports(_device.nabmbar + AC97_PO_SR, sr & 0x1E); - irq_ack(_device.irq); return 1; } @@ -233,16 +241,17 @@ static int ac97_mixer_write(uint32_t knob_id, uint32_t val) { return 0; } -static int init(void) { - debug_print(NOTICE, "Initializing AC97"); +void ac97_install(void) { + //debug_print(NOTICE, "Initializing AC97"); pci_scan(&find_ac97, -1, &_device); if (!_device.pci_device) { - return 1; + return; } _device.nabmbar = pci_read_field(_device.pci_device, AC97_NABMBAR, 2) & ((uint32_t) -1) << 1; _device.nambar = pci_read_field(_device.pci_device, PCI_BAR0, 4) & ((uint32_t) -1) << 1; _device.irq = pci_get_interrupt(_device.pci_device); - irq_install_handler(_device.irq, irq_handler, "ac97"); + //printf("device wants irq %zd\n", _device.irq); + irq_install_handler(_device.irq, ac97_irq_handler, "ac97"); /* Enable all matter of interrupts */ outportb(_device.nabmbar + AC97_PO_CR, AC97_X_CR_FEIE | AC97_X_CR_IOCE); @@ -252,11 +261,13 @@ static int init(void) { outports(_device.nambar + AC97_PCM_OUT_VOLUME, 0x0000); /* Allocate our BDL and our buffers */ - _device.bdl = (void *)kmalloc_p(AC97_BDL_LEN * sizeof(*_device.bdl), &_device.bdl_p); + _device.bdl_p = mmu_allocate_a_frame() << 12; + _device.bdl = mmu_map_from_physical(_device.bdl_p); memset(_device.bdl, 0, AC97_BDL_LEN * sizeof(*_device.bdl)); + for (int i = 0; i < AC97_BDL_LEN; i++) { - _device.bufs[i] = (uint16_t *)kmalloc_p(AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0]), - &_device.bdl[i].pointer); + _device.bdl[i].pointer = mmu_allocate_n_frames(2) << 12; + _device.bufs[i] = mmu_map_from_physical(_device.bdl[i].pointer); memset(_device.bufs[i], 0, AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0])); AC97_CL_SET_LENGTH(_device.bdl[i].cl, AC97_BDL_BUFFER_LEN); /* Set all buffers to interrupt */ @@ -273,26 +284,26 @@ static int init(void) { outports(_device.nambar + AC97_MASTER_VOLUME, 0x2020); uint16_t t = inports(_device.nambar + AC97_MASTER_VOLUME) & 0x1f; if (t == 0x1f) { - debug_print(WARNING, "This device only supports 5 bits of audio volume."); + //debug_print(WARNING, "This device only supports 5 bits of audio volume."); _device.bits = 5; _device.mask = 0x1f; - outports(_device.nambar + AC97_MASTER_VOLUME, 0x0f0f); } else { _device.bits = 6; _device.mask = 0x3f; - outports(_device.nambar + AC97_MASTER_VOLUME, 0x1f1f); } + outports(_device.nambar + AC97_MASTER_VOLUME, 0x0000); snd_register(&_snd); /* Start things playing */ outportb(_device.nabmbar + AC97_PO_CR, inportb(_device.nabmbar + AC97_PO_CR) | AC97_X_CR_RPBM); - debug_print(NOTICE, "AC97 initialized successfully"); + //debug_print(NOTICE, "AC97 initialized successfully"); - return 0; + return; } +#if 0 static int fini(void) { snd_unregister(&_snd); @@ -302,6 +313,5 @@ static int fini(void) { } return 0; } +#endif -MODULE_DEF(ac97, init, fini); -MODULE_DEPENDS(snd); diff --git a/modules/snd.c b/kernel/audio/snd.c similarity index 82% rename from modules/snd.c rename to kernel/audio/snd.c index 00cca3b5..bb3ee259 100644 --- a/modules/snd.c +++ b/kernel/audio/snd.c @@ -1,30 +1,38 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Mike Gerow +/** + * @file kernel/audio/snd.c + * @brief Gerow's Audio Subsystem for ToaruOS * - * Sound subsystem. + * Simple generic mixer interface. Allows userspace to pipe audio data + * to the kernel audio drivers and control volume knobs. * * Currently has the ability to mix several sound sources together. Could use * a /dev/mixer device to allow changing of audio settings. Also could use * the ability to change frequency and format for audio samples. Also doesn't * really support multiple devices despite the interface suggesting it might... + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015 Mike Gerow */ -#include +#include +#include #include -#include -#include +#include +#include +#include -#include +#include #include /* Utility macros */ #define N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define SND_BUF_SIZE 0x4000 -static uint32_t snd_dsp_write(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer); +static uint64_t snd_dsp_write(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer); static int snd_dsp_ioctl(fs_node_t * node, int request, void * argp); static void snd_dsp_open(fs_node_t * node, unsigned int flags); static void snd_dsp_close(fs_node_t * node); @@ -68,17 +76,14 @@ struct dsp_node { int snd_register(snd_device_t * device) { int rv = 0; - debug_print(WARNING, "[snd] _devices lock: %d", _devices_lock); spin_lock(_devices_lock); device->id = _next_device_id; _next_device_id++; if (list_find(&_devices, device)) { - debug_print(WARNING, "[snd] attempt to register duplicate %s", device->name); rv = -1; goto snd_register_cleanup; } list_insert(&_devices, device); - debug_print(NOTICE, "[snd] %s registered", device->name); snd_register_cleanup: spin_unlock(_devices_lock); @@ -90,19 +95,17 @@ int snd_unregister(snd_device_t * device) { node_t * node = list_find(&_devices, device); if (!node) { - debug_print(WARNING, "[snd] attempted to unregister %s, " - "but it was never registered", device->name); + printf("attempted to unregister unknown audio sink: %s\n", device->name); goto snd_unregister_cleanup; } list_delete(&_devices, node); - debug_print(NOTICE, "[snd] %s unregistered", device->name); snd_unregister_cleanup: spin_unlock(_devices_lock); return rv; } -static uint32_t snd_dsp_write(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t snd_dsp_write(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { if (!_devices.length) return -1; /* No sink available. */ struct dsp_node * dsp = node->device; @@ -280,45 +283,8 @@ static snd_device_t * snd_main_device() { return NULL; } -#if 0 -#include -DEFINE_SHELL_FUNCTION(snd_full, "[debug] turn snd master to full") { - snd_main_device()->mixer_write(SND_KNOB_MASTER, UINT32_MAX); - - return 0; -} - -DEFINE_SHELL_FUNCTION(snd_half, "[debug] turn snd master to half") { - snd_main_device()->mixer_write(SND_KNOB_MASTER, UINT32_MAX / 2); - - return 0; -} - -DEFINE_SHELL_FUNCTION(snd_off, "[debug] turn snd master to lowest volume") { - snd_main_device()->mixer_write(SND_KNOB_MASTER, 0); - - return 0; -} -#endif - -static int init(void) { +void snd_install(void) { vfs_mount("/dev/dsp", &_dsp_fnode); vfs_mount("/dev/mixer", &_mixer_fnode); - -#if 0 - BIND_SHELL_FUNCTION(snd_full); - BIND_SHELL_FUNCTION(snd_half); - BIND_SHELL_FUNCTION(snd_off); -#endif - return 0; } -static int fini(void) { - /* umount? */ - return 0; -} - -MODULE_DEF(snd, init, fini); -#if 0 -MODULE_DEPENDS(debugshell); -#endif diff --git a/kernel/binfmt.c b/kernel/binfmt.c new file mode 100644 index 00000000..a255ffb5 --- /dev/null +++ b/kernel/binfmt.c @@ -0,0 +1,149 @@ +/** + * @file kernel/binfmt.c + * @brief Top-level executable parsing. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +extern int elf_exec(const char * path, fs_node_t * file, int argc, char *const argv[], char *const env[], int interp); +int exec(const char * path, int argc, char *const argv[], char *const env[], int interp_depth); + +/** + * @brief hash-exclamation parser + * + * Tries to safely read the first line of a script file to find an appropriate loader. + */ +int exec_shebang(const char * path, fs_node_t * file, int argc, char *const argv[], char *const env[], int interp) { + if (interp > 4) { + /* If an interpreter calls an interpreter too many times, bail. */ + return -ELOOP; + } + + /* Read MAX_LINE... */ + char tmp[100]; + read_fs(file, 0, 100, (unsigned char *)tmp); close_fs(file); + char * cmd = (char *)&tmp[2]; + if (*cmd == ' ') cmd++; /* Handle a leading space */ + char * space_or_linefeed = strpbrk(cmd, " \n"); + char * arg = NULL; + + /* We read too much stuff before finding EOL or another signal + * that the interpreter was found, so bail. */ + if (!space_or_linefeed) { + return -ENOEXEC; + } + + /* If we found a space, accept one argument before the path... */ + if (*space_or_linefeed == ' ') { + *space_or_linefeed = '\0'; + space_or_linefeed++; + arg = space_or_linefeed; + /* ... and look for another EOL. */ + space_or_linefeed = strpbrk(space_or_linefeed, "\n"); + if (!space_or_linefeed) { + /* If we didn't find one, bail. */ + return -ENOEXEC; + } + } + + /* Make sure interpreter or argument is nil-terminated */ + *space_or_linefeed = '\0'; + + char script[strlen(path)+1]; + memcpy(script, path, strlen(path)+1); + + unsigned int nargc = argc + (arg ? 2 : 1); + char * args[nargc + 2]; + args[0] = cmd; + args[1] = arg ? arg : script; + args[2] = arg ? script : NULL; + args[3] = NULL; + + int j = arg ? 3 : 2; + for (int i = 1; i < argc; ++i, ++j) { + args[j] = argv[i]; + } + args[j] = NULL; + + /* Try to execut the interpreter with the new arguments */ + return exec(cmd, nargc, args, env, interp+1); +} + +/* Consider exposing this and making it a list so it can be extended ... */ +typedef int (*exec_func)(const char * path, fs_node_t * file, int argc, char *const argv[], char *const env[], int interp); +typedef struct { + exec_func func; + unsigned char bytes[4]; + unsigned int match; + const char * name; +} exec_def_t; + +exec_def_t fmts[] = { + {elf_exec, {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3}, 4, "ELF"}, + {exec_shebang, {'#', '!', 0, 0}, 2, "#!"}, +}; + +static int matches(unsigned char * a, unsigned char * b, unsigned int len) { + for (unsigned int i = 0; i < len; ++i) { + if (a[i] != b[i]) return 0; + } + return 1; +} + +/** + * @brief Replace the current process with a new one. + * + * @param path Filename of the new executable. + * @param argc Number of arguments passed in @p argv + * @param argv Arguments to supply to the new executable's entry point. + * @param env Environment strings to pass to the new executable. + * @param interp_depth Should be 0 for all external callers. + * @returns Either never or -ENOEXEC on failure. + */ +int exec(const char * path, int argc, char *const argv[], char *const env[], int interp_depth) { + fs_node_t * file = kopen(path, 0); + if (!file) return -ENOENT; + if (!has_permission(file, 01)) return -EACCES; + + unsigned char head[4]; + read_fs(file, 0, 4, head); + + this_core->current_process->name = strdup(path); + gettimeofday((struct timeval*)&this_core->current_process->start, NULL); + + for (unsigned int i = 0; i < sizeof(fmts) / sizeof(exec_def_t); ++i) { + if (matches(fmts[i].bytes, head, fmts[i].match)) { + return fmts[i].func(path, file, argc, argv, env, interp_depth); + } + } + return -ENOEXEC; +} + +/** + * This is generally only called by system startup code to launch /bin/init. + * Copies arguments from kernel constants into the heap, sets up a new MMU context + * from the kernel boot context, and then calls @ref exec. + */ +int system(const char * path, int argc, char *const argv[], char *const envin[]) { + char ** argv_ = malloc(sizeof(char*) * (argc + 1)); + for (int j = 0; j < argc; ++j) { + argv_[j] = malloc((strlen(argv[j]) + 1)); + memcpy((void*)argv_[j], argv[j], strlen(argv[j]) + 1); + } + argv_[argc] = NULL; + char * env[] = {NULL}; + this_core->current_process->thread.page_directory = malloc(sizeof(page_directory_t)); + this_core->current_process->thread.page_directory->directory = mmu_clone(NULL); /* base PML? for exec? */ + this_core->current_process->thread.page_directory->refcount = 1; + spin_init(this_core->current_process->thread.page_directory->lock); + mmu_set_directory(this_core->current_process->thread.page_directory->directory); + this_core->current_process->cmdline = (char**)argv_; + exec(path,argc,argv_,envin ? envin : env,0); + return -EINVAL; +} diff --git a/kernel/boot.S b/kernel/boot.S deleted file mode 100644 index 6b61b85c..00000000 --- a/kernel/boot.S +++ /dev/null @@ -1,60 +0,0 @@ -.set MB_MAGIC, 0x1BADB002 -.set MB_FLAG_PAGE_ALIGN, 1 << 0 -.set MB_FLAG_MEMORY_INFO, 1 << 1 -.set MB_FLAG_GRAPHICS, 1 << 2 -.set MB_FLAGS, MB_FLAG_PAGE_ALIGN | MB_FLAG_MEMORY_INFO | MB_FLAG_GRAPHICS -.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) - -.section .multiboot -.align 4 - -/* Multiboot section */ -.long MB_MAGIC -.long MB_FLAGS -.long MB_CHECKSUM -.long 0x00000000 /* header_addr */ -.long 0x00000000 /* load_addr */ -.long 0x00000000 /* load_end_addr */ -.long 0x00000000 /* bss_end_addr */ -.long 0x00000000 /* entry_addr */ - -/* Request linear graphics mode */ -.long 0x00000000 -.long 0 -.long 0 -.long 32 - -/* .stack resides in .bss */ -.section .stack, "aw", @nobits -stack_bottom: -.skip 32768 /* 32KiB */ -stack_top: - -.section .text - -.global start -.type start, @function - -.extern kmain -.type kmain, @function - -start: - /* Setup our stack */ - mov $stack_top, %esp - - /* Make sure our stack is 16-byte aligned */ - and $-16, %esp - - pushl %esp - pushl %eax /* Multiboot header magic */ - pushl %ebx /* Multiboot header pointer */ - - /* Disable interrupts and call kernel proper */ - cli - call kmain - - /* Clear interrupts and hang if we return from kmain */ - cli -hang: - hlt - jmp hang diff --git a/kernel/cpu/gdt.c b/kernel/cpu/gdt.c deleted file mode 100644 index 3f090707..00000000 --- a/kernel/cpu/gdt.c +++ /dev/null @@ -1,113 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K Lange - * Copyright (C) 2015 Dale Weiler - * - * Global Descriptor Tables module - * - */ -#include -#include -#include - -typedef struct { - /* Limits */ - uint16_t limit_low; - /* Segment address */ - uint16_t base_low; - uint8_t base_middle; - /* Access modes */ - uint8_t access; - uint8_t granularity; - uint8_t base_high; -} __attribute__((packed)) gdt_entry_t; - -typedef struct { - uint16_t limit; - uintptr_t base; -} __attribute__((packed)) gdt_pointer_t; - -/* In the future we may need to put a lock on the access of this */ -static struct { - gdt_entry_t entries[7]; - gdt_pointer_t pointer; - tss_entry_t tss; -} gdt __attribute__((used)); - -extern void gdt_flush(uintptr_t); - -#define ENTRY(X) (gdt.entries[(X)]) - -void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran) { - /* Base Address */ - ENTRY(num).base_low = (base & 0xFFFF); - ENTRY(num).base_middle = (base >> 16) & 0xFF; - ENTRY(num).base_high = (base >> 24) & 0xFF; - /* Limits */ - ENTRY(num).limit_low = (limit & 0xFFFF); - ENTRY(num).granularity = (limit >> 16) & 0X0F; - /* Granularity */ - ENTRY(num).granularity |= (gran & 0xF0); - /* Access flags */ - ENTRY(num).access = access; -} - -void gdt_set_gsbase(uintptr_t base) { - ENTRY(6).base_low = (base & 0xFFFF); - ENTRY(6).base_middle = (base >> 16) & 0xFF; - ENTRY(6).base_high = (base >> 24) & 0xFF; - asm volatile ("mov %0, %%gs" :: "r"((6 << 3) | 0x3)); -} - -uintptr_t gdt_get_gsbase(void) { - return (ENTRY(6).base_low) | (ENTRY(6).base_middle << 16) | (ENTRY(6).base_high << 24); -} - -static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0); - -void gdt_install(void) { - gdt_pointer_t *gdtp = &gdt.pointer; - gdtp->limit = sizeof gdt.entries - 1; - gdtp->base = (uintptr_t)&ENTRY(0); - - gdt_set_gate(0, 0, 0, 0, 0); /* NULL segment */ - gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */ - gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */ - gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); /* User code */ - gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); /* User data */ - write_tss(5, 0x10, 0x0); - gdt_set_gate(6, 0, 0xFFFFFFFF, 0xF2, 0xCF); - - /* Go go go */ - gdt_flush((uintptr_t)gdtp); - tss_flush(); -} - -static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0) { - tss_entry_t * tss = &gdt.tss; - uintptr_t base = (uintptr_t)tss; - uintptr_t limit = base + sizeof *tss; - - /* Add the TSS descriptor to the GDT */ - gdt_set_gate(num, base, limit, 0xE9, 0x00); - - memset(tss, 0x0, sizeof *tss); - - tss->ss0 = ss0; - tss->esp0 = esp0; - tss->cs = 0x0b; - tss->ss = 0x13; - tss->ds = 0x13; - tss->es = 0x13; - tss->fs = 0x13; - tss->gs = 0x13; - - tss->iomap_base = sizeof *tss; -} - -void set_kernel_stack(uintptr_t stack) { - /* Set the kernel stack */ - gdt.tss.esp0 = stack; -} - diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c deleted file mode 100644 index 46e4f223..00000000 --- a/kernel/cpu/idt.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2015 Dale Weiler - * - * Interrupt Descriptor Tables - * - */ -#include -#include - -typedef struct { - uint16_t base_low; - uint16_t sel; - uint8_t zero; - uint8_t flags; - uint16_t base_high; -} __attribute__((packed)) idt_entry_t; - -typedef struct { - uint16_t limit; - uintptr_t base; -} __attribute__((packed)) idt_pointer_t; - -/* In the future we may need to put a lock on the access of this */ -static struct { - idt_entry_t entries[256]; - idt_pointer_t pointer; -} idt __attribute__((used)); - -#define ENTRY(X) (idt.entries[(X)]) - -typedef void (*idt_gate_t)(void); - -extern void idt_load(uintptr_t); - -void idt_set_gate(uint8_t num, idt_gate_t base, uint16_t sel, uint8_t flags) { - ENTRY(num).base_low = ((uintptr_t)base & 0xFFFF); - ENTRY(num).base_high = ((uintptr_t)base >> 16) & 0xFFFF; - ENTRY(num).sel = sel; - ENTRY(num).zero = 0; - ENTRY(num).flags = flags | 0x60; -} - -void idt_install(void) { - idt_pointer_t * idtp = &idt.pointer; - idtp->limit = sizeof idt.entries - 1; - idtp->base = (uintptr_t)&ENTRY(0); - memset(&ENTRY(0), 0, sizeof idt.entries); - - idt_load((uintptr_t)idtp); -} diff --git a/kernel/cpu/irq.c b/kernel/cpu/irq.c deleted file mode 100644 index 35565d0c..00000000 --- a/kernel/cpu/irq.c +++ /dev/null @@ -1,189 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2015 Dale Weiler - * - * Interrupt Requests - * - */ -#include -#include -#include -#include -#include - -/* Programmable interrupt controller */ -#define PIC1 0x20 -#define PIC1_COMMAND PIC1 -#define PIC1_OFFSET 0x20 -#define PIC1_DATA (PIC1+1) - -#define PIC2 0xA0 -#define PIC2_COMMAND PIC2 -#define PIC2_OFFSET 0x28 -#define PIC2_DATA (PIC2+1) - -#define PIC_EOI 0x20 - -#define ICW1_ICW4 0x01 -#define ICW1_INIT 0x10 - -#define PIC_WAIT() \ - do { \ - /* May be fragile */ \ - asm volatile("jmp 1f\n\t" \ - "1:\n\t" \ - " jmp 2f\n\t" \ - "2:"); \ - } while (0) - -/* Interrupts */ -static volatile int sync_depth = 0; - -#define SYNC_CLI() asm volatile("cli") -#define SYNC_STI() asm volatile("sti") - -void int_disable(void) { - /* Check if interrupts are enabled */ - uint32_t flags; - asm volatile("pushf\n\t" - "pop %%eax\n\t" - "movl %%eax, %0\n\t" - : "=r"(flags) - : - : "%eax"); - - /* Disable interrupts */ - SYNC_CLI(); - - /* If interrupts were enabled, then this is the first call depth */ - if (flags & (1 << 9)) { - sync_depth = 1; - } else { - /* Otherwise there is now an additional call depth */ - sync_depth++; - } -} - -void int_resume(void) { - /* If there is one or no call depths, reenable interrupts */ - if (sync_depth == 0 || sync_depth == 1) { - SYNC_STI(); - } else { - sync_depth--; - } -} - -void int_enable(void) { - sync_depth = 0; - SYNC_STI(); -} - -/* Interrupt Requests */ -#define IRQ_CHAIN_SIZE 16 -#define IRQ_CHAIN_DEPTH 4 - -static void (*irqs[IRQ_CHAIN_SIZE])(void); -static irq_handler_chain_t irq_routines[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; -static char * _irq_handler_descriptions[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; - -char * get_irq_handler(int irq, int chain) { - if (irq >= IRQ_CHAIN_SIZE) return NULL; - if (chain >= IRQ_CHAIN_DEPTH) return NULL; - return _irq_handler_descriptions[IRQ_CHAIN_SIZE * chain + irq]; -} - -void irq_install_handler(size_t irq, irq_handler_chain_t handler, char * desc) { - /* Disable interrupts when changing handlers */ - SYNC_CLI(); - for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { - if (irq_routines[i * IRQ_CHAIN_SIZE + irq]) - continue; - irq_routines[i * IRQ_CHAIN_SIZE + irq] = handler; - _irq_handler_descriptions[i * IRQ_CHAIN_SIZE + irq ] = desc; - break; - } - SYNC_STI(); -} - -void irq_uninstall_handler(size_t irq) { - /* Disable interrupts when changing handlers */ - SYNC_CLI(); - for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) - irq_routines[i * IRQ_CHAIN_SIZE + irq] = NULL; - SYNC_STI(); -} - -static void irq_remap(void) { - /* Cascade initialization */ - outportb(PIC1_COMMAND, ICW1_INIT|ICW1_ICW4); PIC_WAIT(); - outportb(PIC2_COMMAND, ICW1_INIT|ICW1_ICW4); PIC_WAIT(); - - /* Remap */ - outportb(PIC1_DATA, PIC1_OFFSET); PIC_WAIT(); - outportb(PIC2_DATA, PIC2_OFFSET); PIC_WAIT(); - - /* Cascade identity with slave PIC at IRQ2 */ - outportb(PIC1_DATA, 0x04); PIC_WAIT(); - outportb(PIC2_DATA, 0x02); PIC_WAIT(); - - /* Request 8086 mode on each PIC */ - outportb(PIC1_DATA, 0x01); PIC_WAIT(); - outportb(PIC2_DATA, 0x01); PIC_WAIT(); -} - -static void irq_setup_gates(void) { - for (size_t i = 0; i < IRQ_CHAIN_SIZE; i++) { - idt_set_gate(32 + i, irqs[i], 0x08, 0x8E); - } -} - -void irq_install(void) { - char buffer[16]; - for (int i = 0; i < IRQ_CHAIN_SIZE; i++) { - sprintf(buffer, "_irq%d", i); - irqs[i] = symbol_find(buffer); - } - irq_remap(); - irq_setup_gates(); - - /** - * This will set a few pins to "level triggered". - * If we don't do this, we may end up on an EFI system where - * they were set to level triggered in expectation - * of an IO APIC taking over... - */ - if (!args_present("noelcr")) { -#if 0 - outportb(0x4D0, 0x00); -#endif - uint8_t val = inportb(0x4D1); - outportb(0x4D1, val | (1 << (10-8)) | (1 << (11-8))); - } -} - -void irq_ack(size_t irq_no) { - if (irq_no >= 8) { - outportb(PIC2_COMMAND, PIC_EOI); - } - outportb(PIC1_COMMAND, PIC_EOI); -} - -void irq_handler(struct regs *r) { - /* Disable interrupts when handling */ - int_disable(); - if (r->int_no <= 47 && r->int_no >= 32) { - for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { - irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)]; - if (!handler) break; - if (handler(r)) { - goto done; - } - } - debug_print(ERROR, "acking irq %d - no other device handled it", r->int_no - 32); - irq_ack(r->int_no - 32); - } -done: - int_resume(); -} diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c deleted file mode 100644 index 699cce10..00000000 --- a/kernel/cpu/isr.c +++ /dev/null @@ -1,94 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2015 Dale Weiler - * - * Interrupt Service Requests - */ -#include -#include -#include -#include - -/* The count is treated as is when setting up IDT gates. However there is an - * additional ISR for the system call vector which is handled explicitly since - * it's mapped at a different address. - */ -#define ISR_COUNT 32 - -static struct { - size_t index; - void (*stub)(void); -} isrs[32 + 1] __attribute__((used)); - -static irq_handler_t isr_routines[256] = { 0 }; - -void isrs_install_handler(size_t isrs, irq_handler_t handler) { - isr_routines[isrs] = handler; -} - -void isrs_uninstall_handler(size_t isrs) { - isr_routines[isrs] = 0; -} - -void isrs_install(void) { - char buffer[16]; - for (int i = 0; i < ISR_COUNT; i++) { - sprintf(buffer, "_isr%d", i); - isrs[i].index = i; - isrs[i].stub = symbol_find(buffer); - } - isrs[ISR_COUNT].index = SYSCALL_VECTOR; - isrs[ISR_COUNT].stub = symbol_find("_isr127"); - - for (int i = 0; i < ISR_COUNT + 1; i++) { - idt_set_gate(isrs[i].index, isrs[i].stub, 0x08, 0x8E); - } -} - -static const char *exception_messages[32] = { - "Division by zero", - "Debug", - "Non-maskable interrupt", - "Breakpoint", - "Detected overflow", - "Out-of-bounds", - "Invalid opcode", - "No coprocessor", - "Double fault", - "Coprocessor segment overrun", - "Bad TSS", - "Segment not present", - "Stack fault", - "General protection fault", - "Page fault", - "Unknown interrupt", - "Coprocessor fault", - "Alignment check", - "Machine check", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved" -}; - -void fault_handler(struct regs * r) { - irq_handler_t handler = isr_routines[r->int_no]; - if (handler) { - handler(r); - } else { - debug_print(CRITICAL, "Unhandled exception: [%d] %s", r->int_no, exception_messages[r->int_no]); - HALT_AND_CATCH_FIRE("Process caused an unhandled exception", r); - STOP; - } -} diff --git a/kernel/devices/cmos.c b/kernel/devices/cmos.c deleted file mode 100644 index 5f776c0d..00000000 --- a/kernel/devices/cmos.c +++ /dev/null @@ -1,194 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * CMOS Driver - * - */ - -#include - -/* CMOS values are stored like so: - * Say it's 8:42 AM, then the values are stored as: - * 0x08, 0x42... why this was a good idea, I have no - * clue, but that's how it usually is. - * - * This function will convert between this "BCD" format - * and regular decimal integers. */ -#define from_bcd(val) ((val / 16) * 10 + (val & 0xf)) - -#define CMOS_ADDRESS 0x70 -#define CMOS_DATA 0x71 - -enum -{ - CMOS_SECOND = 0, - CMOS_MINUTE = 2, - CMOS_HOUR = 4, - CMOS_DAY = 7, - CMOS_MONTH = 8, - CMOS_YEAR = 9 -}; - -void -cmos_dump( - uint16_t * values - ) { - uint16_t index; - for (index = 0; index < 128; ++index) { - outportb(CMOS_ADDRESS, index); - values[index] = inportb(CMOS_DATA); - } -} - -int is_update_in_progress(void) -{ - outportb(CMOS_ADDRESS, 0x0a); - return inportb(CMOS_DATA) & 0x80; -} - -/** - * Get the current month and day. - * - * @param month Pointer to a short to store the month - * @param day Pointer to a short to store the day - */ -void -get_date( - uint16_t * month, - uint16_t * day - ) { - uint16_t values[128]; /* CMOS dump */ - cmos_dump(values); - - *month = from_bcd(values[CMOS_MONTH]); - *day = from_bcd(values[CMOS_DAY]); -} - -/** - * Get the current time. - * - * @param hours Pointer to a short to store the current hour (/24) - * @param minutes Pointer to a short to store the current minute - * @param seconds Pointer to a short to store the current second - */ -void -get_time( - uint16_t * hours, - uint16_t * minutes, - uint16_t * seconds - ) { - uint16_t values[128]; /* CMOS dump */ - cmos_dump(values); - - *hours = from_bcd(values[CMOS_HOUR]); - *minutes = from_bcd(values[CMOS_MINUTE]); - *seconds = from_bcd(values[CMOS_SECOND]); -} - -uint32_t secs_of_years(int years) { - uint32_t days = 0; - years += 2000; - while (years > 1969) { - days += 365; - if (years % 4 == 0) { - if (years % 100 == 0) { - if (years % 400 == 0) { - days++; - } - } else { - days++; - } - } - years--; - } - return days * 86400; -} - -uint32_t secs_of_month(int months, int year) { - year += 2000; - - uint32_t days = 0; - switch(months) { - case 11: - days += 30; - case 10: - days += 31; - case 9: - days += 30; - case 8: - days += 31; - case 7: - days += 31; - case 6: - days += 30; - case 5: - days += 31; - case 4: - days += 30; - case 3: - days += 31; - case 2: - days += 28; - if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) { - days++; - } - case 1: - days += 31; - default: - break; - } - return days * 86400; -} - -uint32_t boot_time = 0; - -uint32_t read_cmos(void) { - uint16_t values[128]; - uint16_t old_values[128]; - - while (is_update_in_progress()) - ; - - cmos_dump(values); - - do - { - memcpy(old_values, values, 128); - while (is_update_in_progress()) - ; - - cmos_dump(values); - } while ((old_values[CMOS_SECOND] != values[CMOS_SECOND]) || - (old_values[CMOS_MINUTE] != values[CMOS_MINUTE]) || - (old_values[CMOS_HOUR] != values[CMOS_HOUR]) || - (old_values[CMOS_DAY] != values[CMOS_DAY]) || - (old_values[CMOS_MONTH] != values[CMOS_MONTH]) || - (old_values[CMOS_YEAR] != values[CMOS_YEAR])); - - /* Math Time */ - uint32_t time = - secs_of_years(from_bcd(values[CMOS_YEAR]) - 1) + - secs_of_month(from_bcd(values[CMOS_MONTH]) - 1, - from_bcd(values[CMOS_YEAR])) + - (from_bcd(values[CMOS_DAY]) - 1) * 86400 + - (from_bcd(values[CMOS_HOUR])) * 3600 + - (from_bcd(values[CMOS_MINUTE])) * 60 + - from_bcd(values[CMOS_SECOND]) + 0; - - return time; -} - -int gettimeofday(struct timeval * t, void *z) { - t->tv_sec = boot_time + timer_ticks + timer_drift; - t->tv_usec = timer_subticks * 1000; - return 0; -} - -uint32_t now(void) { - struct timeval t; - gettimeofday(&t, NULL); - return t.tv_sec; -} - diff --git a/kernel/devices/fpu.c b/kernel/devices/fpu.c deleted file mode 100644 index 3c51fbc5..00000000 --- a/kernel/devices/fpu.c +++ /dev/null @@ -1,142 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * FPU and SSE context handling. - * - * FPU context is kept through context switches, - * but the FPU is disabled. When an FPU instruction - * is executed, it will trap here and the context - * will be saved to its original owner and the context - * for the current process will be loaded or the FPU - * will be reset for the new process. - * - * FPU states are per kernel thread. - * - */ -#include -#include - -#define NO_LAZY_FPU - -process_t * fpu_thread = NULL; - -/** - * Set the FPU control word - * - * @param cw What to set the control word to. - */ -void -set_fpu_cw(const uint16_t cw) { - asm volatile("fldcw %0" :: "m"(cw)); -} - -/** - * Enable the FPU and SSE - */ -void enable_fpu(void) { - asm volatile ("clts"); - size_t t; - asm volatile ("mov %%cr0, %0" : "=r"(t)); - t &= ~(1 << 2); - t |= (1 << 1); - asm volatile ("mov %0, %%cr0" :: "r"(t)); - - asm volatile ("mov %%cr4, %0" : "=r"(t)); - t |= 3 << 9; - asm volatile ("mov %0, %%cr4" :: "r"(t)); - -} - -/** - * Disable FPU and SSE so it traps to the kernel - */ -void disable_fpu(void) { - size_t t; - asm volatile ("mov %%cr0, %0" : "=r"(t)); - t |= 1 << 3; - asm volatile ("mov %0, %%cr0" :: "r"(t)); -} - -/* Temporary aligned buffer for copying around FPU contexts */ -uint8_t saves[512] __attribute__((aligned(16))); - -/** - * Restore the FPU for a process - */ -void restore_fpu(process_t * proc) { - memcpy(&saves,(uint8_t *)&proc->thread.fp_regs,512); - asm volatile ("fxrstor (%0)" :: "r"(saves)); -} - -/** - * Save the FPU for a process - */ -void save_fpu(process_t * proc) { - asm volatile ("fxsave (%0)" :: "r"(saves)); - memcpy((uint8_t *)&proc->thread.fp_regs,&saves,512); -} - -/** - * Initialize the FPU - */ -void init_fpu(void) { - asm volatile ("fninit"); -} - -/** - * Kernel trap for FPU usage when FPU is disabled - */ -void invalid_op(struct regs * r) { - /* First, turn the FPU on */ - enable_fpu(); - if (fpu_thread == current_process) { - /* If this is the thread that last used the FPU, do nothing */ - return; - } - if (fpu_thread) { - /* If there is a thread that was using the FPU, save its state */ - save_fpu(fpu_thread); - } - fpu_thread = (process_t *)current_process; - if (!fpu_thread->thread.fpu_enabled) { - /* - * If the FPU has not been used in this thread previously, - * we need to initialize it. - */ - init_fpu(); - fpu_thread->thread.fpu_enabled = 1; - return; - } - /* Otherwise we restore the context for this thread. */ - restore_fpu(fpu_thread); -} - -/* Called during a context switch; disable the FPU */ -void switch_fpu(void) { -#ifdef NO_LAZY_FPU - save_fpu((process_t *)current_process); -#else - disable_fpu(); -#endif -} - -void unswitch_fpu(void) { -#ifdef NO_LAZY_FPU - restore_fpu((process_t *)current_process); -#endif -} - -/* Enable the FPU context handling */ -void fpu_install(void) { -#ifdef NO_LAZY_FPU - enable_fpu(); - init_fpu(); - save_fpu((void*)current_process); -#else - enable_fpu(); - disable_fpu(); - isrs_install_handler(7, &invalid_op); -#endif -} diff --git a/kernel/devices/timer.c b/kernel/devices/timer.c deleted file mode 100644 index 53f86c39..00000000 --- a/kernel/devices/timer.c +++ /dev/null @@ -1,90 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Programmable Interrupt Timer - */ -#include -#include -#include - -#define PIT_A 0x40 -#define PIT_B 0x41 -#define PIT_C 0x42 -#define PIT_CONTROL 0x43 - -#define PIT_MASK 0xFF -#define PIT_SCALE 1193180 -#define PIT_SET 0x34 - -#define TIMER_IRQ 0 - -#define SUBTICKS_PER_TICK 1000 -#define RESYNC_TIME 1 - -/* - * Set the phase (in hertz) for the Programmable - * Interrupt Timer (PIT). - */ -void -timer_phase( - int hz - ) { - int divisor = PIT_SCALE / hz; - outportb(PIT_CONTROL, PIT_SET); - outportb(PIT_A, divisor & PIT_MASK); - outportb(PIT_A, (divisor >> 8) & PIT_MASK); -} - -/* - * Internal timer counters - */ -unsigned long timer_ticks = 0; -unsigned long timer_subticks = 0; -signed long timer_drift = 0; -signed long _timer_drift = 0; - -static int behind = 0; - -/* - * IRQ handler for when the timer fires - */ -int timer_handler(struct regs *r) { - if (++timer_subticks == SUBTICKS_PER_TICK || (behind && ++timer_subticks == SUBTICKS_PER_TICK)) { - timer_ticks++; - timer_subticks = 0; - if (timer_ticks % RESYNC_TIME == 0) { - uint32_t new_time = read_cmos(); - _timer_drift = new_time - boot_time - timer_ticks; - if (_timer_drift > 0) behind = 1; - else behind = 0; - } - } - irq_ack(TIMER_IRQ); - - wakeup_sleepers(timer_ticks, timer_subticks); - switch_task(1); - return 1; -} - -void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds) { - if (subseconds + timer_subticks > SUBTICKS_PER_TICK) { - *out_seconds = timer_ticks + seconds + 1; - *out_subseconds = (subseconds + timer_subticks) - SUBTICKS_PER_TICK; - } else { - *out_seconds = timer_ticks + seconds; - *out_subseconds = timer_subticks + subseconds; - } -} - -/* - * Device installer for the PIT - */ -void timer_install(void) { - //debug_print(NOTICE,"Initializing interval timer"); - boot_time = read_cmos(); - irq_install_handler(TIMER_IRQ, timer_handler, "pit timer"); - timer_phase(SUBTICKS_PER_TICK); /* 100Hz */ -} - diff --git a/kernel/ds/bitset.c b/kernel/ds/bitset.c deleted file mode 100644 index ebd5c5ab..00000000 --- a/kernel/ds/bitset.c +++ /dev/null @@ -1,65 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015-2018 K. Lange - * 2015 Dale Weiler - */ -#include - -#define CEIL(NUMBER, BASE) \ - (((NUMBER) + (BASE) - 1) & ~((BASE) - 1)) - -#define iom \ - size_t index = bit >> 3; \ - bit = bit - index * 8; \ - size_t offset = bit & 7; \ - size_t mask = 1 << offset; - -void bitset_init(bitset_t *set, size_t size) { - set->size = CEIL(size, 8); - set->data = malloc(set->size); - memset(set->data, 0, set->size); -} - -void bitset_free(bitset_t *set) { - free(set->data); -} - -static void bitset_resize(bitset_t *set, size_t size) { - if (set->size >= size) { - return; - } - - set->data = realloc(set->data, size); - memset(set->data + set->size, 0, size - set->size); - set->size = size; -} - -void bitset_set(bitset_t *set, size_t bit) { - iom; - if (set->size <= index) { - bitset_resize(set, set->size << 1); - } - set->data[index] |= mask; -} - -int bitset_ffub(bitset_t *set) { - for (size_t i = 0; i < set->size * 8; i++) { - if (bitset_test(set, i)) { - continue; - } - return (int)i; - } - return -1; -} - -void bitset_clear(bitset_t *set, size_t bit) { - iom; - set->data[index] &= ~mask; -} - -int bitset_test(bitset_t *set, size_t bit) { - iom; - return !!(mask & set->data[index]); -} - diff --git a/kernel/ds/hashmap.c b/kernel/ds/hashmap.c deleted file mode 120000 index d0b720d5..00000000 --- a/kernel/ds/hashmap.c +++ /dev/null @@ -1 +0,0 @@ -../../lib/hashmap.c \ No newline at end of file diff --git a/kernel/ds/list.c b/kernel/ds/list.c deleted file mode 120000 index 520ecd1a..00000000 --- a/kernel/ds/list.c +++ /dev/null @@ -1 +0,0 @@ -../../lib/list.c \ No newline at end of file diff --git a/kernel/ds/tree.c b/kernel/ds/tree.c deleted file mode 120000 index 15dceb13..00000000 --- a/kernel/ds/tree.c +++ /dev/null @@ -1 +0,0 @@ -../../lib/tree.c \ No newline at end of file diff --git a/kernel/gdt.S b/kernel/gdt.S deleted file mode 100644 index 01c11877..00000000 --- a/kernel/gdt.S +++ /dev/null @@ -1,21 +0,0 @@ -.section .text -.align 4 - -.global gdt_flush -.type gdt_flush, @function - -gdt_flush: - /* Load GDT */ - mov 4(%esp), %eax - lgdt (%eax) - - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %ss - mov %ax, %gs - - ljmp $0x08, $.flush -.flush: - ret diff --git a/kernel/generic.c b/kernel/generic.c new file mode 100644 index 00000000..e8ee2d56 --- /dev/null +++ b/kernel/generic.c @@ -0,0 +1,80 @@ +/** + * @file kernel/generic.c + * @brief Architecture-neutral startup sequences. + * + * The generic startup sequence is broken into two parts: + * @c generic_startup should be called as soon as the platform + * has configured memory and is ready for the VFS and scheduler + * to be initialized. @c generic_main should be called after + * the platform has set up its own device drivers, loaded any + * early filesystems, and is ready to yield control to init. + */ +#include +#include +#include +#include +#include + +extern const char * arch_get_cmdline(void); +extern void tarfs_register_init(void); +extern void tmpfs_register_init(void); +extern void tasking_start(void); +extern void packetfs_initialize(void); +extern void zero_initialize(void); +extern void procfs_initialize(void); +extern void shm_install(void); +extern void random_initialize(void); +extern int system(const char * path, int argc, const char ** argv, const char ** envin); +extern void snd_install(void); +extern void net_install(void); + +void generic_startup(void) { + args_parse(arch_get_cmdline()); + initialize_process_tree(); + shm_install(); + vfs_install(); + tarfs_register_init(); + tmpfs_register_init(); + map_vfs_directory("/dev"); + packetfs_initialize(); + zero_initialize(); + procfs_initialize(); + random_initialize(); + snd_install(); + net_install(); + tasking_start(); +} + +int generic_main(void) { + if (args_present("root")) { + const char * root_type = "tar"; + if (args_present("root_type")) { + root_type = args_value("root_type"); + } + vfs_mount_type(root_type,args_value("root"),"/"); + } + + const char * boot_arg = NULL; + + if (args_present("args")) { + boot_arg = strdup(args_value("args")); + } + + const char * boot_app = "/bin/init"; + if (args_present("init")) { + boot_app = args_value("init"); + } + + const char * argv[] = { + boot_app, + boot_arg, + NULL + }; + int argc = 0; + while (argv[argc]) argc++; + system(argv[0], argc, argv, NULL); + + printf("Failed to execute %s.\n", boot_app); + switch_task(0); + return 0; +} diff --git a/kernel/idt.S b/kernel/idt.S deleted file mode 100644 index d0c31c99..00000000 --- a/kernel/idt.S +++ /dev/null @@ -1,10 +0,0 @@ -.section .text -.align 4 - -.global idt_load -.type idt_load, @function - -idt_load: - mov 4(%esp), %eax - lidt (%eax) - ret diff --git a/kernel/irq.S b/kernel/irq.S deleted file mode 100644 index 56b706fa..00000000 --- a/kernel/irq.S +++ /dev/null @@ -1,67 +0,0 @@ -.section .text -.align 4 - -.macro IRQ ident byte - .global _irq\ident - .type _irq\ident, @function - _irq\ident: - cli - push $0x00 - push $\byte - jmp irq_common -.endm - -/* Interrupt Requests */ -IRQ 0, 32 -IRQ 1, 33 -IRQ 2, 34 -IRQ 3, 35 -IRQ 4, 36 -IRQ 5, 37 -IRQ 6, 38 -IRQ 7, 39 -IRQ 8, 40 -IRQ 9, 41 -IRQ 10, 42 -IRQ 11, 43 -IRQ 12, 44 -IRQ 13, 45 -IRQ 14, 46 -IRQ 15, 47 - -.extern irq_handler -.type irq_handler, @function - -irq_common: - /* Save all registers */ - pusha - - /* Save segment registers */ - push %ds - push %es - push %fs - push %gs - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - cld - - /* Call interrupt handler */ - push %esp - call irq_handler - add $4, %esp - - /* Restore segment registers */ - pop %gs - pop %fs - pop %es - pop %ds - - /* Restore all registers */ - popa - /* Cleanup error code and IRQ # */ - add $8, %esp - /* pop CS, EIP, EFLAGS, SS and ESP */ - iret diff --git a/kernel/isr.S b/kernel/isr.S deleted file mode 100644 index 318c0498..00000000 --- a/kernel/isr.S +++ /dev/null @@ -1,91 +0,0 @@ -.section .text -.align 4 - -.macro ISR_NOERR index - .global _isr\index - _isr\index: - cli - push $0 - push $\index - jmp isr_common -.endm - -.macro ISR_ERR index - .global _isr\index - _isr\index: - cli - push $\index - jmp isr_common -.endm - -/* Standard X86 interrupt service routines */ -ISR_NOERR 0 -ISR_NOERR 1 -ISR_NOERR 2 -ISR_NOERR 3 -ISR_NOERR 4 -ISR_NOERR 5 -ISR_NOERR 6 -ISR_NOERR 7 -ISR_ERR 8 -ISR_NOERR 9 -ISR_ERR 10 -ISR_ERR 11 -ISR_ERR 12 -ISR_ERR 13 -ISR_ERR 14 -ISR_NOERR 15 -ISR_NOERR 16 -ISR_NOERR 17 -ISR_NOERR 18 -ISR_NOERR 19 -ISR_NOERR 20 -ISR_NOERR 21 -ISR_NOERR 22 -ISR_NOERR 23 -ISR_NOERR 24 -ISR_NOERR 25 -ISR_NOERR 26 -ISR_NOERR 27 -ISR_NOERR 28 -ISR_NOERR 29 -ISR_NOERR 30 -ISR_NOERR 31 -ISR_NOERR 127 - -.extern fault_handler -.type fault_handler, @function - -isr_common: - /* Push all registers */ - pusha - - /* Save segment registers */ - push %ds - push %es - push %fs - push %gs - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - cld - - /* Call fault handler */ - push %esp - call fault_handler - add $4, %esp - - /* Restore segment registers */ - pop %gs - pop %fs - pop %es - pop %ds - - /* Restore registers */ - popa - /* Cleanup error code and ISR # */ - add $8, %esp - /* pop CS, EIP, EFLAGS, SS and ESP */ - iret diff --git a/kernel/main.c b/kernel/main.c deleted file mode 100644 index cbb493db..00000000 --- a/kernel/main.c +++ /dev/null @@ -1,282 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * - * The ToAruOS kernel is released under the terms of the - * University of Illinois / NCSA License. - * - * Copyright (C) 2011-2018 K. Lange. All rights reserved. - * Copyright (C) 2012 Markus Schober - * Copyright (C) 2014 Lioncash - * - * Dedicated to the memory of - * Dennis Ritchie - * 1941-2011 - * - * Developed by: ToAruOS Kernel Development Team - * http://github.com/klange/toaruos - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal with 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: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimers. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimers in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the ToAruOS Kernel Development Team, K. Lange, - * nor the names of its contributors may be used to endorse - * or promote products derived from this Software without specific prior - * written permission. - * - * 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 - * CONTRIBUTORS 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 - * WITH THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -uintptr_t initial_esp = 0; - -fs_node_t * ramdisk_mount(uintptr_t, size_t); - -#ifdef EARLY_BOOT_LOG -#define EARLY_LOG_DEVICE 0x3F8 -//#define EARLY_LOG_DEVICE 0x504 -static uint32_t _early_log_write(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - for (unsigned int i = 0; i < size; ++i) { - outportb(EARLY_LOG_DEVICE, buffer[i]); - } - return size; -} -fs_node_t _early_log = { .write = &_early_log_write }; -#define ENABLE_EARLY_BOOT_LOG(level) do { debug_file = &_early_log; debug_level = (level); } while (0) -#define DISABLE_EARLY_BOOT_LOG() do { debug_file = NULL; debug_level = NOTICE; } while (0) -#else -#define ENABLE_EARLY_BOOT_LOG(level) -#define DISABLE_EARLY_BOOT_LOG() -#endif - -struct pack_header { - char head[4]; - uint32_t region_size; -}; - -/* - * multiboot i386 (pc) kernel entry point - */ -int kmain(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) { - initial_esp = esp; - extern char * cmdline; - - uint32_t mboot_mods_count = 0; - mboot_mod_t * mboot_mods = NULL; - mboot_ptr = mboot; - - ENABLE_EARLY_BOOT_LOG(0); - - assert(mboot_mag == MULTIBOOT_EAX_MAGIC && "Didn't boot with multiboot, not sure how we got here."); - debug_print(NOTICE, "Processing Multiboot information."); - - /* Initialize core modules */ - gdt_install(); /* Global descriptor table */ - idt_install(); /* IDT */ - - uintptr_t last_mod = (uintptr_t)&end; - if (mboot_ptr->flags & MULTIBOOT_FLAG_MODS) { - debug_print(NOTICE, "There %s %d module%s starting at 0x%x.", mboot_ptr->mods_count == 1 ? "is" : "are", mboot_ptr->mods_count, mboot_ptr->mods_count == 1 ? "" : "s", mboot_ptr->mods_addr); - debug_print(NOTICE, "Current kernel heap start point would be 0x%x.", &end); - if (mboot_ptr->mods_count > 0) { - uint32_t i; - mboot_mods = (mboot_mod_t *)mboot_ptr->mods_addr; - mboot_mods_count = mboot_ptr->mods_count; - for (i = 0; i < mboot_ptr->mods_count; ++i ) { - mboot_mod_t * mod = &mboot_mods[i]; - uint32_t module_start = mod->mod_start; - uint32_t module_end = mod->mod_end; - if ((uintptr_t)mod + sizeof(mboot_mod_t) > last_mod) { - /* Just in case some silly person put this *behind* the modules... */ - last_mod = (uintptr_t)mod + sizeof(mboot_mod_t); - debug_print(NOTICE, "moving forward to 0x%x", last_mod); - } - debug_print(NOTICE, "Module %d is at 0x%x:0x%x", i, module_start, module_end); - if (last_mod < module_end) { - last_mod = module_end; - } - } - debug_print(NOTICE, "Moving kernel heap start to 0x%x", last_mod); - } - } - if ((uintptr_t)mboot_ptr > last_mod) { - last_mod = (uintptr_t)mboot_ptr + sizeof(struct multiboot); - } - while (last_mod & 0x7FF) last_mod++; - kmalloc_startat(last_mod); - - if (mboot_ptr->flags & MULTIBOOT_FLAG_MEM) { - paging_install(mboot_ptr->mem_upper + mboot_ptr->mem_lower); - } else { - debug_print(CRITICAL, "Missing MEM flag in multiboot header\n"); - } - - if (mboot_ptr->flags & MULTIBOOT_FLAG_MMAP) { - debug_print(NOTICE, "Parsing memory map at 0x%x with length 0x%x", mboot_ptr->mmap_addr, mboot_ptr->mmap_length); - mboot_memmap_t * mmap = (void *)mboot_ptr->mmap_addr; - unsigned long long int previousEnd = 0; - while ((uintptr_t)mmap < mboot_ptr->mmap_addr + mboot_ptr->mmap_length) { - if (previousEnd < mmap->base_addr) { - debug_print(NOTICE, "Need to back fill from 0x%x%x to 0x%x%x as unavailable", - (uint32_t)(previousEnd >> 32), (uint32_t)(previousEnd & 0xFFFFFFFF), - (uint32_t)(mmap->base_addr >> 32), (uint32_t)(mmap->base_addr & 0xFFFFFFFF)); - for (; previousEnd < mmap->base_addr; previousEnd += 0x1000) { - paging_mark_system((previousEnd) & 0xFFFFF000); - } - } - debug_print(NOTICE, "0x%x:0x%x %d", (uint32_t)mmap->base_addr, (uint32_t)mmap->length, mmap->type); - if (mmap->type == 2) { - for (unsigned long long int i = 0; i < mmap->length; i += 0x1000) { - if (mmap->base_addr + i > 0xFFFFFFFF) break; /* xxx */ - //debug_print(INFO, "Marking 0x%x", (uint32_t)(mmap->base_addr + i)); - paging_mark_system((mmap->base_addr + i) & 0xFFFFF000); - } - } - previousEnd = mmap->base_addr + mmap->length; - mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uintptr_t)); - } - } - paging_finalize(); - - { - char cmdline_[1024]; - - size_t len = strlen((char *)mboot_ptr->cmdline); - memmove(cmdline_, (char *)mboot_ptr->cmdline, len + 1); - - /* Relocate the command line */ - cmdline = (char *)kmalloc(len + 1); - memcpy(cmdline, cmdline_, len + 1); - } - - /* Memory management */ - heap_install(); /* Kernel heap */ - - if (cmdline) { - args_parse(cmdline); - } - - isrs_install(); /* Interrupt service requests */ - irq_install(); /* Hardware interrupt requests */ - - vfs_install(); - tasking_install(); /* Multi-tasking */ - timer_install(); /* PIC driver */ - fpu_install(); /* FPU/SSE magic */ - syscalls_install(); /* Install the system calls */ - shm_install(); /* Install shared memory */ - modules_install(); /* Modules! */ - pci_remap(); - - DISABLE_EARLY_BOOT_LOG(); - - /* Load modules from bootloader */ - if (mboot_ptr->flags & MULTIBOOT_FLAG_MODS) { - debug_print(NOTICE, "%d modules to load", mboot_mods_count); - for (unsigned int i = 0; i < mboot_ptr->mods_count; ++i ) { - mboot_mod_t * mod = &mboot_mods[i]; - uint32_t module_start = mod->mod_start; - uint32_t module_end = mod->mod_end; - size_t module_size = module_end - module_start; - - int check_result = module_quickcheck((void *)module_start); - if (check_result == 1) { - debug_print(NOTICE, "Loading a module: 0x%x:0x%x", module_start, module_end); - module_data_t * mod_info = (module_data_t *)module_load_direct((void *)(module_start), module_size); - if (mod_info) { - debug_print(NOTICE, "Loaded: %s", mod_info->mod_info->name); - } - } else if (check_result == 2) { - /* Mod pack */ - debug_print(NOTICE, "Loading modpack. %x", module_start); - struct pack_header * pack_header = (struct pack_header *)module_start; - while (pack_header->region_size) { - void * start = (void *)((uintptr_t)pack_header + 4096); - int result = module_quickcheck(start); - if (result != 1) { - debug_print(WARNING, "Not actually a module?! %x", start); - } - module_data_t * mod_info = (module_data_t *)module_load_direct(start, pack_header->region_size); - if (mod_info) { - debug_print(NOTICE, "Loaded: %s", mod_info->mod_info->name); - } - pack_header = (struct pack_header *)((uintptr_t)start + pack_header->region_size); - } - debug_print(NOTICE, "Done with modpack."); - } else { - debug_print(NOTICE, "Loading ramdisk: 0x%x:0x%x", module_start, module_end); - ramdisk_mount(module_start, module_size); - } - } - } - - /* Map /dev to a device mapper */ - map_vfs_directory("/dev"); - - if (args_present("root")) { - char * root_type = "ext2"; - if (args_present("root_type")) { - root_type = args_value("root_type"); - } - vfs_mount_type(root_type, args_value("root"), "/"); - } - - if (args_present("args")) { - char * c = args_value("args"); - if (!c) { - debug_print(WARNING, "Expected an argument to kernel option `args`. Ignoring."); - } else { - debug_print(NOTICE, "Got init argument: %s", c); - boot_arg = strdup(c); - } - } - - if (!fs_root) { - map_vfs_directory("/"); - } - - char * boot_app = "/bin/init"; - if (args_present("init")) { - boot_app = args_value("init"); - } - - /* Prepare to run /bin/init */ - char * argv[] = { - boot_app, - boot_arg, - NULL - }; - int argc = 0; - while (argv[argc]) { - argc++; - } - system(argv[0], argc, argv, NULL); /* Run init */ - - debug_print(CRITICAL, "init failed"); - switch_task(0); - - return 0; -} - diff --git a/kernel/mem/mem.c b/kernel/mem/mem.c deleted file mode 100644 index 9cc80d5e..00000000 --- a/kernel/mem/mem.c +++ /dev/null @@ -1,566 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2012 Markus Schober - * - * Kernel Memory Manager - */ - -#include -#include -#include -#include -#include -#include - -#include - -#define KERNEL_HEAP_INIT 0x00800000 -#define KERNEL_HEAP_END 0x20000000 - -extern void *end; -uintptr_t placement_pointer = (uintptr_t)&end; -uintptr_t heap_end = (uintptr_t)NULL; -uintptr_t kernel_heap_alloc_point = KERNEL_HEAP_INIT; - -//static volatile uint8_t frame_alloc_lock = 0; -static spin_lock_t frame_alloc_lock = { 0 }; -uint32_t first_n_frames(int n); - -void -kmalloc_startat( - uintptr_t address - ) { - placement_pointer = address; -} - -/* - * kmalloc() is the kernel's dumb placement allocator - */ -uintptr_t -kmalloc_real( - size_t size, - int align, - uintptr_t * phys - ) { - if (heap_end) { - void * address; - if (align) { - address = valloc(size); - } else { - address = malloc(size); - } - if (phys) { - if (align && size >= 0x3000) { - debug_print(NOTICE, "Requested large aligned alloc of size 0x%x", size); - for (uintptr_t i = (uintptr_t)address; i < (uintptr_t)address + size; i += 0x1000) { - clear_frame(map_to_physical(i)); - } - /* XXX This is going to get touchy... */ - spin_lock(frame_alloc_lock); - uint32_t index = first_n_frames((size + 0xFFF) / 0x1000); - if (index == 0xFFFFFFFF) { - spin_unlock(frame_alloc_lock); - return 0; - } - for (unsigned int i = 0; i < (size + 0xFFF) / 0x1000; ++i) { - set_frame((index + i) * 0x1000); - page_t * page = get_page((uintptr_t)address + (i * 0x1000),0,kernel_directory); - ASSUME(page != NULL); - page->frame = index + i; - page->writethrough = 1; - page->cachedisable = 1; - } - spin_unlock(frame_alloc_lock); - } - *phys = map_to_physical((uintptr_t)address); - } - return (uintptr_t)address; - } - - if (align && (placement_pointer & 0x00000FFF)) { - placement_pointer &= 0xFFFFF000; - placement_pointer += 0x1000; - } - if (phys) { - *phys = placement_pointer; - } - uintptr_t address = placement_pointer; - placement_pointer += size; - return (uintptr_t)address; -} -/* - * Normal - */ -uintptr_t -kmalloc( - size_t size - ) { - return kmalloc_real(size, 0, NULL); -} -/* - * Aligned - */ -uintptr_t -kvmalloc( - size_t size - ) { - return kmalloc_real(size, 1, NULL); -} -/* - * With a physical address - */ -uintptr_t -kmalloc_p( - size_t size, - uintptr_t *phys - ) { - return kmalloc_real(size, 0, phys); -} -/* - * Aligned, with a physical address - */ -uintptr_t -kvmalloc_p( - size_t size, - uintptr_t *phys - ) { - return kmalloc_real(size, 1, phys); -} - -/* - * Frame Allocation - */ - -uint32_t *frames; -uint32_t nframes; - -#define INDEX_FROM_BIT(b) (b / 0x20) -#define OFFSET_FROM_BIT(b) (b % 0x20) - -void -set_frame( - uintptr_t frame_addr - ) { - if (frame_addr < nframes * 4 * 0x400) { - uint32_t frame = frame_addr / 0x1000; - uint32_t index = INDEX_FROM_BIT(frame); - uint32_t offset = OFFSET_FROM_BIT(frame); - frames[index] |= ((uint32_t)0x1 << offset); - } -} - -void -clear_frame( - uintptr_t frame_addr - ) { - uint32_t frame = frame_addr / 0x1000; - uint32_t index = INDEX_FROM_BIT(frame); - uint32_t offset = OFFSET_FROM_BIT(frame); - frames[index] &= ~((uint32_t)0x1 << offset); -} - -uint32_t test_frame(uintptr_t frame_addr) { - uint32_t frame = frame_addr / 0x1000; - uint32_t index = INDEX_FROM_BIT(frame); - uint32_t offset = OFFSET_FROM_BIT(frame); - return (frames[index] & ((uint32_t)0x1 << offset)); -} - -uint32_t first_n_frames(int n) { - for (uint32_t i = 0; i < nframes * 0x1000; i += 0x1000) { - int bad = 0; - for (int j = 0; j < n; ++j) { - if (test_frame(i + 0x1000 * j)) { - bad = j+1; - } - } - if (!bad) { - return i / 0x1000; - } - } - return 0xFFFFFFFF; -} - -uint32_t first_frame(void) { - uint32_t i, j; - - for (i = 0; i < INDEX_FROM_BIT(nframes); ++i) { - if (frames[i] != 0xFFFFFFFF) { - for (j = 0; j < 32; ++j) { - uint32_t testFrame = (uint32_t)0x1 << j; - if (!(frames[i] & testFrame)) { - return i * 0x20 + j; - } - } - } - } - - debug_print(CRITICAL, "System claims to be out of usable memory, which means we probably overwrote the page frames.\033[0m"); - - if (debug_video_crash) { - char * msgs[] = {"Out of memory.", NULL}; - debug_video_crash(msgs); - } - - STOP; - - return -1; -} - -void -alloc_frame( - page_t *page, - int is_kernel, - int is_writeable - ) { - ASSUME(page != NULL); - if (page->frame != 0) { - page->present = 1; - page->rw = (is_writeable == 1) ? 1 : 0; - page->user = (is_kernel == 1) ? 0 : 1; - return; - } else { - spin_lock(frame_alloc_lock); - uint32_t index = first_frame(); - assert(index != (uint32_t)-1 && "Out of frames."); - set_frame(index * 0x1000); - page->frame = index; - spin_unlock(frame_alloc_lock); - page->present = 1; - page->rw = (is_writeable == 1) ? 1 : 0; - page->user = (is_kernel == 1) ? 0 : 1; - } -} - -void -dma_frame( - page_t *page, - int is_kernel, - int is_writeable, - uintptr_t address - ) { - ASSUME(page != NULL); - /* Page this address directly */ - page->present = 1; - page->rw = (is_writeable) ? 1 : 0; - page->user = (is_kernel) ? 0 : 1; - page->frame = address / 0x1000; - set_frame(address); -} - -void -free_frame( - page_t *page - ) { - uint32_t frame; - if (!(frame = page->frame)) { - assert(0); - return; - } else { - clear_frame(frame * 0x1000); - page->frame = 0x0; - } -} - -uintptr_t memory_use(void ) { - uintptr_t ret = 0; - uint32_t i, j; - for (i = 0; i < INDEX_FROM_BIT(nframes); ++i) { - for (j = 0; j < 32; ++j) { - uint32_t testFrame = (uint32_t)0x1 << j; - if (frames[i] & testFrame) { - ret++; - } - } - } - return ret * 4; -} - -uintptr_t memory_total(){ - return nframes * 4; -} - -void paging_install(uint32_t memsize) { - nframes = memsize / 4; - frames = (uint32_t *)kmalloc(INDEX_FROM_BIT(nframes * 8)); - memset(frames, 0, INDEX_FROM_BIT(nframes * 8)); - - uintptr_t phys; - kernel_directory = (page_directory_t *)kvmalloc_p(sizeof(page_directory_t),&phys); - memset(kernel_directory, 0, sizeof(page_directory_t)); - - /* Set PAT 111b to Write-Combining */ - asm volatile ( - "mov $0x277, %%ecx\n" /* IA32_MSR_PAT */ - "rdmsr\n" - "or $0x1000000, %%edx\n" /* set bit 56 */ - "and $0xf9ffffff, %%edx\n" /* unset bits 57, 58 */ - "wrmsr\n" - : : : "ecx", "edx", "eax" - ); - -} - -void paging_mark_system(uint64_t addr) { - set_frame(addr); -} - -void paging_finalize(void) { - debug_print(INFO, "Placement pointer is at 0x%x", placement_pointer); -#if 1 - get_page(0,1,kernel_directory)->present = 0; - set_frame(0); - for (uintptr_t i = 0x1000; i < 0x80000; i += 0x1000) { -#else - for (uintptr_t i = 0x0; i < 0x80000; i += 0x1000) { -#endif - dma_frame(get_page(i, 1, kernel_directory), 1, 0, i); - } - for (uintptr_t i = 0x80000; i < 0x100000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 1, 0, i); - } - for (uintptr_t i = 0x100000; i < placement_pointer + 0x3000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 1, 0, i); - } - debug_print(INFO, "Mapping VGA text-mode directly."); - for (uintptr_t j = 0xb8000; j < 0xc0000; j += 0x1000) { - dma_frame(get_page(j, 0, kernel_directory), 0, 1, j); - } - isrs_install_handler(14, page_fault); - kernel_directory->physical_address = (uintptr_t)kernel_directory->physical_tables; - - uintptr_t tmp_heap_start = KERNEL_HEAP_INIT; - - if (tmp_heap_start <= placement_pointer + 0x3000) { - debug_print(ERROR, "Foo: 0x%x, 0x%x", tmp_heap_start, placement_pointer + 0x3000); - tmp_heap_start = placement_pointer + 0x100000; - kernel_heap_alloc_point = tmp_heap_start; - } - - /* Kernel Heap Space */ - for (uintptr_t i = placement_pointer + 0x3000; i < tmp_heap_start; i += 0x1000) { - alloc_frame(get_page(i, 1, kernel_directory), 1, 0); - } - /* And preallocate the page entries for all the rest of the kernel heap as well */ - for (uintptr_t i = tmp_heap_start; i < KERNEL_HEAP_END; i += 0x1000) { - get_page(i, 1, kernel_directory); - } - for (unsigned int i = 0xE000; i <= 0xFFF0; i += 0x40) { - get_page(i << 16UL, 1, kernel_directory); - } - - debug_print(NOTICE, "Setting directory to 0x%x", kernel_directory); - current_directory = clone_directory(kernel_directory); - switch_page_directory(kernel_directory); -} - -uintptr_t map_to_physical(uintptr_t virtual) { - uintptr_t remaining = virtual % 0x1000; - uintptr_t frame = virtual / 0x1000; - uintptr_t table = frame / 1024; - uintptr_t subframe = frame % 1024; - - if (current_directory->tables[table]) { - page_t * p = ¤t_directory->tables[table]->pages[subframe]; - return p->frame * 0x1000 + remaining; - } else { - return 0; - } -} - -void debug_print_directory(page_directory_t * arg) { - page_directory_t * current_directory = arg; - debug_print(INSANE, " ---- [k:0x%x u:0x%x]", kernel_directory, current_directory); - for (uintptr_t i = 0; i < 1024; ++i) { - if (!current_directory->tables[i] || (uintptr_t)current_directory->tables[i] == (uintptr_t)0xFFFFFFFF) { - continue; - } - if (kernel_directory->tables[i] == current_directory->tables[i]) { - debug_print(INSANE, " 0x%x - kern [0x%x/0x%x] 0x%x", current_directory->tables[i], ¤t_directory->tables[i], &kernel_directory->tables[i], i * 0x1000 * 1024); - for (uint16_t j = 0; j < 1024; ++j) { -#if 1 - page_t * p= ¤t_directory->tables[i]->pages[j]; - if (p->frame) { - debug_print(INSANE, " k 0x%x 0x%x %s", (i * 1024 + j) * 0x1000, p->frame * 0x1000, p->present ? "[present]" : ""); - } -#endif - } - } else { - debug_print(INSANE, " 0x%x - user [0x%x] 0x%x [0x%x]", current_directory->tables[i], ¤t_directory->tables[i], i * 0x1000 * 1024, kernel_directory->tables[i]); - for (uint16_t j = 0; j < 1024; ++j) { -#if 1 - page_t * p= ¤t_directory->tables[i]->pages[j]; - if (p->frame) { - debug_print(INSANE, " 0x%x 0x%x %s", (i * 1024 + j) * 0x1000, p->frame * 0x1000, p->present ? "[present]" : ""); - } -#endif - } - } - } - debug_print(INFO, " ---- [done]"); -} - -void -switch_page_directory( - page_directory_t * dir - ) { - current_directory = dir; - asm volatile ( - "mov %0, %%cr3\n" - "mov %%cr0, %%eax\n" - "orl $0x80000000, %%eax\n" - "mov %%eax, %%cr0\n" - :: "r"(dir->physical_address) - : "%eax"); -} - -void invalidate_page_tables(void) { - asm volatile ( - "movl %%cr3, %%eax\n" - "movl %%eax, %%cr3\n" - ::: "%eax"); -} - -void invalidate_tables_at(uintptr_t addr) { - asm volatile ( - "movl %0,%%eax\n" - "invlpg (%%eax)\n" - :: "r"(addr) : "%eax"); -} - -page_t * -get_page( - uintptr_t address, - int make, - page_directory_t * dir - ) { - address /= 0x1000; - uint32_t table_index = address / 1024; - if (dir->tables[table_index]) { - return &dir->tables[table_index]->pages[address % 1024]; - } else if(make) { - uint32_t temp; - dir->tables[table_index] = (page_table_t *)kvmalloc_p(sizeof(page_table_t), (uintptr_t *)(&temp)); - ASSUME(dir->tables[table_index] != NULL); - memset(dir->tables[table_index], 0, sizeof(page_table_t)); - dir->physical_tables[table_index] = temp | 0x7; /* Present, R/w, User */ - return &dir->tables[table_index]->pages[address % 1024]; - } else { - return 0; - } -} - -void -page_fault( - struct regs *r) { - ASSUME(r != NULL); - uint32_t faulting_address; - asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); - - if (r->eip == SIGNAL_RETURN) { - return_from_signal_handler(); - } else if (r->eip == THREAD_RETURN) { - debug_print(INFO, "Returned from thread."); - kexit(0); - } - -#if 1 - int present = !(r->err_code & 0x1) ? 1 : 0; - int rw = r->err_code & 0x2 ? 1 : 0; - int user = r->err_code & 0x4 ? 1 : 0; - int reserved = r->err_code & 0x8 ? 1 : 0; - int id = r->err_code & 0x10 ? 1 : 0; - - debug_print(ERROR, "\033[1;37;41mSegmentation fault. (p:%d,rw:%d,user:%d,res:%d,id:%d) at 0x%x eip: 0x%x pid=%d,%d [%s]\033[0m", - present, rw, user, reserved, id, faulting_address, r->eip, current_process->id, current_process->group, current_process->name); - - if (r->eip < heap_end) { - /* find closest symbol */ - char * closest = NULL; - size_t distance = 0xFFFFFFFF; - uintptr_t addr = 0; - - if (modules_get_symbols()) { - list_t * hash_keys = hashmap_keys(modules_get_symbols()); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - uintptr_t a = (uintptr_t)hashmap_get(modules_get_symbols(), key); - - if (!a) continue; - - size_t d; - if (a <= r->eip) { - d = r->eip - a; - if (d < distance) { - closest = key; - distance = d; - addr = a; - } - } - } - free(hash_keys); - - debug_print(ERROR, "\033[1;31mClosest symbol to faulting address:\033[0m %s [0x%x]", closest, addr); - - hash_keys = hashmap_keys(modules_get_list()); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - module_data_t * m = (module_data_t *)hashmap_get(modules_get_list(), key); - - if ((r->eip >= (uintptr_t)m->bin_data) && (r->eip < m->end)) { - debug_print(ERROR, "\033[1;31mIn module:\033[0m %s (starts at 0x%x)", m->mod_info->name, m->bin_data); - break; - } - } - free(hash_keys); - - debug_print(ERROR, "User EIP: 0x%x", current_process->syscall_registers->eip); - } - - } else { - debug_print(ERROR, "\033[1;31m(In userspace)\033[0m"); - } - -#endif - - send_signal(current_process->id, SIGSEGV, 1); -} - -/* - * Heap - * Stop using kalloc and friends after installing the heap - * otherwise shit will break. I've conveniently broken - * kalloc when installing the heap, just for those of you - * who feel the need to screw up. - */ - - -void heap_install(void ) { - heap_end = (placement_pointer + 0x1000) & ~0xFFF; -} - -void * sbrk(uintptr_t increment) { - assert((increment % 0x1000 == 0) && "Kernel requested to expand heap by a non-page-multiple value"); - assert((heap_end % 0x1000 == 0) && "Kernel heap is not page-aligned!"); - assert((heap_end + increment <= KERNEL_HEAP_END - 1) && "The kernel has attempted to allocate beyond the end of its heap."); - uintptr_t address = heap_end; - - if (heap_end + increment > kernel_heap_alloc_point) { - debug_print(INFO, "Hit the end of available kernel heap, going to allocate more (at 0x%x, want to be at 0x%x)", heap_end, heap_end + increment); - for (uintptr_t i = heap_end; i < heap_end + increment; i += 0x1000) { - debug_print(INFO, "Allocating frame at 0x%x...", i); - page_t * page = get_page(i, 0, kernel_directory); - assert(page && "Kernel heap allocation fault."); - alloc_frame(page, 1, 0); - } - invalidate_page_tables(); - debug_print(INFO, "Done."); - } - - heap_end += increment; - memset((void *)address, 0x0, increment); - return (void *)address; -} - diff --git a/kernel/misc/args.c b/kernel/misc/args.c index 25d305c6..7ae89e63 100644 --- a/kernel/misc/args.c +++ b/kernel/misc/args.c @@ -1,54 +1,49 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Kernel Argument Manager +/** + * @brief Kernel commandline argument parser. * * Arguments to the kernel are provided from the bootloader and * provide information such as what mode to pass to init, or what - * hard disk partition should be mounted as root. + * hard disk partition should be mounted as root. We parse them + * into a hash table for easy lookup by key. * - * This module provides access + * @copyright This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2021 K. Lange */ -#include -#include +#include #include #include - -#include - -char * cmdline = NULL; +#include hashmap_t * kernel_args_map = NULL; /** + * @brief Determine if an argument was passed to the kernel. + * * Check if an argument was provided to the kernel. If the argument is * a simple switch, a response of 1 can be considered "on" for that * argument; otherwise, this just notes that the argument was present, * so the caller should check whether it is correctly set. */ -int args_present(char * karg) { - if (!kernel_args_map) return 0; /* derp */ - +int args_present(const char * karg) { + if (!kernel_args_map) return 0; return hashmap_has(kernel_args_map, karg); } /** - * Return the value associated with an argument provided to the kernel. + * @brief Return the value associated with an argument provided to the kernel. */ -char * args_value(char * karg) { - if (!kernel_args_map) return 0; /* derp */ - +char * args_value(const char * karg) { + if (!kernel_args_map) return 0; return hashmap_get(kernel_args_map, karg); } /** - * Parse the given arguments to the kernel. + * @brief Parse the given arguments to the kernel. * * @param arg A string containing all arguments, separated by spaces. */ -void args_parse(char * _arg) { +void args_parse(const char * _arg) { /* Sanity check... */ if (!_arg) { return; } @@ -57,7 +52,6 @@ void args_parse(char * _arg) { int argc = tokenize(arg, " ", argv); /* New let's parse the tokens into the arguments list so we can index by key */ - if (!kernel_args_map) { kernel_args_map = hashmap_create(10); } @@ -87,6 +81,5 @@ _break: } free(arg); - } diff --git a/kernel/misc/elf.c b/kernel/misc/elf.c deleted file mode 100644 index 514bd303..00000000 --- a/kernel/misc/elf.c +++ /dev/null @@ -1,335 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * ELF Static Executable Loader - * - */ - -#include -#include -#include -#include -#include - -int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) { - Elf32_Header header; - - read_fs(file, 0, sizeof(Elf32_Header), (uint8_t *)&header); - - if (header.e_ident[0] != ELFMAG0 || - header.e_ident[1] != ELFMAG1 || - header.e_ident[2] != ELFMAG2 || - header.e_ident[3] != ELFMAG3) { - debug_print(ERROR, "Not a valid ELF executable."); - close_fs(file); - return -1; - } - - if (file->mask & 0x800) { - debug_print(WARNING, "setuid binary executed [%s, uid:%d]", file->name, file->uid); - current_process->user = file->uid; - } - - for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) { - Elf32_Phdr phdr; - read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); - if (phdr.p_type == PT_DYNAMIC) { - /* Dynamic */ - close_fs(file); - - /* Find interpreter? */ - debug_print(INFO, "Dynamic executable"); - - unsigned int nargc = argc + 3; - char * args[nargc+1]; - args[0] = "ld.so"; - args[1] = "-e"; - args[2] = strdup(current_process->name); - int j = 3; - for (int i = 0; i < argc; ++i, ++j) { - args[j] = argv[i]; - } - args[j] = NULL; - - fs_node_t * file = kopen("/lib/ld.so",0); - if (!file) return -1; - - return exec_elf(NULL, file, nargc, args, env, 1); - } - } - - uintptr_t entry = (uintptr_t)header.e_entry; - uintptr_t base_addr = 0xFFFFFFFF; - uintptr_t end_addr = 0x0; - - for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) { - Elf32_Phdr phdr; - read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); - if (phdr.p_type == PT_LOAD) { - if (phdr.p_vaddr < base_addr) { - base_addr = phdr.p_vaddr; - } - if (phdr.p_memsz + phdr.p_vaddr > end_addr) { - end_addr = phdr.p_memsz + phdr.p_vaddr; - } - } - } - - current_process->image.entry = base_addr; - current_process->image.size = end_addr - base_addr; - - release_directory_for_exec(current_directory); - invalidate_page_tables(); - - - for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) { - Elf32_Phdr phdr; - read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); - if (phdr.p_type == PT_LOAD) { - /* TODO: These virtual address bounds should be in a header somewhere */ - if (phdr.p_vaddr < 0x20000000) return -EINVAL; - /* TODO Upper bounds */ - for (uintptr_t i = phdr.p_vaddr; i < phdr.p_vaddr + phdr.p_memsz; i += 0x1000) { - /* This doesn't care if we already allocated this page */ - alloc_frame(get_page(i, 1, current_directory), 0, 1); - invalidate_tables_at(i); - } - IRQ_RES; - read_fs(file, phdr.p_offset, phdr.p_filesz, (uint8_t *)phdr.p_vaddr); - IRQ_OFF; - size_t r = phdr.p_filesz; - while (r < phdr.p_memsz) { - *(char *)(phdr.p_vaddr + r) = 0; - r++; - } - } - } - - close_fs(file); - - for (uintptr_t stack_pointer = USER_STACK_BOTTOM; stack_pointer < USER_STACK_TOP; stack_pointer += 0x1000) { - alloc_frame(get_page(stack_pointer, 1, current_directory), 0, 1); - invalidate_tables_at(stack_pointer); - } - - /* Collect arguments */ - int envc = 0; - for (envc = 0; env[envc] != NULL; ++envc); - - /* Format auxv */ - Elf32_auxv auxv[] = { - {256, 0xDEADBEEF}, - {0, 0} - }; - int auxvc = 0; - for (auxvc = 0; auxv[auxvc].id != 0; ++auxvc); - auxvc++; - - uintptr_t heap = current_process->image.entry + current_process->image.size; - while (heap & 0xFFF) heap++; - alloc_frame(get_page(heap, 1, current_directory), 0, 1); - invalidate_tables_at(heap); - char ** argv_ = (char **)heap; - heap += sizeof(char *) * (argc + 1); - char ** env_ = (char **)heap; - heap += sizeof(char *) * (envc + 1); - void * auxv_ptr = (void *)heap; - heap += sizeof(Elf32_auxv) * (auxvc); - - for (int i = 0; i < argc; ++i) { - size_t size = strlen(argv[i]) * sizeof(char) + 1; - for (uintptr_t x = heap; x < heap + size + 0x1000; x += 0x1000) { - alloc_frame(get_page(x, 1, current_directory), 0, 1); - } - invalidate_tables_at(heap); - argv_[i] = (char *)heap; - memcpy((void *)heap, argv[i], size); - heap += size; - } - /* Don't forget the NULL at the end of that... */ - argv_[argc] = 0; - - for (int i = 0; i < envc; ++i) { - size_t size = strlen(env[i]) * sizeof(char) + 1; - for (uintptr_t x = heap; x < heap + size + 0x1000; x += 0x1000) { - alloc_frame(get_page(x, 1, current_directory), 0, 1); - } - invalidate_tables_at(heap); - env_[i] = (char *)heap; - memcpy((void *)heap, env[i], size); - heap += size; - } - env_[envc] = 0; - - memcpy(auxv_ptr, auxv, sizeof(Elf32_auxv) * (auxvc)); - - current_process->image.heap = heap; /* heap end */ - current_process->image.heap_actual = heap + (0x1000 - heap % 0x1000); - alloc_frame(get_page(current_process->image.heap_actual, 1, current_directory), 0, 1); - invalidate_tables_at(current_process->image.heap_actual); - current_process->image.user_stack = USER_STACK_TOP; - - current_process->image.start = entry; - - /* Close all fds >= 3 */ - for (unsigned int i = 3; i < current_process->fds->length; ++i) { - if (current_process->fds->entries[i]) { - close_fs(current_process->fds->entries[i]); - current_process->fds->entries[i] = NULL; - } - } - - /* Go go go */ - enter_user_jmp(entry, argc, argv_, USER_STACK_TOP); - - /* We should never reach this code */ - return -1; -} - -int exec_shebang(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) { - if (interp > 4) /* sounds good to me */ { - return -ELOOP; - } - /* Read MAX_LINE... */ - char tmp[100]; - read_fs(file, 0, 100, (unsigned char *)tmp); close_fs(file); - char * cmd = (char *)&tmp[2]; - if (*cmd == ' ') cmd++; /* Handle a leading space */ - char * space_or_linefeed = strpbrk(cmd, " \n"); - char * arg = NULL; - - if (!space_or_linefeed) { - debug_print(WARNING, "No space or linefeed found."); - return -ENOEXEC; - } - - if (*space_or_linefeed == ' ') { - /* Oh lovely, an argument */ - *space_or_linefeed = '\0'; - space_or_linefeed++; - arg = space_or_linefeed; - space_or_linefeed = strpbrk(space_or_linefeed, "\n"); - if (!space_or_linefeed) { - debug_print(WARNING, "Argument exceeded maximum length"); - return -ENOEXEC; - } - } - *space_or_linefeed = '\0'; - - char script[strlen(path)+1]; - memcpy(script, path, strlen(path)+1); - - unsigned int nargc = argc + (arg ? 2 : 1); - char * args[nargc + 2]; - args[0] = cmd; - args[1] = arg ? arg : script; - args[2] = arg ? script : NULL; - args[3] = NULL; - - int j = arg ? 3 : 2; - for (int i = 1; i < argc; ++i, ++j) { - args[j] = argv[i]; - } - args[j] = NULL; - - return exec(cmd, nargc, args, env, interp+1); -} - -/* Consider exposing this and making it a list so it can be extended ... */ -typedef int (*exec_func)(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp); -typedef struct { - exec_func func; - unsigned char bytes[4]; - unsigned int match; - char * name; -} exec_def_t; - -exec_def_t fmts[] = { - {exec_elf, {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3}, 4, "ELF"}, - {exec_shebang, {'#', '!', 0, 0}, 2, "#!"}, -}; - -static int matches(unsigned char * a, unsigned char * b, unsigned int len) { - for (unsigned int i = 0; i < len; ++i) { - if (a[i] != b[i]) return 0; - } - return 1; -} - -/** - * Load an execute a binary. - * - * This determines the binary type (eg., ELF binary, she-bang script, etc.) - * and then calls the appropriate underlying exec function. - * - * @param path Path to the executable to attempt to execute. - * @param argc Number of arguments (because I'm not counting for you) - * @param argv Pointer to a string of arguments - */ -int exec( - char * path, /* Path to the executable to run */ - int argc, /* Argument count (ie, /bin/echo hello world = 3) */ - char ** argv, /* Argument strings (including executable path) */ - char ** env, /* Environmen variables */ - int interp_depth - ) { - /* Open the file */ - fs_node_t * file = kopen(path,0); - if (!file) { - /* Command not found */ - return -ENOENT; - } - - if (!has_permission(file, 01)) { - return -EACCES; - } - - /* Read four bytes of the file */ - unsigned char head[4]; - read_fs(file, 0, 4, head); - - debug_print(INFO, "First four bytes: %c%c%c%c", head[0], head[1], head[2], head[3]); - - current_process->name = strdup(path); - gettimeofday((struct timeval *)¤t_process->start, NULL); - - for (unsigned int i = 0; i < sizeof(fmts) / sizeof(exec_def_t); ++i) { - if (matches(fmts[i].bytes, head, fmts[i].match)) { - debug_print(NOTICE, "Matched executor: %s", fmts[i].name); - return fmts[i].func(path, file, argc, argv, env, interp_depth); - } - } - - debug_print(WARNING, "Exec failed?"); - return -ENOEXEC; -} - - -int -system( - char * path, /* Path to the executable to run */ - int argc, /* Argument count (ie, /bin/echo hello world = 3) */ - char ** argv, /* Argument strings (including executable path) */ - char ** envin - ) { - char ** argv_ = malloc(sizeof(char *) * (argc + 1)); - for (int j = 0; j < argc; ++j) { - argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char)); - memcpy(argv_[j], argv[j], strlen(argv[j]) + 1); - } - argv_[argc] = 0; - char * env[] = {NULL}; - set_process_environment((process_t*)current_process, clone_directory(current_directory)); - current_directory = current_process->thread.page_directory; - switch_page_directory(current_directory); - - current_process->cmdline = argv_; - - exec(path,argc,argv_,envin ? envin : env, 0); - debug_print(ERROR, "Failed to execute process!"); - kexit(-1); - return -1; -} - diff --git a/kernel/misc/elf64.c b/kernel/misc/elf64.c new file mode 100644 index 00000000..6fe4a363 --- /dev/null +++ b/kernel/misc/elf64.c @@ -0,0 +1,233 @@ +/** + * @file kernel/misc/elf64.c + * @brief Elf64 parsing tools for modules and static userspace binaries. + * + * Provides exec() for Elf64 binaries. Note that the loader only directly + * loads static binaries; for dynamic binaries, the requested interpreter + * is loaded, which should generally be /lib/ld.so, which should itself + * be a static binary. This loader is platform-generic. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static Elf64_Shdr * elf_getSection(Elf64_Header * this, Elf64_Word index) { + return (Elf64_Shdr*)((uintptr_t)this + this->e_shoff + index * this->e_shentsize); +} + +void elf_parseModuleFromMemory(void * atAddress) { + struct Elf64_Header * elfHeader = atAddress; + + if (elfHeader->e_ident[0] != ELFMAG0 || + elfHeader->e_ident[1] != ELFMAG1 || + elfHeader->e_ident[2] != ELFMAG2 || + elfHeader->e_ident[3] != ELFMAG3) { + printf("(Not an elf)\n"); + return; + } + if (elfHeader->e_ident[EI_CLASS] != ELFCLASS64) { + printf("(Wrong Elf class)\n"); + return; + } + if (elfHeader->e_type != ET_REL) { + printf("(Not a relocatable object)\n"); + return; + } + + /** + * In order to load a module, we need to link it as an object + * into the running kernel using the symbol table we integrated + * into our binary. + */ + //char * shrstrtab = (char*)elfHeader + elf_getSection(elfHeader, elfHeader->e_shstrndx)->sh_offset; + + /** + * First, we're going to check sections and update their addresses. + */ + for (unsigned int i = 0; i < elfHeader->e_shnum; ++i) { + Elf64_Shdr * shdr = elf_getSection(elfHeader, i); + if (shdr->sh_type == SHT_NOBITS) { + if (shdr->sh_size) { + printf("Warning: Module needs %lu bytes for BSS, we don't have an allocator.\n", + shdr->sh_size); + } + /* otherwise, skip bss */ + } else { + shdr->sh_addr = (uintptr_t)atAddress + shdr->sh_offset; + } + } +} + +int elf_exec(const char * path, fs_node_t * file, int argc, const char *const argv[], const char *const env[], int interp) { + Elf64_Header header; + + read_fs(file, 0, sizeof(Elf64_Header), (uint8_t*)&header); + + if (header.e_ident[0] != ELFMAG0 || + header.e_ident[1] != ELFMAG1 || + header.e_ident[2] != ELFMAG2 || + header.e_ident[3] != ELFMAG3) { + printf("Invalid file: Bad header.\n"); + close_fs(file); + return -EINVAL; + } + + if (header.e_ident[EI_CLASS] != ELFCLASS64) { + printf("(Wrong Elf class)\n"); + return -EINVAL; + } + + /* This loader can only handle basic executables. */ + if (header.e_type != ET_EXEC) { + printf("(Not an executable)\n"); + /* TODO: what about DYN? */ + return -EINVAL; + } + + if (file->mask & 0x800) { + /* setuid */ + this_core->current_process->user = file->uid; + } + + /* First check if it is dynamic and needs an interpreter */ + for (int i = 0; i < header.e_phnum; ++i) { + Elf64_Phdr phdr; + read_fs(file, header.e_phoff + header.e_phentsize * i, sizeof(Elf64_Phdr), (uint8_t*)&phdr); + if (phdr.p_type == PT_DYNAMIC) { + close_fs(file); + unsigned int nargc = argc + 3; + const char * args[nargc+1]; /* oh yeah, great, a stack-allocated dynamic array... wonderful... */ + args[0] = "ld.so"; + args[1] = "-e"; + args[2] = strdup(this_core->current_process->name); + int j = 3; + for (int i = 0; i < argc; ++i, ++j) { + args[j] = argv[i]; + } + args[j] = NULL; + fs_node_t * file = kopen("/lib/ld.so",0); /* FIXME PT_INTERP value */ + if (!file) return -EINVAL; + return elf_exec(NULL, file, nargc, args, env, 1); + } + } + + uintptr_t execBase = -1; + uintptr_t heapBase = 0; + + mmu_set_directory(NULL); + process_release_directory(this_core->current_process->thread.page_directory); + this_core->current_process->thread.page_directory = malloc(sizeof(page_directory_t)); + this_core->current_process->thread.page_directory->refcount = 1; + spin_init(this_core->current_process->thread.page_directory->lock); + this_core->current_process->thread.page_directory->directory = mmu_clone(NULL); + mmu_set_directory(this_core->current_process->thread.page_directory->directory); + + for (int i = 0; i < header.e_phnum; ++i) { + Elf64_Phdr phdr; + read_fs(file, header.e_phoff + header.e_phentsize * i, sizeof(Elf64_Phdr), (uint8_t*)&phdr); + if (phdr.p_type == PT_LOAD) { + for (uintptr_t i = phdr.p_vaddr; i < phdr.p_vaddr + phdr.p_memsz; i += 0x1000) { + union PML * page = mmu_get_page(i, MMU_GET_MAKE); + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(i); + } + + read_fs(file, phdr.p_offset, phdr.p_filesz, (void*)phdr.p_vaddr); + for (size_t i = phdr.p_filesz; i < phdr.p_memsz; ++i) { + *(char*)(phdr.p_vaddr + i) = 0; + } + + if (phdr.p_vaddr + phdr.p_memsz > heapBase) { + heapBase = phdr.p_vaddr + phdr.p_memsz; + } + + if (phdr.p_vaddr < execBase) { + execBase = phdr.p_vaddr; + } + } + /* TODO: Should also be setting up TLS PHDRs. */ + } + + this_core->current_process->image.heap = (heapBase + 0xFFF) & (~0xFFF); + this_core->current_process->image.entry = header.e_entry; + + close_fs(file); + + // arch_set_...? + + /* Map stack space */ + uintptr_t userstack = 0x800000000000; + for (uintptr_t i = userstack - 64 * 0x400; i < userstack; i += 0x1000) { + union PML * page = mmu_get_page(i, MMU_GET_MAKE); + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(i); + } +#define PUSH(type,val) do { \ + userstack -= sizeof(type); \ + while (userstack & (sizeof(type)-1)) userstack--; \ + *((type*)userstack) = (val); \ +} while (0) +#define PUSHSTR(s) do { \ + ssize_t l = strlen(s); \ + do { \ + PUSH(char,s[l]); \ + l--; \ + } while (l>=0); \ +} while (0) + + /* XXX This should probably be done backwards so we can be + * sure that we're aligning the stack properly. It + * doesn't matter too much as our crt0+libc align it + * correctly for us and environ + auxv detection is + * based on the addresses of argv, not the actual + * stack pointer, but it's still weird. */ + char * argv_ptrs[argc]; + for (int i = 0; i < argc; ++i) { + PUSHSTR(argv[i]); + argv_ptrs[i] = (char*)userstack; + } + + /* Now push envp */ + int envc = 0; + char ** envpp = (char**)env; + while (*envpp) { + envc++; + envpp++; + } + char * envp_ptrs[envc]; + for (int i = 0; i < envc; ++i) { + PUSHSTR(env[i]); + envp_ptrs[i] = (char*)userstack; + } + + PUSH(uintptr_t, 0); + PUSH(uintptr_t, this_core->current_process->user); + PUSH(uintptr_t, 11); /* AT_UID */ + PUSH(uintptr_t, this_core->current_process->real_user); + PUSH(uintptr_t, 12); /* AT_EUID */ + PUSH(uintptr_t, 0); + + PUSH(uintptr_t, 0); /* envp NULL */ + for (int i = envc; i > 0; i--) { + PUSH(char*,envp_ptrs[i-1]); + } + char ** _envp = (char**)userstack; + PUSH(uintptr_t, 0); /* argv NULL */ + for (int i = argc; i > 0; i--) { + PUSH(char*,argv_ptrs[i-1]); + } + char ** _argv = (char**)userstack; + PUSH(uintptr_t, argc); + + arch_set_kernel_stack(this_core->current_process->image.stack); + arch_enter_user(header.e_entry, argc, _argv, _envp, userstack); + + return -EINVAL; +} diff --git a/kernel/misc/fbterm.c b/kernel/misc/fbterm.c new file mode 100644 index 00000000..5e492566 --- /dev/null +++ b/kernel/misc/fbterm.c @@ -0,0 +1,252 @@ +/** + * @file kernel/misc/fbterm.c + * @brief Crude framebuffer terminal for 32bpp framebuffer devices. + * @author K. Lange + * + * Provides a simple graphical text renderer for early startup, with + * support for simple escape sequences, on top of a framebuffer set up + * with the `lfbvideo` module. + */ +#include +#include +#include + +/* Exported cell sizing */ +size_t fbterm_width = 0; +size_t fbterm_height = 0; + +/* Whether to scroll or wrap when cursor reaches the bottom. */ +static int fbterm_scroll = 0; + +/* Is this in a header somewhere? */ +extern uint8_t * lfb_vid_memory; +extern uint16_t lfb_resolution_x; +extern uint16_t lfb_resolution_y; +extern uint16_t lfb_resolution_b; +extern uint32_t lfb_resolution_s; +extern size_t lfb_memsize; + +/* Bitmap font details */ +#include "../../apps/terminal-font.h" +#define char_height 20 +#define char_width 9 + +/* Default colors */ +#define BG_COLOR 0xFF050505 /* Background */ +#define FG_COLOR 0xFFCCCCCC /* Main text color */ + +static uint32_t fg_color = FG_COLOR; +static uint32_t bg_color = BG_COLOR; + +static void set_point(int x, int y, uint32_t value) { + ((uint32_t*)lfb_vid_memory)[y * lfb_resolution_x + x] = value; +} + +static void write_char(int x, int y, int val, uint32_t color) { + if (val > 128) { + val = 4; + } + uint16_t * c = large_font[val]; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + if (c[i] & (1 << (15-j))) { + set_point(x+j,y+i,color); + } else { + set_point(x+j,y+i,bg_color); + } + } + } +} + +/* We push text in one pixel, which unfortunately means we have slightly less room, + * but it also means the text doesn't run right into the left and right edges which + * just looks kinda bad. */ +#define LEFT_PAD 1 +static int x = LEFT_PAD; +static int y = 0; + +/** + * @brief Basic 16-color ANSI palette with Tango colors. + */ +static uint32_t term_colors[] = { + 0xFF000000, + 0xFFCC0000, + 0xFF4E9A06, + 0xFFC4A000, + 0xFF3465A4, + 0xFF75507B, + 0xFF06989A, + 0xFFD3D7CF, + + 0xFF555753, + 0xFFEF2929, + 0xFF8AE234, + 0xFFFCE94F, + 0xFF729FCF, + 0xFFAD7FA8, + 0xFF34E2E2, + 0xFFEEEEEC, +}; + +static int term_state = 0; +static char term_buf[1024] = {0}; +static int term_buf_c = 0; + +static void invert_at(int x, int y) { + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + uint32_t current = ((uint32_t*)lfb_vid_memory)[(y+i) * lfb_resolution_x + (x+j)]; + uint8_t r = (current >> 16) & 0xFF; + uint8_t g = (current >> 8) & 0xFF; + uint8_t b = (current) & 0xFF; + current = 0xFF000000 | ((0xFF-r) << 16) | ((0xFF-g) << 8) | ((0xFF-b)); + ((uint32_t*)lfb_vid_memory)[(y+i) * lfb_resolution_x + (x+j)] = current; + } + } +} + +static void process_char(char ch) { + if (term_state == 1) { + if (ch == '[') { + term_buf_c = 0; + term_buf[term_buf_c] = '\0'; + term_state = 2; + } else { + term_state = 0; + process_char(ch); + } + return; + } else if (term_state == 2) { + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { + /* do the thing */ + switch (ch) { + case 'm': { + char * arg = &term_buf[0]; + char * next; + int argC = 0; + int isBold = 0; + do { + next = strchr(arg, ';'); + if (next) { *next = '\0'; next++; } + int asInt = atoi(arg); + if (asInt == 0) { + fg_color = FG_COLOR; + bg_color = BG_COLOR; + isBold = 0; + } else if (asInt == 1) { + isBold = 1; + } else if (asInt == 22) { + fg_color = FG_COLOR; + isBold = 0; + } else if (asInt >= 30 && asInt <= 37) { + fg_color = term_colors[asInt-30 + (isBold ? 8 : 0)]; + } else if (asInt >= 90 && asInt <= 97) { + fg_color = term_colors[asInt-90 + 8]; + } else if (asInt >= 40 && asInt <= 47) { + bg_color = term_colors[asInt-40 + (isBold ? 8 : 0)]; + } else if (asInt >= 100 && asInt <= 107) { + bg_color = term_colors[asInt-100 + 8]; + } else if (asInt == 38) { + fg_color = FG_COLOR; + } else if (asInt == 48) { + bg_color = BG_COLOR; + } else if (asInt == 7) { + uint32_t tmp = fg_color; + fg_color = bg_color; + bg_color = tmp; + } + arg = next; + argC++; + } while (arg); + break; + } + case 'G': { + /* Set cursor column */ + invert_at(x,y); + x = LEFT_PAD + (atoi(term_buf) - 1) * char_width; + invert_at(x,y); + break; + } + case 'K': { + if (atoi(term_buf) == 0) { + for (int j = y; j < y + char_height; ++j) { + for (int i = x; i < lfb_resolution_x; ++i) { + set_point(i,j,bg_color); + } + } + invert_at(x,y); + } + break; + } + } + term_state = 0; + } else { + term_buf[term_buf_c++] = ch; + term_buf[term_buf_c] = '\0'; + } + return; + } else if (ch == '\033') { + term_state = 1; + return; + } + + write_char(x,y,' ',bg_color); + switch (ch) { + case '\n': + x = LEFT_PAD; + y += char_height; + break; + case '\r': + x = LEFT_PAD; + break; + case '\b': + if (x > LEFT_PAD) { + x -= char_width; + write_char(x,y,' ',fg_color); + } + break; + default: + if ((unsigned int)ch > 127) return; + write_char(x,y,ch,fg_color); + x += char_width; + break; + } + if (x > lfb_resolution_x) { + y += char_height; + x = LEFT_PAD; + } + if (y > lfb_resolution_y - char_height) { + if (fbterm_scroll) { + y -= char_height; + memmove(lfb_vid_memory, lfb_vid_memory + sizeof(uint32_t) * lfb_resolution_x * char_height, (lfb_resolution_y - char_height) * lfb_resolution_x * 4); + memset(lfb_vid_memory + sizeof(uint32_t) * (lfb_resolution_y - char_height) * lfb_resolution_x, 0x05, char_height * lfb_resolution_x * 4); + } else { + y = 0; + } + } + invert_at(x,y); +} + +static size_t (*previous_writer)(size_t,uint8_t*) = NULL; + +size_t fbterm_write(size_t size, uint8_t *buffer) { + if (!buffer) return 0; + for (unsigned int i = 0; i < size; ++i) { + process_char(buffer[i]); + } + if (previous_writer) previous_writer(size,buffer); + return size; +} + +void fbterm_initialize(void) { + memset(lfb_vid_memory, 0x05, lfb_resolution_x * lfb_resolution_y * 4); + + if (args_present("fbterm-scroll")) { + fbterm_scroll = 1; + } + + fbterm_width = (lfb_resolution_x - LEFT_PAD) / char_width; + fbterm_height = (lfb_resolution_y) / char_height; + previous_writer = printf_output; + printf_output = fbterm_write; +} diff --git a/kernel/misc/gzip.c b/kernel/misc/gzip.c new file mode 100644 index 00000000..bcabd38c --- /dev/null +++ b/kernel/misc/gzip.c @@ -0,0 +1,490 @@ +/** + * @file kernel/misc/gzip.c + * @brief Gzip/DEFLATE decompression. + * + * Provides decompression for ramdisks. + * Based on the same approach to DEFLATE decompression as libraries + * like "tinf", this is a slow-but-simple implementation of Huffman + * decoding. The kernel version operates directly on two pointers, + * @c gzip_inputPtr and @c gzip_outputPtr. For a more robust API, + * see the userspace version. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2020-2021 K. Lange + */ +#include +#include + +static uint8_t bit_buffer = 0; +static char buffer_size = 0; + +uint8_t * gzip_inputPtr = NULL; +uint8_t * gzip_outputPtr = NULL; + +__attribute__((always_inline)) +static inline uint8_t read_byte(void) { + return *gzip_inputPtr++; +} + +__attribute__((always_inline)) +static inline void _write(unsigned int sym) { + *gzip_outputPtr++ = sym; +} + +/** + * Decoded Huffman table + */ +struct huff { + uint16_t counts[16]; /* Number of symbols of each length */ + uint16_t symbols[288]; /* Ordered symbols */ +}; + +/** + * Fixed Huffman code tables, generated later. + */ +struct huff fixed_lengths; +struct huff fixed_dists; + +/** + * Read a little-endian short from the input. + */ +static uint16_t read_16le(void) { + uint16_t a, b; + a = read_byte(); + b = read_byte(); + return (a << 0) | (b << 8); +} + +/** + * Read a single bit from the source. + * Fills the byte buffer with one byte when it runs out. + */ +static _Bool read_bit(void) { + + /* When we run out of bits... */ + if (buffer_size == 0) { + /* Refill from the next input byte */ + bit_buffer = read_byte(); + /* And restore bit buffer size to 8 bits */ + buffer_size = 8; + } + + /* Get the next available bit */ + int out = bit_buffer & 1; + + /* Shift the bit buffer forward */ + bit_buffer >>= 1; + + /* There is now one less bit available */ + buffer_size--; + + return out; +} + +/** + * Read multible bits, in bit order, from the source. + */ +static uint32_t read_bits(unsigned int count) { + uint32_t out = 0; + for (unsigned int bit = 0; bit < count; bit++) { + /* Read one bit at a time, from least to most significant */ + out |= (read_bit() << bit); + } + return out; +} + +/** + * Build a Huffman table from an array of lengths. + */ +static void build_huffman(uint8_t * lengths, size_t size, struct huff * out) { + + uint16_t offsets[16]; + unsigned int count = 0; + + /* Zero symbol counts */ + for (unsigned int i = 0; i < 16; ++i) out->counts[i] = 0; + + /* Count symbols */ + for (unsigned int i = 0; i < size; ++i) out->counts[lengths[i]]++; + + /* Special case... */ + out->counts[0] = 0; + + /* Figure out offsets */ + for (unsigned int i = 0; i < 16; ++i) { + offsets[i] = count; + count += out->counts[i]; + } + + /* Build symbol ordering */ + for (unsigned int i = 0; i < size; ++i) { + if (lengths[i]) out->symbols[offsets[lengths[i]]++] = i; + } +} + +/** + * Build the fixed Huffman tables + */ +static void build_fixed(void) { + /* From 3.2.6: + * Lit Value Bits Codes + * --------- ---- ----- + * 0 - 143 8 00110000 through + * 10111111 + * 144 - 255 9 110010000 through + * 111111111 + * 256 - 279 7 0000000 through + * 0010111 + * 280 - 287 8 11000000 through + * 11000111 + */ + uint8_t lengths[288]; + for (int i = 0; i < 144; ++i) lengths[i] = 8; + for (int i = 144; i < 256; ++i) lengths[i] = 9; + for (int i = 256; i < 280; ++i) lengths[i] = 7; + for (int i = 280; i < 288; ++i) lengths[i] = 8; + build_huffman(lengths, 288, &fixed_lengths); + + /* Continued from 3.2.6: + * Distance codes 0-31 are represented by (fixed-length) 5-bit + * codes, with possible additional bits as shown in the table + * shown in Paragraph 3.2.5, above. Note that distance codes 30- + * 31 will never actually occur in the compressed data. + */ + for (int i = 0; i < 30; ++i) lengths[i] = 5; + build_huffman(lengths, 30, &fixed_dists); +} + + +/** + * Decode a symbol from the source using a Huffman table. + */ +static int decode(struct huff * huff) { + int count = 0, cur = 0; + for (int i = 1; cur >= 0; i++) { + cur = (cur << 1) | read_bit(); /* Shift */ + count += huff->counts[i]; + cur -= huff->counts[i]; + } + return huff->symbols[count + cur]; +} + +struct huff_ring { + size_t pointer; + uint8_t data[32768]; +}; + +static struct huff_ring data = {0, {0}}; + +/** + * Emit one byte to the output, maintaining the ringbuffer. + * The ringbuffer ensures we can always look back 32K bytes + * while keeping output streaming. + */ +static void emit(unsigned char byte) { + data.data[data.pointer++] = byte; + data.pointer &= 0x7FFF; + _write(byte); +} + +/** + * Look backwards in the output ring buffer. + */ +static void peek(unsigned int offset) { + data.data[data.pointer] = data.data[(data.pointer + 0x8000 - offset) & 0x7FFF]; + _write(data.data[data.pointer++]); + data.pointer &= 0x7FFF; +} + +/** + * Decompress a block of Huffman-encoded data. + */ +static int inflate(struct huff * huff_len, struct huff * huff_dist) { + + /* These are the extra bits for lengths from the tables in section 3.2.5 + * Extra Extra Extra + * Code Bits Length(s) Code Bits Lengths Code Bits Length(s) + * ---- ---- ------ ---- ---- ------- ---- ---- ------- + * 257 0 3 267 1 15,16 277 4 67-82 + * 258 0 4 268 1 17,18 278 4 83-98 + * 259 0 5 269 2 19-22 279 4 99-114 + * 260 0 6 270 2 23-26 280 4 115-130 + * 261 0 7 271 2 27-30 281 5 131-162 + * 262 0 8 272 2 31-34 282 5 163-194 + * 263 0 9 273 3 35-42 283 5 195-226 + * 264 0 10 274 3 43-50 284 5 227-257 + * 265 1 11,12 275 3 51-58 285 0 258 + * 266 1 13,14 276 3 59-66 + */ + static const uint16_t lens[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, + 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 + }; + static const uint16_t lext[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, + 4, 5, 5, 5, 5, 0 + }; + + /* Extra bits for distances.... + * Extra Extra Extra + * Code Bits Dist Code Bits Dist Code Bits Distance + * ---- ---- ---- ---- ---- ------ ---- ---- -------- + * 0 0 1 10 4 33-48 20 9 1025-1536 + * 1 0 2 11 4 49-64 21 9 1537-2048 + * 2 0 3 12 5 65-96 22 10 2049-3072 + * 3 0 4 13 5 97-128 23 10 3073-4096 + * 4 1 5,6 14 6 129-192 24 11 4097-6144 + * 5 1 7,8 15 6 193-256 25 11 6145-8192 + * 6 2 9-12 16 7 257-384 26 12 8193-12288 + * 7 2 13-16 17 7 385-512 27 12 12289-16384 + * 8 3 17-24 18 8 513-768 28 13 16385-24576 + * 9 3 25-32 19 8 769-1024 29 13 24577-32768 + */ + static const uint16_t dists[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, + 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 + }; + static const uint16_t dext[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13 + }; + + while (1) { + unsigned int symbol = decode(huff_len); + if (symbol < 256) { + emit(symbol); + } else if (symbol == 256) { + /* "The literal/length symbol 256 (end of data), ..." */ + break; + } else { + unsigned int length, distance, offset; + symbol -= 257; + length = read_bits(lext[symbol]) + lens[symbol]; + distance = decode(huff_dist); + offset = read_bits(dext[distance]) + dists[distance]; + for (unsigned int i = 0; i < length; ++i) { + peek(offset); + } + } + } + + return 0; +} + +/** + * Decode a dynamic Huffman block. + */ +static void decode_huffman(void) { + + /* Ordering of code length codes: + * (HCLEN + 4) x 3 bits: code lengths for the code length + * alphabet given just above, in the order: ... + */ + static const uint8_t clens[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + + unsigned int literals, distances, clengths; + uint8_t lengths[320] = {0}; + + literals = 257 + read_bits(5); /* 5 Bits: HLIT ... 257 */ + distances = 1 + read_bits(5); /* 5 Bits: HDIST ... 1 */ + clengths = 4 + read_bits(4); /* 4 Bits: HCLEN ... 4 */ + + /* (HCLEN + 4) x 3 bits... */ + for (unsigned int i = 0; i < clengths; ++i) { + lengths[clens[i]] = read_bits(3); + } + + struct huff codes; + build_huffman(lengths, 19, &codes); + + /* Decode symbols: + * HLIT + 257 code lengths for the literal/length alphabet... + * HDIST + 1 code lengths for the distance alphabet... + */ + unsigned int count = 0; + while (count < literals + distances) { + int symbol = decode(&codes); + int rep = 0, length; + switch (symbol) { + case 16: + /* 16: Copy the previous code length 3-6 times */ + rep = lengths[count-1]; + length = read_bits(2) + 3; /* The next 2 bits indicate repeat length */ + break; + case 17: + /* Repeat a code length of 0 for 3 - 10 times */ + length = read_bits(3) + 3; /* 3 bits of length */ + break; + case 18: + /* Repeat a code length of 0 for 11 - 138 times */ + length = read_bits(7) + 11; /* 7 bits of length */ + break; + default: + length = 1; + rep = symbol; + break; + } + while (length--) { + lengths[count++] = rep; + } + } + + /* Build tables from lenghts decoded above */ + struct huff huff_len; + build_huffman(lengths, literals, &huff_len); + struct huff huff_dist; + build_huffman(lengths + literals, distances, &huff_dist); + + inflate(&huff_len, &huff_dist); +} + +/** + * Decode an uncompressed block. + */ +static int uncompressed(void) { + /* Reset byte alignment */ + bit_buffer = 0; + buffer_size = 0; + + /* "The rest of the block consists of the following information:" + * 0 1 2 3 4... + * +---+---+---+---+================================+ + * | LEN | NLEN |... LEN bytes of literal data...| + * +---+---+---+---+================================+ + */ + uint16_t len = read_16le(); /* "the number of data bytes in the block" */ + uint16_t nlen = read_16le(); /* "the one's complement of LEN */ + + /* Sanity check - does the ones-complement length actually match? */ + if ((nlen & 0xFFFF) != (~len & 0xFFFF)) { + return 1; + } + + /* Emit LEN bytes from the source to the output */ + for (int i = 0; i < len; ++i) { + emit(read_byte()); + } + + return 0; +} + +/** + * Decompress DEFLATE-compressed data. + */ +__attribute__((optimize("O2"))) +__attribute__((hot)) +int deflate_decompress(void) { + bit_buffer = 0; + buffer_size = 0; + + build_fixed(); + + /* read compressed data */ + while (1) { + /* Read bit */ + + int is_final = read_bit(); + int type = read_bits(2); + + switch (type) { + case 0x00: /* BTYPE=00 Non-compressed blocks */ + uncompressed(); + break; + case 0x01: /* BYTPE=01 Compressed with fixed Huffman codes */ + inflate(&fixed_lengths, &fixed_dists); + break; + case 0x02: /* BTYPE=02 Compression with dynamic Huffman codes */ + decode_huffman(); + break; + case 0x03: + return 1; + default: + __builtin_unreachable(); + break; + } + + if (is_final) { + break; + } + } + + return 0; +} + +#define GZIP_FLAG_TEXT (1 << 0) +#define GZIP_FLAG_HCRC (1 << 1) +#define GZIP_FLAG_EXTR (1 << 2) +#define GZIP_FLAG_NAME (1 << 3) +#define GZIP_FLAG_COMM (1 << 4) + +static unsigned int read_32le(void) { + unsigned int a, b, c, d; + a = read_byte(); + b = read_byte(); + c = read_byte(); + d = read_byte(); + + return (d << 24) | (c << 16) | (b << 8) | (a << 0); +} + +int gzip_decompress(void) { + + /* Read gzip headers */ + if (read_byte() != 0x1F) return 1; + if (read_byte() != 0x8B) return 1; + + unsigned int cm = read_byte(); + if (cm != 8) return 1; + + unsigned int flags = read_byte(); + + /* Read mtime */ + unsigned int mtime = read_32le(); + (void)mtime; + + /* Read extra flags */ + unsigned int xflags = read_byte(); + (void)xflags; + + /* Read and discord OS flag */ + unsigned int os = read_byte(); + (void)os; + + /* Extra bytes */ + if (flags & GZIP_FLAG_EXTR) { + unsigned short size = read_16le(); + for (unsigned int i = 0; i < size; ++i) read_byte(); + } + + if (flags & GZIP_FLAG_NAME) { + unsigned int c; + while ((c = read_byte()) != 0); + } + + if (flags & GZIP_FLAG_COMM) { + unsigned int c; + while ((c = read_byte()) != 0); + } + + unsigned int crc16 = 0; + if (flags & GZIP_FLAG_HCRC) { + crc16 = read_16le(); + } + (void)crc16; + + int status = deflate_decompress(); + + /* Read CRC and decompressed size from end of input */ + unsigned int crc32 = read_32le(); + unsigned int dsize = read_32le(); + + (void)crc32; + (void)dsize; + + return status; +} + diff --git a/kernel/misc/hashmap.c b/kernel/misc/hashmap.c new file mode 100644 index 00000000..65e18782 --- /dev/null +++ b/kernel/misc/hashmap.c @@ -0,0 +1,230 @@ +/** + * @brief Flexible mapping container. + * @author K. Lange + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2021 K. Lange + */ +#include +#include +#include + +unsigned int hashmap_string_hash(const void * _key) { + unsigned int hash = 0; + char * key = (char *)_key; + int c; + /* This is the so-called "sdbm" hash. It comes from a piece of + * public domain code from a clone of ndbm. */ + while ((c = *key++)) { + hash = c + (hash << 6) + (hash << 16) - hash; + } + return hash; +} + +int hashmap_string_comp(const void * a, const void * b) { + return !strcmp(a,b); +} + +void * hashmap_string_dupe(const void * key) { + return strdup(key); +} + +unsigned int hashmap_int_hash(const void * key) { + return (intptr_t)key; +} + +int hashmap_int_comp(const void * a, const void * b) { + return (intptr_t)a == (intptr_t)b; +} + +void * hashmap_int_dupe(const void * key) { + return (void*)key; +} + +static void hashmap_int_free(void * ptr) { + (void)ptr; + return; +} + + +hashmap_t * hashmap_create(int size) { + hashmap_t * map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_string_hash; + map->hash_comp = &hashmap_string_comp; + map->hash_key_dup = &hashmap_string_dupe; + map->hash_key_free = &free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); + + return map; +} + +hashmap_t * hashmap_create_int(int size) { + hashmap_t * map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_int_hash; + map->hash_comp = &hashmap_int_comp; + map->hash_key_dup = &hashmap_int_dupe; + map->hash_key_free = &hashmap_int_free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); + + return map; +} + +void * hashmap_set(hashmap_t * map, const void * key, void * value) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + map->entries[hash] = e; + return NULL; + } else { + hashmap_entry_t * p = NULL; + do { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + x->value = value; + return out; + } else { + p = x; + x = x->next; + } + } while (x); + hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + + p->next = e; + return NULL; + } +} + +void * hashmap_get(hashmap_t * map, const void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return NULL; + } else { + do { + if (map->hash_comp(x->key, key)) { + return x->value; + } + x = x->next; + } while (x); + return NULL; + } +} + +void * hashmap_remove(hashmap_t * map, const void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return NULL; + } else { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + map->entries[hash] = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + return out; + } else { + hashmap_entry_t * p = x; + x = x->next; + do { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + p->next = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + return out; + } + p = x; + x = x->next; + } while (x); + } + return NULL; + } +} + +int hashmap_has(hashmap_t * map, const void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return 0; + } else { + do { + if (map->hash_comp(x->key, key)) { + return 1; + } + x = x->next; + } while (x); + return 0; + } + +} + +list_t * hashmap_keys(hashmap_t * map) { + list_t * l = list_create("hashmap keys",map); + + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i]; + while (x) { + list_insert(l, x->key); + x = x->next; + } + } + + return l; +} + +list_t * hashmap_values(hashmap_t * map) { + list_t * l = list_create("hashmap values",map); + + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i]; + while (x) { + list_insert(l, x->value); + x = x->next; + } + } + + return l; +} + +void hashmap_free(hashmap_t * map) { + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i], * p; + while (x) { + p = x; + x = x->next; + map->hash_key_free(p->key); + map->hash_val_free(p); + } + } + free(map->entries); +} + +int hashmap_is_empty(hashmap_t * map) { + for (unsigned int i = 0; i < map->size; ++i) { + if (map->entries[i]) return 0; + } + return 1; +} diff --git a/kernel/misc/kprintf.c b/kernel/misc/kprintf.c index de31b2a5..004bc297 100644 --- a/kernel/misc/kprintf.c +++ b/kernel/misc/kprintf.c @@ -1,159 +1,370 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kprintf.c + * @brief Kernel printf implementation. + * + * This is the newer, 64-bit-friendly printf originally implemented + * for EFI builds of Kuroko. It was merged into the ToaruOS libc + * and later became the kernel printf in Misaka. It supports the + * standard set of width specifiers, '0' or ' ' padding, left or + * right alignment, and the usermode version has a (rudimentary, + * inaccurate) floating point printer. This kernel version excludes + * float support. printf output is passed to callback functions + * which can write the output to a string buffer or spit them + * directly at an MMIO port. Support is also present for bounded + * writes, and we've left @c sprintf out of the kernel entirely + * in favor of @c snprintf. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Kernel printf implementation - * - * Simple, painfully lacking, implementation of printf(), - * for the kernel of all things. + * Copyright (C) 2011-2021 K. Lange */ -#include -#include -#include +#include +#include +#include -#include +size_t (*printf_output)(size_t, uint8_t *) = NULL; -/* - * Integer to string - */ -static void print_dec(unsigned int value, unsigned int width, char * buf, int * ptr ) { - unsigned int n_width = 1; - unsigned int i = 9; - while (value > i && i < UINT32_MAX) { - n_width += 1; - i *= 10; - i += 9; +#define OUT(c) do { callback(userData, (c)); written++; } while (0) +static size_t print_dec(unsigned long long value, unsigned int width, int (*callback)(void*,char), void * userData, int fill_zero, int align_right, int precision) { + size_t written = 0; + unsigned long long n_width = 1; + unsigned long long i = 9; + if (precision == -1) precision = 1; + + if (value == 0) { + n_width = 0; + } else { + unsigned long long val = value; + while (val >= 10UL) { + val /= 10UL; + n_width++; + } } + if (n_width < (unsigned long long)precision) n_width = precision; + int printed = 0; - while (n_width + printed < width) { - buf[*ptr] = '0'; - *ptr += 1; - printed += 1; + if (align_right) { + while (n_width + printed < width) { + OUT(fill_zero ? '0' : ' '); + printed += 1; + } + + i = n_width; + char tmp[100]; + while (i > 0) { + unsigned long long n = value / 10; + long long r = value % 10; + tmp[i - 1] = r + '0'; + i--; + value = n; + } + while (i < n_width) { + OUT(tmp[i]); + i++; + } + } else { + i = n_width; + char tmp[100]; + while (i > 0) { + unsigned long long n = value / 10; + long long r = value % 10; + tmp[i - 1] = r + '0'; + i--; + value = n; + printed++; + } + while (i < n_width) { + OUT(tmp[i]); + i++; + } + while (printed < (long long)width) { + OUT(fill_zero ? '0' : ' '); + printed += 1; + } } - i = n_width; - while (i > 0) { - unsigned int n = value / 10; - int r = value % 10; - buf[*ptr + i - 1] = r + '0'; - i--; - value = n; - } - *ptr += n_width; + return written; } /* * Hexadecimal to string */ -static void print_hex(unsigned int value, unsigned int width, char * buf, int * ptr) { +static size_t print_hex(unsigned long long value, unsigned int width, int (*callback)(void*,char), void* userData, int fill_zero, int alt, int caps, int align) { + size_t written = 0; int i = width; - if (i == 0) i = 8; - - unsigned int n_width = 1; - unsigned int j = 0x0F; - while (value > j && j < UINT32_MAX) { + unsigned long long n_width = 1; + unsigned long long j = 0x0F; + while (value > j && j < UINT64_MAX) { n_width += 1; j *= 0x10; j += 0x0F; } - while (i > (int)n_width) { - buf[*ptr] = '0'; - *ptr += 1; - i--; + if (!fill_zero && align == 1) { + while (i > (long long)n_width + 2*!!alt) { + OUT(' '); + i--; + } } - i = (int)n_width; - while (i-- > 0) { - buf[*ptr] = "0123456789abcdef"[(value>>(i*4))&0xF]; - *ptr += + 1; + if (alt) { + OUT('0'); + OUT(caps ? 'X' : 'x'); } + + if (fill_zero && align == 1) { + while (i > (long long)n_width + 2*!!alt) { + OUT('0'); + i--; + } + } + + i = (long long)n_width; + while (i-- > 0) { + char c = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[(value>>(i*4))&0xF]; + OUT(c); + } + + if (align == 0) { + i = width; + while (i > (long long)n_width + 2*!!alt) { + OUT(' '); + i--; + } + } + + return written; } /* * vasprintf() */ -size_t vasprintf(char * buf, const char * fmt, va_list args) { - int i = 0; - char * s; - char * b = buf; +size_t xvasprintf(int (*callback)(void *, char), void * userData, const char * fmt, va_list args) { + const char * s; + size_t written = 0; for (const char *f = fmt; *f; f++) { if (*f != '%') { - *b++ = *f; + OUT(*f); continue; } ++f; unsigned int arg_width = 0; + int align = 1; /* right */ + int fill_zero = 0; + int big = 0; + int alt = 0; + int always_sign = 0; + int precision = -1; + while (1) { + if (*f == '-') { + align = 0; + ++f; + } else if (*f == '#') { + alt = 1; + ++f; + } else if (*f == '*') { + arg_width = (char)va_arg(args, int); + ++f; + } else if (*f == '0') { + fill_zero = 1; + ++f; + } else if (*f == '+') { + always_sign = 1; + ++f; + } else if (*f == ' ') { + always_sign = 2; + ++f; + } else { + break; + } + } while (*f >= '0' && *f <= '9') { arg_width *= 10; arg_width += *f - '0'; ++f; } + if (*f == '.') { + ++f; + precision = 0; + if (*f == '*') { + precision = (int)va_arg(args, int); + ++f; + } else { + while (*f >= '0' && *f <= '9') { + precision *= 10; + precision += *f - '0'; + ++f; + } + } + } + if (*f == 'l') { + big = 1; + ++f; + if (*f == 'l') { + big = 2; + ++f; + } + } + if (*f == 'j') { + big = (sizeof(uintmax_t) == sizeof(unsigned long long) ? 2 : + sizeof(uintmax_t) == sizeof(unsigned long) ? 1 : 0); + ++f; + } + if (*f == 'z') { + big = (sizeof(size_t) == sizeof(unsigned long long) ? 2 : + sizeof(size_t) == sizeof(unsigned long) ? 1 : 0); + ++f; + } + if (*f == 't') { + big = (sizeof(ptrdiff_t) == sizeof(unsigned long long) ? 2 : + sizeof(ptrdiff_t) == sizeof(unsigned long) ? 1 : 0); + ++f; + } /* fmt[i] == '%' */ switch (*f) { case 's': /* String pointer -> String */ - s = (char *)va_arg(args, char *); - if (s == NULL) { - s = "(null)"; - } - while (*s) { - *b++ = *s++; + { + size_t count = 0; + if (big) { + return written; + } else { + s = (char *)va_arg(args, char *); + if (s == NULL) { + s = "(null)"; + } + if (precision >= 0) { + while (*s && precision > 0) { + OUT(*s++); + count++; + precision--; + if (arg_width && count == arg_width) break; + } + } else { + while (*s) { + OUT(*s++); + count++; + if (arg_width && count == arg_width) break; + } + } + } + while (count < arg_width) { + OUT(' '); + count++; + } } break; case 'c': /* Single character */ - *b++ = (char)va_arg(args, int); + OUT((char)va_arg(args,int)); break; + case 'p': + alt = 1; + if (sizeof(void*) == sizeof(long long)) big = 2; + /* fallthrough */ + case 'X': case 'x': /* Hexadecimal number */ - i = b - buf; - print_hex((unsigned long)va_arg(args, unsigned long), arg_width, buf, &i); - b = buf + i; + { + unsigned long long val; + if (big == 2) { + val = (unsigned long long)va_arg(args, unsigned long long); + } else if (big == 1) { + val = (unsigned long)va_arg(args, unsigned long); + } else { + val = (unsigned int)va_arg(args, unsigned int); + } + written += print_hex(val, arg_width, callback, userData, fill_zero, alt, !(*f & 32), align); + } break; + case 'i': case 'd': /* Decimal number */ - i = b - buf; - print_dec((unsigned long)va_arg(args, unsigned long), arg_width, buf, &i); - b = buf + i; + { + long long val; + if (big == 2) { + val = (long long)va_arg(args, long long); + } else if (big == 1) { + val = (long)va_arg(args, long); + } else { + val = (int)va_arg(args, int); + } + if (val < 0) { + OUT('-'); + val = -val; + } else if (always_sign) { + OUT(always_sign == 2 ? ' ' : '+'); + } + written += print_dec(val, arg_width, callback, userData, fill_zero, align, precision); + } + break; + case 'u': /* Unsigned ecimal number */ + { + unsigned long long val; + if (big == 2) { + val = (unsigned long long)va_arg(args, unsigned long long); + } else if (big == 1) { + val = (unsigned long)va_arg(args, unsigned long); + } else { + val = (unsigned int)va_arg(args, unsigned int); + } + written += print_dec(val, arg_width, callback, userData, fill_zero, align, precision); + } break; case '%': /* Escape */ - *b++ = '%'; + OUT('%'); break; default: /* Nothing at all, just dump it */ - *b++ = *f; + OUT(*f); break; } } - /* Ensure the buffer ends in a null */ - *b = '\0'; - return b - buf; - + return written; } -static unsigned short * textmemptr = (unsigned short *)0xB8000; -static void placech(unsigned char c, int x, int y, int attr) { - unsigned short *where; - unsigned att = attr << 8; - where = textmemptr + (y * 80 + x); - *where = c | att; +struct CBData { + char * str; + size_t size; + size_t written; +}; + +static int cb_sprintf(void * user, char c) { + struct CBData * data = user; + if (data->size > data->written + 1) { + data->str[data->written] = c; + data->written++; + if (data->written < data->size) { + data->str[data->written] = '\0'; + } + } + return 0; } -int fprintf(fs_node_t * device, char *fmt, ...) { - va_list args; - va_start(args, fmt); - char buffer[1024]; - vasprintf(buffer, fmt, args); - va_end(args); - - return write_fs(device, 0, strlen(buffer), (uint8_t *)buffer); -} - - -int sprintf(char * buf, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - int out = vasprintf(buf, fmt, args); - va_end(args); +int vsnprintf(char *str, size_t size, const char *format, va_list ap) { + struct CBData data = {str,size,0}; + int out = xvasprintf(cb_sprintf, &data, format, ap); + cb_sprintf(&data, '\0'); return out; } +int snprintf(char * str, size_t size, const char * format, ...) { + struct CBData data = {str,size,0}; + va_list args; + va_start(args, format); + int out = xvasprintf(cb_sprintf, &data, format, args); + va_end(args); + cb_sprintf(&data, '\0'); + return out; +} + +static int cb_printf(void * user, char c) { + printf_output(1,(uint8_t*)&c); + return 0; +} + +int printf(const char * fmt, ...) { + va_list args; + va_start(args, fmt); + int out = xvasprintf(cb_printf, NULL, fmt, args); + va_end(args); + return out; +} diff --git a/kernel/misc/lgcc.c b/kernel/misc/lgcc.c deleted file mode 100644 index 203c9b83..00000000 --- a/kernel/misc/lgcc.c +++ /dev/null @@ -1,11 +0,0 @@ -/* Garbage */ - -#include - -#define USES(func) void * _USES_ ## func (void) { return (void*)(uintptr_t)&func; } - -extern unsigned long __umoddi3 (unsigned long a, unsigned long b); -USES(__umoddi3) - -extern unsigned long __udivdi3 (unsigned long a, unsigned long b); -USES(__udivdi3) diff --git a/kernel/misc/list.c b/kernel/misc/list.c new file mode 100644 index 00000000..79d6d64f --- /dev/null +++ b/kernel/misc/list.c @@ -0,0 +1,257 @@ +/** + * @brief General-purpose list implementations. + * @author K. Lange + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2021 K. Lange + */ + +#include +#include +#include + +void list_destroy(list_t * list) { + /* Free all of the contents of a list */ + node_t * n = list->head; + while (n) { + free(n->value); + n = n->next; + } +} + +void list_free(list_t * list) { + /* Free the actual structure of a list */ + node_t * n = list->head; + while (n) { + node_t * s = n->next; + free(n); + n = s; + } +} + +void list_append(list_t * list, node_t * node) { + //assert(!(node->next || node->prev) && "Node is already in a list."); + node->next = NULL; + /* Insert a node onto the end of a list */ + node->owner = list; + if (!list->length) { + list->head = node; + list->tail = node; + node->prev = NULL; + node->next = NULL; + list->length++; + return; + } + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + list->length++; +} + +node_t * list_insert(list_t * list, void * item) { + /* Insert an item into a list */ + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append(list, node); + + return node; +} + +void list_append_after(list_t * list, node_t * before, node_t * node) { + //assert(!(node->next || node->prev) && "Node is already in a list."); + node->owner = list; + if (!list->length) { + list_append(list, node); + return; + } + if (before == NULL) { + node->next = list->head; + node->prev = NULL; + list->head->prev = node; + list->head = node; + list->length++; + return; + } + if (before == list->tail) { + list->tail = node; + } else { + before->next->prev = node; + node->next = before->next; + } + node->prev = before; + before->next = node; + list->length++; +} + +node_t * list_insert_after(list_t * list, node_t * before, void * item) { + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append_after(list, before, node); + return node; +} + +void list_append_before(list_t * list, node_t * after, node_t * node) { + //assert(!(node->next || node->prev) && "Node is already in a list."); + node->owner = list; + if (!list->length) { + list_append(list, node); + return; + } + if (after == NULL) { + node->next = NULL; + node->prev = list->tail; + list->tail->next = node; + list->tail = node; + list->length++; + return; + } + if (after == list->head) { + list->head = node; + } else { + after->prev->next = node; + node->prev = after->prev; + } + node->next = after; + after->prev = node; + list->length++; +} + +node_t * list_insert_before(list_t * list, node_t * after, void * item) { + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append_before(list, after, node); + return node; +} + +list_t * list_create(const char * name, const void * metadata) { + /* Create a fresh list */ + list_t * out = malloc(sizeof(list_t)); + out->head = NULL; + out->tail = NULL; + out->length = 0; + out->name = name; + out->metadata = metadata; + return out; +} + +node_t * list_find(list_t * list, void * value) { + foreach(item, list) { + if (item->value == value) { + return item; + } + } + return NULL; +} + +int list_index_of(list_t * list, void * value) { + int i = 0; + foreach(item, list) { + if (item->value == value) { + return i; + } + i++; + } + return -1; /* not find */ +} + +void * list_index(list_t * list, int index) { + int i = 0; + foreach(item, list) { + if (i == index) return item->value; + i++; + } + return NULL; +} + +void list_remove(list_t * list, size_t index) { + /* remove index from the list */ + if (index > list->length) return; + size_t i = 0; + node_t * n = list->head; + while (i < index) { + n = n->next; + i++; + } + list_delete(list, n); +} + +void list_delete(list_t * list, node_t * node) { + /* remove node from the list */ + //assert(node->owner == list && "Tried to remove a list node from a list it does not belong to."); + if (node == list->head) { + list->head = node->next; + } + if (node == list->tail) { + list->tail = node->prev; + } + if (node->prev) { + node->prev->next = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } + node->prev = NULL; + node->next = NULL; + node->owner = NULL; + list->length--; +} + +node_t * list_pop(list_t * list) { + /* Remove and return the last value in the list + * If you don't need it, you still probably want to free it! + * Try free(list_pop(list)); ! + * */ + if (!list->tail) return NULL; + node_t * out = list->tail; + list_delete(list, out); + return out; +} + +node_t * list_dequeue(list_t * list) { + if (!list->head) return NULL; + node_t * out = list->head; + list_delete(list, out); + return out; +} + +list_t * list_copy(list_t * original) { + /* Create a new copy of original */ + list_t * out = list_create(original->name, original->metadata); + node_t * node = original->head; + while (node) { + list_insert(out, node->value); + } + return out; +} + +void list_merge(list_t * target, list_t * source) { + /* Destructively merges source into target */ + foreach(node, source) { + node->owner = target; + } + if (source->head) { + source->head->prev = target->tail; + } + if (target->tail) { + target->tail->next = source->head; + } else { + target->head = source->head; + } + if (source->tail) { + target->tail = source->tail; + } + target->length += source->length; + free(source); +} + diff --git a/kernel/misc/logging.c b/kernel/misc/logging.c deleted file mode 100644 index e0c8863a..00000000 --- a/kernel/misc/logging.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Kernel Logging Facility - * - * Maintains a log in-memory as well as to serial (unless - * told not to). - */ - -#include -#include -#include - -#include -#include - -log_type_t debug_level = NOTICE; -void * debug_file = NULL; -void (*debug_hook)(void *, char *) = NULL; -void (*debug_video_crash)(char **) = NULL; - -static char * c_messages[] = { - " \033[1;34mINFO\033[0m:", - " \033[1;35mNOTICE\033[0m:", - " \033[1;33mWARNING\033[0m:", - " \033[1;31mERROR\033[0m:", - " \033[1;37;41mCRITICAL\033[0m:", - " \033[1;31;44mINSANE\033[0m:" -}; - -static char buffer[1024]; - -void _debug_print(char * title, int line_no, log_type_t level, char *fmt, ...) { - if (level >= debug_level && debug_file) { - va_list args; - va_start(args, fmt); - vasprintf(buffer, fmt, args); - va_end(args); - - char * type; - if (level > INSANE) { - type = ""; - } else { - type = c_messages[level]; - } - - fprintf(debug_file, "[%10d.%3d:%s:%d]%s %s\n", timer_ticks, timer_subticks, title, line_no, type, buffer); - - } - /* else ignore */ -} - diff --git a/kernel/mem/alloc.c b/kernel/misc/malloc.c similarity index 71% rename from kernel/mem/alloc.c rename to kernel/misc/malloc.c index 7af7844c..8538cee6 100644 --- a/kernel/mem/alloc.c +++ b/kernel/misc/malloc.c @@ -1,108 +1,40 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/misc/malloc.c + * @brief klange's Slab Allocator * - * klange's Slab Allocator + * This is one of the oldest parts of ToaruOS: the infamous heap allocator. + * Used in userspace and the kernel alike, this is a straightforward "slab"- + * style allocator. It has a handful of fixed sizes to stick small objects + * in and keeps several together in a single page. It's surprisingly fast, + * needs only an 'sbrk', makes only page-multiple calls to that sbrk, and + * throwing a big lock around the whole thing seems to have worked just fine + * for making it thread-safe in userspace applications (not necessarily + * tested in the kernel). * - * Implemented for CS241, Fall 2010, machine problem 7 - * at the University of Illinois, Urbana-Champaign. + * FIXME The heap allocator has long been lacking an ability to merge large + * freed blocks. There's #if 0'd code dating back over a decade in here. * - * Overall competition winner for speed. - * Well ranked in memory usage. - * - * Copyright (c) 2010-2018 K. Lange. All rights reserved. + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (c) 2010-2021 K. Lange. All rights reserved. * * Developed by: K. Lange * Dave Majnemer * Assocation for Computing Machinery * University of Illinois, Urbana-Champaign * http://acm.uiuc.edu - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal with 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: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimers. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimers in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the Association for Computing Machinery, the - * University of Illinois, nor the names of its contributors may be used - * to endorse or promote products derived from this Software without - * specific prior written permission. - * - * 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 - * CONTRIBUTORS 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 - * WITH THE SOFTWARE. - * - * ########## - * # README # - * ########## - * - * About the slab allocator - * """""""""""""""""""""""" - * - * This is a simple implementation of a "slab" allocator. It works by operating - * on "bins" of items of predefined sizes and a set of pseudo-bins of any size. - * When a new allocation request is made, the allocator determines if it will - * fit in an existing bin. If there are no bins of the correct size for a given - * allocation request, the allocator will make a bin and add it to a(n empty) - * list of available bins of that size. In this implementation, we use sizes - * from 4 bytes (32 bit) or 8 bytes (64-bit) to 2KB for bins, fitting a 4K page - * size. The implementation allows the number of pages in a single bin to be - * increased, as well as allowing for changing the size of page (though this - * should, for the most part, remain 4KB under any modern system). - * - * Special thanks - * """""""""""""" - * - * I would like to thank Dave Majnemer, who I have credited above as a - * contributor, for his assistance. Without Dave, klmalloc would be a mash - * up of bits of forward movement in no discernible pattern. Dave helped - * me ensure that I could build a proper slab allocator and has consantly - * derided me for not fixing the bugs and to-do items listed in the last - * section of this readme. - * - * GCC Function Attributes - * """"""""""""""""""""""" - * - * A couple of GCC function attributes, designated by the __attribute__ - * directive, are used in this code to streamline optimization. - * I've chosen to include a brief overview of the particular attributes - * I am making use of: - * - * - malloc: - * Tells gcc that a given function is a memory allocator - * and that non-NULL values it returns should never be - * associated with other chunks of memory. We use this for - * alloc, realloc and calloc, as is requested in the gcc - * documentation for the attribute. - * - * - always_inline: - * Tells gcc to always inline the given code, regardless of the - * optmization level. Small functions that would be noticeably - * slower with the overhead of paramter handling are given - * this attribute. - * - * - pure: - * Tells gcc that a function only uses inputs and its output. - * - * Things to work on - * """"""""""""""""" - * - * TODO: Try to be more consistent on comment widths... - * FIXME: Make thread safe! Not necessary for competition, but would be nice. - * FIXME: Splitting/coalescing is broken. Fix this ASAP! - * -**/ + */ /* Includes {{{ */ -#include +#include +#include +#include + +#include +#include +#include +#include /* }}} */ /* Definitions {{{ */ @@ -110,8 +42,13 @@ * Defines for often-used integral values * related to our binning and paging strategy. */ +#ifdef __x86_64__ +#define NUM_BINS 10U /* Number of bins, total, under 64-bit. */ +#define SMALLEST_BIN_LOG 3U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */ +#else #define NUM_BINS 11U /* Number of bins, total, under 32-bit. */ #define SMALLEST_BIN_LOG 2U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */ +#endif #define BIG_BIN (NUM_BINS - 1) /* Index for the big bin, (NUM_BINS - 1) */ #define SMALLEST_BIN (1UL << SMALLEST_BIN_LOG) /* Size of the smallest bin. */ @@ -122,46 +59,15 @@ #define BIN_MAGIC 0xDEFAD00D -/* }}} */ - -//#define _DEBUG_MALLOC - -#ifdef _DEBUG_MALLOC -#define EARLY_LOG_DEVICE 0x3F8 -static uint32_t _kmalloc_log_write(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - for (unsigned int i = 0; i < size; ++i) { - outportb(EARLY_LOG_DEVICE, buffer[i]); - } - return size; -} -static fs_node_t _kmalloc_log = { .write = &_kmalloc_log_write }; -extern uintptr_t map_to_physical(uintptr_t virtual); - -#define HALT_ON(_addr) do { \ - if ((uintptr_t)ptr == _addr) { \ - IRQ_OFF; \ - struct { \ - char c; \ - uint32_t addr; \ - uint32_t size; \ - uint32_t extra; \ - uint32_t eip; \ - } __attribute__((packed)) log = {'h',_addr,0,0,0}; \ - write_fs(&_kmalloc_log, 0, sizeof(log), (uint8_t *)&log); \ - while (1) {} \ - } } while (0) - -#define STACK_TRACE(base) \ - uint32_t _eip = 0; \ - unsigned int * ebp = (unsigned int *)(&(base) - 2); \ - for (unsigned int frame = 0; frame < 1; ++frame) { \ - unsigned int eip = ebp[1]; \ - if (eip == 0) break; \ - ebp = (unsigned int *)(ebp[0]); \ - _eip = eip; \ - } +#if 0 +#define assert(statement) ((statement) ? (void)0 : printf("assertion failed in %s:%d %s\n", __FILE__, __LINE__, __FUNCTION__, #statement)) +#else +#define assert(statement) (void)0 #endif + +/* }}} */ + /* * Internal functions. */ @@ -175,156 +81,48 @@ static spin_lock_t mem_lock = { 0 }; void * __attribute__ ((malloc)) malloc(uintptr_t size) { spin_lock(mem_lock); -#ifdef _DEBUG_MALLOC - size += 8; -#endif - void * ret = klmalloc(size); -#ifdef _DEBUG_MALLOC - STACK_TRACE(size); - if (ret) { - char * c = ret; - uintptr_t s = size-8; - memcpy(&c[size-4],&s,sizeof(uintptr_t)); - s = 0xDEADBEEF; - memcpy(&c[size-8],&s,sizeof(uintptr_t)); - } - struct { - char c; - uint32_t addr; - uint32_t size; - uint32_t extra; - uint32_t eip; - } __attribute__((packed)) log = {'m',(uint32_t)ret,size-8,0xDEADBEEF,_eip}; - write_fs(&_kmalloc_log, 0, sizeof(log), (uint8_t *)&log); -#endif + void * out = klmalloc(size); spin_unlock(mem_lock); - return ret; + return out; } void * __attribute__ ((malloc)) realloc(void * ptr, uintptr_t size) { spin_lock(mem_lock); -#ifdef _DEBUG_MALLOC - size += 8; -#endif - void * ret = klrealloc(ptr, size); -#ifdef _DEBUG_MALLOC - STACK_TRACE(ptr); - if (ret) { - char * c = ret; - uintptr_t s = size-8; - memcpy(&c[size-4],&s,sizeof(uintptr_t)); - s = 0xDEADBEEF; - memcpy(&c[size-8],&s,sizeof(uintptr_t)); - } - struct { - char c; - uint32_t addr; - uint32_t size; - uint32_t extra; - uint32_t eip; - } __attribute__((packed)) log = {'r',(uint32_t)ptr,size-8,(uint32_t)ret,_eip}; - write_fs(&_kmalloc_log, 0, sizeof(log), (uint8_t *)&log); -#endif + void * out = klrealloc(ptr, size); spin_unlock(mem_lock); - return ret; + return out; } void * __attribute__ ((malloc)) calloc(uintptr_t nmemb, uintptr_t size) { spin_lock(mem_lock); - void * ret = klcalloc(nmemb, size); -#ifdef _DEBUG_MALLOC - struct { - char c; - uint32_t addr; - uint32_t size; - uint32_t extra; - uint32_t eip; - } __attribute__((packed)) log = {'c',(uint32_t)ret,size,nmemb,0}; - write_fs(&_kmalloc_log, 0, sizeof(log), (uint8_t *)&log); -#endif + void * out = klcalloc(nmemb, size); spin_unlock(mem_lock); - return ret; + return out; } void * __attribute__ ((malloc)) valloc(uintptr_t size) { spin_lock(mem_lock); -#ifdef _DEBUG_MALLOC - size += 8; -#endif - void * ret = klvalloc(size); -#ifdef _DEBUG_MALLOC - STACK_TRACE(size); - if (ret) { - char * c = ret; - uintptr_t s = size-8; - memcpy(&c[size-4],&s,sizeof(uintptr_t)); - s = 0xDEADBEEF; - memcpy(&c[size-8],&s,sizeof(uintptr_t)); - } - struct { - char c; - uint32_t addr; - uint32_t size; - uint32_t extra; - uint32_t eip; - } __attribute__((packed)) log = {'v',(uint32_t)ret,size-8,0xDEADBEEF,_eip}; - write_fs(&_kmalloc_log, 0, sizeof(log), (uint8_t *)&log); -#endif + void * out = klvalloc(size); spin_unlock(mem_lock); - return ret; + return out; } void free(void * ptr) { spin_lock(mem_lock); - if ((uintptr_t)ptr > placement_pointer) { -#ifdef _DEBUG_MALLOC - IRQ_OFF; - - STACK_TRACE(ptr); - - char * tag = ptr; - uintptr_t i = 0; - uint32_t * x; - int _failed = 1; - while (i < 0x40000) { - x = (uint32_t*)(tag + i); - if (map_to_physical((uintptr_t)x) == 0 || map_to_physical((uintptr_t)x + 8) == 0) { - x = (uint32_t *)tag; - break; - } - page_t * page = get_page((uintptr_t)x, 0, current_directory); - if (page->present != 1) break; - page = get_page((uintptr_t)x + 8, 0, current_directory); - if (page->present != 1) break; - if (*x == 0xDEADBEEF) { - if (x[1] == i) { - _failed = 0; - break; - } - } - i++; - } - struct { - char c; - uint32_t addr; - uint32_t size; - uint32_t extra; - uint32_t eip; - } __attribute__((packed)) log = {'f',(uint32_t)ptr,_failed ? 0xFFFFFFFF : x[1],_failed ? 0xFFFFFFFF : x[0],_eip}; - write_fs(&_kmalloc_log, 0, sizeof(log), (uint8_t *)&log); -#endif - klfree(ptr); + if (ptr < (void*)0xffffff0000000000) { + printf("Invalid free detected (%p)\n", ptr); + while (1) {}; } + klfree(ptr); spin_unlock(mem_lock); } - /* Bin management {{{ */ /* * Adjust bin size in bin_size call to proper bounds. */ -inline static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uintptr_t bin) +static inline uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uintptr_t bin) { if (bin <= (uintptr_t)SMALLEST_BIN_LOG) { @@ -341,7 +139,7 @@ inline static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_b * Given a size value, find the correct bin * to place the requested allocation in. */ -inline static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_bin_size(uintptr_t size) { +static inline uintptr_t __attribute__ ((always_inline, pure)) klmalloc_bin_size(uintptr_t size) { uintptr_t bin = sizeof(size) * CHAR_BIT - __builtin_clzl(size); bin += !!(size & (size - 1)); return klmalloc_adjust_bin(bin); @@ -402,7 +200,7 @@ static klmalloc_big_bin_header * klmalloc_newest_big = NULL; /* Newest big bin * position in the list by linking * its neighbors to eachother. */ -inline static void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { +static inline void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { klmalloc_bin_header *next = node->next; head->first = next; node->next = NULL; @@ -415,7 +213,7 @@ inline static void __attribute__ ((always_inline)) klmalloc_list_decouple(klmall * elements are updated to point back * to it (our list is doubly linked). */ -inline static void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { +static inline void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { node->next = head->first; head->first = node; } @@ -426,7 +224,7 @@ inline static void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc * are really great, and just in case * we change the list implementation. */ -inline static klmalloc_bin_header * __attribute__ ((always_inline)) klmalloc_list_head(klmalloc_bin_header_head *head) { +static inline klmalloc_bin_header * __attribute__ ((always_inline)) klmalloc_list_head(klmalloc_bin_header_head *head) { return head->first; } @@ -462,7 +260,7 @@ static uint32_t __attribute__ ((pure)) klmalloc_skip_rand(void) { /* * Generate a random level for a skip node */ -inline static int __attribute__ ((pure, always_inline)) klmalloc_random_level(void) { +static inline int __attribute__ ((pure, always_inline)) klmalloc_random_level(void) { int level = 0; /* * Keep trying to check rand() against 50% of its maximum. @@ -665,7 +463,7 @@ static void * klmalloc_stack_pop(klmalloc_bin_header *header) { assert((uintptr_t)header->head < (uintptr_t)header + PAGE_SIZE); assert((uintptr_t)header->head > (uintptr_t)header + sizeof(klmalloc_bin_header) - 1); } - + /* * Remove the current head and point * the head to where the old head pointed. @@ -704,7 +502,7 @@ static void klmalloc_stack_push(klmalloc_bin_header *header, void *ptr) { * stack, so there is no more free * space available in the block. */ -inline static int __attribute__ ((always_inline)) klmalloc_stack_empty(klmalloc_bin_header *header) { +static inline int __attribute__ ((always_inline)) klmalloc_stack_empty(klmalloc_bin_header *header) { return header->head == NULL; } @@ -905,7 +703,7 @@ static void klfree(void *ptr) { if (bucket_id > (uintptr_t)NUM_BINS) { bucket_id = BIG_BIN; klmalloc_big_bin_header *bheader = (klmalloc_big_bin_header*)header; - + assert(bheader); assert(bheader->head == NULL); assert((bheader->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); @@ -1102,7 +900,7 @@ static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size) /* * Allocate memory and zero it before returning * a pointer to the newly allocated memory. - * + * * Implemented by way of a simple malloc followed * by a memset to 0x00 across the length of the * requested memory chunk. @@ -1114,3 +912,5 @@ static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size) return ptr; } /* }}} */ + + diff --git a/kernel/misc/multiboot.c b/kernel/misc/multiboot.c deleted file mode 100644 index 917cbd5f..00000000 --- a/kernel/misc/multiboot.c +++ /dev/null @@ -1,76 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Multiboot (GRUB) handler - */ -#include -#include -#include - -char * ramdisk = NULL; -struct multiboot * mboot_ptr = NULL; - -struct multiboot * -copy_multiboot( - struct multiboot *mboot_ptr - ) { - struct multiboot *new_header = (struct multiboot *)kmalloc(sizeof(struct multiboot)); - memcpy(new_header, mboot_ptr, sizeof(struct multiboot)); - return new_header; -} - -void -dump_multiboot( - struct multiboot *mboot_ptr - ) { - debug_print(INFO, "MULTIBOOT header at 0x%x:", (uintptr_t)mboot_ptr); - debug_print(INFO, "Flags : 0x%x", mboot_ptr->flags); - debug_print(INFO, "Mem Lo: 0x%x", mboot_ptr->mem_lower); - debug_print(INFO, "Mem Hi: 0x%x", mboot_ptr->mem_upper); - debug_print(INFO, "Boot d: 0x%x", mboot_ptr->boot_device); - debug_print(INFO, "cmdlin: 0x%x", mboot_ptr->cmdline); - debug_print(INFO, "Mods : 0x%x", mboot_ptr->mods_count); - debug_print(INFO, "Addr : 0x%x", mboot_ptr->mods_addr); - debug_print(INFO, "ELF n : 0x%x", mboot_ptr->num); - debug_print(INFO, "ELF s : 0x%x", mboot_ptr->size); - debug_print(INFO, "ELF a : 0x%x", mboot_ptr->addr); - debug_print(INFO, "ELF h : 0x%x", mboot_ptr->shndx); - debug_print(INFO, "MMap : 0x%x", mboot_ptr->mmap_length); - debug_print(INFO, "Addr : 0x%x", mboot_ptr->mmap_addr); - debug_print(INFO, "Drives: 0x%x", mboot_ptr->drives_length); - debug_print(INFO, "Addr : 0x%x", mboot_ptr->drives_addr); - debug_print(INFO, "Config: 0x%x", mboot_ptr->config_table); - debug_print(INFO, "Loader: 0x%x", mboot_ptr->boot_loader_name); - debug_print(INFO, "APM : 0x%x", mboot_ptr->apm_table); - debug_print(INFO, "VBE Co: 0x%x", mboot_ptr->vbe_control_info); - debug_print(INFO, "VBE Mo: 0x%x", mboot_ptr->vbe_mode_info); - debug_print(INFO, "VBE In: 0x%x", mboot_ptr->vbe_mode); - debug_print(INFO, "VBE se: 0x%x", mboot_ptr->vbe_interface_seg); - debug_print(INFO, "VBE of: 0x%x", mboot_ptr->vbe_interface_off); - debug_print(INFO, "VBE le: 0x%x", mboot_ptr->vbe_interface_len); - if (mboot_ptr->flags & (1 << 2)) { - debug_print(INFO, "Started with: %s", (char *)mboot_ptr->cmdline); - } - if (mboot_ptr->flags & (1 << 9)) { - debug_print(INFO, "Booted from: %s", (char *)mboot_ptr->boot_loader_name); - } - if (mboot_ptr->flags & (1 << 0)) { - debug_print(INFO, "%dkB lower memory", mboot_ptr->mem_lower); - int mem_mb = mboot_ptr->mem_upper / 1024; - debug_print(INFO, "%dkB higher memory (%dMB)", mboot_ptr->mem_upper, mem_mb); - } - if (mboot_ptr->flags & (1 << 3)) { - debug_print(INFO, "Found %d module(s).", mboot_ptr->mods_count); - if (mboot_ptr->mods_count > 0) { - uint32_t i; - for (i = 0; i < mboot_ptr->mods_count; ++i ) { - uint32_t module_start = *((uint32_t*)mboot_ptr->mods_addr + 8 * i); - uint32_t module_end = *(uint32_t*)(mboot_ptr->mods_addr + 8 * i + 4); - debug_print(INFO, "Module %d is at 0x%x:0x%x", i+1, module_start, module_end); - } - } - } -} - diff --git a/kernel/devices/pci.c b/kernel/misc/pci.c similarity index 51% rename from kernel/devices/pci.c rename to kernel/misc/pci.c index 4ac3d3ec..b3cb6acc 100644 --- a/kernel/devices/pci.c +++ b/kernel/misc/pci.c @@ -1,20 +1,35 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange +/** + * @file kernel/misc/pci.c + * @brief PCI configuration and scanning. * - * ToAruOS PCI Initialization + * Functions for dealing with PCI devices through configuration mode #1 + * (CPU port I/O methods), including scanning and modifying device + * configuration bytes. + * + * This used to have methods for dealing with ISA bridge IRQ remapping, + * but it has been removed for the moment. + * + * TODO: Implement MSI configuration? */ - -#include +#include +#include #include -#include +/* TODO: PCI is sufficiently generic this shouldn't depend + * directly on x86-64 hardware... */ +#include + +/** + * @brief Write to a PCI device configuration space field. + */ void pci_write_field(uint32_t device, int field, int size, uint32_t value) { outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); outportl(PCI_VALUE_PORT, value); } +/** + * @brief Read from a PCI device configuration space field. + */ uint32_t pci_read_field(uint32_t device, int field, int size) { outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); @@ -31,12 +46,14 @@ uint32_t pci_read_field(uint32_t device, int field, int size) { return 0xFFFF; } +/** + * @brief Obtain the device type from the class and subclass fields. + */ uint16_t pci_find_type(uint32_t dev) { return (pci_read_field(dev, PCI_CLASS, 1) << 8) | pci_read_field(dev, PCI_SUBCLASS, 1); } - -void pci_scan_hit(pci_func_t f, uint32_t dev, void * extra) { +static void pci_scan_hit(pci_func_t f, uint32_t dev, void * extra) { int dev_vend = (int)pci_read_field(dev, PCI_VENDOR_ID, 2); int dev_dvid = (int)pci_read_field(dev, PCI_DEVICE_ID, 2); @@ -76,8 +93,14 @@ void pci_scan_bus(pci_func_t f, int type, int bus, void * extra) { } } +/** + * @brief Scan PCI buses for devices, calling the given function for each device. + * + * Used by drivers to implement device discovery, runs a callback function for ever + * device found. A device consists of a bus, slot, and function. Also performs + * recursive scans of bridges. + */ void pci_scan(pci_func_t f, int type, void * extra) { - if ((pci_read_field(0, PCI_HEADER_TYPE, 1) & 0x80) == 0) { pci_scan_bus(f,type,0,extra); return; @@ -93,59 +116,11 @@ void pci_scan(pci_func_t f, int type, void * extra) { } } -static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { - *((uint32_t *)extra) = device; - } -} -static uint32_t pci_isa = 0; -static uint8_t pci_remaps[4] = {0}; -void pci_remap(void) { - pci_scan(&find_isa_bridge, -1, &pci_isa); - if (pci_isa) { - for (int i = 0; i < 4; ++i) { - pci_remaps[i] = pci_read_field(pci_isa, 0x60+i, 1); - if (pci_remaps[i] == 0x80) { - pci_remaps[i] = 10 + (i%1); - } - } - uint32_t out = 0; - memcpy(&out, &pci_remaps, 4); - pci_write_field(pci_isa, 0x60, 4, out); - } -} - +/** + * @brief Extract the interrupt line from a device. + * + * Previously also did IRQ pin decoding, but we don't do that anymore. + */ int pci_get_interrupt(uint32_t device) { - - if (pci_isa) { - uint32_t irq_pin = pci_read_field(device, 0x3D, 1); - if (irq_pin == 0) { - /* ??? */ - debug_print(ERROR, "PCI device does not specific interrupt line"); - return pci_read_field(device, PCI_INTERRUPT_LINE, 1); - } - int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4; - int int_line = pci_read_field(device, PCI_INTERRUPT_LINE, 1); - debug_print(ERROR, "slot is %d, irq pin is %d, so pirq is %d and that maps to %d? int_line=%d", pci_extract_slot(device), irq_pin, pirq, pci_remaps[pirq], int_line); - for (int i = 0; i < 4; ++i) { - debug_print(ERROR, " irq[%d] = %d", i, pci_remaps[i]); - } - if (pci_remaps[pirq] >= 0x80) { - debug_print(ERROR, "not mapped, remapping?"); - if (int_line == 0xFF) { - int_line = 10; - pci_write_field(device, PCI_INTERRUPT_LINE, 1, int_line); - debug_print(ERROR, "? Just going in blind here.\n"); - } - pci_remaps[pirq] = int_line; - uint32_t out = 0; - memcpy(&out, &pci_remaps, 4); - pci_write_field(pci_isa, 0x60, 4, out); - return int_line; - } - pci_write_field(device, PCI_INTERRUPT_LINE, 1, pci_remaps[pirq]); - return pci_remaps[pirq]; - } else { - return pci_read_field(device, PCI_INTERRUPT_LINE, 1); - } + return pci_read_field(device, PCI_INTERRUPT_LINE, 1); } diff --git a/kernel/ds/ringbuffer.c b/kernel/misc/ringbuffer.c similarity index 87% rename from kernel/ds/ringbuffer.c rename to kernel/misc/ringbuffer.c index 94c67721..2b4bc9ff 100644 --- a/kernel/ds/ringbuffer.c +++ b/kernel/misc/ringbuffer.c @@ -1,11 +1,24 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/misc/ringbuffer.c + * @brief Generic ringbuffer with blocking reads and writes. + * + * Provides a buffer interface for devices such as at PTYs with + * blocking reads and writes. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2018 K. Lange + * Copyright (C) 2013-2021 K. Lange */ -#include +#include +#include +#include #include #include +#include +#include +#include +#include size_t ring_buffer_unread(ring_buffer_t * ring_buffer) { if (ring_buffer->read_ptr == ring_buffer->write_ptr) { @@ -62,7 +75,7 @@ void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer) { void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process) { if (!ring_buffer->alert_waiters) { - ring_buffer->alert_waiters = list_create(); + ring_buffer->alert_waiters = list_create("ringbuffer alerts", ring_buffer); } if (!list_find(ring_buffer->alert_waiters, process)) { @@ -137,8 +150,8 @@ ring_buffer_t * ring_buffer_create(size_t size) { out->internal_stop = 0; out->discard = 0; - out->wait_queue_readers = list_create(); - out->wait_queue_writers = list_create(); + out->wait_queue_readers = list_create("ringbuffer readers",out); + out->wait_queue_writers = list_create("ringbuffer writers",out); return out; } diff --git a/kernel/libc.c b/kernel/misc/string.c similarity index 82% rename from kernel/libc.c rename to kernel/misc/string.c index 5070fd9e..3865b7fe 100644 --- a/kernel/libc.c +++ b/kernel/misc/string.c @@ -1,71 +1,81 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Dale Weiler - * - * Standard C library for kernel - * +/** + * @file kernel/misc/string.c + * @brief Generic string functions and C standard library implementations for the kernel. + * @author Copyright (C) 2015-2021 K. Lange + * @author Copyright (C) 2015 Dale Weiler */ +#include +#include -#include - -#ifndef UCHAR_MAX -#define UCHAR_MAX 255 -#endif - -#define ALIGN (sizeof(size_t)) -#define ONES ((size_t)-1/UCHAR_MAX) -#define HIGHS (ONES * (UCHAR_MAX/2+1)) -#define HASZERO(X) (((X)-ONES) & ~(X) & HIGHS) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) #define BITOP(A, B, OP) \ ((A)[(size_t)(B)/(8*sizeof *(A))] OP (size_t)1<<((size_t)(B)%(8*sizeof *(A)))) +unsigned short * memsetw(unsigned short * dest, unsigned short val, int count) { + int i = 0; + for ( ; i < count; ++i ) { + dest[i] = val; + } + return dest; +} + +#if 0 void * memcpy(void * restrict dest, const void * restrict src, size_t n) { - asm volatile("cld; rep movsb" - : "=c"((int){0}) - : "D"(dest), "S"(src), "c"(n) + char * d = dest; + const char * s = src; + for (; n > 0; n--) { + *d++ = *s++; + } + return dest; +} +#else +/* FIXME why is there an x86-specific memcpy outside of the arch dir... */ +void * memcpy(void * restrict dest, const void * restrict src, size_t n) { + asm volatile("rep movsb" + : : "D"(dest), "S"(src), "c"(n) : "flags", "memory"); return dest; } +#endif -void * memset(void * dest, int c, size_t n) { - asm volatile("cld; rep stosb" - : "=c"((int){0}) - : "D"(dest), "a"(c), "c"(n) - : "flags", "memory"); - return dest; -} -int memcmp(const void * vl, const void * vr, size_t n) { - const unsigned char *l = vl; - const unsigned char *r = vr; - for (; n && *l == *r; n--, l++, r++); - return n ? *l-*r : 0; -} - -void * memchr(const void * src, int c, size_t n) { - const unsigned char * s = src; - c = (unsigned char)c; - for (; ((uintptr_t)s & (ALIGN - 1)) && n && *s != c; s++, n--); - if (n && *s != c) { - const size_t * w; - size_t k = ONES * c; - for (w = (const void *)s; n >= sizeof(size_t) && !HASZERO(*w^k); w++, n -= sizeof(size_t)); - for (s = (const void *)w; n && *s != c; s++, n--); - } - return n ? (void *)s : 0; -} - -void * memrchr(const void * m, int c, size_t n) { - const unsigned char * s = m; - c = (unsigned char)c; - while (n--) { - if (s[n] == c) { - return (void*)(s+n); +size_t strlen(const char * s) { + const char * a = s; + const size_t * w; + for (; (uintptr_t)s % ALIGN; s++) { + if (!*s) { + return s-a; } } - return 0; + for (w = (const void *)s; !HASZERO(*w); w++); + for (s = (const void *)w; *s; s++); + return s-a; +} + + +int strcmp(const char * a, const char * b) { + uint32_t i = 0; + while (1) { + if (a[i] < b[i]) { + return -1; + } else if (a[i] > b[i]) { + return 1; + } else { + if (a[i] == '\0') { + return 0; + } + ++i; + } + } +} + +void * memset(void * dest, int c, size_t n) { + size_t i = 0; + for ( ; i < n; ++i ) { + ((char *)dest)[i] = c; + } + return dest; } void * memmove(void * dest, const void * src, size_t n) { @@ -117,54 +127,29 @@ void * memmove(void * dest, const void * src, size_t n) { return dest; } -int strcmp(const char * l, const char * r) { - for (; *l == *r && *l; l++, r++); - return *(unsigned char *)l - *(unsigned char *)r; +void * memchr(const void * src, int c, size_t n) { + const unsigned char * s = src; + c = (unsigned char)c; + for (; ((uintptr_t)s & (ALIGN - 1)) && n && *s != c; s++, n--); + if (n && *s != c) { + const size_t * w; + size_t k = ONES * c; + for (w = (const void *)s; n >= sizeof(size_t) && !HASZERO(*w^k); w++, n -= sizeof(size_t)); + for (s = (const void *)w; n && *s != c; s++, n--); + } + return n ? (void *)s : 0; } -size_t strlen(const char * s) { - const char * a = s; - const size_t * w; - for (; (uintptr_t)s % ALIGN; s++) { - if (!*s) { - return s-a; + +void * memrchr(const void * m, int c, size_t n) { + const unsigned char * s = m; + c = (unsigned char)c; + while (n--) { + if (s[n] == c) { + return (void*)(s+n); } } - for (w = (const void *)s; !HASZERO(*w); w++); - for (s = (const void *)w; *s; s++); - return s-a; -} - -char * strdup(const char * s) { - size_t l = strlen(s); - return memcpy(malloc(l+1), s, l+1); -} - -char * stpcpy(char * restrict d, const char * restrict s) { - size_t * wd; - const size_t * ws; - - if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) { - for (; (uintptr_t)s % ALIGN; s++, d++) { - if (!(*d = *s)) { - return d; - } - } - wd = (void *)d; - ws = (const void *)s; - for (; !HASZERO(*ws); *wd++ = *ws++); - d = (void *)wd; - s = (const void *)ws; - } - - for (; (*d=*s); s++, d++); - - return d; -} - -char * strcpy(char * restrict dest, const char * restrict src) { - stpcpy(dest, src); - return dest; + return 0; } size_t strspn(const char * s, const char * c) { @@ -185,6 +170,7 @@ size_t strspn(const char * s, const char * c) { return s-a; } + char * strchrnul(const char * s, int c) { size_t * w; size_t k; @@ -215,6 +201,42 @@ char * strrchr(const char * s, int c) { return memrchr(s, c, strlen(s) + 1); } + +char * stpcpy(char * restrict d, const char * restrict s) { + size_t * wd; + const size_t * ws; + + if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) { + for (; (uintptr_t)s % ALIGN; s++, d++) { + if (!(*d = *s)) { + return d; + } + } + wd = (void *)d; + ws = (const void *)s; + for (; !HASZERO(*ws); *wd++ = *ws++); + d = (void *)wd; + s = (const void *)ws; + } + + for (; (*d=*s); s++, d++); + + return d; +} + +char * strcpy(char * restrict dest, const char * restrict src) { + stpcpy(dest, src); + return dest; +} + +size_t lfind(const char * str, const char accept) { + return (size_t)strchr(str, accept); +} + +size_t rfind(const char * str, const char accept) { + return (size_t)strrchr(str, accept); +} + size_t strcspn(const char * s, const char * c) { const char *a = s; if (c[0] && c[1]) { @@ -231,6 +253,27 @@ char * strpbrk(const char * s, const char * b) { return *s ? (char *)s : 0; } +char * strtok_r(char * str, const char * delim, char ** saveptr) { + char * token; + if (str == NULL) { + str = *saveptr; + } + str += strspn(str, delim); + if (*str == '\0') { + *saveptr = str; + return NULL; + } + token = str; + str = strpbrk(token, delim); + if (str == NULL) { + *saveptr = (char *)lfind(token, '\0'); + } else { + *str = '\0'; + *saveptr = str + 1; + } + return token; +} + static char *strstr_2b(const unsigned char * h, const unsigned char * n) { uint16_t nw = n[0] << 8 | n[1]; uint16_t hw = h[0] << 8 | h[1]; @@ -252,6 +295,13 @@ static char *strstr_4b(const unsigned char * h, const unsigned char * n) { return *h ? (char *)h-3 : 0; } +int memcmp(const void * vl, const void * vr, size_t n) { + const unsigned char *l = vl; + const unsigned char *r = vr; + for (; n && *l == *r; n--, l++, r++); + return n ? *l-*r : 0; +} + static char *strstr_twoway(const unsigned char * h, const unsigned char * n) { size_t mem; size_t mem0; @@ -405,53 +455,30 @@ char *strstr(const char * h, const char * n) { return strstr_twoway((void *)h, (void *)n); } -static inline int isdigit(int ch) { - return (unsigned int)ch-'0' < 10; +uint8_t startswith(const char * str, const char * accept) { + return strstr(str, accept) == str; } -static inline int isspace(int ch) { - return ch == ' ' || (unsigned int)ch-'\t' < 5; +char * strdup(const char * c) { + char * out = malloc(strlen(c) + 1); + memcpy(out, c, strlen(c)+1); + return out; } -int atoi(const char * s) { - int n = 0; - int neg = 0; - while (isspace(*s)) { - s++; +int atoi(const char * c) { + int sign = 1; + long out = 0; + if (*c == '-') { + sign = '-'; + c++; } - switch (*s) { - case '-': - neg = 1; - /* Fallthrough is intentional here */ - case '+': - s++; + + while (*c) { + out *= 10; + out += (*c - '0'); + c++; } - while (isdigit(*s)) { - n = 10*n - (*s++ - '0'); - } - /* The sign order may look incorrect here but this is correct as n is calculated - * as a negative number to avoid overflow on INT_MAX. - */ - return neg ? n : -n; + + return out * sign; } -char * strtok_r(char * str, const char * delim, char ** saveptr) { - char * token; - if (str == NULL) { - str = *saveptr; - } - str += strspn(str, delim); - if (*str == '\0') { - *saveptr = str; - return NULL; - } - token = str; - str = strpbrk(token, delim); - if (str == NULL) { - *saveptr = (char *)lfind(token, '\0'); - } else { - *str = '\0'; - *saveptr = str + 1; - } - return token; -} diff --git a/kernel/misc/tokenize.c b/kernel/misc/tokenize.c index 1dde37f5..be7052ca 100644 --- a/kernel/misc/tokenize.c +++ b/kernel/misc/tokenize.c @@ -1,13 +1,11 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2018 K. Lange +/** + * @file kernel/misc/tokenize.c + * @brief Wrapper around strtok_r, used to turn strings into arrays. */ -#include -#include +#include #include -int tokenize(char * str, char * sep, char **buf) { +int tokenize(char * str, const char * sep, char **buf) { char * pch_i; char * save_i; int argc = 0; diff --git a/kernel/misc/tree.c b/kernel/misc/tree.c new file mode 100644 index 00000000..92bf89c1 --- /dev/null +++ b/kernel/misc/tree.c @@ -0,0 +1,190 @@ +/** + * @file kernel/misc/tree.c + * @brief General-purpose tree implementation. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2018 K. Lange + */ + +#include +#include +#include +#include + +tree_t * tree_create(void) { + /* Create a new tree */ + tree_t * out = malloc(sizeof(tree_t)); + out->nodes = 0; + out->root = NULL; + return out; +} + +void tree_set_root(tree_t * tree, void * value) { + /* Set the root node for a new tree. */ + tree_node_t * root = tree_node_create(value); + tree->root = root; + tree->nodes = 1; +} + +void tree_node_destroy(tree_node_t * node) { + /* Free the contents of a node and its children, but not the nodes themselves */ + foreach(child, node->children) { + tree_node_destroy((tree_node_t *)child->value); + } + free(node->value); +} + +void tree_destroy(tree_t * tree) { + /* Free the contents of a tree, but not the nodes */ + if (tree->root) { + tree_node_destroy(tree->root); + } +} + +void tree_node_free(tree_node_t * node) { + /* Free a node and its children, but not their contents */ + if (!node) return; + foreach(child, node->children) { + tree_node_free(child->value); + } + free(node); +} + +void tree_free(tree_t * tree) { + /* Free all of the nodes in a tree, but not their contents */ + tree_node_free(tree->root); +} + +tree_node_t * tree_node_create(void * value) { + /* Create a new tree node pointing to the given value */ + tree_node_t * out = malloc(sizeof(tree_node_t)); + out->value = value; + out->children = list_create("tree node children",out); + out->parent = NULL; + return out; +} + +void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node) { + /* Insert a node as a child of parent */ + list_insert(parent->children, node); + node->parent = parent; + tree->nodes++; +} + +tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value) { + /* Insert a (fresh) node as a child of parent */ + tree_node_t * out = tree_node_create(value); + tree_node_insert_child_node(tree, parent, out); + return out; +} + +tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle) { + /* Recursive node part of tree_find_parent */ + tree_node_t * found = NULL; + foreach(child, haystack->children) { + if (child->value == needle) { + return haystack; + } + found = tree_node_find_parent((tree_node_t *)child->value, needle); + if (found) { + break; + } + } + return found; +} + +tree_node_t * tree_find_parent(tree_t * tree, tree_node_t * node) { + /* Return the parent of a node, inefficiently. */ + if (!tree->root) return NULL; + return tree_node_find_parent(tree->root, node); +} + +size_t tree_count_children(tree_node_t * node) { + /* return the number of children this node has */ + if (!node) return 0; + if (!node->children) return 0; + size_t out = node->children->length; + foreach(child, node->children) { + out += tree_count_children((tree_node_t *)child->value); + } + return out; +} + +void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node) { + /* remove a node when we know its parent; update node counts for the tree */ + tree->nodes -= tree_count_children(node) + 1; + list_delete(parent->children, list_find(parent->children, node)); + tree_node_free(node); +} + +void tree_node_remove(tree_t * tree, tree_node_t * node) { + /* remove an entire branch given its root */ + tree_node_t * parent = node->parent; + if (!parent) { + if (node == tree->root) { + tree->nodes = 0; + tree->root = NULL; + tree_node_free(node); + } + } + tree_node_parent_remove(tree, parent, node); +} + +void tree_remove(tree_t * tree, tree_node_t * node) { + /* Remove this node and move its children into its parent's list of children */ + tree_node_t * parent = node->parent; + /* This is something we just can't do. We don't know how to merge our + * children into our "parent" because then we'd have more than one root node. + * A good way to think about this is actually what this tree struct + * primarily exists for: processes. Trying to remove the root is equivalent + * to trying to kill init! Which is bad. We immediately fault on such + * a case anyway ("Tried to kill init, shutting down!"). + */ + if (!parent) return; + tree->nodes--; + list_delete(parent->children, list_find(parent->children, node)); + foreach(child, node->children) { + /* Reassign the parents */ + ((tree_node_t *)child->value)->parent = parent; + } + list_merge(parent->children, node->children); + free(node); +} + +void tree_remove_reparent_root(tree_t * tree, tree_node_t * node) { + /* Remove this node and move its children into the root children */ + tree_node_t * parent = node->parent; + if (!parent) return; + tree->nodes--; + list_delete(parent->children, list_find(parent->children, node)); + foreach(child, node->children) { + /* Reassign the parents */ + ((tree_node_t *)child->value)->parent = tree->root; + } + list_merge(tree->root->children, node->children); + free(node); +} + +void tree_break_off(tree_t * tree, tree_node_t * node) { + tree_node_t * parent = node->parent; + if (!parent) return; + list_delete(parent->children, list_find(parent->children, node)); +} + +tree_node_t * tree_node_find(tree_node_t * node, void * search, tree_comparator_t comparator) { + if (comparator(node->value,search)) { + return node; + } + tree_node_t * found; + foreach(child, node->children) { + found = tree_node_find((tree_node_t *)child->value, search, comparator); + if (found) return found; + } + return NULL; +} + +tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator) { + return tree_node_find(tree->root, value, comparator); +} diff --git a/kernel/misc/ubsan.c b/kernel/misc/ubsan.c deleted file mode 100644 index 1ba7bdfc..00000000 --- a/kernel/misc/ubsan.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#define EARLY_LOG_DEVICE 0x3F8 -static uint32_t _ubsan_log_write(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - for (unsigned int i = 0; i < size; ++i) { - outportb(EARLY_LOG_DEVICE, buffer[i]); - } - return size; -} -static fs_node_t _ubsan_log = { .write = &_ubsan_log_write }; - -void ubsan_debug(struct SourceLocation * location) { - fprintf(&_ubsan_log, "[ubsan] %s:%d:%dc - ", location->file_name, location->line, location->column); -} - -void __ubsan_handle_add_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "Overflow in add: %d %d\n", lhs, rhs); -} - -void __ubsan_handle_sub_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "Overflow in sub: %d %d\n", lhs, rhs); -} - -void __ubsan_handle_mul_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "Overflow in mul: %d %d\n", lhs, rhs); -} - -void __ubsan_handle_divrem_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "Overflow in divrem: %d %d\n", lhs, rhs); -} - -void __ubsan_handle_negate_overflow(struct OverflowData * data, unsigned long old) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "Overflow in negate: %d\n", old); -} - -void __ubsan_handle_builtin_unreachable(struct UnreachableData * data) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "called __builtin_unreachable()\n"); -} - -void __ubsan_handle_out_of_bounds(struct OutOfBoundsData * data, unsigned long index) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "out of bounds array reference at %s[%d]\n", data->array_type->type_name, index); -} - -void __ubsan_handle_shift_out_of_bounds(struct ShiftOutOfBoundsData * data, unsigned long lhs, unsigned long rhs) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "shift is out of bounds: %d %d\n", lhs, rhs); -} - -#define IS_ALIGNED(a, b) (((a) & ((__typeof__(a))(b)-1)) == 0) - -void __ubsan_handle_type_mismatch(struct TypeMismatchData * data, unsigned long ptr) { - return; /* Unaligned reads are valid on x86, and we have some very ugly code where this goes poorly. */ - ubsan_debug(&data->location); - if (data->alignment && !IS_ALIGNED(ptr, data->alignment)) { - fprintf(&_ubsan_log, "bad alignment in read at 0x%x (wanted %d)\n", ptr, data->alignment); - } else { - fprintf(&_ubsan_log, "type mismatch in reference at 0x%x\n", ptr); - } -} - -void __ubsan_handle_vla_bound_not_positive(struct VLABoundData * data, unsigned long bound) { - ubsan_debug(&data->location); - fprintf(&_ubsan_log, "vla bound not positive: %d\n", bound); -} - diff --git a/kernel/net/e1000.c b/kernel/net/e1000.c new file mode 100644 index 00000000..1d308260 --- /dev/null +++ b/kernel/net/e1000.c @@ -0,0 +1,496 @@ +/** + * @file kernel/net/e1000.c + * @brief Intel Gigabit Ethernet device driver + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2017-2021 K. Lange + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define INTS ((1 << 2) | (1 << 6) | (1 << 7) | (1 << 1) | (1 << 0)) + +struct e1000_nic { + /* This should be generic netif struct stuff... */ + char if_name[32]; + uint8_t mac[6]; + /* TODO: Address lists? */ + + fs_node_t * device_node; + uint32_t pci_device; + uint16_t deviceid; + uintptr_t mmio_addr; + int irq_number; + + int has_eeprom; + int rx_index; + int tx_index; + int link_status; + + spin_lock_t net_queue_lock; + spin_lock_t alert_lock; + list_t * net_queue; + list_t * rx_wait; + list_t * alert_wait; + + uint8_t * rx_virt[E1000_NUM_RX_DESC]; + uint8_t * tx_virt[E1000_NUM_TX_DESC]; + struct e1000_rx_desc * rx; + struct e1000_tx_desc * tx; + uintptr_t rx_phys; + uintptr_t tx_phys; +}; + +static int device_count = 0; +static struct e1000_nic * devices[32] = {NULL}; + +static uint32_t mmio_read32(uintptr_t addr) { + return *((volatile uint32_t*)(addr)); +} +static void mmio_write32(uintptr_t addr, uint32_t val) { + (*((volatile uint32_t*)(addr))) = val; +} + +static void write_command(struct e1000_nic * device, uint16_t addr, uint32_t val) { + mmio_write32(device->mmio_addr + addr, val); +} + +static uint32_t read_command(struct e1000_nic * device, uint16_t addr) { + return mmio_read32(device->mmio_addr + addr); +} + +static void delay_yield(size_t subticks) { + unsigned long s, ss; + relative_time(0, subticks, &s, &ss); + sleep_until((process_t *)this_core->current_process, s, ss); + switch_task(0); +} + +static void enqueue_packet(struct e1000_nic * device, void * buffer) { + spin_lock(device->net_queue_lock); + list_insert(device->net_queue, buffer); + spin_unlock(device->net_queue_lock); +} + +static struct ethernet_packet * dequeue_packet(struct e1000_nic * device) { + while (!device->net_queue->length) { + sleep_on(device->rx_wait); + } + + spin_lock(device->net_queue_lock); + node_t * n = list_dequeue(device->net_queue); + void* value = n->value; + free(n); + spin_unlock(device->net_queue_lock); + + return value; +} + +static int eeprom_detect(struct e1000_nic * device) { + + /* Definitely not */ + if (device->deviceid == 0x10d3) return 0; + + write_command(device, E1000_REG_EEPROM, 1); + + for (int i = 0; i < 100000 && !device->has_eeprom; ++i) { + uint32_t val = read_command(device, E1000_REG_EEPROM); + if (val & 0x10) device->has_eeprom = 1; + } + + return 0; +} + +static uint16_t eeprom_read(struct e1000_nic * device, uint8_t addr) { + uint32_t temp = 0; + write_command(device, E1000_REG_EEPROM, 1 | ((uint32_t)(addr) << 8)); + while (!((temp = read_command(device, E1000_REG_EEPROM)) & (1 << 4))); + return (uint16_t)((temp >> 16) & 0xFFFF); +} + +static void write_mac(struct e1000_nic * device) { + uint32_t low, high; + memcpy(&low, &device->mac[0], 4); + memcpy(&high,&device->mac[4], 2); + memset((uint8_t *)&high + 2, 0, 2); + high |= 0x80000000; + write_command(device, E1000_REG_RXADDR + 0, low); + write_command(device, E1000_REG_RXADDR + 4, high); +} + +static void read_mac(struct e1000_nic * device) { + if (device->has_eeprom) { + uint32_t t; + t = eeprom_read(device, 0); + device->mac[0] = t & 0xFF; + device->mac[1] = t >> 8; + t = eeprom_read(device, 1); + device->mac[2] = t & 0xFF; + device->mac[3] = t >> 8; + t = eeprom_read(device, 2); + device->mac[4] = t & 0xFF; + device->mac[5] = t >> 8; + } else { + uint32_t mac_addr_low = *(uint32_t *)(device->mmio_addr + E1000_REG_RXADDR); + uint32_t mac_addr_high = *(uint32_t *)(device->mmio_addr + E1000_REG_RXADDR + 4); + device->mac[0] = (mac_addr_low >> 0 ) & 0xFF; + device->mac[1] = (mac_addr_low >> 8 ) & 0xFF; + device->mac[2] = (mac_addr_low >> 16) & 0xFF; + device->mac[3] = (mac_addr_low >> 24) & 0xFF; + device->mac[4] = (mac_addr_high>> 0 ) & 0xFF; + device->mac[5] = (mac_addr_high>> 8 ) & 0xFF; + } +} + +static void e1000_alert_waiters(struct e1000_nic * nic) { + spin_lock(nic->alert_lock); + while (nic->alert_wait->head) { + node_t * node = list_dequeue(nic->alert_wait); + process_t * p = node->value; + free(node); + spin_unlock(nic->alert_lock); + process_alert_node(p, nic->device_node); + spin_lock(nic->alert_lock); + } + spin_unlock(nic->alert_lock); +} + +static void e1000_handle(struct e1000_nic * nic, uint32_t status) { + if (status & ICR_LSC) { + /* TODO: Change interface link status. */ + nic->link_status= (read_command(nic, E1000_REG_STATUS) & (1 << 1)); + } + + if (status & ICR_TXQE) { + /* Transmit queue empty; nothing to do. */ + } + + if (status & ICR_TXDW) { + /* transmit descriptor written */ + } + + if (status & (ICR_RXO | ICR_RXT0)) { + /* Packet received. */ + do { + nic->rx_index = read_command(nic, E1000_REG_RXDESCTAIL); + if (nic->rx_index == (int)read_command(nic, E1000_REG_RXDESCHEAD)) return; + nic->rx_index = (nic->rx_index + 1) % E1000_NUM_RX_DESC; + if (nic->rx[nic->rx_index].status & 0x01) { + uint8_t * pbuf = (uint8_t *)nic->rx_virt[nic->rx_index]; + uint16_t plen = nic->rx[nic->rx_index].length; + + void * packet = malloc(8092); + memcpy(packet, pbuf, plen); + + nic->rx[nic->rx_index].status = 0; + + enqueue_packet(nic, packet); + + write_command(nic, E1000_REG_RXDESCTAIL, nic->rx_index); + } else { + break; + } + } while (1); + wakeup_queue(nic->rx_wait); + e1000_alert_waiters(nic); + } +} + +static int irq_handler(struct regs *r) { + int irq = r->int_no - 32; + int handled = 0; + + for (int i = 0; i < device_count; ++i) { + if (devices[i]->irq_number == irq) { + uint32_t status = read_command(devices[i], E1000_REG_ICR); + if (status) { + write_command(devices[i], 0x00D8,INTS); + e1000_handle(devices[i], status); + read_command(devices[i], E1000_REG_ICR); + if (!handled) { + handled = 1; + irq_ack(irq); + } + write_command(devices[i], 0x00D0,INTS); + } + } + } + + return handled; +} + +static void send_packet(struct e1000_nic * device, uint8_t* payload, size_t payload_size) { + device->tx_index = read_command(device, E1000_REG_TXDESCTAIL); + + memcpy(device->tx_virt[device->tx_index], payload, payload_size); + device->tx[device->tx_index].length = payload_size; + device->tx[device->tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS; + device->tx[device->tx_index].status = 0; + + device->tx_index = (device->tx_index + 1) % E1000_NUM_TX_DESC; + write_command(device, E1000_REG_TXDESCTAIL, device->tx_index); +} + +static void init_rx(struct e1000_nic * device) { + write_command(device, E1000_REG_RXDESCLO, device->rx_phys); + write_command(device, E1000_REG_RXDESCHI, 0); + write_command(device, E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(struct e1000_rx_desc)); + write_command(device, E1000_REG_RXDESCHEAD, 0); + write_command(device, E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1); + + device->rx_index = 0; + + write_command(device, E1000_REG_RCTRL, + RCTL_EN | + (1 << 2) | /* store bad packets */ + (1 << 4) | /* multicast promiscuous */ + (1 << 15) | /* broadcast accept */ + (1 << 26) /* strip CRC */ + ); +} + +static void init_tx(struct e1000_nic * device) { + write_command(device, E1000_REG_TXDESCLO, device->tx_phys); + write_command(device, E1000_REG_TXDESCHI, 0); + write_command(device, E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(struct e1000_tx_desc)); + write_command(device, E1000_REG_TXDESCHEAD, 0); + write_command(device, E1000_REG_TXDESCTAIL, 0); + + device->tx_index = 0; + + write_command(device, E1000_REG_TCTRL, + TCTL_EN | + TCTL_PSP | + read_command(device, E1000_REG_TCTRL)); +} + +static int ioctl_e1000(fs_node_t * node, int request, void * argp) { + struct e1000_nic * nic = node->device; + + switch (request) { + case 0x12340001: + /* fill argp with mac */ + memcpy(argp, nic->mac, 6); + return 0; + default: + return -EINVAL; + } +} + +static uint64_t write_e1000(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { + struct e1000_nic * nic = node->device; + /* write packet */ + send_packet(nic, buffer, size); + return size; +} + +static uint64_t read_e1000(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { + if (size != 8092) return 0; + struct e1000_nic * nic = node->device; + + struct ethernet_packet * packet = dequeue_packet(nic); + memcpy(buffer, packet, 8092); + free(packet); + + return 8092; +} + +static int check_e1000(fs_node_t *node) { + struct e1000_nic * nic = node->device; + return nic->net_queue->head ? 0 : 1; +} + +static int wait_e1000(fs_node_t *node, void * process) { + struct e1000_nic * nic = node->device; + spin_lock(nic->alert_lock); + if (!list_find(nic->alert_wait, process)) { + list_insert(nic->alert_wait, process); + } + list_insert(((process_t *)process)->node_waits, nic->device_node); + spin_unlock(nic->alert_lock); + return 0; +} + +static void e1000_init(void * data) { + struct e1000_nic * nic = data; + uint32_t e1000_device_pci = nic->pci_device; + + nic->rx_phys = mmu_allocate_a_frame() << 12; + if (nic->rx_phys == 0) { + printf("e1000[%s]: unable to allocate memory for buffers\n", nic->if_name); + switch_task(0); + } + nic->rx = mmu_map_from_physical(nic->rx_phys); + nic->tx_phys = nic->rx_phys + 512; + nic->tx = mmu_map_from_physical(nic->tx_phys); + + /* Allocate buffers */ + for (int i = 0; i < E1000_NUM_RX_DESC; ++i) { + nic->rx[i].addr = mmu_allocate_n_frames(2) << 12; + if (nic->rx[i].addr == 0) { + printf("e1000[%s]: unable to allocate memory for receive buffer\n", nic->if_name); + switch_task(0); + } + nic->rx_virt[i] = mmu_map_from_physical(nic->rx[i].addr); + nic->rx[i].status = 0; + } + + for (int i = 0; i < E1000_NUM_TX_DESC; ++i) { + nic->tx[i].addr = mmu_allocate_n_frames(2) << 12; + if (nic->tx[i].addr == 0) { + printf("e1000[%s]: unable to allocate memory for receive buffer\n", nic->if_name); + switch_task(0); + } + nic->tx_virt[i] = mmu_map_from_physical(nic->tx[i].addr); + nic->tx[i].status = 0; + nic->tx[i].cmd = (1 << 0); + } + + uint16_t command_reg = pci_read_field(e1000_device_pci, PCI_COMMAND, 2); + command_reg |= (1 << 2); + command_reg |= (1 << 0); + pci_write_field(e1000_device_pci, PCI_COMMAND, 2, command_reg); + + delay_yield(10000); + + /* Is this size enough? */ + uint32_t initial_bar = pci_read_field(e1000_device_pci, PCI_BAR0, 4); + nic->mmio_addr = (uintptr_t)mmu_map_mmio_region(initial_bar, 0x8000); + + eeprom_detect(nic); + read_mac(nic); + write_mac(nic); + uint32_t ctrl = read_command(nic, E1000_REG_CTRL); + + /* reset phy */ + write_command(nic, E1000_REG_CTRL, ctrl | (0x80000000)); + read_command(nic, E1000_REG_STATUS); + delay_yield(10000); + + /* reset mac */ + write_command(nic, E1000_REG_CTRL, ctrl | (0x04000000)); + read_command(nic, E1000_REG_STATUS); + delay_yield(10000); + + /* Reload EEPROM */ + write_command(nic, E1000_REG_CTRL, ctrl | (0x00002000)); + read_command(nic, E1000_REG_STATUS); + delay_yield(20000); + + /* initialize */ + write_command(nic, E1000_REG_CTRL, ctrl | (1 << 26)); + delay_yield(10000); + + uint32_t status = read_command(nic, E1000_REG_CTRL); + status |= (1 << 5); /* set auto speed detection */ + status |= (1 << 6); /* set link up */ + status &= ~(1 << 3); /* unset link reset */ + status &= ~(1UL << 31UL); /* unset phy reset */ + status &= ~(1 << 7); /* unset invert loss-of-signal */ + write_command(nic, E1000_REG_CTRL, status); + + /* Disables flow control */ + write_command(nic, 0x0028, 0); + write_command(nic, 0x002c, 0); + write_command(nic, 0x0030, 0); + write_command(nic, 0x0170, 0); + + /* Unset flow control */ + status = read_command(nic, E1000_REG_CTRL); + status &= ~(1 << 30); + write_command(nic, E1000_REG_CTRL, status); + delay_yield(10000); + + nic->net_queue = list_create("e1000 net queue", nic); + nic->rx_wait = list_create("e1000 rx sem", nic); + nic->alert_wait = list_create("e1000 select waiters", nic); + + nic->irq_number = pci_get_interrupt(e1000_device_pci); + + irq_install_handler(nic->irq_number, irq_handler, nic->if_name); + + for (int i = 0; i < 128; ++i) { + write_command(nic, 0x5200 + i * 4, 0); + } + + for (int i = 0; i < 64; ++i) { + write_command(nic, 0x4000 + i * 4, 0); + } + + init_rx(nic); + init_tx(nic); + + /* Twiddle interrupts */ + write_command(nic, 0x00D0, 0xFFFFFFFF); + write_command(nic, 0x00D8, 0xFFFFFFFF); + write_command(nic, 0x00D0, INTS); + delay_yield(10000); + + nic->link_status = (read_command(nic, E1000_REG_STATUS) & (1 << 1)); + + nic->device_node = calloc(sizeof(fs_node_t),1); + snprintf(nic->device_node->name, 100, "%s", nic->if_name); + nic->device_node->flags = FS_BLOCKDEVICE; /* NETDEVICE? */ + nic->device_node->mask = 0666; /* let everyone in on the party for now */ + nic->device_node->ioctl = ioctl_e1000; + nic->device_node->write = write_e1000; + nic->device_node->read = read_e1000; + nic->device_node->selectcheck = check_e1000; + nic->device_node->selectwait = wait_e1000; + nic->device_node->device = nic; + + char tmp[100]; + snprintf(tmp,100,"/dev/net/%s", nic->if_name); + vfs_mount(tmp, nic->device_node); + + switch_task(0); +} + +static void find_e1000(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * found) { + if ((vendorid == 0x8086) && (deviceid == 0x100e || deviceid == 0x1004 || deviceid == 0x100f || deviceid == 0x10ea || deviceid == 0x10d3)) { + /* Allocate a device */ + struct e1000_nic * nic = calloc(1,sizeof(struct e1000_nic)); + nic->pci_device = device; + nic->deviceid = deviceid; + devices[device_count++] = nic; + + snprintf(nic->if_name, 31, + "enp%ds%d", + (int)pci_extract_bus(device), + (int)pci_extract_slot(device)); + + char worker_name[34]; + snprintf(worker_name, 33, "[%s]", nic->if_name); + spawn_worker_thread(e1000_init, worker_name, nic); + + *(int*)found = 1; + } +} + +void e1000_initialize(void) { + uint32_t found = 0; + pci_scan(&find_e1000, -1, &found); + + if (!found) { + /* TODO: Clean up? Remove ourselves? */ + return; + } +} + diff --git a/kernel/net/ipv4.c b/kernel/net/ipv4.c new file mode 100644 index 00000000..1f581376 --- /dev/null +++ b/kernel/net/ipv4.c @@ -0,0 +1,29 @@ +/** + * @file kernel/net/ipv4.c + * @brief IPv4 protocol implementation. + * + * @copyright This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * @author 2021 K. Lange + */ +#include +#include +#include +#include +#include + +#include + +long net_ipv4_socket(int type, int protocol) { + /* Ignore protocol, make socket for 'type' only... */ + switch (type) { + case SOCK_DGRAM: + printf("udp socket...\n"); + return -EINVAL; + case SOCK_STREAM: + printf("tcp socket...\n"); + return -EINVAL; + default: + return -EINVAL; + } +} diff --git a/kernel/net/netif.c b/kernel/net/netif.c new file mode 100644 index 00000000..7d82154a --- /dev/null +++ b/kernel/net/netif.c @@ -0,0 +1,22 @@ +/** + * @file kernel/net/netif.c + * @brief Network interface manager. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2021 K. Lange + */ + +#include +#include +#include +#include +#include +#include + +#include + +void net_install(void) { + map_vfs_directory("/dev/net"); +} diff --git a/kernel/net/socket.c b/kernel/net/socket.c new file mode 100644 index 00000000..fbaa6004 --- /dev/null +++ b/kernel/net/socket.c @@ -0,0 +1,68 @@ +/** + * @file kernel/net/socket.c + * @brief Top-level socket manager. + * + * Provides the standard socket interface. + * + * @copyright This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * @author 2021 K. Lange + */ +#include +#include +#include +#include + +#include + +/** + * TODO: Should we have an interface for modules to install protocol handlers? + * Thinking this should work like the VFS, with method tables for different + * protocol handlers, but a lot of this stuff is also just generic... + */ +extern long net_ipv4_socket(int,int); + +long net_socket(int domain, int type, int protocol) { + switch (domain) { + case AF_INET: + return net_ipv4_socket(type, protocol); + default: + return -EINVAL; + } +} + +long net_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { + return -EINVAL; +} + +long net_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { + return -EINVAL; +} + +long net_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + return -EINVAL; +} + +long net_accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen) { + return -EINVAL; +} + +long net_listen(int sockd, int backlog) { + return -EINVAL; +} + +long net_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + return -EINVAL; +} + +long net_recv(int sockfd, struct msghdr * msg, int flags) { + return -EINVAL; +} + +long net_send(int sockfd, const struct msghdr * msg, int flags) { + return -EINVAL; +} + +long net_shutdown(int sockfd, int how) { + return -EINVAL; +} diff --git a/kernel/spin.c b/kernel/spin.c deleted file mode 100644 index 102a9191..00000000 --- a/kernel/spin.c +++ /dev/null @@ -1,57 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2015 Dale Weiler - * - * Spin locks with waiters - * - */ -#include - -static inline int arch_atomic_swap(volatile int * x, int v) { - asm("xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory"); - return v; -} - -static inline void arch_atomic_store(volatile int * p, int x) { - asm("movl %1, %0" : "=m"(*p) : "r"(x) : "memory"); -} - -static inline void arch_atomic_inc(volatile int * x) { - asm("lock; incl %0" : "=m"(*x) : "m"(*x) : "memory"); -} - -static inline void arch_atomic_dec(volatile int * x) { - asm("lock; decl %0" : "=m"(*x) : "m"(*x) : "memory"); -} - -void spin_wait(volatile int * addr, volatile int * waiters) { - if (waiters) { - arch_atomic_inc(waiters); - } - while (*addr) { - switch_task(1); - } - if (waiters) { - arch_atomic_dec(waiters); - } -} - -void spin_lock(spin_lock_t lock) { - while (arch_atomic_swap(lock, 1)) { - spin_wait(lock, lock+1); - } -} - -void spin_init(spin_lock_t lock) { - lock[0] = 0; - lock[1] = 0; -} - -void spin_unlock(spin_lock_t lock) { - if (lock[0]) { - arch_atomic_store(lock, 0); - if (lock[1]) - switch_task(1); - } -} diff --git a/kernel/sys/module.c b/kernel/sys/module.c deleted file mode 100644 index a4252a5e..00000000 --- a/kernel/sys/module.c +++ /dev/null @@ -1,441 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include - -#include - -#define SYMBOLTABLE_HASHMAP_SIZE 10 -#define MODULE_HASHMAP_SIZE 10 - -static hashmap_t * symboltable = NULL; -static hashmap_t * modules = NULL; - -extern char kernel_symbols_start[]; -extern char kernel_symbols_end[]; - -typedef struct { - uintptr_t addr; - char name[]; -} kernel_symbol_t; - -/* Cannot use symboltable here because symbol_find is used during initialization - * of IRQs and ISRs. - */ -void (* symbol_find(const char * name))(void) { - kernel_symbol_t * k = (kernel_symbol_t *)&kernel_symbols_start; - - while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { - if (strcmp(k->name, name)) { - k = (kernel_symbol_t *)((uintptr_t)k + sizeof *k + strlen(k->name) + 1); - continue; - } - return (void (*)(void))k->addr; - } - - return NULL; -} - -int module_quickcheck(void * blob) { - - Elf32_Header * target = (Elf32_Header *)blob; - char * head = (char *)blob; - - if (target->e_ident[0] != ELFMAG0 || - target->e_ident[1] != ELFMAG1 || - target->e_ident[2] != ELFMAG2 || - target->e_ident[3] != ELFMAG3) { - - goto _maybe_pack; - } - - if (target->e_type != ET_REL) { - goto _maybe_pack; - } - - return 1; - -_maybe_pack: - if (head[0] == 'P' && head[1] == 'A' && head[2] == 'C' && head[3] == 'K') { - return 2; - } - - return 0; -} - -void * module_load_direct(void * blob, size_t length) { - Elf32_Header * target = (Elf32_Header *)blob; - - if (target->e_ident[0] != ELFMAG0 || - target->e_ident[1] != ELFMAG1 || - target->e_ident[2] != ELFMAG2 || - target->e_ident[3] != ELFMAG3) { - - debug_print(ERROR, "Module is not a valid ELF object."); - - goto mod_load_error_unload; - } - - char * shstrtab = NULL; - char * symstrtab = NULL; - Elf32_Shdr * sym_shdr = NULL; - char * deps = NULL; - size_t deps_length = 0; - - /* TODO: Actually load the ELF somewhere! This is moronic, you're not initializing a BSS! */ - /* (and maybe keep the elf header somewhere) */ - - { - unsigned int i = 0; - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (i == target->e_shstrndx) { - shstrtab = (char *)((uintptr_t)target + shdr->sh_offset); - } - i++; - } - } - if (!shstrtab) { - debug_print(ERROR, "Could not locate module section header string table."); - goto mod_load_error_unload; - } - - { - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (shdr->sh_type == SHT_STRTAB && (!strcmp((char *)((uintptr_t)shstrtab + shdr->sh_name), ".strtab"))) { - symstrtab = (char *)((uintptr_t)target + shdr->sh_offset); - } - } - } - if (!shstrtab) { - debug_print(ERROR, "Could not locate module symbol string table."); - goto mod_load_error_unload; - } - - { - debug_print(INFO, "Checking dependencies."); - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if ((!strcmp((char *)((uintptr_t)shstrtab + shdr->sh_name), "moddeps"))) { - deps = (char*)((Elf32_Addr)target + shdr->sh_offset); - deps_length = shdr->sh_size; - - unsigned int i = 0; - while (i < deps_length) { - if (strlen(&deps[i]) && !hashmap_get(modules, &deps[i])) { - debug_print(ERROR, " %s - not loaded", &deps[i]); - goto mod_load_error_unload; - } - debug_print(INFO, " %s", &deps[i]); - i += strlen(&deps[i]) + 1; - } - } - } - } - - { - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (shdr->sh_type == SHT_SYMTAB) { - sym_shdr = shdr; - } - } - } - if (!sym_shdr) { - debug_print(ERROR, "Could not locate section for symbol table."); - goto mod_load_error_unload; - } - - uintptr_t text_addr = 0; - - { - debug_print(INFO, "Loading sections."); - int index = 0; - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (shdr->sh_type == SHT_NOBITS) { - shdr->sh_addr = (Elf32_Addr)malloc(shdr->sh_size); - memset((void *)shdr->sh_addr, 0x00, shdr->sh_size); - } else { - shdr->sh_addr = (Elf32_Addr)target + shdr->sh_offset; - if (index == 1) { - text_addr = shdr->sh_addr; - } - } - index++; - } - } - - int undefined = 0; - - hashmap_t * local_symbols = hashmap_create(10); - { - Elf32_Sym * table = (Elf32_Sym *)((uintptr_t)target + sym_shdr->sh_offset); - while ((uintptr_t)table - ((uintptr_t)target + sym_shdr->sh_offset) < sym_shdr->sh_size) { - if (table->st_name) { - if (ELF32_ST_BIND(table->st_info) == STB_GLOBAL) { - char * name = (char *)((uintptr_t)symstrtab + table->st_name); - if (table->st_shndx == 0) { - if (!hashmap_get(symboltable, name)) { - debug_print(ERROR, "Unresolved symbol in module: %s", name); - undefined = 1; - } - } else { - Elf32_Shdr * s = NULL; - { - int i = 0; - int set = 0; - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (i == table->st_shndx) { - set = 1; - s = shdr; - break; - } - i++; - } - /* - * Common symbols - * If we were a proper linker, we'd look at a bunch of objects - * to find out if one of them defined this, but instead we have - * a strict hierarchy of symbol resolution, so we know that an - * undefined common symbol at this point should be immediately - * allocated and zeroed. - */ - if (!set && table->st_shndx == 65522) { - if (!hashmap_get(symboltable, name)) { - void * final = malloc(table->st_value); - memset(final, 0, table->st_value); - debug_print(NOTICE, "point %s to 0x%x", name, (uintptr_t)final); - hashmap_set(symboltable, name, (void *)final); - hashmap_set(local_symbols, name, (void *)final); - } - } - } - if (s) { - uintptr_t final = s->sh_addr + table->st_value; - hashmap_set(symboltable, name, (void *)final); - hashmap_set(local_symbols, name, (void *)final); - } else { - debug_print(ERROR, "Not resolving %s", name); - } - } - } else if (ELF32_ST_BIND(table->st_info) == STB_LOCAL) { - char * name = (char *)((uintptr_t)symstrtab + table->st_name); - Elf32_Shdr * s = NULL; - { - int i = 0; - int set = 0; - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (i == table->st_shndx) { - set = 1; - s = shdr; - break; - } - i++; - } - if (!set && table->st_shndx == 65522) { - if (!hashmap_get(symboltable, name)) { - void * final = calloc(1, table->st_value); - debug_print(NOTICE, "point %s to 0x%x", name, (uintptr_t)final); - hashmap_set(local_symbols, name, (void *)final); - } - } - } - if (s) { - uintptr_t final = s->sh_addr + table->st_value; - hashmap_set(local_symbols, name, (void *)final); - } - } - } - table++; - } - } - if (undefined) { - debug_print(ERROR, "This module is faulty! Verify it specifies all of its"); - debug_print(ERROR, "dependencies properly with MODULE_DEPENDS."); - goto mod_load_error; - } - - { - for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { - Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); - if (shdr->sh_type == SHT_REL) { - Elf32_Rel * section_rel = (void *)(shdr->sh_addr); - Elf32_Rel * table = section_rel; - Elf32_Sym * symtable = (Elf32_Sym *)(sym_shdr->sh_addr); - while ((uintptr_t)table - (shdr->sh_addr) < shdr->sh_size) { - Elf32_Sym * sym = &symtable[ELF32_R_SYM(table->r_info)]; - Elf32_Shdr * rs = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + shdr->sh_info * target->e_shentsize)); - - uintptr_t addend = 0; - uintptr_t place = 0; - uintptr_t symbol = 0; - uintptr_t *ptr = NULL; - - if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { - Elf32_Shdr * s = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + sym->st_shndx * target->e_shentsize)); - ptr = (uintptr_t *)(table->r_offset + rs->sh_addr); - addend = *ptr; - place = (uintptr_t)ptr; - symbol = s->sh_addr; - } else { - char * name = (char *)((uintptr_t)symstrtab + sym->st_name); - ptr = (uintptr_t *)(table->r_offset + rs->sh_addr); - addend = *ptr; - place = (uintptr_t)ptr; - if (!hashmap_get(symboltable, name)) { - if (!hashmap_get(local_symbols, name)) { - debug_print(ERROR, "Wat? Missing symbol %s", name); - debug_print(ERROR, "Here's all the symbols:"); - } else { - symbol = (uintptr_t)hashmap_get(local_symbols, name); - } - } else { - symbol = (uintptr_t)hashmap_get(symboltable, name); - } - } - switch (ELF32_R_TYPE(table->r_info)) { - case 1: - *ptr = addend + symbol; - break; - case 2: - *ptr = addend + symbol - place; - break; - default: - debug_print(ERROR, "Unsupported relocation type: %d", ELF32_R_TYPE(table->r_info)); - goto mod_load_error; - } - - table++; - } - } - } - } - - debug_print(INFO, "Locating module information..."); - module_defs * mod_info = NULL; - list_t * hash_keys = hashmap_keys(local_symbols); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - if (startswith(key, "module_info_")) { - mod_info = hashmap_get(local_symbols, key); - } - } - list_free(hash_keys); - free(hash_keys); - if (!mod_info) { - debug_print(ERROR, "Failed to locate module information structure!"); - goto mod_load_error; - } - - mod_info->initialize(); - - debug_print(NOTICE, "Finished loading module %s", mod_info->name); - - /* We don't do this anymore - * TODO: Do this in the module unload function - hashmap_free(local_symbols); - free(local_symbols); - */ - - module_data_t * mod_data = malloc(sizeof(module_data_t)); - mod_data->mod_info = mod_info; - mod_data->bin_data = target; - mod_data->symbols = local_symbols; - mod_data->end = (uintptr_t)target + length; - mod_data->deps = deps; - mod_data->deps_length = deps_length; - mod_data->text_addr = text_addr; - - hashmap_set(modules, mod_info->name, (void *)mod_data); - - return mod_data; - -mod_load_error_unload: - return (void *)-1; - -mod_load_error: - return NULL; -} - -uintptr_t module_get_text_addr(char * name) { - module_data_t * mod_data = hashmap_get(modules, name); - if (!mod_data) return -1; - return mod_data->text_addr; -} - -/** - * Install a module from a file and return - * a pointer to its module_info structure. - */ -void * module_load(char * filename) { - fs_node_t * file = kopen(filename, 0); - if (!file) { - debug_print(ERROR, "Failed to load module: %s", filename); - return NULL; - } - - debug_print(NOTICE, "Attempting to load kernel module: %s", filename); - - void * blob = (void *)kvmalloc(file->length); - read_fs(file, 0, file->length, (uint8_t *)blob); - - void * result = module_load_direct(blob, file->length); - - if (result == (void *)-1) { - debug_print(ERROR, "Error loading module."); - free(blob); - result = NULL; - } - - close_fs(file); - return result; -} - -/** - * Remove a loaded module. - */ -void module_unload(char * name) { - /* XXX: Lookup the module by name and verify it has no dependencies loaded. */ - /* XXX: Call module_info->finish() */ - /* XXX: Unmap symbols defined the module that weren't otherwise defined. */ - /* XXX: Deallocate the regions the module was mapped into */ -} - -void modules_install(void) { - /* Initialize the symboltable, we use a hashmap of symbols to addresses */ - symboltable = hashmap_create(SYMBOLTABLE_HASHMAP_SIZE); - - /* Load all of the kernel symbols into the symboltable */ - kernel_symbol_t * k = (kernel_symbol_t *)&kernel_symbols_start; - - while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { - hashmap_set(symboltable, k->name, (void *)k->addr); - k = (kernel_symbol_t *)((uintptr_t)k + sizeof(kernel_symbol_t) + strlen(k->name) + 1); - } - - /* Also add the kernel_symbol_start and kernel_symbol_end (these were excluded from the generator) */ - hashmap_set(symboltable, "kernel_symbols_start", &kernel_symbols_start); - hashmap_set(symboltable, "kernel_symbols_end", &kernel_symbols_end); - - /* Initialize the module name -> object hashmap */ - modules = hashmap_create(MODULE_HASHMAP_SIZE); -} - -/* Accessors. */ -hashmap_t * modules_get_list(void) { - return modules; -} - -hashmap_t * modules_get_symbols(void) { - return symboltable; -} diff --git a/kernel/sys/panic.c b/kernel/sys/panic.c deleted file mode 100644 index 05cf1f07..00000000 --- a/kernel/sys/panic.c +++ /dev/null @@ -1,102 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Panic functions - */ -#include -#include -#include -#include - -void halt_and_catch_fire(char * error_message, const char * file, int line, struct regs * regs) { - IRQ_OFF; - debug_print(ERROR, "HACF: %s", error_message); - debug_print(ERROR, "Proc: %d", getpid()); - debug_print(ERROR, "File: %s", file); - debug_print(ERROR, "Line: %d", line); - if (regs) { - debug_print(ERROR, "Registers at interrupt:"); - debug_print(ERROR, "eax=0x%x ebx=0x%x", regs->eax, regs->ebx); - debug_print(ERROR, "ecx=0x%x edx=0x%x", regs->ecx, regs->edx); - debug_print(ERROR, "esp=0x%x ebp=0x%x", regs->esp, regs->ebp); - debug_print(ERROR, "Error code: 0x%x", regs->err_code); - debug_print(ERROR, "EFLAGS: 0x%x", regs->eflags); - debug_print(ERROR, "User ESP: 0x%x", regs->useresp); - debug_print(ERROR, "eip=0x%x", regs->eip); - } - send_signal(current_process->id, SIGILL, 1); -} - -char * probable_function_name(uintptr_t ip, uintptr_t * out_addr) { - char * closest = NULL; - size_t distance = 0xFFFFFFFF; - uintptr_t addr = 0; - - if (modules_get_symbols()) { - list_t * hash_keys = hashmap_keys(modules_get_symbols()); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - uintptr_t a = (uintptr_t)hashmap_get(modules_get_symbols(), key); - - if (!a) continue; - - size_t d = 0xFFFFFFFF; - if (a <= ip) { - d = ip - a; - } - if (d < distance) { - closest = key; - distance = d; - addr = a; - } - } - free(hash_keys); - - } - *out_addr = addr; - return closest; -} - -void assert_failed(const char *file, uint32_t line, const char *desc) { - IRQ_OFF; - debug_print(INSANE, "Kernel Assertion Failed: %s", desc); - debug_print(INSANE, "File: %s", file); - debug_print(INSANE, "Line: %d", line); - debug_print(INSANE, "System Halted!"); - -#if 1 - unsigned int * ebp = (unsigned int *)(&file - 2); - - debug_print(INSANE, "Stack trace:"); - - for (unsigned int frame = 0; frame < 20; ++frame) { - unsigned int eip = ebp[1]; - if (eip == 0) break; - ebp = (unsigned int *)(ebp[0]); - unsigned int * args = &ebp[2]; - (void)args; - uintptr_t addr; - char * func = probable_function_name(eip, &addr); - debug_print(INSANE, " 0x%x (%s+%d)\n", eip, func, eip-addr); - } - - -#endif - - if (debug_video_crash) { - char msg[4][256]; - sprintf(msg[0], "Kernel Assertion Failed: %s", desc); - sprintf(msg[1], "File: %s", file); - sprintf(msg[2], "Line: %d", line); - sprintf(msg[3], "System Halted!"); - char * msgs[] = {msg[0], msg[1], msg[2], msg[3], NULL}; - debug_video_crash(msgs); - } - - while (1) { - IRQ_OFF; - PAUSE; - } -} diff --git a/kernel/sys/process.c b/kernel/sys/process.c index d2260cc6..73be21d3 100644 --- a/kernel/sys/process.c +++ b/kernel/sys/process.c @@ -1,44 +1,219 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2012 Markus Schober - * Copyright (C) 2015 Dale Weiler +/** + * @file kernel/sys/process.c + * @brief Task switch and thread scheduling. * - * Processes + * Implements the primary scheduling primitives for the kernel. * - * Internal format format for a process and functions to spawn - * new processes and manage the process tree. + * Generally, what the kernel refers to as a "process" is an individual thread. + * The POSIX concept of a "process" is represented in Misaka as a collection of + * threads and their shared paging, signal, and file descriptor tables. + * + * Kernel threads are also "processes", referred to as "tasklets". + * + * Misaka allows nested kernel preemption, and task switching involves saving + * kernel state in a manner similar to setjmp/longjmp, as well as saving the + * outer context in the case of a nested task switch. + * + * @copyright This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * @author 2011-2021 K. Lange + * @author 2012 Markus Schober + * @author 2015 Dale Weiler */ -#include +#include #include -#include -#include -#include #include - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include -#include -#include +/* FIXME: This only needs the size of the regs struct... */ +#include -tree_t * process_tree; /* Parent->Children tree */ -list_t * process_list; /* Flat storage */ -list_t * process_queue; /* Ready queue */ -list_t * sleep_queue; -volatile process_t * current_process = NULL; -process_t * kernel_idle_task = NULL; +tree_t * process_tree; /* Stores the parent-child process relationships; the root of this graph is 'init'. */ +list_t * process_list; /* Stores all existing processes. Mostly used for sanity checking or for places where iterating over all processes is useful. */ +list_t * process_queue; /* Scheduler ready queue. This the round-robin source. The head is the next process to run. */ +list_t * sleep_queue; /* Ordered list of processes waiting to be awoken by timeouts. The head is the earliest thread to awaken. */ +struct ProcessorLocal processor_local_data[32] = {0}; +int processor_count = 1; + +/* The following locks protect access to the process tree, scheduler queue, + * sleeping, and the very special wait queue... */ static spin_lock_t tree_lock = { 0 }; static spin_lock_t process_queue_lock = { 0 }; static spin_lock_t wait_lock_tmp = { 0 }; static spin_lock_t sleep_lock = { 0 }; -static bitset_t pid_set; +/** + * @brief Restore the context of the next available process's kernel thread. + * + * Loads the next ready process from the scheduler queue and resumes it. + * + * If no processes are available, the local idle task will be run from the beginning + * of its function entry. + * + * If the next process in the queue has been marked as finished, it will be discard + * until a non-finished process is found. + * + * If the next process is new, it will be marked as started, and its entry point + * jumped to. + * + * For all other cases, the process's stored kernel thread state will be restored + * and execution will contain in @ref switch_task with a return value of 1. + * + * Note that switch_next does not return and should be called only when the current + * process has been properly added to a scheduling queue, or marked as awaiting cleanup, + * otherwise its return state if resumed is undefined and generally whatever the state + * was when that process last entered switch_task. + * + * @returns never. + */ +void switch_next(void) { + this_core->previous_process = this_core->current_process; -/* Default process name string */ -char * default_name = "[unnamed]"; + /* Get the next available process, discarded anything in the queue + * marked as finished. */ + do { + this_core->current_process = next_ready_process(); + } while (this_core->current_process->flags & PROC_FLAG_FINISHED); + /* Restore paging and task switch context. */ + mmu_set_directory(this_core->current_process->thread.page_directory->directory); + arch_set_kernel_stack(this_core->current_process->image.stack); + + if ((this_core->current_process->flags & PROC_FLAG_FINISHED) || (!this_core->current_process->signal_queue)) { + printf("Should not have this process...\n"); + if (this_core->current_process->flags & PROC_FLAG_FINISHED) printf("It is marked finished.\n"); + if (!this_core->current_process->signal_queue) printf("It doesn't have a signal queue.\n"); + arch_fatal(); + __builtin_unreachable(); + } + + if (this_core->current_process->flags & PROC_FLAG_STARTED) { + /* If this process has a signal pending, we save its current context - including + * the entire kernel stack - before resuming switch_task. */ + if (!this_core->current_process->signal_kstack) { + if (this_core->current_process->signal_queue->length > 0) { + this_core->current_process->signal_kstack = malloc(KERNEL_STACK_SIZE); + memcpy(this_core->current_process->signal_kstack, (void*)(this_core->current_process->image.stack - KERNEL_STACK_SIZE), KERNEL_STACK_SIZE); + memcpy((thread_t*)&this_core->current_process->signal_state, (thread_t*)&this_core->current_process->thread, sizeof(thread_t)); + } + } + } + + /* Mark the process as running and started. */ + __sync_or_and_fetch(&this_core->current_process->flags, PROC_FLAG_STARTED); + + /* Jump to next */ + arch_restore_context(&this_core->current_process->thread); + __builtin_unreachable(); +} + +extern void * _ret_from_preempt_source; + +/** + * @brief Yield the processor to the next available task. + * + * Yields the current process, allowing the next to run. Can be called both as + * part of general preemption or from blocking tasks; in the latter case, + * the process should be added to a scheduler queue to be awakoen later when the + * blocking operation is completed and @p reschedule should be set to 0. + * + * @param reschedule Non-zero if this process should be added to the ready queue. + */ +void switch_task(uint8_t reschedule) { + + /* switch_task() called but the scheduler isn't enabled? Resume... this is probably a bug. */ + if (!this_core->current_process) return; + + if (this_core->current_process == this_core->kernel_idle_task && __builtin_return_address(0) != &_ret_from_preempt_source) { + printf("Context switch from kernel_idle_task triggered from somewhere other than pre-emption source. Halting.\n"); + printf("This generally means that a driver responding to interrupts has attempted to yield in its interrupt context.\n"); + printf("Ensure that all device drivers which respond to interrupts do so with non-blocking data structures.\n"); + printf(" Return address of switch_task: %p\n", __builtin_return_address(0)); + arch_fatal(); + } + + /* If a process got to switch_task but was not marked as running, it must be exiting and we don't + * want to waste time saving context for it. Also, kidle is always resumed from the top of its + * loop function, so we don't save any context for it either. */ + if (!(this_core->current_process->flags & PROC_FLAG_RUNNING) || (this_core->current_process == this_core->kernel_idle_task)) { + switch_next(); + return; + } + + arch_save_floating((process_t*)this_core->current_process); + + /* 'setjmp' - save the execution context. When this call returns '1' we are back + * from a task switch and have been awoken if we were sleeping. */ + if (arch_save_context(&this_core->current_process->thread) == 1) { + arch_restore_floating((process_t*)this_core->current_process); + + fix_signal_stacks(); + if (!(this_core->current_process->flags & PROC_FLAG_FINISHED)) { + if (this_core->current_process->signal_queue->length > 0) { + node_t * node = list_dequeue(this_core->current_process->signal_queue); + signal_t * sig = node->value; + free(node); + handle_signal((process_t*)this_core->current_process,sig); + } + } + + return; + } + + /* If this is a normal yield, we reschedule. + * XXX: Is this going to work okay with SMP? I think this whole thing + * needs to be wrapped in a lock, but also what if we put the + * thread into a schedule queue previously but a different core + * picks it up before we saved the thread context or the FPU state... */ + if (reschedule) { + make_process_ready((process_t*)this_core->current_process); + } + + /* @ref switch_next() does not return. */ + switch_next(); +} + +/** + * @brief Initial scheduler datastructures. + * + * Called by early system startup to allocate trees and lists + * the schedule uses to track processes. + */ +void initialize_process_tree(void) { + process_tree = tree_create(); + process_list = list_create("global process list",NULL); + process_queue = list_create("global scheduler queue",NULL); + sleep_queue = list_create("global timed sleep queue",NULL); + + /* TODO: PID bitset? */ +} + +/** + * @brief Determines if a process is alive and valid. + * + * Scans @ref process_list to see if @p process is a valid + * process object or not. + * + * XXX This is horribly inefficient, and its very existence + * is likely indicative of bugs whereever it needed to + * be called... + * + * @param process Process object to check. + * @returns 1 if the process is valid, 0 if it is not. + */ int is_valid_process(process_t * process) { foreach(lnode, process_list) { if (lnode->value == process) { @@ -49,263 +224,165 @@ int is_valid_process(process_t * process) { return 0; } -/* - * This makes a nice 4096-byte bitmap. It also happens - * to be pid_max on 32-bit Linux, so that's kinda nice. - */ -#define MAX_PID 32768 - -/* - * Initialize the process tree and ready queue. - */ -void initialize_process_tree(void) { - process_tree = tree_create(); - process_list = list_create(); - process_queue = list_create(); - sleep_queue = list_create(); - - /* Start off with enough bits for 64 processes */ - bitset_init(&pid_set, MAX_PID / 8); - /* First two bits are set by default */ - bitset_set(&pid_set, 0); - bitset_set(&pid_set, 1); -} - -/* - * Recursively print a process node to the console. +/** + * @brief Allocate a new file descriptor. * - * @param node Node to print. - * @param height Current depth in the tree. - */ -void debug_print_process_tree_node(tree_node_t * node, size_t height) { - /* End recursion on a blank entry */ - if (!node) return; - char * tmp = malloc(512); - memset(tmp, 0, 512); - char * c = tmp; - /* Indent output */ - for (uint32_t i = 0; i < height; ++i) { - c += sprintf(c, " "); - } - /* Get the current process */ - process_t * proc = (process_t *)node->value; - /* Print the process name */ - c += sprintf(c, "%d.%d %s", proc->group ? proc->group : proc->id, proc->id, proc->name); - if (proc->description) { - /* And, if it has one, its description */ - c += sprintf(c, " %s", proc->description); - } - if (proc->finished) { - c += sprintf(c, " [zombie]"); - } - /* Linefeed */ - debug_print(NOTICE, "%s", tmp); - free(tmp); - foreach(child, node->children) { - /* Recursively print the children */ - debug_print_process_tree_node(child->value, height + 1); - } -} - -/* - * Print the process tree to the console. - */ -void debug_print_process_tree(void) { - debug_print_process_tree_node(process_tree->root, 0); -} - -/* - * Retreive the next ready process. - * XXX: POPs from the ready queue! + * Adds a new entry to the file descriptor table for @p proc + * pointing to the file @p node. The file descriptor's offset + * and file modes must be set by the caller afterwards. * - * @return A pointer to the next process in the queue. + * @param proc Process whose file descriptor should be modified. + * @param node VFS object to add a reference to. + * @returns the new file descriptor index */ -process_t * next_ready_process(void) { - if (!process_available()) { - return kernel_idle_task; - } - if (process_queue->head->owner != process_queue) { - debug_print(ERROR, "Erroneous process located in process queue: node 0x%x has owner 0x%x, but process_queue is 0x%x", process_queue->head, process_queue->head->owner, process_queue); - - process_t * proc = process_queue->head->value; - - debug_print(ERROR, "PID associated with this node is %d", proc->id); - } - node_t * np = list_dequeue(process_queue); - assert(np && "Ready queue is empty."); - process_t * next = np->value; - return next; -} - -/* - * Reinsert a process into the ready queue. - * - * @param proc Process to reinsert - */ -void make_process_ready(process_t * proc) { - if (proc->sleep_node.owner != NULL) { - if (proc->sleep_node.owner == sleep_queue) { - /* XXX can't wake from timed sleep */ - if (proc->timed_sleep_node) { - IRQ_OFF; - spin_lock(sleep_lock); - list_delete(sleep_queue, proc->timed_sleep_node); - spin_unlock(sleep_lock); - IRQ_RES; - proc->sleep_node.owner = NULL; - free(proc->timed_sleep_node->value); - } - /* Else: I have no idea what happened. */ - } else { - proc->sleep_interrupted = 1; - spin_lock(wait_lock_tmp); - list_delete((list_t*)proc->sleep_node.owner, &proc->sleep_node); - spin_unlock(wait_lock_tmp); +unsigned long process_append_fd(process_t * proc, fs_node_t * node) { + spin_lock(proc->fds->lock); + /* Fill gaps */ + for (unsigned long i = 0; i < proc->fds->length; ++i) { + if (!proc->fds->entries[i]) { + proc->fds->entries[i] = node; + /* modes, offsets must be set by caller */ + proc->fds->modes[i] = 0; + proc->fds->offsets[i] = 0; + spin_unlock(proc->fds->lock); + return i; } } - if (proc->sched_node.owner) { - debug_print(WARNING, "Can't make process ready without removing from owner list: %d", proc->id); - debug_print(WARNING, " (This is a bug) Current owner list is 0x%x (ready queue is 0x%x)", proc->sched_node.owner, process_queue); - return; + /* No gaps, expand */ + if (proc->fds->length == proc->fds->capacity) { + proc->fds->capacity *= 2; + proc->fds->entries = realloc(proc->fds->entries, sizeof(fs_node_t *) * proc->fds->capacity); + proc->fds->modes = realloc(proc->fds->modes, sizeof(int) * proc->fds->capacity); + proc->fds->offsets = realloc(proc->fds->offsets, sizeof(uint64_t) * proc->fds->capacity); } - spin_lock(process_queue_lock); - list_append(process_queue, &proc->sched_node); - spin_unlock(process_queue_lock); + proc->fds->entries[proc->fds->length] = node; + /* modes, offsets must be set by caller */ + proc->fds->modes[proc->fds->length] = 0; + proc->fds->offsets[proc->fds->length] = 0; + proc->fds->length++; + spin_unlock(proc->fds->lock); + return proc->fds->length-1; } - -extern void tree_remove_reparent_root(tree_t * tree, tree_node_t * node); - -/* - * Delete a process from the process tree +/** + * @brief Allocate a process identifier. * - * @param proc Process to find and remove. + * Obtains the next available process identifier. + * + * FIXME This used to use a bitset in Toaru32 so it could + * handle overflow of the pid counter. We need to + * bring that back. */ -void delete_process(process_t * proc) { - tree_node_t * entry = proc->tree_entry; - - /* The process must exist in the tree, or the client is at fault */ - if (!entry) return; - - /* We can not remove the root, which is an error anyway */ - assert((entry != process_tree->root) && "Attempted to kill init."); - - if (process_tree->root == entry) { - /* We are init, don't even bother. */ - return; - } - - /* Remove the entry. */ - spin_lock(tree_lock); - /* Reparent everyone below me to init */ - int has_children = entry->children->length; - tree_remove_reparent_root(process_tree, entry); - list_delete(process_list, list_find(process_list, proc)); - spin_unlock(tree_lock); - - if (has_children) { - process_t * init = process_tree->root->value; - wakeup_queue(init->wait_queue); - } - - bitset_clear(&pid_set, proc->id); - - /* Uh... */ - free(proc); +pid_t get_next_pid(void) { + static pid_t _next_pid = 2; + return __sync_fetch_and_add(&_next_pid,1); } +/** + * @brief The idle task. + * + * Sits in a loop forever. Scheduled whenever there is nothing + * else to do. Actually always enters from the top of the function + * whenever scheduled, as we don't both to save its state. + */ static void _kidle(void) { while (1) { - IRQ_ON; - PAUSE; + arch_pause(); } } -/* - * Spawn the idle "process". +static void _kburn(void) { + while (1) { + //arch_pause(); + if (((volatile list_t *)process_queue)->head) switch_next(); + } +} + +/** + * @brief Release a process's paging data. + * + * If this is a thread in a POSIX process with other + * living threads, the directory is not actually released + * but the reference count for it is decremented. + * + * XXX There's probably no reason for this to take an argument; + * we only ever free directories in two places: on exec, or + * when a thread exits, and that's always the current thread. */ -process_t * spawn_kidle(void) { - process_t * idle = malloc(sizeof(process_t)); - memset(idle, 0x00, sizeof(process_t)); +void process_release_directory(page_directory_t * dir) { + spin_lock(dir->lock); + dir->refcount--; + if (dir->refcount < 1) { + mmu_free(dir->directory); + free(dir); + } else { + spin_unlock(dir->lock); + } +} + +process_t * spawn_kidle(int bsp) { + process_t * idle = calloc(1,sizeof(process_t)); idle->id = -1; idle->name = strdup("[kidle]"); - idle->is_tasklet = 1; + idle->flags = PROC_FLAG_IS_TASKLET | PROC_FLAG_STARTED | PROC_FLAG_RUNNING; + idle->image.stack = (uintptr_t)valloc(KERNEL_STACK_SIZE)+ KERNEL_STACK_SIZE; - idle->image.stack = (uintptr_t)malloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; - idle->thread.eip = (uintptr_t)&_kidle; - idle->thread.esp = idle->image.stack; - idle->thread.ebp = idle->image.stack; - - idle->started = 1; - idle->running = 1; - idle->wait_queue = list_create(); - idle->shm_mappings = list_create(); - idle->signal_queue = list_create(); + /* TODO arch_initialize_context(uintptr_t) ? */ + idle->thread.context.ip = bsp ? (uintptr_t)&_kidle : (uintptr_t)&_kburn; + idle->thread.context.sp = idle->image.stack; + idle->thread.context.bp = idle->image.stack; + /* FIXME Why does the idle thread have wait queues and shm mappings? + * Can we make sure these are never referenced and not allocate them? */ + idle->wait_queue = list_create("process wait queue (kidle)",idle); + idle->shm_mappings = list_create("process shm mappings (kidle)",idle); + idle->signal_queue = list_create("process signal queue (kidle)",idle); gettimeofday(&idle->start, NULL); - - set_process_environment(idle, current_directory); + idle->thread.page_directory = malloc(sizeof(page_directory_t)); + idle->thread.page_directory->refcount = 1; + idle->thread.page_directory->directory = mmu_clone(this_core->current_pml); + spin_init(idle->thread.page_directory->lock); return idle; } -/* - * Spawn the initial process. - * - * @return A pointer to the new initial process entry - */ process_t * spawn_init(void) { - /* We can only do this once. */ - assert((!process_tree->root) && "Tried to regenerate init!"); + process_t * init = calloc(1,sizeof(process_t)); + tree_set_root(process_tree, (void*)init); - /* Allocate space for a new process */ - process_t * init = malloc(sizeof(process_t)); - /* Set it as the root process */ - tree_set_root(process_tree, (void *)init); - /* Set its tree entry pointer so we can keep track - * of the process' entry in the process tree. */ init->tree_entry = process_tree->root; - init->id = 1; /* Init is PID 1 */ - init->group = 0; /* thread group id (real PID) */ - init->job = 1; /* process group id (jobs) */ - init->session = 1; /* session leader id */ - init->name = strdup("init"); /* Um, duh. */ - init->cmdline = NULL; - init->user = 0; /* UID 0 */ - init->real_user = 0; - init->mask = 022; /* umask */ - init->status = 0; /* Run status */ - init->fds = malloc(sizeof(fd_table_t)); - init->fds->refs = 1; - init->fds->length = 0; /* Initialize the file descriptors */ - init->fds->capacity = 4; - init->fds->entries = malloc(sizeof(fs_node_t *) * init->fds->capacity); - init->fds->modes = malloc(sizeof(int) * init->fds->capacity); - init->fds->offsets = malloc(sizeof(uint64_t) * init->fds->capacity); + init->id = 1; + init->group = 0; + init->job = 1; + init->session = 1; + init->name = strdup("init"); + init->cmdline = NULL; + init->user = USER_ROOT_UID; + init->real_user = USER_ROOT_UID; + init->mask = 022; + init->status = 0; + + init->fds = malloc(sizeof(fd_table_t)); + init->fds->refs = 1; + init->fds->length = 0; + init->fds->capacity = 4; + init->fds->entries = malloc(init->fds->capacity * sizeof(fs_node_t *)); + init->fds->modes = malloc(init->fds->capacity * sizeof(int)); + init->fds->offsets = malloc(init->fds->capacity * sizeof(uint64_t)); + spin_init(init->fds->lock); - /* Set the working directory */ init->wd_node = clone_fs(fs_root); init->wd_name = strdup("/"); - /* Heap and stack pointers (and actuals) */ - init->image.entry = 0; - init->image.heap = 0; - init->image.heap_actual = 0; - init->image.stack = initial_esp + 1; - init->image.user_stack = 0; - init->image.size = 0; - init->image.shm_heap = SHM_START; /* Yeah, a bit of a hack. */ + init->image.entry = 0; + init->image.heap = 0; + init->image.stack = (uintptr_t)valloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; + init->image.shm_heap = 0x200000000; /* That's 8GiB? That should work fine... */ - spin_init(init->image.lock); - - /* Process is not finished */ - init->finished = 0; - init->suspended = 0; - init->started = 1; - init->running = 1; - init->wait_queue = list_create(); - init->shm_mappings = list_create(); - init->signal_queue = list_create(); - init->signal_kstack = NULL; /* None yet initialized */ + init->flags = PROC_FLAG_STARTED | PROC_FLAG_RUNNING; + init->wait_queue = list_create("process wait queue (init)", init); + init->shm_mappings = list_create("process shm mapping (init)", init); + init->signal_queue = list_create("process signal queue (init)", init); + init->signal_kstack = NULL; /* Initialized later */ init->sched_node.prev = NULL; init->sched_node.next = NULL; @@ -317,176 +394,376 @@ process_t * spawn_init(void) { init->timed_sleep_node = NULL; - init->is_tasklet = 0; - - set_process_environment(init, current_directory); - - /* What the hey, let's also set the description on this one */ + init->thread.page_directory = malloc(sizeof(page_directory_t)); + init->thread.page_directory->refcount = 1; + init->thread.page_directory->directory = this_core->current_pml; + spin_init(init->thread.page_directory->lock); init->description = strdup("[init]"); - list_insert(process_list, (void *)init); + list_insert(process_list, (void*)init); return init; } -/* - * Get the next available PID - * - * @return A usable PID for a new process. - */ -static int _next_pid = 2; -pid_t get_next_pid(void) { - if (_next_pid > MAX_PID) { - int index = bitset_ffub(&pid_set); - /* - * Honestly, we don't have the memory to really risk reaching - * the point where we have MAX_PID processes running - * concurrently, so this assertion should be "safe enough". - */ - assert(index != -1); - bitset_set(&pid_set, index); - return index; - } - int pid = _next_pid; - _next_pid++; - assert(!bitset_test(&pid_set, pid) && "Next PID already allocated?"); - bitset_set(&pid_set, pid); - return pid; -} +process_t * spawn_process(volatile process_t * parent, int flags) { + process_t * proc = calloc(1,sizeof(process_t)); -/* - * Disown a process from its parent. - */ -void process_disown(process_t * proc) { - assert(process_tree->root && "No init, has the process tree been initialized?"); + proc->id = get_next_pid(); + proc->group = proc->id; + proc->name = strdup(parent->name); + proc->description = NULL; + proc->cmdline = parent->cmdline; /* FIXME dup it? */ - /* Find the process in the tree */ - tree_node_t * entry = proc->tree_entry; - /* Break it of from its current parent */ - spin_lock(tree_lock); - tree_break_off(process_tree, entry); - /* And insert it back elsewhere */ - tree_node_insert_child_node(process_tree, process_tree->root, entry); - spin_unlock(tree_lock); -} + proc->user = parent->user; + proc->real_user = parent->real_user; + proc->mask = parent->mask; + proc->job = parent->job; + proc->session = parent->session; -/* - * Spawn a new process. - * - * @param parent The parent process to spawn the new one off of. - * @return A pointer to the new process. - */ -process_t * spawn_process(volatile process_t * parent, int reuse_fds) { - assert(process_tree->root && "Attempted to spawn a process without init."); - - /* Allocate a new process */ - debug_print(INFO," process_t {"); - process_t * proc = malloc(sizeof(process_t)); - memset(proc, 0, sizeof(process_t)); - debug_print(INFO," }"); - proc->id = get_next_pid(); /* Set its PID */ - proc->group = proc->id; /* Set the GID */ - proc->name = strdup(parent->name); /* Use the default name */ - proc->description = NULL; /* No description */ - proc->cmdline = parent->cmdline; - - /* Copy permissions */ - proc->user = parent->user; - proc->real_user = parent->real_user; - proc->mask = parent->mask; - - /* Until specified otherwise */ - proc->job = parent->job; - proc->session = parent->session; - - /* Zero out the ESP/EBP/EIP */ - proc->thread.esp = 0; - proc->thread.ebp = 0; - proc->thread.eip = 0; - proc->thread.fpu_enabled = 0; + proc->thread.context.sp = 0; + proc->thread.context.bp = 0; + proc->thread.context.ip = 0; memcpy((void*)proc->thread.fp_regs, (void*)parent->thread.fp_regs, 512); - /* Set the process image information from the parent */ + /* Entry is only stored for reference. */ proc->image.entry = parent->image.entry; proc->image.heap = parent->image.heap; - proc->image.heap_actual = parent->image.heap_actual; - proc->image.size = parent->image.size; - debug_print(INFO," stack {"); - proc->image.stack = (uintptr_t)kvmalloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; - debug_print(INFO," }"); - proc->image.user_stack = parent->image.user_stack; - proc->image.shm_heap = SHM_START; /* Yeah, a bit of a hack. */ + proc->image.stack = (uintptr_t)valloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; + proc->image.shm_heap = 0x200000000; /* FIXME this should be a macro def */ - spin_init(proc->image.lock); - - assert(proc->image.stack && "Failed to allocate kernel stack for new process."); - - /* Clone the file descriptors from the original process */ - if (reuse_fds) { + if (flags & PROC_REUSE_FDS) { + spin_lock(parent->fds->lock); proc->fds = parent->fds; proc->fds->refs++; + spin_unlock(parent->fds->lock); } else { proc->fds = malloc(sizeof(fd_table_t)); - proc->fds->refs = 1; - proc->fds->length = parent->fds->length; + spin_init(proc->fds->lock); + proc->fds->refs = 1; + spin_lock(parent->fds->lock); + proc->fds->length = parent->fds->length; proc->fds->capacity = parent->fds->capacity; - debug_print(INFO," fds / files {"); - proc->fds->entries = malloc(sizeof(fs_node_t *) * proc->fds->capacity); - proc->fds->modes = malloc(sizeof(int) * proc->fds->capacity); - proc->fds->offsets = malloc(sizeof(uint64_t) * proc->fds->capacity); - assert(proc->fds->entries && "Failed to allocate file descriptor table for new process."); - debug_print(INFO," ---"); + proc->fds->entries = malloc(proc->fds->capacity * sizeof(fs_node_t *)); + proc->fds->modes = malloc(proc->fds->capacity * sizeof(int)); + proc->fds->offsets = malloc(proc->fds->capacity * sizeof(uint64_t)); for (uint32_t i = 0; i < parent->fds->length; ++i) { proc->fds->entries[i] = clone_fs(parent->fds->entries[i]); proc->fds->modes[i] = parent->fds->modes[i]; proc->fds->offsets[i] = parent->fds->offsets[i]; } - debug_print(INFO," }"); + spin_unlock(parent->fds->lock); } - /* As well as the working directory */ proc->wd_node = clone_fs(parent->wd_node); proc->wd_name = strdup(parent->wd_name); - /* Zero out the process status */ - proc->status = 0; - proc->finished = 0; - proc->suspended = 0; - proc->started = 0; - proc->running = 0; - memset(proc->signals.functions, 0x00, sizeof(uintptr_t) * NUMSIGNALS); - proc->wait_queue = list_create(); - proc->shm_mappings = list_create(); - proc->signal_queue = list_create(); - proc->signal_kstack = NULL; /* None yet initialized */ + proc->wait_queue = list_create("process wait queue",proc); + proc->shm_mappings = list_create("process shm mappings",proc); + proc->signal_queue = list_create("process signal queue",proc); - proc->sched_node.prev = NULL; - proc->sched_node.next = NULL; proc->sched_node.value = proc; - - proc->sleep_node.prev = NULL; - proc->sleep_node.next = NULL; proc->sleep_node.value = proc; - proc->timed_sleep_node = NULL; - - proc->is_tasklet = 0; - gettimeofday(&proc->start, NULL); - - /* Insert the process into the process tree as a child - * of the parent process. */ tree_node_t * entry = tree_node_create(proc); - assert(entry && "Failed to allocate a process tree node for new process."); proc->tree_entry = entry; + spin_lock(tree_lock); tree_node_insert_child_node(process_tree, parent->tree_entry, entry); - list_insert(process_list, (void *)proc); + list_insert(process_list, (void*)proc); spin_unlock(tree_lock); - - /* Return the new process */ return proc; } +extern void tree_remove_reparent_root(tree_t * tree, tree_node_t * node); + +/** + * @brief Remove a process from the valid process list. + * + * Deletes a process from both the valid list and the process tree. + * Any the process has any children, they become orphaned and are + * moved under 'init', which is awoken if it was blocked on 'waitpid'. + * + * Finally, the process is freed. + */ +void process_delete(process_t * proc) { + tree_node_t * entry = proc->tree_entry; + if (!entry) return; + if (process_tree->root == entry) { + return; + } + spin_lock(tree_lock); + int has_children = entry->children->length; + tree_remove_reparent_root(process_tree, entry); + list_delete(process_list, list_find(process_list, proc)); + spin_unlock(tree_lock); + if (has_children) { + process_t * init = process_tree->root->value; + wakeup_queue(init->wait_queue); + } + // FIXME bitset_clear(&pid_set, proc->id); + proc->tree_entry = NULL; + + /* Free these later */ + shm_release_all(proc); + free(proc->shm_mappings); + + if (proc->signal_kstack) { + free(proc->signal_kstack); + } + free((void *)(proc->image.stack - KERNEL_STACK_SIZE)); + process_release_directory(proc->thread.page_directory); + + free(proc->name); + free(proc); +} + +/** + * @brief Place an available process in the ready queue. + * + * Marks a process as available for general scheduling. + * If the process was currently in a sleep queue, it is + * marked as having been interrupted and removed from its + * owning queue before being moved. + * + * The process must not otherwise have been in a scheduling + * queue before it is placed in the ready queue. + */ +void make_process_ready(volatile process_t * proc) { + if (proc->sleep_node.owner != NULL) { + if (proc->sleep_node.owner == sleep_queue) { + /* The sleep queue is slightly special... */ + if (proc->timed_sleep_node) { + spin_lock(sleep_lock); + list_delete(sleep_queue, proc->timed_sleep_node); + spin_unlock(sleep_lock); + proc->sleep_node.owner = NULL; + free(proc->timed_sleep_node->value); + } + } else { + /* This was blocked on a semaphore we can interrupt. */ + __sync_or_and_fetch(&proc->flags, PROC_FLAG_SLEEP_INT); + list_delete((list_t*)proc->sleep_node.owner, (node_t*)&proc->sleep_node); + } + } + + if (proc->sched_node.owner) { + /* There's only one ready queue, so this means the process was already ready, which + * is indicative of a bug somewhere as we shouldn't be added processes to the ready + * queue multiple times. */ + printf("Can't make process ready without removing it from owner list: %d\n", proc->id); + printf(" (This is a bug) Current owner list is %s@%p (ready queue is %p)\n", + proc->sched_node.owner->name, (void *)proc->sched_node.owner, (void*)process_queue); + return; + } + + spin_lock(process_queue_lock); + list_append(process_queue, (node_t*)&proc->sched_node); + spin_unlock(process_queue_lock); + + arch_wakeup_others(); +} + +/** + * @brief Pop the next available process from the queue. + * + * Gets the next available process from the round-robin scheduling + * queue. If there is no process to run, the idle task is returned. + * + * TODO This needs more locking for SMP... + */ +volatile process_t * next_ready_process(void) { + spin_lock(process_queue_lock); + + if (!process_queue->head) { + spin_unlock(process_queue_lock); + return this_core->kernel_idle_task; + } + + node_t * np = list_dequeue(process_queue); + + if ((uintptr_t)np < 0xFFFFff0000000000UL || (uintptr_t)np > 0xFFFFff0000f00000UL) { + printf("Suspicious pointer in queue: %#zx\n", (uintptr_t)np); + arch_fatal(); + } + volatile process_t * next = np->value; + + if ((next->flags & PROC_FLAG_RUNNING) && (next->owner != this_core->cpu_id)) { + /* We pulled a process too soon, switch to idle for a bit so the + * core that marked this process as ready can finish switching away from it. */ + list_append(process_queue, (node_t*)&next->sched_node); + spin_unlock(process_queue_lock); + return this_core->kernel_idle_task; + } + + spin_unlock(process_queue_lock); + + __sync_or_and_fetch(&next->flags, PROC_FLAG_RUNNING); + next->owner = this_core->cpu_id; + + return next; +} + +/** + * @brief Signal a semaphore. + * + * Okay, so toaru32 used these general-purpose lists of processes + * as a sort of sempahore system, so often when you see 'queue' it + * can be read as 'semaphore' and be equally valid (outside of the + * 'ready queue', I guess). This will awaken all processes currently + * in the semaphore @p queue, unless they were marked as finished in + * which case they will be discarded. + * + * Note that these "semaphore queues" are binary semaphores - simple + * locks, but with smarter logic than the "spin_lock" primitive also + * used throughout the kernel, as that just blindly switches tasks + * until its atomic swap succeeds. + * + * @param queue The semaphore to signal + * @returns the number of processes successfully awoken + */ +int wakeup_queue(list_t * queue) { + int awoken_processes = 0; + spin_lock(wait_lock_tmp); + while (queue->length > 0) { + node_t * node = list_pop(queue); + if (!(((process_t *)node->value)->flags & PROC_FLAG_FINISHED)) { + make_process_ready(node->value); + } + awoken_processes++; + } + spin_unlock(wait_lock_tmp); + return awoken_processes; +} + +/** + * @brief Signal a semaphore, exceptionally. + * + * Wake up everything in the semaphore @p queue but mark every + * waiter as having been interrupted, rather than gracefully awoken. + * Generally that means the event they were waiting for did not + * happen and may never happen. + * + * Otherwise, same semantics as @ref wakeup_queue. + */ +int wakeup_queue_interrupted(list_t * queue) { + int awoken_processes = 0; + spin_lock(wait_lock_tmp); + while (queue->length > 0) { + node_t * node = list_pop(queue); + if (!(((process_t *)node->value)->flags & PROC_FLAG_FINISHED)) { + process_t * proc = node->value; + __sync_or_and_fetch(&proc->flags, PROC_FLAG_SLEEP_INT); + make_process_ready(proc); + } + awoken_processes++; + } + spin_unlock(wait_lock_tmp); + return awoken_processes; +} + +/** + * @brief Wait for a binary semaphore. + * + * Wait for an event with everyone else in @p queue. + * + * @returns 1 if the wait was interrupted (eg. the event did not occur); 0 otherwise. + */ +int sleep_on(list_t * queue) { + if (this_core->current_process->sleep_node.owner) { + switch_task(0); + return 0; + } + __sync_and_and_fetch(&this_core->current_process->flags, ~(PROC_FLAG_SLEEP_INT)); + spin_lock(wait_lock_tmp); + list_append(queue, (node_t*)&this_core->current_process->sleep_node); + spin_unlock(wait_lock_tmp); + switch_task(0); + return !!(this_core->current_process->flags & PROC_FLAG_SLEEP_INT); +} + +/** + * @brief Indicates whether a process is ready to be run but not currently running. + */ +int process_is_ready(process_t * proc) { + return (proc->sched_node.owner != NULL && !(proc->flags & PROC_FLAG_RUNNING)); +} + +/** + * @brief Wake up processes that were sleeping on timers. + * + * Reschedule all processes whose timed waits have expired as of + * the time indicated by @p seconds and @p subseconds. If the sleep + * was part of an fswait system call timing out, the call is marked + * as timed out before the process is rescheduled. + */ +void wakeup_sleepers(unsigned long seconds, unsigned long subseconds) { + spin_lock(sleep_lock); + if (sleep_queue->length) { + sleeper_t * proc = ((sleeper_t *)sleep_queue->head->value); + while (proc && (proc->end_tick < seconds || (proc->end_tick == seconds && proc->end_subtick <= subseconds))) { + + if (proc->is_fswait) { + proc->is_fswait = -1; + process_alert_node(proc->process,proc); + } else { + process_t * process = proc->process; + process->sleep_node.owner = NULL; + process->timed_sleep_node = NULL; + if (!process_is_ready(process)) { + spin_lock(wait_lock_tmp); + make_process_ready(process); + spin_unlock(wait_lock_tmp); + } + } + free(proc); + free(list_dequeue(sleep_queue)); + if (sleep_queue->length) { + proc = ((sleeper_t *)sleep_queue->head->value); + } else { + break; + } + } + } + spin_unlock(sleep_lock); +} + +/** + * @brief Wait until a given time. + * + * Suspends the current process until the given time. The process may + * still be resumed by a signal or other mechanism, in which case the + * sleep will not be resumed by the kernel. + */ +void sleep_until(process_t * process, unsigned long seconds, unsigned long subseconds) { + spin_lock(sleep_lock); + if (this_core->current_process->sleep_node.owner) { + spin_unlock(sleep_lock); + /* Can't sleep, sleeping already */ + return; + } + process->sleep_node.owner = sleep_queue; + + node_t * before = NULL; + foreach(node, sleep_queue) { + sleeper_t * candidate = ((sleeper_t *)node->value); + if (!candidate) { + printf("null candidate?\n"); + continue; + } + if (candidate->end_tick > seconds || (candidate->end_tick == seconds && candidate->end_subtick > subseconds)) { + break; + } + before = node; + } + sleeper_t * proc = malloc(sizeof(sleeper_t)); + proc->process = process; + proc->end_tick = seconds; + proc->end_subtick = subseconds; + proc->is_fswait = 0; + process->timed_sleep_node = list_insert_after(sleep_queue, before, proc); + spin_unlock(sleep_lock); +} + uint8_t process_compare(void * proc_v, void * pid_v) { pid_t pid = (*(pid_t *)pid_v); process_t * proc = (process_t *)proc_v; @@ -506,121 +783,8 @@ process_t * process_from_pid(pid_t pid) { return NULL; } -process_t * process_get_parent(process_t * process) { - process_t * result = NULL; - spin_lock(tree_lock); - tree_node_t * entry = process->tree_entry; - - if (entry->parent) { - result = entry->parent->value; - } - - spin_unlock(tree_lock); - return result; -} - -/* - * Wait for children. - * - * @param process Process doing the waiting. - * @param pid PID to wait for - * @param status [out] Where to put the status conditions of the waited-for process - * @param options Options (unused) - * @return A pointer to the process that broke the wait - */ -process_t * process_wait(process_t * process, pid_t pid, int * status, int options) { - /* `options` is ignored */ - if (pid == -1) { - /* wait for any child process */ - } else if (pid < 0) { - /* wait for any porcess whose ->group == processes[abs(pid)]->group */ - } else if (pid == 0) { - /* wait for any process whose ->group == process->group */ - } else { - /* wait for processes[pid] */ - } - return NULL; -} - -/* - * Wake up a sleeping process - * - * @param process Process to wake up - * @param caller Who woke it up - * @return Don't know yet, but I think it should return something. - */ -int process_wake(process_t * process, process_t * caller) { - - return 0; -} - -/* - * Set the directory for a process. - * - * @param proc Process to set the directory for. - * @param directory Directory to set. - */ -void set_process_environment(process_t * proc, page_directory_t * directory) { - assert(proc); - assert(directory); - - proc->thread.page_directory = directory; -} - -/* - * Are there any processes available in the queue? - * (Queue not empty) - * - * @return 1 if there are processes available, 0 otherwise - */ -uint8_t process_available(void) { - return (process_queue->head != NULL); -} - -/* - * Append a file descriptor to a process. - * - * @param proc Process to append to - * @param node The VFS node - * @return The actual fd, for use in userspace - */ -uint32_t process_append_fd(process_t * proc, fs_node_t * node) { - /* Fill gaps */ - for (unsigned int i = 0; i < proc->fds->length; ++i) { - if (!proc->fds->entries[i]) { - proc->fds->entries[i] = node; - /* modes, offsets must be set by caller */ - proc->fds->modes[i] = 0; - proc->fds->offsets[i] = 0; - return i; - } - } - /* No gaps, expand */ - if (proc->fds->length == proc->fds->capacity) { - proc->fds->capacity *= 2; - proc->fds->entries = realloc(proc->fds->entries, sizeof(fs_node_t *) * proc->fds->capacity); - proc->fds->modes = realloc(proc->fds->modes, sizeof(int) * proc->fds->capacity); - proc->fds->offsets = realloc(proc->fds->offsets, sizeof(uint64_t) * proc->fds->capacity); - } - proc->fds->entries[proc->fds->length] = node; - /* modes, offsets must be set by caller */ - proc->fds->modes[proc->fds->length] = 0; - proc->fds->offsets[proc->fds->length] = 0; - proc->fds->length++; - return proc->fds->length-1; -} - -/* - * dup2() -> Move the file pointed to by `s(ou)rc(e)` into - * the slot pointed to be `dest(ination)`. - * - * @param proc Process to do this for - * @param src Source file descriptor - * @param dest Destination file descriptor - * @return The destination file descriptor, -1 on failure - */ -uint32_t process_move_fd(process_t * proc, int src, int dest) { +long process_move_fd(process_t * proc, long src, long dest) { if ((size_t)src >= proc->fds->length || (dest != -1 && (size_t)dest >= proc->fds->length)) { return -1; } @@ -637,176 +801,17 @@ uint32_t process_move_fd(process_t * proc, int src, int dest) { return dest; } -int wakeup_queue(list_t * queue) { - int awoken_processes = 0; - while (queue->length > 0) { - spin_lock(wait_lock_tmp); - node_t * node = list_pop(queue); - spin_unlock(wait_lock_tmp); - if (!((process_t *)node->value)->finished) { - make_process_ready(node->value); - } - awoken_processes++; - } - return awoken_processes; +void tasking_start(void) { + this_core->current_process = spawn_init(); + this_core->kernel_idle_task = spawn_kidle(1); } -int wakeup_queue_interrupted(list_t * queue) { - int awoken_processes = 0; - while (queue->length > 0) { - spin_lock(wait_lock_tmp); - node_t * node = list_pop(queue); - spin_unlock(wait_lock_tmp); - if (!((process_t *)node->value)->finished) { - process_t * proc = node->value; - proc->sleep_interrupted = 1; - make_process_ready(proc); - } - awoken_processes++; - } - return awoken_processes; -} - - -int sleep_on(list_t * queue) { - if (current_process->sleep_node.owner) { - /* uh, we can't sleep right now, we're marked as ready */ - switch_task(0); - return 0; - } - current_process->sleep_interrupted = 0; - spin_lock(wait_lock_tmp); - list_append(queue, (node_t *)¤t_process->sleep_node); - spin_unlock(wait_lock_tmp); - switch_task(0); - return current_process->sleep_interrupted; -} - -int process_is_ready(process_t * proc) { - return (proc->sched_node.owner != NULL); -} - - -void wakeup_sleepers(unsigned long seconds, unsigned long subseconds) { - IRQ_OFF; - spin_lock(sleep_lock); - if (sleep_queue->length) { - sleeper_t * proc = ((sleeper_t *)sleep_queue->head->value); - while (proc && (proc->end_tick < seconds || (proc->end_tick == seconds && proc->end_subtick <= subseconds))) { - - if (proc->is_fswait) { - proc->is_fswait = -1; - process_alert_node(proc->process,proc); - } else { - process_t * process = proc->process; - process->sleep_node.owner = NULL; - process->timed_sleep_node = NULL; - if (!process_is_ready(process)) { - make_process_ready(process); - } - } - free(proc); - free(list_dequeue(sleep_queue)); - if (sleep_queue->length) { - proc = ((sleeper_t *)sleep_queue->head->value); - } else { - break; - } - } - } - spin_unlock(sleep_lock); - IRQ_RES; -} - -void sleep_until(process_t * process, unsigned long seconds, unsigned long subseconds) { - if (current_process->sleep_node.owner) { - /* Can't sleep, sleeping already */ - return; - } - process->sleep_node.owner = sleep_queue; - - IRQ_OFF; - spin_lock(sleep_lock); - node_t * before = NULL; - foreach(node, sleep_queue) { - sleeper_t * candidate = ((sleeper_t *)node->value); - if (candidate->end_tick > seconds || (candidate->end_tick == seconds && candidate->end_subtick > subseconds)) { - break; - } - before = node; - } - sleeper_t * proc = malloc(sizeof(sleeper_t)); - proc->process = process; - proc->end_tick = seconds; - proc->end_subtick = subseconds; - proc->is_fswait = 0; - process->timed_sleep_node = list_insert_after(sleep_queue, before, proc); - spin_unlock(sleep_lock); - IRQ_RES; -} - -void cleanup_process(process_t * proc, int retval) { - proc->status = retval; - proc->finished = 1; - - list_free(proc->wait_queue); - free(proc->wait_queue); - list_free(proc->signal_queue); - free(proc->signal_queue); - free(proc->wd_name); - - - if (proc->node_waits) { - list_free(proc->node_waits); - free(proc->node_waits); - proc->node_waits = NULL; - } - debug_print(INFO, "Releasing shared memory for %d", proc->id); - shm_release_all(proc); - free(proc->shm_mappings); - debug_print(INFO, "Freeing more mems %d", proc->id); - if (proc->signal_kstack) { - free(proc->signal_kstack); - } - - release_directory(proc->thread.page_directory); - - debug_print(INFO, "Dec'ing fds for %d", proc->id); - proc->fds->refs--; - if (proc->fds->refs == 0) { - debug_print(INFO, "Reached 0, all dependencies are closed for %d's file descriptors and page directories", proc->id); - debug_print(INFO, "Going to clear out the file descriptors %d", proc->id); - for (uint32_t i = 0; i < proc->fds->length; ++i) { - if (proc->fds->entries[i]) { - close_fs(proc->fds->entries[i]); - proc->fds->entries[i] = NULL; - } - } - debug_print(INFO, "... and their storage %d", proc->id); - free(proc->fds->entries); - free(proc->fds->offsets); - free(proc->fds->modes); - free(proc->fds); - debug_print(INFO, "... and the kernel stack (hope this ain't us) %d", proc->id); - free((void *)(proc->image.stack - KERNEL_STACK_SIZE)); - } -} - -void reap_process(process_t * proc) { - debug_print(INFO, "Reaping process %d; mem before = %d", proc->id, memory_use()); - free(proc->name); - debug_print(INFO, "Reaped process %d; mem after = %d", proc->id, memory_use()); - - delete_process(proc); - debug_print_process_tree(); -} - -static int wait_candidate(process_t * parent, int pid, int options, process_t * proc) { +static int wait_candidate(volatile process_t * parent, int pid, int options, volatile process_t * proc) { if (!proc) return 0; if (options & WNOKERN) { /* Skip kernel processes */ - if (proc->is_tasklet) return 0; + if (proc->flags & PROC_FLAG_IS_TASKLET) return 0; } if (pid < -1) { @@ -824,15 +829,13 @@ static int wait_candidate(process_t * parent, int pid, int options, process_t * } int waitpid(int pid, int * status, int options) { - process_t * proc = (process_t *)current_process; + volatile process_t * volatile proc = (process_t*)this_core->current_process; if (proc->group) { proc = process_from_pid(proc->group); } - debug_print(INFO, "waitpid(%s%d, ..., %d) (from pid=%d.%d)", (pid >= 0) ? "" : "-", (pid >= 0) ? pid : -pid, options, current_process->id, current_process->group); - do { - process_t * candidate = NULL; + volatile process_t * candidate = NULL; int has_children = 0; /* First, find out if there is anyone to reap */ @@ -840,15 +843,15 @@ int waitpid(int pid, int * status, int options) { if (!node->value) { continue; } - process_t * child = ((tree_node_t *)node->value)->value; + volatile process_t * volatile child = ((tree_node_t *)node->value)->value; if (wait_candidate(proc, pid, options, child)) { has_children = 1; - if (child->finished) { + if (child->flags & PROC_FLAG_FINISHED) { candidate = child; break; } - if ((options & WSTOPPED) && child->suspended) { + if ((options & WSTOPPED) && child->flags & PROC_FLAG_SUSPENDED) { candidate = child; break; } @@ -857,28 +860,25 @@ int waitpid(int pid, int * status, int options) { if (!has_children) { /* No valid children matching this description */ - debug_print(INFO, "No children matching description."); return -ECHILD; } if (candidate) { - debug_print(INFO, "Candidate found (%x:%d), bailing early.", candidate, candidate->id); if (status) { *status = candidate->status; } int pid = candidate->id; - if (candidate->finished) { - reap_process(candidate); + if (candidate->flags & PROC_FLAG_FINISHED) { + while (*((volatile int *)&candidate->flags) & PROC_FLAG_RUNNING); + process_delete((process_t*)candidate); } return pid; } else { if (options & WNOHANG) { return 0; } - debug_print(INFO, "Sleeping until queue is done."); /* Wait */ if (sleep_on(proc->wait_queue) != 0) { - debug_print(INFO, "wait() was interrupted"); return -EINTR; } } @@ -886,15 +886,12 @@ int waitpid(int pid, int * status, int options) { } int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout) { - assert(!process->node_waits && "Tried to wait on nodes while already waiting on nodes."); - fs_node_t ** n = nodes; int index = 0; if (*n) { do { int result = selectcheck_fs(*n); if (result < 0) { - debug_print(NOTICE, "An invalid descriptor was specified: %d (0x%x) (pid=%d)", index, *n, current_process->id); return -1; } if (result == 0) { @@ -911,22 +908,21 @@ int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout) { n = nodes; - process->node_waits = list_create(); + spin_lock(process->sched_lock); + process->node_waits = list_create("process fswaiters",process); if (*n) { do { if (selectwait_fs(*n, process) < 0) { - debug_print(NOTICE, "Bad selectwait? 0x%x", *n); + printf("bad selectwait?\n"); } n++; } while (*n); } if (timeout > 0) { - debug_print(INFO, "fswait with a timeout of %d (pid=%d)", timeout, current_process->id); unsigned long s, ss; - relative_time(0, timeout, &s, &ss); + relative_time(0, timeout * 1000, &s, &ss); - IRQ_OFF; spin_lock(sleep_lock); node_t * before = NULL; foreach(node, sleep_queue) { @@ -944,12 +940,13 @@ int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout) { list_insert(((process_t *)process)->node_waits, proc); process->timeout_node = list_insert_after(sleep_queue, before, proc); spin_unlock(sleep_lock); - IRQ_RES; } else { process->timeout_node = NULL; } process->awoken_index = -1; + spin_unlock(process->sched_lock); + /* Wait. */ switch_task(0); @@ -970,20 +967,24 @@ int process_awaken_from_fswait(process_t * process, int index) { } } process->timeout_node = NULL; + spin_lock(wait_lock_tmp); make_process_ready(process); + spin_unlock(wait_lock_tmp); + spin_unlock(process->sched_lock); return 0; } int process_alert_node(process_t * process, void * value) { if (!is_valid_process(process)) { - debug_print(WARNING, "Invalid process in alert from fswait."); + printf("invalid process\n"); return 0; } - + spin_lock(process->sched_lock); if (!process->node_waits) { + spin_unlock(process->sched_lock); return 0; /* Possibly already returned. Wait for another call. */ } @@ -995,6 +996,184 @@ int process_alert_node(process_t * process, void * value) { index++; } + spin_unlock(process->sched_lock); return -1; } +process_t * process_get_parent(process_t * process) { + process_t * result = NULL; + spin_lock(tree_lock); + + tree_node_t * entry = process->tree_entry; + + if (entry->parent) { + result = entry->parent->value; + } + + spin_unlock(tree_lock); + return result; +} + +void task_exit(int retval) { + this_core->current_process->status = retval; + + /* free whatever we can */ + list_free(this_core->current_process->wait_queue); + free(this_core->current_process->wait_queue); + list_free(this_core->current_process->signal_queue); + free(this_core->current_process->signal_queue); + free(this_core->current_process->wd_name); + if (this_core->current_process->node_waits) { + list_free(this_core->current_process->node_waits); + free(this_core->current_process->node_waits); + this_core->current_process->node_waits = NULL; + } + + if (this_core->current_process->fds) { + this_core->current_process->fds->refs--; + if (this_core->current_process->fds->refs == 0) { + for (uint32_t i = 0; i < this_core->current_process->fds->length; ++i) { + if (this_core->current_process->fds->entries[i]) { + close_fs(this_core->current_process->fds->entries[i]); + this_core->current_process->fds->entries[i] = NULL; + } + } + free(this_core->current_process->fds->entries); + free(this_core->current_process->fds->offsets); + free(this_core->current_process->fds->modes); + free(this_core->current_process->fds); + this_core->current_process->fds = NULL; + } + } + + process_t * parent = process_get_parent((process_t *)this_core->current_process); + __sync_or_and_fetch(&this_core->current_process->flags, PROC_FLAG_FINISHED); + + if (parent && !(parent->flags & PROC_FLAG_FINISHED)) { + send_signal(parent->group, SIGCHLD, 1); + wakeup_queue(parent->wait_queue); + } + switch_next(); +} + +#define PUSH(stack, type, item) stack -= sizeof(type); \ + *((type *) stack) = item + +pid_t fork(void) { + uintptr_t sp, bp; + process_t * parent = (process_t*)this_core->current_process; + union PML * directory = mmu_clone(parent->thread.page_directory->directory); + process_t * new_proc = spawn_process(parent, 0); + new_proc->thread.page_directory = malloc(sizeof(page_directory_t)); + new_proc->thread.page_directory->refcount = 1; + new_proc->thread.page_directory->directory = directory; + spin_init(new_proc->thread.page_directory->lock); + + struct regs r; + memcpy(&r, parent->syscall_registers, sizeof(struct regs)); + sp = new_proc->image.stack; + bp = sp; + + arch_syscall_return(&r, 0); + PUSH(sp, struct regs, r); + new_proc->syscall_registers = (void*)sp; + new_proc->thread.context.sp = sp; + new_proc->thread.context.bp = bp; + new_proc->thread.context.tls_base = parent->thread.context.tls_base; + new_proc->thread.context.ip = (uintptr_t)&arch_resume_user; + if (parent->flags & PROC_FLAG_IS_TASKLET) new_proc->flags |= PROC_FLAG_IS_TASKLET; + make_process_ready(new_proc); + return new_proc->id; +} + +pid_t clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { + uintptr_t sp, bp; + process_t * parent = (process_t *)this_core->current_process; + process_t * new_proc = spawn_process(this_core->current_process, 1); + new_proc->thread.page_directory = this_core->current_process->thread.page_directory; + spin_lock(new_proc->thread.page_directory->lock); + new_proc->thread.page_directory->refcount++; + spin_unlock(new_proc->thread.page_directory->lock); + + struct regs r; + memcpy(&r, parent->syscall_registers, sizeof(struct regs)); + sp = new_proc->image.stack; + bp = sp; + + /* Set the gid */ + if (this_core->current_process->group) { + new_proc->group = this_core->current_process->group; + } else { + /* We are the session leader */ + new_proc->group = this_core->current_process->id; + } + + /* different calling convention */ + r.rdi = arg; + PUSH(new_stack, uintptr_t, (uintptr_t)0xFFFFB00F); + PUSH(sp, struct regs, r); + new_proc->syscall_registers = (void*)sp; + new_proc->syscall_registers->rsp = new_stack; + new_proc->syscall_registers->rbp = new_stack; + new_proc->syscall_registers->rip = thread_func; + new_proc->thread.context.sp = sp; + new_proc->thread.context.bp = bp; + new_proc->thread.context.tls_base = this_core->current_process->thread.context.tls_base; + new_proc->thread.context.ip = (uintptr_t)&arch_resume_user; + if (parent->flags & PROC_FLAG_IS_TASKLET) new_proc->flags |= PROC_FLAG_IS_TASKLET; + make_process_ready(new_proc); + return new_proc->id; +} + +process_t * spawn_worker_thread(void (*entrypoint)(void * argp), const char * name, void * argp) { + process_t * proc = calloc(1,sizeof(process_t)); + + proc->flags = PROC_FLAG_IS_TASKLET | PROC_FLAG_STARTED; + + proc->id = get_next_pid(); + proc->group = proc->id; + proc->name = strdup(name); + proc->description = NULL; + proc->cmdline = NULL; + + /* Are these necessary for tasklets? Should probably all be zero. */ + proc->user = 0; + proc->real_user = 0; + proc->mask = 0; + proc->job = proc->id; + proc->session = proc->id; + + proc->thread.page_directory = malloc(sizeof(page_directory_t)); + proc->thread.page_directory->refcount = 1; + proc->thread.page_directory->directory = mmu_clone(mmu_get_kernel_directory()); + spin_init(proc->thread.page_directory->lock); + + proc->image.stack = (uintptr_t)valloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; + PUSH(proc->image.stack, uintptr_t, (uintptr_t)entrypoint); + PUSH(proc->image.stack, void*, argp); + + proc->thread.context.sp = proc->image.stack; + proc->thread.context.bp = proc->image.stack; + proc->thread.context.ip = (uintptr_t)&arch_enter_tasklet; + + + proc->wait_queue = list_create("worker thread wait queue",proc); + proc->shm_mappings = list_create("worker thread shm mappings",proc); + proc->signal_queue = list_create("worker thread signal queue",proc); + + proc->sched_node.value = proc; + proc->sleep_node.value = proc; + + gettimeofday(&proc->start, NULL); + tree_node_t * entry = tree_node_create(proc); + proc->tree_entry = entry; + + spin_lock(tree_lock); + tree_node_insert_child_node(process_tree, this_core->current_process->tree_entry, entry); + list_insert(process_list, (void*)proc); + spin_unlock(tree_lock); + + make_process_ready(proc); + + return proc; +} diff --git a/kernel/mem/shm.c b/kernel/sys/shm.c similarity index 66% rename from kernel/mem/shm.c rename to kernel/sys/shm.c index 8468e08b..98dce2de 100644 --- a/kernel/mem/shm.c +++ b/kernel/sys/shm.c @@ -1,19 +1,29 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/sys/shm.c + * @brief Shared memory subsystem + * + * Provides shared memory mappings for userspace processes and + * manages their allocation/deallocation for process cleanup. + * Used primarily to implement text buffers for the compositor. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2018 K. Lange + * Copyright (C) 2012-2021 K. Lange * Copyright (C) 2012 Markus Schober - * - * Shared Memory */ -#include +#include +#include +#include +#include #include -#include +#include #include -#include +#include +#include -#include -#include +#include +#include //static volatile uint8_t bsl; // big shm lock @@ -22,7 +32,6 @@ tree_t * shm_tree = NULL; void shm_install(void) { - debug_print(NOTICE, "Installing shared memory layer..."); shm_tree = tree_create(); tree_set_root(shm_tree, NULL); } @@ -82,12 +91,10 @@ static shm_node_t * get_node (char * shm_path, int create) { static shm_chunk_t * create_chunk (shm_node_t * parent, size_t size) { - debug_print(WARNING, "Size supplied to create_chunk was 0"); if (!size) return NULL; shm_chunk_t *chunk = malloc(sizeof(shm_chunk_t)); if (chunk == NULL) { - debug_print(ERROR, "Failed to allocate a shm_chunk_t!"); return NULL; } @@ -98,19 +105,15 @@ static shm_chunk_t * create_chunk (shm_node_t * parent, size_t size) { chunk->num_frames = (size / 0x1000) + ((size % 0x1000) ? 1 : 0); chunk->frames = malloc(sizeof(uintptr_t) * chunk->num_frames); if (chunk->frames == NULL) { - debug_print(ERROR, "Failed to allocate uintptr_t[%d]", chunk->num_frames); free(chunk); return NULL; } /* Now grab some frames for this guy. */ for (uint32_t i = 0; i < chunk->num_frames; i++) { - page_t tmp = {0}; - alloc_frame(&tmp, 0, 0); - chunk->frames[i] = tmp.frame; -#if 0 - debug_print(WARNING, "Using frame 0x%x for chunk[%d] (name=%s)", tmp.frame * 0x1000, i, parent->name); -#endif + /* Allocate frame */ + uintptr_t index = mmu_allocate_a_frame(); + chunk->frames[i] = index; } return chunk; @@ -128,7 +131,7 @@ static int release_chunk (shm_chunk_t * chunk) { /* First, free the frames used by this chunk */ for (uint32_t i = 0; i < chunk->num_frames; i++) { - clear_frame(chunk->frames[i] * 0x1000); + mmu_frame_clear(chunk->frames[i] << 12); } /* Then, get rid of the damn thing */ @@ -146,21 +149,19 @@ static int release_chunk (shm_chunk_t * chunk) { /* Mapping and Unmapping */ -static uintptr_t proc_sbrk(uint32_t num_pages, process_t * proc) { +static uintptr_t proc_sbrk(uint32_t num_pages, volatile process_t * volatile proc) { uintptr_t initial = proc->image.shm_heap; - assert(!(initial & 0xFFF) && "shm_heap not page-aligned!"); - if (initial % 0x1000) { - initial += 0x1000 - (initial % 0x1000); + if (initial & 0xFFF) { + initial += 0x1000 - (initial & 0xFFF); proc->image.shm_heap = initial; } - proc->image.shm_heap += num_pages * 0x1000; - assert(!(proc->image.shm_heap & 0xFFF) && "math is wrong, dumbass"); + proc->image.shm_heap += num_pages << 12; return initial; } -static void * map_in (shm_chunk_t * chunk, process_t * proc) { +static void * map_in (shm_chunk_t * chunk, volatile process_t * volatile proc) { if (!chunk) { return NULL; } @@ -170,23 +171,19 @@ static void * map_in (shm_chunk_t * chunk, process_t * proc) { mapping->num_vaddrs = chunk->num_frames; mapping->vaddrs = malloc(sizeof(uintptr_t) * mapping->num_vaddrs); - debug_print(INFO, "want %d bytes, running through mappings...", mapping->num_vaddrs * 0x1000); - uintptr_t last_address = SHM_START; + uintptr_t last_address = 0x200000000; foreach(node, proc->shm_mappings) { shm_mapping_t * m = node->value; if (m->vaddrs[0] > last_address) { size_t gap = (uintptr_t)m->vaddrs[0] - last_address; - debug_print(INFO, "gap found at 0x%x of size %d", last_address, gap); if (gap >= mapping->num_vaddrs * 0x1000) { - debug_print(INFO, "Gap is sufficient, we can insert here."); - /* Map the gap */ for (unsigned int i = 0; i < chunk->num_frames; ++i) { - page_t * page = get_page(last_address + i * 0x1000, 1, proc->thread.page_directory); - page->frame = chunk->frames[i]; - alloc_frame(page, 0, 1); - invalidate_tables_at(last_address + i * 0x1000); - mapping->vaddrs[i] = last_address + i * 0x1000; + union PML * page = mmu_get_page(last_address + (i << 12), MMU_GET_MAKE); + page->bits.page = chunk->frames[i]; + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(last_address + (i << 12)); + mapping->vaddrs[i] = last_address + (i << 12); } /* Insert us before this node */ @@ -196,46 +193,34 @@ static void * map_in (shm_chunk_t * chunk, process_t * proc) { } } last_address = m->vaddrs[0] + m->num_vaddrs * 0x1000; - debug_print(INFO, "[0x%x:0x%x] %s", m->vaddrs[0], last_address, m->chunk->parent->name); } + if (proc->image.shm_heap > last_address) { size_t gap = proc->image.shm_heap - last_address; - debug_print(INFO, "gap found at 0x%x of size %d", last_address, gap); if (gap >= mapping->num_vaddrs * 0x1000) { - debug_print(INFO, "Gap is sufficient, we can insert here."); for (unsigned int i = 0; i < chunk->num_frames; ++i) { - page_t * page = get_page(last_address + i * 0x1000, 1, proc->thread.page_directory); - page->frame = chunk->frames[i]; - alloc_frame(page, 0, 1); - invalidate_tables_at(last_address + i * 0x1000); - mapping->vaddrs[i] = last_address + i * 0x1000; + union PML * page = mmu_get_page(last_address + (i << 12), MMU_GET_MAKE); + page->bits.page = chunk->frames[i]; + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(last_address + (i << 12)); + mapping->vaddrs[i] = last_address + (i << 12); } list_insert(proc->shm_mappings, mapping); - return (void *)mapping->vaddrs[0]; - } else { - debug_print(INFO, "should be more efficient here - there is space available, but we are not going to use it"); } } for (uint32_t i = 0; i < chunk->num_frames; i++) { uintptr_t new_vpage = proc_sbrk(1, proc); - assert(new_vpage % 0x1000 == 0); - page_t * page = get_page(new_vpage, 1, proc->thread.page_directory); - assert(page && "Page not allocated by sys_sbrk?"); - - page->frame = chunk->frames[i]; - alloc_frame(page, 0, 1); - invalidate_tables_at(new_vpage); + union PML * page = mmu_get_page(new_vpage, MMU_GET_MAKE); + page->bits.page = chunk->frames[i]; + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(new_vpage); mapping->vaddrs[i] = new_vpage; - -#if 0 - debug_print(INFO, "mapping vaddr 0x%x --> #%d", new_vpage, page->frame); -#endif } list_insert(proc->shm_mappings, mapping); @@ -253,22 +238,19 @@ static size_t chunk_size (shm_chunk_t * chunk) { void * shm_obtain (char * path, size_t * size) { spin_lock(bsl); - process_t * proc = (process_t *)current_process; + volatile process_t * volatile proc = this_core->current_process; if (proc->group != 0) { proc = process_from_pid(proc->group); } shm_node_t * node = get_node(path, 1); // (if it exists, just get it) - assert(node && "shm_node_t not created by get_node"); shm_chunk_t * chunk = node->chunk; if (chunk == NULL) { /* There's no chunk for that key -- we need to allocate it! */ - debug_print(NOTICE, "Allocating a new shmem chunk for process %d", proc->id); - - if (size == 0) { + if (!size) { // The process doesn't want a chunk...? spin_unlock(bsl); return NULL; @@ -276,7 +258,6 @@ void * shm_obtain (char * path, size_t * size) { chunk = create_chunk(node, *size); if (chunk == NULL) { - debug_print(ERROR, "Could not allocate a shm_chunk_t"); spin_unlock(bsl); return NULL; } @@ -286,18 +267,18 @@ void * shm_obtain (char * path, size_t * size) { /* New accessor! */ chunk->ref_count++; } + void * vshm_start = map_in(chunk, proc); *size = chunk_size(chunk); spin_unlock(bsl); - invalidate_page_tables(); return vshm_start; } int shm_release (char * path) { spin_lock(bsl); - process_t * proc = (process_t *)current_process; + process_t * proc = (process_t *)this_core->current_process; if (proc->group != 0) { proc = process_from_pid(proc->group); @@ -329,12 +310,9 @@ int shm_release (char * path) { /* Clear the mappings from the process's address space */ for (uint32_t i = 0; i < mapping->num_vaddrs; i++) { - page_t * page = get_page(mapping->vaddrs[i], 0, proc->thread.page_directory); - assert(page && "Shared memory mapping was invalid!"); - - memset(page, 0, sizeof(page_t)); + union PML * page = mmu_get_page(mapping->vaddrs[i], 0); + page->bits.present = 0; } - invalidate_page_tables(); /* Clean up */ release_chunk(chunk); diff --git a/kernel/sys/signal.c b/kernel/sys/signal.c index 05aab4a8..0b639a97 100644 --- a/kernel/sys/signal.c +++ b/kernel/sys/signal.c @@ -1,87 +1,74 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/sys/signal.c + * @brief Signal handling. + * + * Provides signal entry and delivery; also handles suspending + * and resuming jobs (SIGTSTP, SIGCONT). + * + * Signal delivery in ToaruOS is a bit odd; we save a lot of the + * kernel context from before the signal, including the entire + * kernel stack, so that we can resume userspace in a new context; + * essentially we build a whole new kernel thread for the signal + * handler to run in, and then restore the original when the signal + * handler exits. Signal handler exits are generally handled by + * a page fault at a magic known address. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2018 K. Lange - * - * Signal Handling + * Copyright (C) 2012-2021 K. Lange */ - -#include +#include +#include +#include +#include +#include +#include +#include #include -#include - -void enter_signal_handler(uintptr_t location, int signum, uintptr_t stack) { - IRQ_OFF; - uintptr_t ebp = current_process->syscall_registers->ebp; - uintptr_t esp = current_process->syscall_registers->useresp; - asm volatile( - "mov %2, %%esp\n" - "pushl %4\n" - "pushl %3\n" - "pushl %1\n" /* argument count */ - "pushl $" STRSTR(SIGNAL_RETURN) "\n" - "mov $0x23, %%ax\n" /* Segment selector */ - "mov %%ax, %%ds\n" - "mov %%ax, %%es\n" - "mov %%ax, %%fs\n" - "mov $0x33, %%ax\n" /* Segment selector */ - "mov %%ax, %%gs\n" - "mov %%esp, %%eax\n" /* Stack -> EAX */ - "pushl $0x23\n" /* Segment selector again */ - "pushl %%eax\n" - "pushf\n" /* Push flags */ - "popl %%eax\n" /* Fix the Interrupt flag */ - "orl $0x200, %%eax\n" - "pushl %%eax\n" - "pushl $0x1B\n" - "pushl %0\n" /* Push the entry point */ - "iret\n" - : : "m"(location), "m"(signum), "r"(stack), "m"(ebp), "m"(esp) : "%ax", "%esp", "%eax"); - - debug_print(CRITICAL, "Failed to jump to signal handler!"); -} +#include static spin_lock_t sig_lock; static spin_lock_t sig_lock_b; char isdeadly[] = { 0, /* 0? */ - 1, /* SIGHUP */ - 1, /* SIGINT */ - 2, /* SIGQUIT */ - 2, /* SIGILL */ - 2, /* SIGTRAP */ - 2, /* SIGABRT */ - 2, /* SIGEMT */ - 2, /* SIGFPE */ - 1, /* SIGKILL */ - 2, /* SIGBUS */ - 2, /* SIGSEGV */ - 2, /* SIGSYS */ - 1, /* SIGPIPE */ - 1, /* SIGALRM */ - 1, /* SIGTERM */ - 1, /* SIGUSR1 */ - 1, /* SIGUSR2 */ - 0, /* SIGCHLD */ - 0, /* SIGPWR */ - 0, /* SIGWINCH */ - 0, /* SIGURG */ - 0, /* SIGPOLL */ - 3, /* SIGSTOP */ - 3, /* SIGTSTP */ - 4, /* SIGCONT */ - 3, /* SIGTTIN */ - 3, /* SIGTTOUT */ - 1, /* SIGVTALRM */ - 1, /* SIGPROF */ - 2, /* SIGXCPU */ - 2, /* SIGXFSZ */ - 0, /* SIGWAITING */ - 1, /* SIGDIAF */ - 0, /* SIGHATE */ - 0, /* SIGWINEVENT*/ - 0, /* SIGCAT */ + [SIGHUP ] = 1, + [SIGINT ] = 1, + [SIGQUIT ] = 2, + [SIGILL ] = 2, + [SIGTRAP ] = 2, + [SIGABRT ] = 2, + [SIGEMT ] = 2, + [SIGFPE ] = 2, + [SIGKILL ] = 1, + [SIGBUS ] = 2, + [SIGSEGV ] = 2, + [SIGSYS ] = 2, + [SIGPIPE ] = 1, + [SIGALRM ] = 1, + [SIGTERM ] = 1, + [SIGUSR1 ] = 1, + [SIGUSR2 ] = 1, + [SIGCHLD ] = 0, + [SIGPWR ] = 0, + [SIGWINCH ] = 0, + [SIGURG ] = 0, + [SIGPOLL ] = 0, + [SIGSTOP ] = 3, + [SIGTSTP ] = 3, + [SIGCONT ] = 4, + [SIGTTIN ] = 3, + [SIGTTOUT ] = 3, + [SIGVTALRM ] = 1, + [SIGPROF ] = 1, + [SIGXCPU ] = 2, + [SIGXFSZ ] = 2, + [SIGWAITING ] = 0, + [SIGDIAF ] = 1, + [SIGHATE ] = 0, + [SIGWINEVENT] = 0, + [SIGCAT ] = 0, }; void handle_signal(process_t * proc, signal_t * sig) { @@ -89,7 +76,7 @@ void handle_signal(process_t * proc, signal_t * sig) { uintptr_t signum = sig->signum; free(sig); - if (proc->finished) { + if (proc->flags & PROC_FLAG_FINISHED) { return; } @@ -101,17 +88,15 @@ void handle_signal(process_t * proc, signal_t * sig) { if (!handler) { char dowhat = isdeadly[signum]; if (dowhat == 1 || dowhat == 2) { - debug_print(WARNING, "Process %d killed by unhandled signal (%d)", proc->id, signum); - kexit(((128 + signum) << 8) | signum); + task_exit(((128 + signum) << 8) | signum); __builtin_unreachable(); } else if (dowhat == 3) { - debug_print(WARNING, "suspending pid %d", proc->id); - current_process->suspended = 1; - current_process->status = 0x7F; + __sync_or_and_fetch(&this_core->current_process->flags, PROC_FLAG_SUSPENDED); + this_core->current_process->status = 0x7F; - process_t * parent = process_get_parent((process_t *)current_process); + process_t * parent = process_get_parent((process_t *)this_core->current_process); - if (parent && !parent->finished) { + if (parent && !(parent->flags & PROC_FLAG_FINISHED)) { wakeup_queue(parent->wait_queue); } @@ -119,8 +104,6 @@ void handle_signal(process_t * proc, signal_t * sig) { } else if (dowhat == 4) { switch_task(1); return; - } else { - debug_print(WARNING, "Ignoring signal %d by default in pid %d", signum, proc->id); } /* XXX dowhat == 2: should dump core */ /* XXX dowhat == 3: stop */ @@ -131,33 +114,18 @@ void handle_signal(process_t * proc, signal_t * sig) { return; } - debug_print(NOTICE, "handling signal in process %d (%d) (0x%x)", proc->id, signum, handler); - - uintptr_t stack = 0xFFFF0000; - if (proc->syscall_registers->useresp < 0x10000100) { - stack = proc->image.user_stack; - } else { - stack = proc->syscall_registers->useresp; - } - - /* Not marked as ignored, must call signal */ - enter_signal_handler(handler, signum, stack); - + arch_enter_signal_handler(handler, signum); } list_t * rets_from_sig; void return_from_signal_handler(void) { -#if 0 - debug_print(ERROR, "Return From Signal for process %d", current_process->id); -#endif - if (__builtin_expect(!rets_from_sig, 0)) { - rets_from_sig = list_create(); + rets_from_sig = list_create("global return-from-signal queue",NULL); } spin_lock(sig_lock); - list_insert(rets_from_sig, (process_t *)current_process); + list_insert(rets_from_sig, (process_t *)this_core->current_process); spin_unlock(sig_lock); switch_next(); @@ -176,17 +144,14 @@ void fix_signal_stacks(void) { } process_t * p = n->value; free(n); - if (p == current_process) { + if (p == this_core->current_process) { redo_me = 1; continue; } - p->thread.esp = p->signal_state.esp; - p->thread.eip = p->signal_state.eip; - p->thread.ebp = p->signal_state.ebp; + memcpy(&p->thread, &p->signal_state, sizeof(thread_t)); if (!p->signal_kstack) { - debug_print(ERROR, "Cannot restore signal stack for pid=%d - unset?", p->id); + printf("Cannot restore signal stack for pid=%d - unset?\n", p->id); } else { - debug_print(ERROR, "Restoring signal stack for pid=%d", p->id); memcpy((void *)(p->image.stack - KERNEL_STACK_SIZE), p->signal_kstack, KERNEL_STACK_SIZE); free(p->signal_kstack); p->signal_kstack = NULL; @@ -197,13 +162,13 @@ void fix_signal_stacks(void) { } if (redo_me) { spin_lock(sig_lock); - list_insert(rets_from_sig, (process_t *)current_process); + list_insert(rets_from_sig, (process_t *)this_core->current_process); spin_unlock(sig_lock); switch_next(); } } -int send_signal(pid_t process, uint32_t signal, int force_root) { +int send_signal(pid_t process, int signal, int force_root) { process_t * receiver = process_from_pid(process); if (!receiver) { @@ -211,53 +176,60 @@ int send_signal(pid_t process, uint32_t signal, int force_root) { return -ESRCH; } - if (!force_root && receiver->user != current_process->user && current_process->user != USER_ROOT_UID) { - if (!(signal == SIGCONT && receiver->session == current_process->session)) { + if (!force_root && receiver->user != this_core->current_process->user && this_core->current_process->user != USER_ROOT_UID) { + if (!(signal == SIGCONT && receiver->session == this_core->current_process->session)) { return -EPERM; } } + if (receiver->flags & PROC_FLAG_IS_TASKLET) { + /* Can not send signals to kernel tasklets */ + return -EINVAL; + } + if (signal > NUMSIGNALS) { /* Invalid signal */ return -EINVAL; } - if (receiver->finished) { + if (receiver->flags & PROC_FLAG_FINISHED) { /* Can't send signals to finished processes */ return -EINVAL; } - if (!receiver->signals.functions[signal] && !isdeadly[signal]) { + if (!receiver->signals[signal] && !isdeadly[signal]) { /* If we're blocking a signal and it's not going to kill us, don't deliver it */ return 0; } if (isdeadly[signal] == 4) { - if (!receiver->suspended) { + if (!(receiver->flags & PROC_FLAG_SUSPENDED)) { return -EINVAL; } else { - debug_print(WARNING, "Resuming pid %d from suspend", receiver->id); - receiver->suspended = 0; + __sync_and_and_fetch(&receiver->flags, ~(PROC_FLAG_SUSPENDED)); receiver->status = 0; } } /* Append signal to list */ signal_t * sig = malloc(sizeof(signal_t)); - sig->handler = (uintptr_t)receiver->signals.functions[signal]; + sig->handler = (uintptr_t)receiver->signals[signal]; sig->signum = signal; - memset(&sig->registers_before, 0x00, sizeof(regs_t)); + memset(&sig->registers_before, 0x00, sizeof(struct regs)); + spin_lock(receiver->sched_lock); if (receiver->node_waits) { process_awaken_from_fswait(receiver, -1); + } else { + spin_unlock(receiver->sched_lock); } - if (!process_is_ready(receiver)) { + if (!process_is_ready(receiver) || receiver == this_core->current_process) { make_process_ready(receiver); } list_insert(receiver->signal_queue, sig); - if (receiver == current_process) { + if (receiver == this_core->current_process) { /* Forces us to be rescheduled and enter signal handler */ if (receiver->signal_kstack) { switch_next(); @@ -269,20 +241,16 @@ int send_signal(pid_t process, uint32_t signal, int force_root) { return 0; } -int group_send_signal(int group, uint32_t signal, int force_root) { +int group_send_signal(pid_t group, int signal, int force_root) { int kill_self = 0; int killed_something = 0; - debug_print(WARNING, "killing group %d", group); - foreach(node, process_list) { process_t * proc = node->value; - debug_print(WARNING, "examining %d %d %d", proc->id, proc->job, proc->group); if (proc->group == proc->id && proc->job == group) { /* Only thread group leaders */ - debug_print(WARNING, "killing %d", proc->group); - if (proc->group == current_process->group) { + if (proc->group == this_core->current_process->group) { kill_self = 1; } else { if (send_signal(proc->group, signal, force_root) == 0) { @@ -293,7 +261,7 @@ int group_send_signal(int group, uint32_t signal, int force_root) { } if (kill_self) { - if (send_signal(current_process->group, signal, force_root) == 0) { + if (send_signal(this_core->current_process->group, signal, force_root) == 0) { killed_something = 1; } } diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c index d7069d2a..0c98ce1c 100644 --- a/kernel/sys/syscall.c +++ b/kernel/sys/syscall.c @@ -1,349 +1,181 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2012 Markus Schober - * - * Syscall Tables - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include +#include +#include +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include static char hostname[256]; static size_t hostname_len = 0; -#define FD_INRANGE(FD) \ - ((FD) < (int)current_process->fds->length && (FD) >= 0) -#define FD_ENTRY(FD) \ - (current_process->fds->entries[(FD)]) -#define FD_CHECK(FD) \ - (FD_INRANGE(FD) && FD_ENTRY(FD)) -#define FD_OFFSET(FD) \ - (current_process->fds->offsets[(FD)]) -#define FD_MODE(FD) \ - (current_process->fds->modes[(FD)]) - -#define PTR_INRANGE(PTR) \ - ((uintptr_t)(PTR) > current_process->image.entry) -#define PTR_VALIDATE(PTR) \ - ptr_validate((void *)(PTR), __func__) - -static void ptr_validate(void * ptr, const char * syscall) { +void ptr_validate(void * ptr, const char * syscall) { if (ptr && !PTR_INRANGE(ptr)) { - debug_print(ERROR, "SEGFAULT: invalid pointer passed to %s. (0x%x < 0x%x)", - syscall, (uintptr_t)ptr, current_process->image.entry); - HALT_AND_CATCH_FIRE("Segmentation fault", NULL); + printf("invalid pointer passed to %s (%p < %p)\n", + syscall, ptr, (void*)this_core->current_process->image.entry); + while (1) {} } } -void validate(void * ptr) { - ptr_validate(ptr, "syscall"); -} - -/* - * Exit the current task. - * DOES NOT RETURN! - */ -static int __attribute__((noreturn)) sys_exit(int retval) { - /* Deschedule the current task */ - task_exit((retval & 0xFF) << 8); - for (;;) ; -} - -static int sys_read(int fd, char * ptr, int len) { - if (FD_CHECK(fd)) { - PTR_VALIDATE(ptr); - - fs_node_t * node = FD_ENTRY(fd); - if (!(FD_MODE(fd) & 01)) { - debug_print(WARNING, "access denied (read, fd=%d, mode=%d, %s, %s)", fd, FD_MODE(fd), node->name, current_process->name); - return -EACCES; +static long sys_sbrk(ssize_t size) { + if (size & 0xFFF) return -EINVAL; + volatile process_t * volatile proc = this_core->current_process; + if (proc->group != 0) { + proc = process_from_pid(proc->group); + } + spin_lock(proc->image.lock); + uintptr_t out = proc->image.heap; + for (uintptr_t i = out; i < out + size; i += 0x1000) { + union PML * page = mmu_get_page(i, MMU_GET_MAKE); + if (page->bits.page != 0) { + printf("odd, %#zx is already allocated?\n", i); } - uint32_t out = read_fs(node, FD_OFFSET(fd), len, (uint8_t *)ptr); - FD_OFFSET(fd) += out; - return (int)out; + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(i); } - return -EBADF; + proc->image.heap += size; + spin_unlock(proc->image.lock); + return (long)out; } -static int sys_ioctl(int fd, int request, void * argp) { - if (FD_CHECK(fd)) { - PTR_VALIDATE(argp); - return ioctl_fs(FD_ENTRY(fd), request, argp); - } - return -EBADF; -} - -static int sys_readdir(int fd, int index, struct dirent * entry) { - if (FD_CHECK(fd)) { - PTR_VALIDATE(entry); - struct dirent * kentry = readdir_fs(FD_ENTRY(fd), (uint32_t)index); - if (kentry) { - memcpy(entry, kentry, sizeof *entry); - free(kentry); - return 1; - } else { +static long sys_sysfunc(long fn, char ** args) { + /* FIXME: Most of these should be top-level, many are hacks/broken in Misaka */ + switch (fn) { + case TOARU_SYS_FUNC_SYNC: + /* FIXME: There is no sync ability in the VFS at the moment. */ + printf("sync: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_LOGHERE: + /* FIXME: Needs to redirect kprintf to the argument */ + printf("loghere: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_SETFDS: + /* XXX Unused */ + printf("setfds: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_WRITESDB: + /* XXX Unused */ + printf("writesdb: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_KDEBUG: + /* FIXME: Starts kernel debugger as a child task of this process */ + printf("kdebug: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_INSMOD: + /* FIXME: Load module */ + printf("insmod: not implemented\n"); + return -EINVAL; + /* Begin unpriv */ + case TOARU_SYS_FUNC_SETHEAP: { + volatile process_t * volatile proc = this_core->current_process; + if (proc->group != 0) proc = process_from_pid(proc->group); + spin_lock(proc->image.lock); + proc->image.heap = (uintptr_t)args[0]; + spin_unlock(proc->image.lock); return 0; } + case TOARU_SYS_FUNC_MMAP: { + /* FIXME: This whole thing should be removed, tbh */ + volatile process_t * volatile proc = this_core->current_process; + if (proc->group != 0) proc = process_from_pid(proc->group); + spin_lock(proc->image.lock); + /* Align inputs */ + uintptr_t start = ((uintptr_t)args[0]) & 0xFFFFffffFFFFf000UL; + uintptr_t end = ((uintptr_t)args[0] + (size_t)args[1] + 0xFFF) & 0xFFFFffffFFFFf000UL; + for (uintptr_t i = start; i < end; i += 0x1000) { + union PML * page = mmu_get_page(i, MMU_GET_MAKE); + mmu_frame_allocate(page, MMU_FLAG_WRITABLE); + mmu_invalidate(i); + } + spin_unlock(proc->image.lock); + return 0; + } + case TOARU_SYS_FUNC_THREADNAME: { + /* This should probably be moved to a new system call. */ + int count = 0; + char **arg = args; + PTR_VALIDATE(args); + while (*arg) { + PTR_VALIDATE(*args); + count++; + arg++; + } + this_core->current_process->cmdline = malloc(sizeof(char*)*(count+1)); + int i = 0; + while (i < count) { + this_core->current_process->cmdline[i] = strdup(args[i]); + i++; + } + this_core->current_process->cmdline[i] = NULL; + return 0; + } + case TOARU_SYS_FUNC_DEBUGPRINT: + /* XXX I think _xlog uses this? */ + printf("debugprint: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_SETVGACURSOR: + /* XXX This should be a device driver, along with the text-mode window... */ + printf("setvgacursor: not implemented\n"); + return -EINVAL; + case TOARU_SYS_FUNC_SETGSBASE: + PTR_VALIDATE(args); + this_core->current_process->thread.context.tls_base = (uintptr_t)args[0]; + arch_set_tls_base(this_core->current_process->thread.context.tls_base); + return 0; + default: + printf("Bad system function: %ld\n", fn); + return -EINVAL; } - return -EBADF; } -static int sys_write(int fd, char * ptr, int len) { +__attribute__((noreturn)) +static long sys_exit(long exitcode) { + /* TODO remove print */ + //printf("(process %d [%s] exited with %ld)\n", current_process->id, current_process->name, exitcode); + + task_exit((exitcode & 0xFF) << 8); + __builtin_unreachable(); +} + +static long sys_write(int fd, char * ptr, unsigned long len) { if (FD_CHECK(fd)) { PTR_VALIDATE(ptr); fs_node_t * node = FD_ENTRY(fd); - if (!(FD_MODE(fd) & 02)) { - debug_print(WARNING, "access denied (write, fd=%d)", fd); - return -EACCES; + if (!(FD_MODE(fd) & 2)) return -EACCES; + int64_t out = write_fs(node, FD_OFFSET(fd), len, (uint8_t*)ptr); + if (out > 0) { + FD_OFFSET(fd) += out; } - uint32_t out = write_fs(node, FD_OFFSET(fd), len, (uint8_t *)ptr); - FD_OFFSET(fd) += out; return out; } return -EBADF; } -static int sys_waitpid(int pid, int * status, int options) { - if (status && !PTR_INRANGE(status)) { - return -EINVAL; - } - return waitpid(pid, status, options); -} - -static int sys_open(const char * file, int flags, int mode) { - PTR_VALIDATE(file); - debug_print(NOTICE, "open(%s) flags=0x%x; mode=0x%x", file, flags, mode); - fs_node_t * node = kopen((char *)file, flags); - - int access_bits = 0; - - if (node && (flags & O_CREAT) && (flags & O_EXCL)) { - close_fs(node); - return -EEXIST; - } - - if (!(flags & O_WRONLY) || (flags & O_RDWR)) { - if (node && !has_permission(node, 04)) { - debug_print(WARNING, "access denied (read, sys_open, file=%s)", file); - close_fs(node); - return -EACCES; - } else { - access_bits |= 01; - } - } - - if ((flags & O_RDWR) || (flags & O_WRONLY)) { - if (node && !has_permission(node, 02)) { - close_fs(node); - return -EACCES; - } - if (node && (node->flags & FS_DIRECTORY)) { - return -EISDIR; - } - if ((flags & O_RDWR) || (flags & O_WRONLY)) { - /* truncate doesn't grant write permissions */ - access_bits |= 02; - } - } - - if (!node && (flags & O_CREAT)) { - /* TODO check directory permissions */ - debug_print(NOTICE, "- file does not exist and create was requested."); - /* Um, make one */ - int result = create_file_fs((char *)file, mode); - if (!result) { - node = kopen((char *)file, flags); - } else { - return result; - } - } - - if (node && (flags & O_DIRECTORY)) { - if (!(node->flags & FS_DIRECTORY)) { - return -ENOTDIR; - } - } - - if (node && (flags & O_TRUNC)) { - if (!(access_bits & 02)) { - close_fs(node); - return -EINVAL; - } - truncate_fs(node); - } - - if (!node) { - return -ENOENT; - } - if (node && (flags & O_CREAT) && (node->flags & FS_DIRECTORY)) { - close_fs(node); - return -EISDIR; - } - int fd = process_append_fd((process_t *)current_process, node); - FD_MODE(fd) = access_bits; - if (flags & O_APPEND) { - FD_OFFSET(fd) = node->length; - } else { - FD_OFFSET(fd) = 0; - } - debug_print(INFO, "[open] pid=%d %s -> %d", getpid(), file, fd); - return fd; -} - -static int sys_access(const char * file, int flags) { - PTR_VALIDATE(file); - debug_print(INFO, "access(%s, 0x%x) from pid=%d", file, flags, getpid()); - fs_node_t * node = kopen((char *)file, 0); - if (!node) return -ENOENT; - close_fs(node); - return 0; -} - -static int sys_close(int fd) { - if (FD_CHECK(fd)) { - close_fs(FD_ENTRY(fd)); - FD_ENTRY(fd) = NULL; - return 0; - } - return -EBADF; -} - -static int sys_sbrk(int size) { - process_t * proc = (process_t *)current_process; - if (proc->group != 0) { - proc = process_from_pid(proc->group); - } - spin_lock(proc->image.lock); - uintptr_t ret = proc->image.heap; - uintptr_t i_ret = ret; - ret = (ret + 0xfff) & ~0xfff; /* Rounds ret to 0x1000 in O(1) */ - proc->image.heap += (ret - i_ret) + size; - while (proc->image.heap > proc->image.heap_actual) { - proc->image.heap_actual += 0x1000; - assert(proc->image.heap_actual % 0x1000 == 0); - alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1); - invalidate_tables_at(proc->image.heap_actual); - } - spin_unlock(proc->image.lock); - return ret; -} - -static int sys_getpid(void) { - /* The user actually wants the pid of the originating thread (which can be us). */ - if (current_process->group) { - return current_process->group; - } else { - /* We are the leader */ - return current_process->id; - } -} - -/* Actual getpid() */ -static int sys_gettid(void) { - return getpid(); -} - -static int sys_execve(const char * filename, char *const argv[], char *const envp[]) { - PTR_VALIDATE(argv); - PTR_VALIDATE(filename); - PTR_VALIDATE(envp); - - if (args_present("traceexec")) { - debug_print(WARNING, "%d = exec(%s", current_process->id, filename); - for (char * const * arg = argv; *arg; ++arg) { - debug_print(WARNING, " %s", *arg); - } - debug_print(WARNING, " )"); - } - - int argc = 0; - int envc = 0; - while (argv[argc]) { - PTR_VALIDATE(argv[argc]); - ++argc; - } - - if (envp) { - while (envp[envc]) { - PTR_VALIDATE(envp[envc]); - ++envc; - } - } - - debug_print(INFO, "Allocating space for arguments..."); - char ** argv_ = malloc(sizeof(char *) * (argc + 1)); - for (int j = 0; j < argc; ++j) { - argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char)); - memcpy(argv_[j], argv[j], strlen(argv[j]) + 1); - } - argv_[argc] = 0; - char ** envp_; - if (envp && envc) { - envp_ = malloc(sizeof(char *) * (envc + 1)); - for (int j = 0; j < envc; ++j) { - envp_[j] = malloc((strlen(envp[j]) + 1) * sizeof(char)); - memcpy(envp_[j], envp[j], strlen(envp[j]) + 1); - } - envp_[envc] = 0; - } else { - envp_ = malloc(sizeof(char *)); - envp_[0] = NULL; - } - debug_print(INFO,"Releasing all shmem regions..."); - shm_release_all((process_t *)current_process); - - current_process->cmdline = argv_; - - debug_print(INFO,"Executing..."); - /* Discard envp */ - return exec((char *)filename, argc, (char **)argv_, (char **)envp_, 0); -} - -static int sys_seek(int fd, int offset, int whence) { - if (FD_CHECK(fd)) { - if ((FD_ENTRY(fd)->flags & FS_PIPE) || (FD_ENTRY(fd)->flags & FS_CHARDEVICE)) return -ESPIPE; - switch (whence) { - case 0: - FD_OFFSET(fd) = offset; - break; - case 1: - FD_OFFSET(fd) += offset; - break; - case 2: - FD_OFFSET(fd) = FD_ENTRY(fd)->length + offset; - break; - default: - return -EINVAL; - } - return FD_OFFSET(fd); - } - return -EBADF; -} - -static int stat_node(fs_node_t * fn, uintptr_t st) { +static long stat_node(fs_node_t * fn, uintptr_t st) { struct stat * f = (struct stat *)st; PTR_VALIDATE(f); if (!fn) { + /* XXX: Does this need to zero the stat struct when returning -ENOENT? */ memset(f, 0x00, sizeof(struct stat)); - debug_print(INFO, "stat: This file doesn't exist"); return -ENOENT; } - f->st_dev = (uint16_t)(((uint32_t)fn->device & 0xFFFF0) >> 8); + + f->st_dev = (uint16_t)(((uint64_t)fn->device & 0xFFFF0) >> 8); f->st_ino = fn->inode; uint32_t flags = 0; @@ -373,7 +205,15 @@ static int stat_node(fs_node_t * fn, uintptr_t st) { return 0; } -static int sys_statf(char * file, uintptr_t st) { +static long sys_stat(int fd, uintptr_t st) { + PTR_VALIDATE(st); + if (FD_CHECK(fd)) { + return stat_node(FD_ENTRY(fd), st); + } + return -EBADF; +} + +static long sys_statf(char * file, uintptr_t st) { int result; PTR_VALIDATE(file); PTR_VALIDATE(st); @@ -385,90 +225,321 @@ static int sys_statf(char * file, uintptr_t st) { return result; } -static int sys_chmod(char * file, int mode) { - int result; - PTR_VALIDATE(file); - fs_node_t * fn = kopen(file, 0); - if (fn) { - /* Can group members change bits? I think it's only owners. */ - if (current_process->user != 0 && current_process->user != fn->uid) { - close_fs(fn); - return -EACCES; - } - result = chmod_fs(fn, mode); - close_fs(fn); - return result; - } else { - return -ENOENT; - } +static long sys_symlink(char * target, char * name) { + PTR_VALIDATE(target); + PTR_VALIDATE(name); + return symlink_fs(target, name); } -static int sys_chown(char * file, int uid, int gid) { - int result; +static long sys_readlink(const char * file, char * ptr, long len) { PTR_VALIDATE(file); - fs_node_t * fn = kopen(file, 0); - if (fn) { - /* TODO: Owners can change groups... */ - if (current_process->user != 0) { - close_fs(fn); - return -EACCES; - } - result = chown_fs(fn, uid, gid); - close_fs(fn); - return result; - } else { + fs_node_t * node = kopen((char *) file, O_PATH | O_NOFOLLOW); + if (!node) { return -ENOENT; } + long rv = readlink_fs(node, ptr, len); + close_fs(node); + return rv; } - -static int sys_stat(int fd, uintptr_t st) { +static long sys_lstat(char * file, uintptr_t st) { + PTR_VALIDATE(file); PTR_VALIDATE(st); + fs_node_t * fn = kopen(file, O_PATH | O_NOFOLLOW); + long result = stat_node(fn, st); + if (fn) { + close_fs(fn); + } + return result; +} + +static long sys_open(const char * file, long flags, long mode) { + PTR_VALIDATE(file); + fs_node_t * node = kopen((char *)file, flags); + + int access_bits = 0; + + if (node && (flags & O_CREAT) && (flags & O_EXCL)) { + close_fs(node); + return -EEXIST; + } + + if (!(flags & O_WRONLY) || (flags & O_RDWR)) { + if (node && !has_permission(node, 04)) { + close_fs(node); + return -EACCES; + } else { + access_bits |= 01; + } + } + + if ((flags & O_RDWR) || (flags & O_WRONLY)) { + if (node && !has_permission(node, 02)) { + close_fs(node); + return -EACCES; + } + if (node && (node->flags & FS_DIRECTORY)) { + return -EISDIR; + } + if ((flags & O_RDWR) || (flags & O_WRONLY)) { + /* truncate doesn't grant write permissions */ + access_bits |= 02; + } + } + + if (!node && (flags & O_CREAT)) { + /* TODO check directory permissions */ + int result = create_file_fs((char *)file, mode); + if (!result) { + node = kopen((char *)file, flags); + } else { + return result; + } + } + + if (node && (flags & O_DIRECTORY)) { + if (!(node->flags & FS_DIRECTORY)) { + return -ENOTDIR; + } + } + + if (node && (flags & O_TRUNC)) { + if (!(access_bits & 02)) { + close_fs(node); + return -EINVAL; + } + truncate_fs(node); + } + + if (!node) { + return -ENOENT; + } + if (node && (flags & O_CREAT) && (node->flags & FS_DIRECTORY)) { + close_fs(node); + return -EISDIR; + } + int fd = process_append_fd((process_t *)this_core->current_process, node); + FD_MODE(fd) = access_bits; + if (flags & O_APPEND) { + FD_OFFSET(fd) = node->length; + } else { + FD_OFFSET(fd) = 0; + } + return fd; +} + +static long sys_close(int fd) { if (FD_CHECK(fd)) { - return stat_node(FD_ENTRY(fd), st); + close_fs(FD_ENTRY(fd)); + FD_ENTRY(fd) = NULL; + return 0; } return -EBADF; } -static int sys_mkpipe(void) { - fs_node_t * node = make_pipe(4096 * 2); - open_fs(node, 0); - int fd = process_append_fd((process_t *)current_process, node); - FD_MODE(fd) = 03; /* read write */ - return fd; +static long sys_seek(int fd, long offset, long whence) { + if (FD_CHECK(fd)) { + if ((FD_ENTRY(fd)->flags & FS_PIPE) || (FD_ENTRY(fd)->flags & FS_CHARDEVICE)) return -ESPIPE; + switch (whence) { + case 0: + FD_OFFSET(fd) = offset; + break; + case 1: + FD_OFFSET(fd) += offset; + break; + case 2: + FD_OFFSET(fd) = FD_ENTRY(fd)->length + offset; + break; + default: + return -EINVAL; + } + return FD_OFFSET(fd); + } + return -EBADF; } -static int sys_dup2(int old, int new) { - return process_move_fd((process_t *)current_process, old, new); +static long sys_read(int fd, char * ptr, unsigned long len) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(ptr); + + fs_node_t * node = FD_ENTRY(fd); + if (!(FD_MODE(fd) & 01)) { + return -EACCES; + } + uint64_t out = read_fs(node, FD_OFFSET(fd), len, (uint8_t *)ptr); + FD_OFFSET(fd) += out; + return out; + } + return -EBADF; } -static int sys_getuid(void) { - return current_process->real_user; +static long sys_ioctl(int fd, int request, void * argp) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(argp); + return ioctl_fs(FD_ENTRY(fd), request, argp); + } + return -EBADF; } -static int sys_geteuid(void) { - return current_process->user; +static long sys_readdir(int fd, long index, struct dirent * entry) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(entry); + struct dirent * kentry = readdir_fs(FD_ENTRY(fd), (uint64_t)index); + if (kentry) { + memcpy(entry, kentry, sizeof *entry); + free(kentry); + return 1; + } else { + return 0; + } + } + return -EBADF; } -static int sys_setuid(user_t new_uid) { - if (current_process->user == USER_ROOT_UID) { - current_process->user = new_uid; - current_process->real_user = new_uid; +static long sys_mkdir(char * path, uint64_t mode) { + return mkdir_fs(path, mode); +} + +static long sys_access(const char * file, long flags) { + PTR_VALIDATE(file); + fs_node_t * node = kopen((char *)file, 0); + if (!node) return -ENOENT; + close_fs(node); + return 0; +} + +static long sys_chmod(char * file, long mode) { + PTR_VALIDATE(file); + fs_node_t * fn = kopen(file, 0); + if (fn) { + /* Can group members change bits? I think it's only owners. */ + if (this_core->current_process->user != 0 && this_core->current_process->user != fn->uid) { + close_fs(fn); + return -EACCES; + } + long result = chmod_fs(fn, mode); + close_fs(fn); + return result; + } else { + return -ENOENT; + } +} + +static long sys_chown(char * file, uid_t uid, uid_t gid) { + PTR_VALIDATE(file); + fs_node_t * fn = kopen(file, 0); + if (fn) { + /* TODO: Owners can change groups... */ + if (this_core->current_process->user != 0) { + close_fs(fn); + return -EACCES; + } + long result = chown_fs(fn, uid, gid); + close_fs(fn); + return result; + } else { + return -ENOENT; + } +} + +static long sys_gettimeofday(struct timeval * tv, void * tz) { + PTR_VALIDATE(tv); + PTR_VALIDATE(tz); + return gettimeofday(tv, tz); +} + +static long sys_getuid(void) { + return (long)this_core->current_process->real_user; +} + +static long sys_geteuid(void) { + return (long)this_core->current_process->user; +} + +static long sys_setuid(uid_t new_uid) { + if (this_core->current_process->user == USER_ROOT_UID) { + this_core->current_process->user = new_uid; + this_core->current_process->real_user = new_uid; return 0; } return -EPERM; } -static int sys_uname(struct utsname * name) { +static long sys_getpid(void) { + /* The user actually wants the pid of the originating thread (which can be us). */ + return this_core->current_process->group ? (long)this_core->current_process->group : (long)this_core->current_process->id; +} + +static long sys_gettid(void) { + return (long)this_core->current_process->id; +} + +static long sys_setsid(void) { + if (this_core->current_process->job == this_core->current_process->group) { + return -EPERM; + } + this_core->current_process->session = this_core->current_process->group; + this_core->current_process->job = this_core->current_process->group; + return this_core->current_process->session; +} + +static long sys_setpgid(pid_t pid, pid_t pgid) { + if (pgid < 0) { + return -EINVAL; + } + process_t * proc = NULL; + if (pid == 0) { + proc = (process_t*)this_core->current_process; + } else { + proc = process_from_pid(pid); + } + + if (!proc) { + return -ESRCH; + } + if (proc->session != this_core->current_process->session || proc->session == proc->group) { + return -EPERM; + } + + if (pgid == 0) { + proc->job = proc->group; + } else { + process_t * pgroup = process_from_pid(pgid); + + if (!pgroup || pgroup->session != proc->session) { + return -EPERM; + } + + proc->job = pgid; + } + return 0; +} + +static long sys_getpgid(pid_t pid) { + process_t * proc; + if (pid == 0) { + proc = (process_t*)this_core->current_process; + } else { + proc = NULL; process_from_pid(pid); + } + + if (!proc) { + return -ESRCH; + } + + return proc->job; +} + +static long sys_uname(struct utsname * name) { PTR_VALIDATE(name); char version_number[256]; - sprintf(version_number, __kernel_version_format, + snprintf(version_number, 255, __kernel_version_format, __kernel_version_major, __kernel_version_minor, __kernel_version_lower, __kernel_version_suffix); char version_string[256]; - sprintf(version_string, "%s %s %s", + snprintf(version_string, 255, "%s %s %s", __kernel_version_codename, __kernel_build_date, __kernel_build_time); @@ -477,55 +548,13 @@ static int sys_uname(struct utsname * name) { strcpy(name->release, version_number); strcpy(name->version, version_string); strcpy(name->machine, __kernel_arch); - strcpy(name->domainname, ""); + strcpy(name->domainname, ""); /* TODO */ return 0; } -static int sys_signal(uint32_t signum, uintptr_t handler) { - if (signum > NUMSIGNALS) { - return -EINVAL; - } - uintptr_t old = current_process->signals.functions[signum]; - current_process->signals.functions[signum] = handler; - return (int)old; -} - -/* -static void inspect_memory (uintptr_t vaddr) { - // Please use this scary hack of a function as infrequently as possible. - shmem_debug_frame(vaddr); -} -*/ - -extern void idt_load(uint32_t *); - -static int sys_reboot(void) { - debug_print(NOTICE, "[kernel] Reboot requested from process %d by user #%d", current_process->id, current_process->user); - if (current_process->user != USER_ROOT_UID) { - return -EPERM; - } else { - debug_print(ERROR, "[kernel] Good bye!"); - /* Goodbye, cruel world */ - IRQ_OFF; - uintptr_t phys; - uint32_t * virt = (void*)kvmalloc_p(0x1000, &phys); - virt[0] = 0; - virt[1] = 0; - virt[2] = 0; - idt_load(virt); - uint8_t out = 0x02; - while ((out & 0x02) != 0) { - out = inportb(0x64); - } - outportb(0x64, 0xFE); /* Reset */ - STOP; - } - return 0; -} - -static int sys_chdir(char * newdir) { +static long sys_chdir(char * newdir) { PTR_VALIDATE(newdir); - char * path = canonicalize_path(current_process->wd_name, newdir); + char * path = canonicalize_path(this_core->current_process->wd_name, newdir); fs_node_t * chd = kopen(path, 0); if (chd) { if ((chd->flags & FS_DIRECTORY) == 0) { @@ -537,26 +566,30 @@ static int sys_chdir(char * newdir) { return -EACCES; } close_fs(chd); - free(current_process->wd_name); - current_process->wd_name = malloc(strlen(path) + 1); - memcpy(current_process->wd_name, path, strlen(path) + 1); + free(this_core->current_process->wd_name); + this_core->current_process->wd_name = malloc(strlen(path) + 1); + memcpy(this_core->current_process->wd_name, path, strlen(path) + 1); return 0; } else { return -ENOENT; } } -static int sys_getcwd(char * buf, size_t size) { +static long sys_getcwd(char * buf, size_t size) { if (buf) { PTR_VALIDATE(buf); - size_t len = strlen(current_process->wd_name) + 1; - return (int)memcpy(buf, current_process->wd_name, MIN(size, len)); + size_t len = strlen(this_core->current_process->wd_name) + 1; + return (long)memcpy(buf, this_core->current_process->wd_name, size < len ? size : len); } return 0; } -static int sys_sethostname(char * new_hostname) { - if (current_process->user == USER_ROOT_UID) { +static long sys_dup2(int old, int new) { + return process_move_fd((process_t *)this_core->current_process, old, new); +} + +static long sys_sethostname(char * new_hostname) { + if (this_core->current_process->user == USER_ROOT_UID) { PTR_VALIDATE(new_hostname); size_t len = strlen(new_hostname) + 1; if (len > 256) { @@ -570,331 +603,127 @@ static int sys_sethostname(char * new_hostname) { } } -static int sys_gethostname(char * buffer) { +static long sys_gethostname(char * buffer) { PTR_VALIDATE(buffer); memcpy(buffer, hostname, hostname_len); return hostname_len; } -extern int mkdir_fs(char *name, uint16_t permission); +static long sys_mount(char * arg, char * mountpoint, char * type, unsigned long flags, void * data) { + /* TODO: Make use of flags and data from mount command. */ + (void)flags; + (void)data; -static int sys_mkdir(char * path, uint32_t mode) { - return mkdir_fs(path, mode); -} - -/* - * Yield the rest of the quantum; - * useful for busy waiting and other such things - */ -static int sys_yield(void) { - switch_task(1); - return 1; -} - -/* - * System Function - */ -static int sys_sysfunc(int fn, char ** args) { - /* System Functions are special debugging system calls */ - if (current_process->user == USER_ROOT_UID) { - switch (fn) { - case 3: - debug_print(ERROR, "sync is currently unimplemented"); - //ext2_disk_sync(); - return 0; - case 4: - /* Request kernel output to file descriptor in arg0*/ - debug_print(NOTICE, "Setting output to file object in process %d's fd=%d!", getpid(), (int)args); - debug_file = current_process->fds->entries[(int)args]; - return 0; - case 5: - { - char *arg; - PTR_VALIDATE(args); - for (arg = args[0]; arg; arg++) - PTR_VALIDATE(arg); - debug_print(NOTICE, "Replacing process %d's file descriptors with pointers to %s", getpid(), (char *)args); - fs_node_t * repdev = kopen((char *)args, 0); - while (current_process->fds->length < 3) { - process_append_fd((process_t *)current_process, repdev); - } - FD_ENTRY(0) = repdev; - FD_ENTRY(1) = repdev; - FD_ENTRY(2) = repdev; - } - return 0; - case 6: - debug_print(WARNING, "writing contents of file %s to sdb", args[0]); - { - PTR_VALIDATE(args); - PTR_VALIDATE(args[0]); - fs_node_t * file = kopen((char *)args[0], 0); - if (!file) { - return -EINVAL; - } - size_t length = file->length; - uint8_t * buffer = malloc(length); - read_fs(file, 0, length, (uint8_t *)buffer); - close_fs(file); - debug_print(WARNING, "Finished reading file, going to write it now."); - - fs_node_t * f = kopen("/dev/sdb", 0); - if (!f) { - return 1; - } - - write_fs(f, 0, length, buffer); - - free(buffer); - return 0; - } - case 7: - debug_print(NOTICE, "Spawning debug hook as child of process %d.", getpid()); - if (debug_hook) { - fs_node_t * tty = FD_ENTRY(0); - return create_kernel_tasklet(debug_hook, "[kttydebug]", tty); - } else { - return -EINVAL; - } - case 8: - debug_print(NOTICE, "Loading module %s.", args[0]); - { - /* Check file existence */ - fs_node_t * file = kopen(args[0], 0); - if (!file) { - return 1; - } - close_fs(file); - - module_data_t * mod_info = module_load(args[0]); - if (!mod_info) { - return 2; - } - return 0; - } - } + if (this_core->current_process->user != USER_ROOT_UID) { + return -EPERM; } - switch (fn) { - /* The following functions are here to support the loader and are probably bad. */ - case 9: - { - process_t * proc = (process_t *)current_process; - if (proc->group != 0) { - proc = process_from_pid(proc->group); - } - spin_lock(proc->image.lock); - /* Set new heap start */ - uintptr_t address = (uintptr_t)args[0]; - /* TODO: These virtual address bounds should be in a header somewhere */ - if (address < 0x20000000) { - spin_unlock(proc->image.lock); - return -EINVAL; - } - proc->image.heap = (uintptr_t)address; - proc->image.heap_actual = proc->image.heap & 0xFFFFF000; - assert(proc->image.heap_actual % 0x1000 == 0); - alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1); - invalidate_tables_at(proc->image.heap_actual); - while (proc->image.heap > proc->image.heap_actual) { - proc->image.heap_actual += 0x1000; - alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1); - invalidate_tables_at(proc->image.heap_actual); - } - spin_unlock(proc->image.lock); - return 0; - } - case 10: - { - /* Load pages to fit region. */ - uintptr_t address = (uintptr_t)args[0]; - /* TODO: These virtual address bounds should be in a header somewhere */ - if (address < 0x20000000) return -EINVAL; - /* TODO: Upper bounds */ - size_t size = (size_t)args[1]; - /* TODO: Other arguments for read/write? */ - if (address & 0xFFF) { - size += address & 0xFFF; - address &= 0xFFFFF000; - } - - process_t * proc = (process_t *)current_process; - if (proc->group != 0) { - proc = process_from_pid(proc->group); - } - - spin_lock(proc->image.lock); - for (size_t x = 0; x < size; x += 0x1000) { - alloc_frame(get_page(address + x, 1, current_directory), 0, 1); - invalidate_tables_at(address + x); - } - spin_unlock(proc->image.lock); - - return 0; - } - - case 11: - { - /* Set command line (meant for threads to set descriptions) */ - int count = 0; - char **arg = args; - PTR_VALIDATE(args); - while (*arg) { - PTR_VALIDATE(*args); - count++; - arg++; - } - /* - * XXX We have a pretty obvious leak in storing command lines, since - * we never free them! Unfortunately, at the moment, they are - * shared between different processes, so until that gets fixed - * we're going to be just as bad as the rest of the codebase and - * just not free the previous value. - */ - current_process->cmdline = malloc(sizeof(char*)*(count+1)); - int i = 0; - while (i < count) { - current_process->cmdline[i] = strdup(args[i]); - i++; - } - current_process->cmdline[i] = NULL; - return 0; - } - - case 12: - /* - * Print a debug message to the kernel console - * XXX: This probably should be a thing normal users can do. - */ - PTR_VALIDATE(args); - debug_print(WARNING, "0x%x 0x%x 0x%x 0x%x", args[0], args[1], args[2], args[3]); - _debug_print(args[0], (uintptr_t)args[1], (uint32_t)args[2], args[3] ? args[3] : "(null)"); - return 0; - - case 13: - /* - * Set VGA text-mode cursor location - * (Not actually used to place a cursor, we use this to move the cursor off screen) - */ - PTR_VALIDATE(args); - outportb(0x3D4, 14); - outportb(0x3D5, (unsigned int)args[0]); - outportb(0x3D4, 15); - outportb(0x3D5, (unsigned int)args[1]); - - return 0; - - case 14: - PTR_VALIDATE(args); - current_process->thread.gsbase = (uintptr_t)args[0]; - gdt_set_gsbase(current_process->thread.gsbase); - return 0; - - default: - debug_print(ERROR, "Bad system function %d", fn); - break; + if (PTR_INRANGE(arg) && PTR_INRANGE(mountpoint) && PTR_INRANGE(type)) { + return vfs_mount_type(type, arg, mountpoint); } - return -EINVAL; /* Bad system function or access failure */ + + return -EFAULT; } -static int sys_sleepabs(unsigned long seconds, unsigned long subseconds) { - /* Mark us as asleep until */ - sleep_until((process_t *)current_process, seconds, subseconds); - - /* Switch without adding us to the queue */ - switch_task(0); - - if (seconds > timer_ticks || (seconds == timer_ticks && subseconds >= timer_subticks)) { - return 0; - } else { - return 1; - } -} - -static int sys_sleep(unsigned long seconds, unsigned long subseconds) { - unsigned long s, ss; - relative_time(seconds, subseconds * 10, &s, &ss); - return sys_sleepabs(s, ss); -} - -static int sys_umask(int mode) { - current_process->mask = mode & 0777; +static long sys_umask(long mode) { + this_core->current_process->mask = mode & 0777; return 0; } -static int sys_unlink(char * file) { +static long sys_unlink(char * file) { PTR_VALIDATE(file); return unlink_fs(file); } -static int sys_fork(void) { - return (int)fork(); +static long sys_execve(const char * filename, char *const argv[], char *const envp[]) { + PTR_VALIDATE(filename); + PTR_VALIDATE(argv); + PTR_VALIDATE(envp); + + int argc = 0; + int envc = 0; + while (argv[argc]) { + PTR_VALIDATE(argv[argc]); + ++argc; + } + + if (envp) { + while (envp[envc]) { + PTR_VALIDATE(envp[envc]); + ++envc; + } + } + + char **argv_ = malloc(sizeof(char*) * (argc + 1)); + for (int j = 0; j < argc; ++j) { + argv_[j] = malloc(strlen(argv[j]) + 1); + memcpy(argv_[j], argv[j], strlen(argv[j]) + 1); + } + argv_[argc] = 0; + char ** envp_; + if (envp && envc) { + envp_ = malloc(sizeof(char*) * (envc + 1)); + for (int j = 0; j < envc; ++j) { + envp_[j] = malloc(strlen(envp[j]) + 1); + memcpy(envp_[j], envp[j], strlen(envp[j]) + 1); + } + envp_[envc] = 0; + } else { + envp_ = malloc(sizeof(char*)); + envp_[0] = NULL; + } + + // shm_release_all + this_core->current_process->cmdline = argv_; + return exec(filename, argc, argv_, envp_, 0); } -static int sys_clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { +static long sys_fork(void) { + return fork(); +} + +static long sys_clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { if (!new_stack || !PTR_INRANGE(new_stack)) return -EINVAL; if (!thread_func || !PTR_INRANGE(thread_func)) return -EINVAL; return (int)clone(new_stack, thread_func, arg); } -static int sys_shm_obtain(char * path, size_t * size) { - PTR_VALIDATE(path); - PTR_VALIDATE(size); - - return (int)shm_obtain(path, size); +static long sys_waitpid(int pid, int * status, int options) { + if (status && !PTR_INRANGE(status)) return -EINVAL; + return waitpid(pid, status, options); } -static int sys_shm_release(char * path) { - PTR_VALIDATE(path); - - return shm_release(path); +static long sys_yield(void) { + switch_task(1); + return 1; } -static int sys_kill(pid_t process, uint32_t signal) { - if (process < -1) { - return group_send_signal(-process, signal, 0); - } else if (process == 0) { - return group_send_signal(current_process->job, signal, 0); +static long sys_sleepabs(unsigned long seconds, unsigned long subseconds) { + /* Mark us as asleep until */ + sleep_until((process_t *)this_core->current_process, seconds, subseconds); + + /* Switch without adding us to the queue */ + //printf("process %p (pid=%d) entering sleep until %ld.%06ld\n", current_process, current_process->id, seconds, subseconds); + switch_task(0); + + unsigned long timer_ticks = 0, timer_subticks = 0; + relative_time(0,0,&timer_ticks,&timer_subticks); + //printf("process %p (pid=%d) resumed from sleep at %ld.%06ld\n", current_process, current_process->id, timer_ticks, timer_subticks); + + if (seconds > timer_ticks || (seconds == timer_ticks && subseconds >= timer_subticks)) { + return 1; } else { - return send_signal(process, signal, 0); + return 0; } } -static int sys_gettimeofday(struct timeval * tv, void * tz) { - PTR_VALIDATE(tv); - PTR_VALIDATE(tz); - - return gettimeofday(tv, tz); +static long sys_sleep(unsigned long seconds, unsigned long subseconds) { + unsigned long s, ss; + relative_time(seconds, subseconds * 10000, &s, &ss); + return sys_sleepabs(s, ss); } -static int sys_openpty(int * master, int * slave, char * name, void * _ign0, void * size) { - /* We require a place to put these when we are done. */ - if (!master || !slave) return -EINVAL; - if (master && !PTR_INRANGE(master)) return -EINVAL; - if (slave && !PTR_INRANGE(slave)) return -EINVAL; - if (size && !PTR_INRANGE(size)) return -EINVAL; - - /* Create a new pseudo terminal */ - fs_node_t * fs_master; - fs_node_t * fs_slave; - - pty_create(size, &fs_master, &fs_slave); - - /* Append the master and slave to the calling process */ - *master = process_append_fd((process_t *)current_process, fs_master); - *slave = process_append_fd((process_t *)current_process, fs_slave); - - FD_MODE(*master) = 03; - FD_MODE(*slave) = 03; - - open_fs(fs_master, 0); - open_fs(fs_slave, 0); - - /* Return success */ - return 0; -} - -static int sys_pipe(int pipes[2]) { +static long sys_pipe(int pipes[2]) { if (pipes && !PTR_INRANGE(pipes)) { return -EFAULT; } @@ -906,59 +735,23 @@ static int sys_pipe(int pipes[2]) { open_fs(outpipes[0], 0); open_fs(outpipes[1], 0); - pipes[0] = process_append_fd((process_t *)current_process, outpipes[0]); - pipes[1] = process_append_fd((process_t *)current_process, outpipes[1]); + pipes[0] = process_append_fd((process_t *)this_core->current_process, outpipes[0]); + pipes[1] = process_append_fd((process_t *)this_core->current_process, outpipes[1]); FD_MODE(pipes[0]) = 03; FD_MODE(pipes[1]) = 03; return 0; } -static int sys_mount(char * arg, char * mountpoint, char * type, unsigned long flags, void * data) { - /* TODO: Make use of flags and data from mount command. */ - (void)flags; - (void)data; - - if (current_process->user != USER_ROOT_UID) { - return -EPERM; +static long sys_signal(long signum, uintptr_t handler) { + if (signum > NUMSIGNALS) { + return -EINVAL; } - - if (PTR_INRANGE(arg) && PTR_INRANGE(mountpoint) && PTR_INRANGE(type)) { - return vfs_mount_type(type, arg, mountpoint); - } - - return -EFAULT; + uintptr_t old = this_core->current_process->signals[signum]; + this_core->current_process->signals[signum] = handler; + return old; } -static int sys_symlink(char * target, char * name) { - PTR_VALIDATE(target); - PTR_VALIDATE(name); - return symlink_fs(target, name); -} - -static int sys_readlink(const char * file, char * ptr, int len) { - PTR_VALIDATE(file); - fs_node_t * node = kopen((char *) file, O_PATH | O_NOFOLLOW); - if (!node) { - return -ENOENT; - } - int rv = readlink_fs(node, ptr, len); - close_fs(node); - return rv; -} - -static int sys_lstat(char * file, uintptr_t st) { - int result; - PTR_VALIDATE(file); - PTR_VALIDATE(st); - fs_node_t * fn = kopen(file, O_PATH | O_NOFOLLOW); - result = stat_node(fn, st); - if (fn) { - close_fs(fn); - } - return result; -} - -static int sys_fswait(int c, int fds[]) { +static long sys_fswait(int c, int fds[]) { PTR_VALIDATE(fds); for (int i = 0; i < c; ++i) { if (!FD_CHECK(fds[i])) return -EBADF; @@ -969,12 +762,12 @@ static int sys_fswait(int c, int fds[]) { } nodes[c] = NULL; - int result = process_wait_nodes((process_t *)current_process, nodes, -1); + int result = process_wait_nodes((process_t *)this_core->current_process, nodes, -1); free(nodes); return result; } -static int sys_fswait_timeout(int c, int fds[], int timeout) { +static long sys_fswait_timeout(int c, int fds[], int timeout) { PTR_VALIDATE(fds); for (int i = 0; i < c; ++i) { if (!FD_CHECK(fds[i])) return -EBADF; @@ -985,12 +778,12 @@ static int sys_fswait_timeout(int c, int fds[], int timeout) { } nodes[c] = NULL; - int result = process_wait_nodes((process_t *)current_process, nodes, timeout); + int result = process_wait_nodes((process_t *)this_core->current_process, nodes, timeout); free(nodes); return result; } -static int sys_fswait_multi(int c, int fds[], int timeout, int out[]) { +static long sys_fswait_multi(int c, int fds[], int timeout, int out[]) { PTR_VALIDATE(fds); PTR_VALIDATE(out); int has_match = -1; @@ -1010,84 +803,78 @@ static int sys_fswait_multi(int c, int fds[], int timeout, int out[]) { if (has_match != -1) return has_match; int result = sys_fswait_timeout(c, fds, timeout); - if (result != -1) out[result] = 1; - if (result == -1) { - debug_print(ERROR,"negative result from fswait3"); - } + if (result >= 0) out[result] = 1; return result; } -static int sys_setsid(void) { - if (current_process->job == current_process->group) { - return -EPERM; - } - current_process->session = current_process->group; - current_process->job = current_process->group; - return current_process->session; +static long sys_shm_obtain(char * path, size_t * size) { + PTR_VALIDATE(path); + PTR_VALIDATE(size); + return (long)shm_obtain(path, size); } -static int sys_setpgid(pid_t pid, pid_t pgid) { - if (pgid < 0) { - return -EINVAL; - } - process_t * proc; - if (pid == 0) { - proc = (process_t*)current_process; - } else { - proc = process_from_pid(pid); - } - if (!proc) { - debug_print(WARNING, "not found"); - return -ESRCH; - } - if (proc->session != current_process->session) { - debug_print(WARNING, "child is in different sesion"); - return -EPERM; - } - if (proc->session == proc->group) { - debug_print(WARNING, "process is session leader"); - return -EPERM; - } +static long sys_shm_release(char * path) { + PTR_VALIDATE(path); + return shm_release(path); +} - if (pgid == 0) { - proc->job = proc->group; - } else { - process_t * pgroup = process_from_pid(pgid); +static long sys_openpty(int * master, int * slave, char * name, void * _ign0, void * size) { + /* We require a place to put these when we are done. */ + if (!master || !slave) return -EINVAL; + if (master && !PTR_INRANGE(master)) return -EINVAL; + if (slave && !PTR_INRANGE(slave)) return -EINVAL; + if (size && !PTR_INRANGE(size)) return -EINVAL; - if (!pgroup) { - debug_print(WARNING, "bad session id"); - return -EPERM; - } + /* Create a new pseudo terminal */ + fs_node_t * fs_master; + fs_node_t * fs_slave; - if (pgroup->session != proc->session) { - debug_print(WARNING, "tried to move to different session"); - return -EPERM; - } + pty_create(size, &fs_master, &fs_slave); - proc->job = pgid; - } + /* Append the master and slave to the calling process */ + *master = process_append_fd((process_t *)this_core->current_process, fs_master); + *slave = process_append_fd((process_t *)this_core->current_process, fs_slave); + + FD_MODE(*master) = 03; + FD_MODE(*slave) = 03; + + open_fs(fs_master, 0); + open_fs(fs_slave, 0); + + /* Return success */ return 0; } -static int sys_getpgid(pid_t pid) { - process_t * proc; - if (pid == 0) { - proc = (process_t*)current_process; +static long sys_kill(pid_t process, int signal) { + if (process < -1) { + return group_send_signal(-process, signal, 0); + } else if (process == 0) { + return group_send_signal(this_core->current_process->job, signal, 0); } else { - proc = process_from_pid(pid); + return send_signal(process, signal, 0); } - - if (!proc) { - return -ESRCH; - } - - return proc->job; } -/* - * System Call Internals - */ -static int (*syscalls[])() = { +static long sys_reboot(void) { + if (this_core->current_process->user != USER_ROOT_UID) { + return -EPERM; + } + + return arch_reboot(); +} + +extern long net_socket(); +extern long net_setsockopt(); +extern long net_bind(); +extern long net_accept(); +extern long net_listen(); +extern long net_connect(); +extern long net_getsockopt(); +extern long net_recv(); +extern long net_send(); +extern long net_shutdown(); + +static long (*syscalls[])() = { /* System Call Table */ [SYS_EXT] = sys_exit, [SYS_GETEUID] = sys_geteuid, @@ -1096,91 +883,79 @@ static int (*syscalls[])() = { [SYS_WRITE] = sys_write, [SYS_CLOSE] = sys_close, [SYS_GETTIMEOFDAY] = sys_gettimeofday, - [SYS_EXECVE] = sys_execve, - [SYS_FORK] = sys_fork, [SYS_GETPID] = sys_getpid, [SYS_SBRK] = sys_sbrk, [SYS_UNAME] = sys_uname, - [SYS_OPENPTY] = sys_openpty, [SYS_SEEK] = sys_seek, [SYS_STAT] = sys_stat, - [SYS_MKPIPE] = sys_mkpipe, - [SYS_DUP2] = sys_dup2, [SYS_GETUID] = sys_getuid, [SYS_SETUID] = sys_setuid, - [SYS_REBOOT] = sys_reboot, [SYS_READDIR] = sys_readdir, [SYS_CHDIR] = sys_chdir, [SYS_GETCWD] = sys_getcwd, - [SYS_CLONE] = sys_clone, [SYS_SETHOSTNAME] = sys_sethostname, [SYS_GETHOSTNAME] = sys_gethostname, [SYS_MKDIR] = sys_mkdir, - [SYS_SHM_OBTAIN] = sys_shm_obtain, - [SYS_SHM_RELEASE] = sys_shm_release, - [SYS_KILL] = sys_kill, - [SYS_SIGNAL] = sys_signal, [SYS_GETTID] = sys_gettid, - [SYS_YIELD] = sys_yield, [SYS_SYSFUNC] = sys_sysfunc, - [SYS_SLEEPABS] = sys_sleepabs, - [SYS_SLEEP] = sys_sleep, [SYS_IOCTL] = sys_ioctl, [SYS_ACCESS] = sys_access, [SYS_STATF] = sys_statf, [SYS_CHMOD] = sys_chmod, [SYS_UMASK] = sys_umask, [SYS_UNLINK] = sys_unlink, - [SYS_WAITPID] = sys_waitpid, - [SYS_PIPE] = sys_pipe, [SYS_MOUNT] = sys_mount, [SYS_SYMLINK] = sys_symlink, [SYS_READLINK] = sys_readlink, [SYS_LSTAT] = sys_lstat, - [SYS_FSWAIT] = sys_fswait, - [SYS_FSWAIT2] = sys_fswait_timeout, - [SYS_FSWAIT3] = sys_fswait_multi, [SYS_CHOWN] = sys_chown, [SYS_SETSID] = sys_setsid, [SYS_SETPGID] = sys_setpgid, [SYS_GETPGID] = sys_getpgid, + [SYS_DUP2] = sys_dup2, + [SYS_EXECVE] = sys_execve, + [SYS_FORK] = sys_fork, + [SYS_WAITPID] = sys_waitpid, + [SYS_YIELD] = sys_yield, + [SYS_SLEEPABS] = sys_sleepabs, + [SYS_SLEEP] = sys_sleep, + [SYS_PIPE] = sys_pipe, + [SYS_FSWAIT] = sys_fswait, + [SYS_FSWAIT2] = sys_fswait_timeout, + [SYS_FSWAIT3] = sys_fswait_multi, + [SYS_CLONE] = sys_clone, + [SYS_OPENPTY] = sys_openpty, + [SYS_SHM_OBTAIN] = sys_shm_obtain, + [SYS_SHM_RELEASE] = sys_shm_release, + [SYS_SIGNAL] = sys_signal, + [SYS_KILL] = sys_kill, + [SYS_REBOOT] = sys_reboot, + + [SYS_SOCKET] = net_socket, + [SYS_SETSOCKOPT] = net_setsockopt, + [SYS_BIND] = net_bind, + [SYS_ACCEPT] = net_accept, + [SYS_LISTEN] = net_listen, + [SYS_CONNECT] = net_connect, + [SYS_GETSOCKOPT] = net_getsockopt, + [SYS_RECV] = net_recv, + [SYS_SEND] = net_send, + [SYS_SHUTDOWN] = net_shutdown, }; -uint32_t num_syscalls = sizeof(syscalls) / sizeof(*syscalls); - -typedef uint32_t (*scall_func)(unsigned int, ...); - -pid_t trace_pid = 0; +static long num_syscalls = sizeof(syscalls) / sizeof(*syscalls); +typedef long (*scall_func)(); void syscall_handler(struct regs * r) { - if (r->eax >= num_syscalls) { + + if (arch_syscall_number(r) >= num_syscalls) { + arch_syscall_return(r, -EINVAL); return; } - uintptr_t location = (uintptr_t)syscalls[r->eax]; - if (!location) { - return; - } - - /* Update the syscall registers for this process */ - current_process->syscall_registers = r; - - if (trace_pid && current_process->id == trace_pid) { - debug_print(WARNING, "[syscall trace] %d (0x%x) 0x%x 0x%x 0x%x 0x%x 0x%x", r->eax, location, r->ebx, r->ecx, r->edx, r->esi, r->edi); - } - - /* Call the syscall function */ - scall_func func = (scall_func)location; - uint32_t ret = func(r->ebx, r->ecx, r->edx, r->esi, r->edi); - - if ((current_process->syscall_registers == r) || - (location != (uintptr_t)&fork && location != (uintptr_t)&clone)) { - r->eax = ret; - } + scall_func func = syscalls[arch_syscall_number(r)]; + this_core->current_process->syscall_registers = r; + arch_syscall_return(r, func( + arch_syscall_arg0(r), arch_syscall_arg1(r), arch_syscall_arg2(r), + arch_syscall_arg3(r), arch_syscall_arg4(r))); } - -void syscalls_install(void) { - debug_print(NOTICE, "Initializing syscall table with %d functions", num_syscalls); - isrs_install_handler(0x7F, &syscall_handler); -} - diff --git a/kernel/sys/task.c b/kernel/sys/task.c deleted file mode 100644 index b0008120..00000000 --- a/kernel/sys/task.c +++ /dev/null @@ -1,538 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * Copyright (C) 2012 Markus Schober - * - * Task Switching and Management Functions - * - */ -#include -#include -#include -#include -#include - -#define TASK_MAGIC 0xDEADBEEF - -uint32_t next_pid = 0; - -#define PUSH(stack, type, item) stack -= sizeof(type); \ - *((type *) stack) = item - -page_directory_t *kernel_directory; -page_directory_t *current_directory; - -/* - * Clone a page directory and its contents. - * (If you do not intend to clone the contents, do it yourself!) - * - * @param src Pointer to source directory to clone from. - * @return A pointer to a new directory. - */ -page_directory_t * -clone_directory( - page_directory_t * src - ) { - /* Allocate a new page directory */ - uintptr_t phys; - page_directory_t * dir = (page_directory_t *)kvmalloc_p(sizeof(page_directory_t), &phys); - /* Clear it out */ - memset(dir, 0, sizeof(page_directory_t)); - dir->ref_count = 1; - - /* And store it... */ - dir->physical_address = phys; - uint32_t i; - for (i = 0; i < 1024; ++i) { - /* Copy each table */ - if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { - continue; - } - if (kernel_directory->tables[i] == src->tables[i]) { - /* Kernel tables are simply linked together */ - dir->tables[i] = src->tables[i]; - dir->physical_tables[i] = src->physical_tables[i]; - } else { - if (i * 0x1000 * 1024 < SHM_START) { - /* User tables must be cloned */ - uintptr_t phys; - dir->tables[i] = clone_table(src->tables[i], &phys); - dir->physical_tables[i] = phys | 0x07; - } - } - } - return dir; -} - -/* - * Free a directory and its tables - */ -void release_directory(page_directory_t * dir) { - dir->ref_count--; - - if (dir->ref_count < 1) { - uint32_t i; - for (i = 0; i < 1024; ++i) { - if (!dir->tables[i] || (uintptr_t)dir->tables[i] == (uintptr_t)0xFFFFFFFF) { - continue; - } - if (kernel_directory->tables[i] != dir->tables[i]) { - if (i * 0x1000 * 1024 < SHM_START) { - for (uint32_t j = 0; j < 1024; ++j) { - if (dir->tables[i]->pages[j].frame) { - free_frame(&(dir->tables[i]->pages[j])); - } - } - } - free(dir->tables[i]); - } - } - free(dir); - } -} - -void release_directory_for_exec(page_directory_t * dir) { - uint32_t i; - /* This better be the only owner of this directory... */ - for (i = 0; i < 1024; ++i) { - if (!dir->tables[i] || (uintptr_t)dir->tables[i] == (uintptr_t)0xFFFFFFFF) { - continue; - } - if (kernel_directory->tables[i] != dir->tables[i]) { - if (i * 0x1000 * 1024 < USER_STACK_BOTTOM) { - for (uint32_t j = 0; j < 1024; ++j) { - if (dir->tables[i]->pages[j].frame) { - free_frame(&(dir->tables[i]->pages[j])); - } - } - dir->physical_tables[i] = 0; - free(dir->tables[i]); - dir->tables[i] = 0; - } - } - } -} - -extern char * default_name; - -/* - * Clone a page table - * - * @param src Pointer to a page table to clone. - * @param physAddr [out] Pointer to the physical address of the new page table - * @return A pointer to a new page table. - */ -page_table_t * -clone_table( - page_table_t * src, - uintptr_t * physAddr - ) { - /* Allocate a new page table */ - page_table_t * table = (page_table_t *)kvmalloc_p(sizeof(page_table_t), physAddr); - memset(table, 0, sizeof(page_table_t)); - uint32_t i; - for (i = 0; i < 1024; ++i) { - /* For each frame in the table... */ - if (!src->pages[i].frame) { - continue; - } - /* Allocate a new frame */ - alloc_frame(&table->pages[i], 0, 0); - /* Set the correct access bit */ - if (src->pages[i].present) table->pages[i].present = 1; - if (src->pages[i].rw) table->pages[i].rw = 1; - if (src->pages[i].user) table->pages[i].user = 1; - if (src->pages[i].writethrough) table->pages[i].writethrough = 1; - if (src->pages[i].cachedisable) table->pages[i].cachedisable = 1; - /* Copy the contents of the page from the old table to the new one */ - copy_page_physical(src->pages[i].frame * 0x1000, table->pages[i].frame * 0x1000); - } - return table; -} - -uintptr_t frozen_stack = 0; - -/* - * Install multitasking functionality. - */ -void tasking_install(void) { - IRQ_OFF; /* Disable interrupts */ - - debug_print(NOTICE, "Initializing multitasking"); - - /* Initialize the process tree */ - initialize_process_tree(); - /* Spawn the initial process */ - current_process = spawn_init(); - kernel_idle_task = spawn_kidle(); - /* Initialize the paging environment */ -#if 0 - set_process_environment((process_t *)current_process, current_directory); -#endif - /* Switch to the kernel directory */ - switch_page_directory(current_process->thread.page_directory); - - frozen_stack = (uintptr_t)valloc(KERNEL_STACK_SIZE); - - /* Reenable interrupts */ - IRQ_RES; -} - -/* - * Fork. - * - * @return To the parent: PID of the child; to the child: 0 - */ -uint32_t fork(void) { - IRQ_OFF; - - uintptr_t esp, ebp; - - current_process->syscall_registers->eax = 0; - - /* Make a pointer to the parent process (us) on the stack */ - process_t * parent = (process_t *)current_process; - assert(parent && "Forked from nothing??"); - /* Clone the current process' page directory */ - page_directory_t * directory = clone_directory(current_directory); - assert(directory && "Could not allocate a new page directory!"); - /* Spawn a new process from this one */ - debug_print(INFO,"\033[1;32mALLOC {\033[0m"); - process_t * new_proc = spawn_process(current_process, 0); - debug_print(INFO,"\033[1;32m}\033[0m"); - assert(new_proc && "Could not allocate a new process!"); - /* Set the new process' page directory to clone */ - set_process_environment(new_proc, directory); - - struct regs r; - memcpy(&r, current_process->syscall_registers, sizeof(struct regs)); - new_proc->syscall_registers = &r; - - esp = new_proc->image.stack; - ebp = esp; - - new_proc->syscall_registers->eax = 0; - - PUSH(esp, struct regs, r); - - new_proc->thread.esp = esp; - new_proc->thread.ebp = ebp; - new_proc->thread.gsbase = current_process->thread.gsbase; - - new_proc->is_tasklet = parent->is_tasklet; - - new_proc->thread.eip = (uintptr_t)&return_to_userspace; - - /* Add the new process to the ready queue */ - make_process_ready(new_proc); - - IRQ_RES; - - /* Return the child PID */ - return new_proc->id; -} - -int create_kernel_tasklet(tasklet_t tasklet, char * name, void * argp) { - IRQ_OFF; - - uintptr_t esp, ebp; - - if (current_process->syscall_registers) { - current_process->syscall_registers->eax = 0; - } - - page_directory_t * directory = kernel_directory; - /* Spawn a new process from this one */ - process_t * new_proc = spawn_process(current_process, 0); - assert(new_proc && "Could not allocate a new process!"); - /* Set the new process' page directory to the original process' */ - set_process_environment(new_proc, directory); - directory->ref_count++; - /* Read the instruction pointer */ - - - if (current_process->syscall_registers) { - struct regs r; - memcpy(&r, current_process->syscall_registers, sizeof(struct regs)); - new_proc->syscall_registers = &r; - } - - esp = new_proc->image.stack; - ebp = esp; - - if (current_process->syscall_registers) { - new_proc->syscall_registers->eax = 0; - } - new_proc->is_tasklet = 1; - new_proc->name = name; - - PUSH(esp, uintptr_t, (uintptr_t)name); - PUSH(esp, uintptr_t, (uintptr_t)argp); - PUSH(esp, uintptr_t, (uintptr_t)&task_exit); - - new_proc->thread.esp = esp; - new_proc->thread.ebp = ebp; - new_proc->thread.gsbase = current_process->thread.gsbase; - - new_proc->thread.eip = (uintptr_t)tasklet; - - /* Add the new process to the ready queue */ - make_process_ready(new_proc); - - IRQ_RES; - - /* Return the child PID */ - return new_proc->id; -} - - -/* - * clone the current thread and create a new one in the same - * memory space with the given pointer as its new stack. - */ -uint32_t -clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { - uintptr_t esp, ebp; - - IRQ_OFF; - - current_process->syscall_registers->eax = 0; - - /* Make a pointer to the parent process (us) on the stack */ - process_t * parent = (process_t *)current_process; - assert(parent && "Cloned from nothing??"); - page_directory_t * directory = current_directory; - /* Spawn a new process from this one */ - process_t * new_proc = spawn_process(current_process, 1); - assert(new_proc && "Could not allocate a new process!"); - /* Set the new process' page directory to the original process' */ - set_process_environment(new_proc, directory); - directory->ref_count++; - /* Read the instruction pointer */ - - struct regs r; - memcpy(&r, current_process->syscall_registers, sizeof(struct regs)); - new_proc->syscall_registers = &r; - - esp = new_proc->image.stack; - ebp = esp; - - /* Set the gid */ - if (current_process->group) { - new_proc->group = current_process->group; - } else { - /* We are the session leader */ - new_proc->group = current_process->id; - } - - new_proc->syscall_registers->ebp = new_stack; - new_proc->syscall_registers->eip = thread_func; - - /* Push arg, bogus return address onto the new thread's stack */ - PUSH(new_stack, uintptr_t, arg); - PUSH(new_stack, uintptr_t, THREAD_RETURN); - - /* Set esp, ebp, and eip for the new thread */ - new_proc->syscall_registers->esp = new_stack; - new_proc->syscall_registers->useresp = new_stack; - - PUSH(esp, struct regs, r); - - new_proc->thread.esp = esp; - new_proc->thread.ebp = ebp; - new_proc->thread.gsbase = current_process->thread.gsbase; - - new_proc->is_tasklet = parent->is_tasklet; - - new_proc->thread.eip = (uintptr_t)&return_to_userspace; - - /* Add the new process to the ready queue */ - make_process_ready(new_proc); - - IRQ_RES; - - /* Return the child PID */ - return new_proc->id; -} - -/* - * Get the process ID of the current process. - * - * @return The PID of the current process. - */ -uint32_t getpid(void) { - /* Fairly self-explanatory. */ - return current_process->id; -} - -/* - * Switch to the next ready task. - * - * This is called from the interrupt handler for the interval timer to - * perform standard task switching. - */ -void switch_task(uint8_t reschedule) { - if (!current_process) { - /* Tasking is not yet installed. */ - return; - } - if (!current_process->running) { - switch_next(); - } - - /* Collect the current kernel stack and instruction pointers */ - uintptr_t esp, ebp, eip; - asm volatile ("mov %%esp, %0" : "=r" (esp)); - asm volatile ("mov %%ebp, %0" : "=r" (ebp)); - eip = read_eip(); - if (eip == 0x10000) { - /* Returned from EIP after task switch, we have - * finished switching. */ - fix_signal_stacks(); - - /* XXX: Signals */ - if (!current_process->finished) { - if (current_process->signal_queue->length > 0) { - node_t * node = list_dequeue(current_process->signal_queue); - signal_t * sig = node->value; - free(node); - handle_signal((process_t *)current_process, sig); - } - } - - return; - } - - /* Remember this process' ESP/EBP/EIP */ - current_process->thread.eip = eip; - current_process->thread.esp = esp; - current_process->thread.ebp = ebp; - current_process->thread.gsbase = gdt_get_gsbase(); - current_process->running = 0; - - /* Save floating point state */ - switch_fpu(); - - if (reschedule && current_process != kernel_idle_task) { - /* And reinsert it into the ready queue */ - make_process_ready((process_t *)current_process); - } - - /* Switch to the next task */ - switch_next(); -} - -/* - * Immediately switch to the next task. - * - * Does not store the ESP/EBP/EIP of the current thread. - */ -void switch_next(void) { - uintptr_t esp, ebp, eip; - /* Get the next available process */ - current_process = next_ready_process(); - /* Retreive the ESP/EBP/EIP */ - eip = current_process->thread.eip; - esp = current_process->thread.esp; - ebp = current_process->thread.ebp; - gdt_set_gsbase(current_process->thread.gsbase); - unswitch_fpu(); - - /* Validate */ - if ((eip < (uintptr_t)&code) || (eip > (uintptr_t)heap_end)) { - debug_print(WARNING, "Skipping broken process %d! [eip=0x%x <0x%x or >0x%x]", current_process->id, eip, &code, &end); - switch_next(); - } - - if (current_process->finished) { - debug_print(WARNING, "Tried to switch to process %d, but it claims it is finished.", current_process->id); - switch_next(); - } - - /* Set the page directory */ - current_directory = current_process->thread.page_directory; - switch_page_directory(current_directory); - /* Set the kernel stack in the TSS */ - set_kernel_stack(current_process->image.stack); - - if (current_process->started) { - if (!current_process->signal_kstack) { - if (current_process->signal_queue->length > 0) { - current_process->signal_kstack = malloc(KERNEL_STACK_SIZE); - current_process->signal_state.esp = current_process->thread.esp; - current_process->signal_state.eip = current_process->thread.eip; - current_process->signal_state.ebp = current_process->thread.ebp; - memcpy(current_process->signal_kstack, (void *)(current_process->image.stack - KERNEL_STACK_SIZE), KERNEL_STACK_SIZE); - } - } - } else { - current_process->started = 1; - } - - current_process->running = 1; - - /* Jump, baby, jump */ - asm volatile ( - "mov %0, %%ebx\n" - "mov %1, %%esp\n" - "mov %2, %%ebp\n" - "mov %3, %%cr3\n" - "mov $0x10000, %%eax\n" /* read_eip() will return 0x10000 */ - "jmp *%%ebx" - : : "r" (eip), "r" (esp), "r" (ebp), "r" (current_directory->physical_address) - : "%ebx", "%esp", "%eax"); -} - -extern void enter_userspace(uintptr_t location, uintptr_t stack); - -/* - * Enter ring 3 and jump to `location`. - * - * @param location Address to jump to in user space - * @param argc Argument count - * @param argv Argument pointers - * @param stack Userspace stack address - */ -void -enter_user_jmp(uintptr_t location, int argc, char ** argv, uintptr_t stack) { - IRQ_OFF; - set_kernel_stack(current_process->image.stack); - - PUSH(stack, uintptr_t, (uintptr_t)argv); - PUSH(stack, int, argc); - enter_userspace(location, stack); -} - -/* - * Dequeue the current task and set it as finished - * - * @param retval Set the return value to this. - */ -void task_exit(int retval) { - /* Free the image memory */ - if (__builtin_expect(current_process->id == 0,0)) { - /* This is probably bad... */ - switch_next(); - return; - } - cleanup_process((process_t *)current_process, retval); - - process_t * parent = process_get_parent((process_t *)current_process); - - if (parent && !parent->finished) { - send_signal(parent->group, SIGCHLD, 1); - wakeup_queue(parent->wait_queue); - } - - switch_next(); -} - -/* - * Call task_exit() and immediately STOP if we can't. - */ -void kexit(int retval) { - task_exit(retval); - debug_print(CRITICAL, "Process returned from task_exit! Environment is definitely unclean. Stopping."); - STOP; -} diff --git a/kernel/sys/version.c b/kernel/sys/version.c index 85caa414..dc3c9734 100644 --- a/kernel/sys/version.c +++ b/kernel/sys/version.c @@ -1,23 +1,30 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/sys/version.c + * @brief Kernel version macros. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange + * Copyright (C) 2011-2021 K. Lange */ #include +#define STR(x) #x +#define STRSTR(x) STR(x) + /* Kernel name. If you change this, you're not * my friend any more. */ -char * __kernel_name = "toaru"; +const char * __kernel_name = "toaru"; /* This really shouldn't change, and if it does, * always ensure it still has the correct arguments * when used as a vsprintf() format. */ -char * __kernel_version_format = "%d.%d.%d-%s"; +const char * __kernel_version_format = "%d.%d.%d-%s"; /* Version numbers X.Y.Z */ int __kernel_version_major = 1; -int __kernel_version_minor = 14; +int __kernel_version_minor = 99; int __kernel_version_lower = 0; /* Kernel build suffix, which doesn't necessarily @@ -25,25 +32,21 @@ int __kernel_version_lower = 0; * between different features included while * building multiple kernels. */ #ifdef KERNEL_GIT_TAG -# define STR(x) #x -# define STRSTR(x) STR(x) # define KERNEL_VERSION_SUFFIX STRSTR(KERNEL_GIT_TAG) #else # define KERNEL_VERSION_SUFFIX "r" #endif -char * __kernel_version_suffix = KERNEL_VERSION_SUFFIX; +const char * __kernel_version_suffix = KERNEL_VERSION_SUFFIX; /* The release codename. */ -char * __kernel_version_codename = "core"; +const char * __kernel_version_codename = "misaka"; -/* Build architecture (should probably not be - * here as a string, but rather some sort of - * preprocessor macro, or pulled from a script) */ -char * __kernel_arch = "i686"; +/* Build architecture */ +const char * __kernel_arch = STRSTR(KERNEL_ARCH); /* Rebuild from clean to reset these. */ -char * __kernel_build_date = __DATE__; -char * __kernel_build_time = __TIME__; +const char * __kernel_build_date = __DATE__; +const char * __kernel_build_time = __TIME__; #if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER)) # define COMPILER_VERSION "gcc " __VERSION__ @@ -53,4 +56,4 @@ char * __kernel_build_time = __TIME__; # define COMPILER_VERSION "unknown-compiler how-did-you-do-that" #endif -char * __kernel_compiler_version = COMPILER_VERSION; +const char * __kernel_compiler_version = COMPILER_VERSION; diff --git a/kernel/task.S b/kernel/task.S deleted file mode 100644 index 1b64fd01..00000000 --- a/kernel/task.S +++ /dev/null @@ -1,64 +0,0 @@ -.section .text -.align 4 - -/* Disable paging mask */ -.set dp, 0x7FFFFFFF -/* Enable paging mask */ -.set ep, 0x80000000 - -.global copy_page_physical -.type copy_page_physical, @function - -copy_page_physical: - /* Preserve contents of EBX */ - push %ebx - - /* Preserve contents of EFLAGS */ - pushf - cli - - /* Load source and destination addresses */ - mov 12(%esp), %ebx - mov 16(%esp), %ecx - - /* Get control register and disable paging*/ - mov %cr0, %edx - and $dp, %edx - mov %edx, %cr0 - - /* Copy 4096 bytes */ - mov $0x400, %edx -.page_loop: - /* Get word at source address */ - mov (%ebx), %eax - - /* Store it at destination address */ - mov %eax, (%ecx) - - /* Increment source and destination addresses to next word */ - add $4, %ebx - add $4, %ecx - - /* One less word to copy */ - dec %edx - jnz .page_loop - - /* Get control register again and enable paging */ - mov %cr0, %edx - or $ep, %edx - mov %edx, %cr0 - - /* Restore EFLAGS */ - popf - - /* Restore EBX */ - pop %ebx - ret - -/* Read EIP */ -.global read_eip -.type read_eip, @function - -read_eip: - mov (%esp), %eax - ret diff --git a/kernel/tss.S b/kernel/tss.S deleted file mode 100644 index 0812faaf..00000000 --- a/kernel/tss.S +++ /dev/null @@ -1,10 +0,0 @@ -.section .text -.align 4 - -.global tss_flush -.type tss_flush, @function - -tss_flush: - mov $0x2B, %ax - ltr %ax - ret diff --git a/kernel/user.S b/kernel/user.S deleted file mode 100644 index 52f3e5c3..00000000 --- a/kernel/user.S +++ /dev/null @@ -1,63 +0,0 @@ -/* Return to Userspace (from thread creation) */ - -.global return_to_userspace -.type return_to_userspace, @function - -return_to_userspace: - pop %gs - pop %fs - pop %es - pop %ds - popa - add $8, %esp - iret - -/* Enter userspace (ring3) */ -.global enter_userspace -.type enter_userspace, @function - -.set MAGIC, 0xDECADE21 - -enter_userspace: - pushl %ebp - mov %esp, %ebp - mov 0xC(%ebp), %edx - mov %edx, %esp - pushl $MAGIC - - /* Segement selector */ - mov $0x23,%ax - - /* Save segement registers */ - mov %eax, %ds - mov %eax, %es - mov %eax, %fs - - mov $0x33, %ax - mov %eax, %gs - /* %ss is handled by iret */ - - /* Store stack address in %eax */ - mov %esp, %eax - - /* Data segmenet with bottom 2 bits set for ring3 */ - pushl $0x23 - - /* Push the stack address */ - pushl %eax - - /* Push flags and fix interrupt flag */ - pushf - popl %eax - - /* Request ring3 */ - orl $0x200, %eax - pushl %eax - pushl $0x1B - - /* Push entry point */ - pushl 0x8(%ebp) - - iret - popl %ebp - ret diff --git a/modules/packetfs.c b/kernel/vfs/packetfs.c similarity index 78% rename from modules/packetfs.c rename to kernel/vfs/packetfs.c index 88902a15..a8470463 100644 --- a/modules/packetfs.c +++ b/kernel/vfs/packetfs.c @@ -1,17 +1,39 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/packetfs.c + * @brief Packet-based multiple-client IPC mechanism. aka PEX + * + * Provides a server-client packet-based IPC socket system for + * userspace applications. Primarily used by the compositor to + * communicate with clients. + * + * Care must be taken to ensure that this is backed by an atomic + * stream; the legacy pseudo-pipe interface is used at the moment. + * + * @bug We leak kernel heap addresses directly to userspace as the + * client identifiers in PEX messages. We should probably do + * something else. I'm also reasonably certain a server can + * just throw a random address at the PEX API? + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange + * Copyright (C) 2014-2021 K. Lange */ -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include +#include #include #define MAX_PACKET_SIZE 1024 +#define debug_print(x, ...) do { if (0) {printf("packetfs.c [%s] ", #x); printf(__VA_ARGS__); printf("\n"); } } while (0) typedef struct packet_manager { /* uh, nothing, lol */ @@ -58,6 +80,9 @@ static void receive_packet(fs_node_t * socket, packet_t ** out) { static void send_to_server(pex_ex_t * p, pex_client_t * c, size_t size, void * data) { size_t p_size = size + sizeof(struct packet); packet_t * packet = malloc(p_size); + if ((uintptr_t)c < 0x800000000) { + printf("suspicious pex client received: %p\n", (void*)c); + } packet->source = c; packet->size = size; @@ -79,6 +104,10 @@ static int send_to_client(pex_ex_t * p, pex_client_t * c, size_t size, void * da return -1; } + if ((uintptr_t)c < 0x800000000) { + printf("suspicious pex client received: %p\n", (void*)c); + } + packet_t * packet = malloc(p_size); memcpy(packet->data, data, size); @@ -98,7 +127,7 @@ static pex_client_t * create_client(pex_ex_t * p) { return out; } -static uint32_t read_server(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { +static uint64_t read_server(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t * buffer) { pex_ex_t * p = (pex_ex_t *)node->device; debug_print(INFO, "[pex] server read(...)"); @@ -106,20 +135,20 @@ static uint32_t read_server(fs_node_t * node, uint64_t offset, uint32_t size, ui receive_packet(p->server_pipe, &packet); - debug_print(INFO, "Server recevied packet of size %d, was waiting for at most %d", packet->size, size); + debug_print(INFO, "Server recevied packet of size %zu, was waiting for at most %lu", packet->size, size); if (packet->size + sizeof(packet_t) > size) { return -1; } memcpy(buffer, packet, packet->size + sizeof(packet_t)); - uint32_t out = packet->size + sizeof(packet_t); + uint64_t out = packet->size + sizeof(packet_t); free(packet); return out; } -static uint32_t write_server(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { +static uint64_t write_server(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t * buffer) { pex_ex_t * p = (pex_ex_t *)node->device; debug_print(INFO, "[pex] server write(...)"); @@ -133,18 +162,18 @@ static uint32_t write_server(fs_node_t * node, uint64_t offset, uint32_t size, u /* Brodcast packet */ spin_lock(p->lock); foreach(f, p->clients) { - debug_print(INFO, "Sending to client 0x%x", f->value); + debug_print(INFO, "Sending to client %p", f->value); send_to_client(p, (pex_client_t *)f->value, size - sizeof(header_t), head->data); } spin_unlock(p->lock); debug_print(INFO, "Done broadcasting to clients."); return size; } else if (head->target->parent != p) { - debug_print(WARNING, "[pex] Invalid packet from server? (pid=%d)", current_process->id); + debug_print(WARNING, "[pex] Invalid packet from server? (pid=%d)", this_core->current_process->id); return -1; } - return send_to_client(p, head->target, size - sizeof(header_t), head->data); + return send_to_client(p, head->target, size - sizeof(header_t), head->data) + sizeof(header_t); } static int ioctl_server(fs_node_t * node, int request, void * argp) { @@ -158,7 +187,7 @@ static int ioctl_server(fs_node_t * node, int request, void * argp) { } } -static uint32_t read_client(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { +static uint64_t read_client(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t * buffer) { pex_client_t * c = (pex_client_t *)node->inode; if (c->parent != node->device) { debug_print(WARNING, "[pex] Invalid device endpoint on client read?"); @@ -172,20 +201,20 @@ static uint32_t read_client(fs_node_t * node, uint64_t offset, uint32_t size, ui receive_packet(c->pipe, &packet); if (packet->size > size) { - debug_print(WARNING, "[pex] Client is not reading enough bytes to hold packet of size %d", packet->size); + debug_print(WARNING, "[pex] Client is not reading enough bytes to hold packet of size %zu", packet->size); return -1; } memcpy(buffer, &packet->data, packet->size); uint32_t out = packet->size; - debug_print(INFO, "[pex] Client received packet of size %d", packet->size); + debug_print(INFO, "[pex] Client received packet of size %zu", packet->size); free(packet); return out; } -static uint32_t write_client(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { +static uint64_t write_client(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t * buffer) { pex_client_t * c = (pex_client_t *)node->inode; if (c->parent != node->device) { debug_print(WARNING, "[pex] Invalid device endpoint on client write?"); @@ -195,11 +224,11 @@ static uint32_t write_client(fs_node_t * node, uint64_t offset, uint32_t size, u debug_print(INFO, "[pex] client write(...)"); if (size > MAX_PACKET_SIZE) { - debug_print(WARNING, "Size of %d is too big.", size); + debug_print(WARNING, "Size of %lu is too big.", size); return -1; } - debug_print(INFO, "Sending packet of size %d to parent", size); + debug_print(INFO, "Sending packet of size %lu to parent", size); send_to_server(c->parent, c, size, buffer); return size; @@ -220,7 +249,7 @@ static void close_client(fs_node_t * node) { pex_client_t * c = (pex_client_t *)node->inode; pex_ex_t * p = c->parent; - debug_print(WARNING, "Closing packetfs client: 0x%x:0x%x", p, c); + debug_print(WARNING, "Closing packetfs client: %p:%p", (void*)p, (void*)c); spin_lock(p->lock); @@ -272,7 +301,7 @@ static void open_pex(fs_node_t * node, unsigned int flags) { node->selectcheck = check_server; node->selectwait = wait_server; debug_print(INFO, "[pex] Server launched: %s", t->name); - debug_print(INFO, "fs_node = 0x%x", node); + debug_print(INFO, "fs_node = %p", (void*)node); } else if (!(flags & O_CREAT)) { pex_client_t * client = create_client(t); node->inode = (uintptr_t)client; @@ -288,7 +317,7 @@ static void open_pex(fs_node_t * node, unsigned int flags) { list_insert(t->clients, client); /* XXX: Send plumbing message to server for new client connection */ - debug_print(INFO, "[pex] Client connected: %s:0%x", t->name, node->inode); + debug_print(INFO, "[pex] Client connected: %s:%lx", t->name, node->inode); } else if (flags & O_CREAT && !t->fresh) { /* XXX: You dun goofed */ } @@ -296,11 +325,11 @@ static void open_pex(fs_node_t * node, unsigned int flags) { return; } -static struct dirent * readdir_packetfs(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_packetfs(fs_node_t *node, uint64_t index) { pex_t * p = (pex_t *)node->device; unsigned int i = 0; - debug_print(INFO, "[pex] readdir(%d)", index); + debug_print(INFO, "[pex] readdir(%lu)", index); if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); @@ -332,7 +361,7 @@ static struct dirent * readdir_packetfs(fs_node_t *node, uint32_t index) { pex_ex_t * t = (pex_ex_t *)f->value; struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); - out->ino = (uint32_t)t; + out->ino = (uint64_t)t; strcpy(out->name, t->name); return out; } else { @@ -403,7 +432,7 @@ static int create_packetfs(fs_node_t *parent, char *name, uint16_t permission) { new_exchange->name = strdup(name); new_exchange->fresh = 1; - new_exchange->clients = list_create(); + new_exchange->clients = list_create("pex clients",new_exchange); new_exchange->server_pipe = make_pipe(4096); spin_init(new_exchange->lock); @@ -455,7 +484,7 @@ static int unlink_packetfs(fs_node_t *parent, char *name) { static fs_node_t * packetfs_manager(void) { pex_t * pex = malloc(sizeof(pex_t)); - pex->exchanges = list_create(); + pex->exchanges = list_create("pex exchanges",pex); spin_init(pex->lock); @@ -474,14 +503,7 @@ static fs_node_t * packetfs_manager(void) { return fnode; } -static int init(void) { +void packetfs_initialize(void) { fs_node_t * packet_mgr = packetfs_manager(); vfs_mount("/dev/pex", packet_mgr); - return 0; } - -static int fini(void) { - return 0; -} - -MODULE_DEF(packetfs, init, fini); diff --git a/kernel/fs/pipe.c b/kernel/vfs/pipe.c similarity index 61% rename from kernel/fs/pipe.c rename to kernel/vfs/pipe.c index efb07f60..9fee9cbe 100644 --- a/kernel/fs/pipe.c +++ b/kernel/vfs/pipe.c @@ -1,17 +1,34 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/pipe.c + * @brief Legacy buffered pipe, used for char devices. + * + * This is the legacy pipe implementation. If you are looking for + * the userspace pipes, @ref read_unixpipe. + * + * This implements a simple one-direction buffer suitable for use + * by, eg., device drivers that want to offer a character-driven + * interface to userspace without having to worry too much about + * timing or getting blocked. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2012-2018 K. Lange - * - * Buffered Pipe - * + * Copyright (C) 2012-2021 K. Lange */ -#include -#include +#include +#include +#include #include +#include #include -#include +#include +#include +#include +#include +#include + +#include #define DEBUG_PIPES 0 @@ -28,7 +45,10 @@ static inline size_t pipe_unread(pipe_device_t * pipe) { int pipe_size(fs_node_t * node) { pipe_device_t * pipe = (pipe_device_t *)node->device; - return pipe_unread(pipe); + spin_lock(pipe->ptr_lock); + int out = pipe_unread(pipe); + spin_unlock(pipe->ptr_lock); + return out; } static inline size_t pipe_available(pipe_device_t * pipe) { @@ -45,21 +65,28 @@ static inline size_t pipe_available(pipe_device_t * pipe) { int pipe_unsize(fs_node_t * node) { pipe_device_t * pipe = (pipe_device_t *)node->device; - return pipe_available(pipe); + spin_lock(pipe->ptr_lock); + int out = pipe_available(pipe); + spin_unlock(pipe->ptr_lock); + return out; } static inline void pipe_increment_read(pipe_device_t * pipe) { + spin_lock(pipe->ptr_lock); pipe->read_ptr++; if (pipe->read_ptr == pipe->size) { pipe->read_ptr = 0; } + spin_unlock(pipe->ptr_lock); } static inline void pipe_increment_write(pipe_device_t * pipe) { + spin_lock(pipe->ptr_lock); pipe->write_ptr++; if (pipe->write_ptr == pipe->size) { pipe->write_ptr = 0; } + spin_unlock(pipe->ptr_lock); } static inline void pipe_increment_write_by(pipe_device_t * pipe, size_t amount) { @@ -67,37 +94,26 @@ static inline void pipe_increment_write_by(pipe_device_t * pipe, size_t amount) } static void pipe_alert_waiters(pipe_device_t * pipe) { - if (pipe->alert_waiters) { - while (pipe->alert_waiters->head) { - node_t * node = list_dequeue(pipe->alert_waiters); - process_t * p = node->value; - process_alert_node(p, pipe); - free(node); - } + spin_lock(pipe->alert_lock); + while (pipe->alert_waiters->head) { + node_t * node = list_dequeue(pipe->alert_waiters); + process_t * p = node->value; + free(node); + spin_unlock(pipe->alert_lock); + + process_alert_node(p, pipe); + + spin_lock(pipe->alert_lock); } + spin_unlock(pipe->alert_lock); } -uint32_t read_pipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - assert(node->device != 0 && "Attempted to read from a fully-closed pipe."); - +uint64_t read_pipe(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { /* Retreive the pipe object associated with this file node */ pipe_device_t * pipe = (pipe_device_t *)node->device; -#if DEBUG_PIPES - if (pipe->size > 300) { /* Ignore small pipes (ie, keyboard) */ - debug_print(INFO, "[debug] Call to read from pipe 0x%x", node->device); - debug_print(INFO, " Unread bytes: %d", pipe_unread(pipe)); - debug_print(INFO, " Total size: %d", pipe->size); - debug_print(INFO, " Request size: %d", size); - debug_print(INFO, " Write pointer: %d", pipe->write_ptr); - debug_print(INFO, " Read pointer: %d", pipe->read_ptr); - debug_print(INFO, " Buffer address: 0x%x", pipe->buffer); - } -#endif - if (pipe->dead) { - debug_print(WARNING, "Pipe is dead?"); - send_signal(getpid(), SIGPIPE, 1); + send_signal(this_core->current_process->id, SIGPIPE, 1); return 0; } @@ -120,56 +136,26 @@ uint32_t read_pipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buf return collected; } -uint32_t write_pipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - assert(node->device != 0 && "Attempted to write to a fully-closed pipe."); - +uint64_t write_pipe(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { /* Retreive the pipe object associated with this file node */ pipe_device_t * pipe = (pipe_device_t *)node->device; -#if DEBUG_PIPES - if (pipe->size > 300) { /* Ignore small pipes (ie, keyboard) */ - debug_print(INFO, "[debug] Call to write to pipe 0x%x", node->device); - debug_print(INFO, " Available space: %d", pipe_available(pipe)); - debug_print(INFO, " Total size: %d", pipe->size); - debug_print(INFO, " Request size: %d", size); - debug_print(INFO, " Write pointer: %d", pipe->write_ptr); - debug_print(INFO, " Read pointer: %d", pipe->read_ptr); - debug_print(INFO, " Buffer address: 0x%x", pipe->buffer); - debug_print(INFO, " Write: %s", buffer); - } -#endif - if (pipe->dead) { - debug_print(WARNING, "Pipe is dead?"); - send_signal(getpid(), SIGPIPE, 1); + send_signal(this_core->current_process->id, SIGPIPE, 1); return 0; } size_t written = 0; while (written < size) { spin_lock(pipe->lock_write); - -#if 0 - size_t available = 0; - if (pipe->read_ptr <= pipe->write_ptr) { - available = pipe->size - pipe->write_ptr; - } else { - available = pipe->read_ptr - pipe->write_ptr - 1; + /* These pipes enforce atomic writes, poorly. */ + if (pipe_available(pipe) > size) { + while (pipe_available(pipe) > 0 && written < size) { + pipe->buffer[pipe->write_ptr] = buffer[written]; + pipe_increment_write(pipe); + written++; + } } - if (available) { - available = min(available, size - written); - memcpy(&pipe->buffer[pipe->write_ptr], buffer, available); - pipe_increment_write_by(pipe, available); - written += available; - } -#else - while (pipe_available(pipe) > 0 && written < size) { - pipe->buffer[pipe->write_ptr] = buffer[written]; - pipe_increment_write(pipe); - written++; - } -#endif - spin_unlock(pipe->lock_write); wakeup_queue(pipe->wait_queue_readers); pipe_alert_waiters(pipe); @@ -182,8 +168,6 @@ uint32_t write_pipe(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *bu } void open_pipe(fs_node_t * node, unsigned int flags) { - assert(node->device != 0 && "Attempted to open a fully-closed pipe."); - /* Retreive the pipe object associated with this file node */ pipe_device_t * pipe = (pipe_device_t *)node->device; @@ -194,8 +178,6 @@ void open_pipe(fs_node_t * node, unsigned int flags) { } void close_pipe(fs_node_t * node) { - assert(node->device != 0 && "Attempted to close an already fully-closed pipe."); - /* Retreive the pipe object associated with this file node */ pipe_device_t * pipe = (pipe_device_t *)node->device; @@ -231,14 +213,15 @@ static int pipe_check(fs_node_t * node) { static int pipe_wait(fs_node_t * node, void * process) { pipe_device_t * pipe = (pipe_device_t *)node->device; - if (!pipe->alert_waiters) { - pipe->alert_waiters = list_create(); - } - + spin_lock(pipe->alert_lock); if (!list_find(pipe->alert_waiters, process)) { list_insert(pipe->alert_waiters, process); } + spin_unlock(pipe->alert_lock); + + spin_lock(pipe->wait_lock); list_insert(((process_t *)process)->node_waits, pipe); + spin_unlock(pipe->wait_lock); return 0; } @@ -251,7 +234,7 @@ fs_node_t * make_pipe(size_t size) { fnode->device = 0; fnode->name[0] = '\0'; - sprintf(fnode->name, "[pipe]"); + snprintf(fnode->name, 100, "[pipe]"); fnode->uid = 0; fnode->gid = 0; fnode->mask = 0666; @@ -283,9 +266,13 @@ fs_node_t * make_pipe(size_t size) { spin_init(pipe->lock_read); spin_init(pipe->lock_write); + spin_init(pipe->alert_lock); + spin_init(pipe->wait_lock); + spin_init(pipe->ptr_lock); - pipe->wait_queue_writers = list_create(); - pipe->wait_queue_readers = list_create(); + pipe->wait_queue_writers = list_create("pipe writers",pipe); + pipe->wait_queue_readers = list_create("pip readers",pipe); + pipe->alert_waiters = list_create("pipe alert waiters",pipe); return fnode; } diff --git a/modules/portio.c b/kernel/vfs/portio.c similarity index 70% rename from modules/portio.c rename to kernel/vfs/portio.c index 231b2e46..08393801 100644 --- a/modules/portio.c +++ b/kernel/vfs/portio.c @@ -1,17 +1,21 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/portio.c + * @brief File-based interface to x86 CPU port I/O. + * + * Provides a seek/read/write interface to x86 ports at /dev/port + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2018 K. Lange - * - * provides /dev/port - * + * Copyright (C) 2018-2021 K. Lange */ -#include -#include -#include +#include +#include +#include +#include -static uint32_t read_port(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t read_port(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { switch (size) { case 1: buffer[0] = inportb(offset); @@ -32,7 +36,7 @@ static uint32_t read_port(fs_node_t *node, uint64_t offset, uint32_t size, uint8 return size; } -static uint32_t write_port(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t write_port(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { switch (size) { case 1: outportb(offset, buffer[0]); @@ -72,13 +76,6 @@ static fs_node_t * port_device_create(void) { return fnode; } -static int port_initialize(void) { +void portio_initialize(void) { vfs_mount("/dev/port", port_device_create()); - return 0; } - -static int port_finalize(void) { - return 0; -} - -MODULE_DEF(portio, port_initialize, port_finalize); diff --git a/modules/procfs.c b/kernel/vfs/procfs.c similarity index 65% rename from modules/procfs.c rename to kernel/vfs/procfs.c index 8fe565ab..f41aa196 100644 --- a/modules/procfs.c +++ b/kernel/vfs/procfs.c @@ -1,23 +1,41 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/procfs.c + * @brief Extensible file-based information interface. + * + * Provides /proc and its contents, which allow userspace tools + * to query kernel status through directory and text file interfaces. + * + * The way this is implemented is a bit messy... every time a read + * request happens, we generate a text blob and then try to provide + * the part the reader actually asked for. This is susceptible to + * corruption if the layout of data changed between two read calls. + * We should probably be generating data on open and disposing of + * it on call... + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange + * Copyright (C) 2014-2021 K. Lange */ -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include #define PROCFS_STANDARD_ENTRIES (sizeof(std_entries) / sizeof(struct procfs_entry)) #define PROCFS_PROCDIR_ENTRIES (sizeof(procdir_entries) / sizeof(struct procfs_entry)) -static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) { +static fs_node_t * procfs_generic_create(const char * name, read_type_t read_func) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); fnode->inode = 0; @@ -38,7 +56,7 @@ static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) { return fnode; } -static uint32_t proc_cmdline_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t proc_cmdline_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; process_t * proc = process_from_pid(node->inode); @@ -48,7 +66,7 @@ static uint32_t proc_cmdline_func(fs_node_t *node, uint64_t offset, uint32_t siz } if (!proc->cmdline) { - sprintf(buf, "%s", proc->name); + snprintf(buf, 100, "%s", proc->name); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; @@ -81,54 +99,7 @@ static uint32_t proc_cmdline_func(fs_node_t *node, uint64_t offset, uint32_t siz return size; } -static size_t calculate_memory_usage(page_directory_t * src) { - size_t pages = 0; - for (uint32_t i = 0; i < 1024; ++i) { - if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { - continue; - } - if (kernel_directory->tables[i] == src->tables[i]) { - continue; - } - /* For each table */ - if (i * 0x1000 * 1024 < SHM_START) { - /* Ignore shared memory for now */ - for (int j = 0; j < 1024; ++j) { - /* For each frame in the table... */ - if (!src->tables[i]->pages[j].frame) { - continue; - } - pages++; - } - } - } - return pages; -} - -static size_t calculate_shm_resident(page_directory_t * src) { - size_t pages = 0; - for (uint32_t i = 0; i < 1024; ++i) { - if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { - continue; - } - if (kernel_directory->tables[i] == src->tables[i]) { - continue; - } - if (i * 0x1000 * 1024 < SHM_START) { - continue; - } - for (int j = 0; j < 1024; ++j) { - /* For each frame in the table... */ - if (!src->tables[i]->pages[j].frame) { - continue; - } - pages++; - } - } - return pages; -} - -static uint32_t proc_status_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t proc_status_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[2048]; process_t * proc = process_from_pid(node->inode); process_t * parent = process_get_parent(proc); @@ -138,8 +109,8 @@ static uint32_t proc_status_func(fs_node_t *node, uint64_t offset, uint32_t size return 0; } - char state = proc->finished ? 'Z' : - (proc->suspended ? 'T' : + char state = (proc->flags & PROC_FLAG_FINISHED) ? 'Z' : + ((proc->flags & PROC_FLAG_SUSPENDED) ? 'T' : (process_is_ready(proc) ? 'R' : 'S')); char * name = proc->name + strlen(proc->name) - 1; @@ -153,31 +124,32 @@ static uint32_t proc_status_func(fs_node_t *node, uint64_t offset, uint32_t size } /* Calculate process memory usage */ - int mem_usage = calculate_memory_usage(proc->thread.page_directory) * 4; - int shm_usage = calculate_shm_resident(proc->thread.page_directory) * 4; - int mem_permille = 1000 * (mem_usage + shm_usage) / memory_total(); + long mem_usage = mmu_count_user(proc->thread.page_directory->directory) * 4; + long shm_usage = mmu_count_shm(proc->thread.page_directory->directory) * 4; + long mem_permille = 1000 * (mem_usage + shm_usage) / mmu_total_memory(); - sprintf(buf, - "Name:\t%s\n" /* name */ - "State:\t%c\n" /* yeah, do this at some point */ - "Tgid:\t%d\n" /* group ? group : pid */ - "Pid:\t%d\n" /* pid */ - "PPid:\t%d\n" /* parent pid */ - "Pgid:\t%d\n" /* progress group id */ - "Sid:\t%d\n" /* session id */ + snprintf(buf, 2000, + "Name:\t%s\n" /* name */ + "State:\t%c\n" + "Tgid:\t%d\n" /* group ? group : pid */ + "Pid:\t%d\n" /* pid */ + "PPid:\t%d\n" /* parent pid */ + "Pgid:\t%d\n" /* progress group id (job) */ + "Sid:\t%d\n" /* session id */ "Uid:\t%d\n" - "Ueip:\t0x%x\n" - "SCid:\t%d\n" - "SC0:\t0x%x\n" - "SC1:\t0x%x\n" - "SC2:\t0x%x\n" - "SC3:\t0x%x\n" - "SC4:\t0x%x\n" - "UserStack:\t0x%x\n" + "Ueip:\t%#zx\n" + "SCid:\t%zu\n" + "SC0:\t%#zx\n" + "SC1:\t%#zx\n" + "SC2:\t%#zx\n" + "SC3:\t%#zx\n" + "SC4:\t%#zx\n" + "UserStack:\t%#zx\n" "Path:\t%s\n" - "VmSize:\t %d kB\n" - "RssShmem:\t %d kB\n" - "MemPermille:\t %d\n" + "VmSize:\t %ld kB\n" + "RssShmem:\t %ld kB\n" + "MemPermille:\t %ld\n" + "LastCore:\t %d\n" , name, state, @@ -187,16 +159,17 @@ static uint32_t proc_status_func(fs_node_t *node, uint64_t offset, uint32_t size proc->job, proc->session, proc->user, - proc->syscall_registers ? proc->syscall_registers->eip : 0, - proc->syscall_registers ? proc->syscall_registers->eax : 0, - proc->syscall_registers ? proc->syscall_registers->ebx : 0, - proc->syscall_registers ? proc->syscall_registers->ecx : 0, - proc->syscall_registers ? proc->syscall_registers->edx : 0, - proc->syscall_registers ? proc->syscall_registers->esi : 0, - proc->syscall_registers ? proc->syscall_registers->edi : 0, - proc->syscall_registers ? proc->syscall_registers->useresp : 0, + proc->syscall_registers ? arch_user_ip(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_syscall_number(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_syscall_arg0(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_syscall_arg1(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_syscall_arg2(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_syscall_arg3(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_syscall_arg4(proc->syscall_registers) : 0, + proc->syscall_registers ? arch_stack_pointer(proc->syscall_registers) : 0, proc->cmdline ? proc->cmdline[0] : "(none)", - mem_usage, shm_usage, mem_permille + mem_usage, shm_usage, mem_permille, + proc->owner ); size_t _bsize = strlen(buf); @@ -212,7 +185,7 @@ static struct procfs_entry procdir_entries[] = { {2, "status", proc_status_func}, }; -static struct dirent * readdir_procfs_procdir(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_procfs_procdir(fs_node_t *node, uint64_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); @@ -261,7 +234,7 @@ static fs_node_t * procfs_procdir_create(process_t * process) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); fnode->inode = pid; - sprintf(fnode->name, "%d", pid); + snprintf(fnode->name, 100, "%d", pid); fnode->uid = 0; fnode->gid = 0; fnode->mask = 0555; @@ -279,36 +252,32 @@ static fs_node_t * procfs_procdir_create(process_t * process) { return fnode; } -#define cpuid(in,a,b,c,d) do { asm volatile ("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(in)); } while(0) +static uint64_t cpuinfo_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { + char buf[4096]; + size_t _bsize = 0; -static uint32_t cpuinfo_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - char buf[1024]; - - unsigned long a, b, unused;; - cpuid(0,unused,b,unused,unused); - - char * _manu = "Unknown"; - int _model = 0, _family = 0; - - if (b == 0x756e6547) { - cpuid(1, a, b, unused, unused); - _manu = "Intel"; - _model = (a >> 4) & 0x0F; - _family = (a >> 8) & 0x0F; - } else if (b == 0x68747541) { - cpuid(1, a, unused, unused, unused); - _manu = "AMD"; - _model = (a >> 4) & 0x0F; - _family = (a >> 8) & 0x0F; +#ifdef __x86_64__ + for (int i = 0; i < processor_count; ++i) { + _bsize += snprintf(buf + _bsize, 1000, + "Processor: %d\n" + "Manufacturer: %s\n" + "MHz: %zd\n" + "Family: %d\n" + "Model: %d\n" + "Model name: %s\n" + "LAPIC id: %d\n" + "\n", + processor_local_data[i].cpu_id, + processor_local_data[i].cpu_manufacturer, + arch_cpu_mhz(), /* TODO Should this be per-cpu? */ + processor_local_data[i].cpu_family, + processor_local_data[i].cpu_model, + processor_local_data[i].cpu_model_name, + processor_local_data[i].lapic_id + ); } +#endif - sprintf(buf, - "Manufacturer: %s\n" - "Family: %d\n" - "Model: %d\n" - , _manu, _family, _model); - - size_t _bsize = strlen(buf); if (offset > _bsize) return 0; if (size > _bsize - offset) size = _bsize - offset; @@ -316,21 +285,16 @@ static uint32_t cpuinfo_func(fs_node_t *node, uint64_t offset, uint32_t size, ui return size; } -extern uintptr_t heap_end; -extern uintptr_t kernel_heap_alloc_point; - -static uint32_t meminfo_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t meminfo_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; - unsigned int total = memory_total(); - unsigned int free = total - memory_use(); - unsigned int kheap = (heap_end - kernel_heap_alloc_point) / 1024; + size_t total = mmu_total_memory(); + size_t free = total - mmu_used_memory(); + size_t kheap = ((uintptr_t)sbrk(0) - 0xffffff0000000000UL) / 1024; - - - sprintf(buf, - "MemTotal: %d kB\n" - "MemFree: %d kB\n" - "KHeapUse: %d kB\n" + snprintf(buf, 1000, + "MemTotal: %zu kB\n" + "MemFree: %zu kB\n" + "KHeapUse: %zu kB\n" , total, free, kheap); size_t _bsize = strlen(buf); @@ -341,13 +305,15 @@ static uint32_t meminfo_func(fs_node_t *node, uint64_t offset, uint32_t size, ui return size; } -static uint32_t pat_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +#ifdef __x86_64__ +static uint64_t pat_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; - uint64_t pat_values; - asm volatile ( "rdmsr" : "=A" (pat_values) : "c" (0x277) ); + uint32_t pat_value_low, pat_value_high; + asm volatile ( "rdmsr" : "=a" (pat_value_low), "=d" (pat_value_high): "c" (0x277) ); + uint64_t pat_values = ((uint64_t)pat_value_high << 32) | (pat_value_low); - char * pat_names[] = { + const char * pat_names[] = { "uncacheable (UC)", "write combining (WC)", "Reserved", @@ -367,7 +333,7 @@ static uint32_t pat_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_ int pa_6 = (pat_values >> 48) & 0x7; int pa_7 = (pat_values >> 56) & 0x7; - sprintf(buf, + snprintf(buf, 1000, "PA0: %d %s\n" "PA1: %d %s\n" "PA2: %d %s\n" @@ -393,11 +359,13 @@ static uint32_t pat_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_ memcpy(buffer, buf + offset, size); return size; } +#endif - -static uint32_t uptime_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t uptime_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; - sprintf(buf, "%d.%3d\n", timer_ticks, timer_subticks); + unsigned long timer_ticks, timer_subticks; + relative_time(0,0,&timer_ticks,&timer_subticks); + snprintf(buf, 100, "%lu.%06lu\n", timer_ticks, timer_subticks); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; @@ -407,10 +375,10 @@ static uint32_t uptime_func(fs_node_t *node, uint64_t offset, uint32_t size, uin return size; } -static uint32_t cmdline_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t cmdline_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; - extern char * cmdline; - sprintf(buf, "%s\n", cmdline ? cmdline : ""); + const char * cmdline = arch_get_cmdline(); + snprintf(buf, 1000, "%s\n", cmdline ? cmdline : ""); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; @@ -418,17 +386,19 @@ static uint32_t cmdline_func(fs_node_t *node, uint64_t offset, uint32_t size, ui memcpy(buffer, buf + offset, size); return size; + return 0; } -static uint32_t version_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t version_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; char version_number[512]; - sprintf(version_number, __kernel_version_format, + snprintf(version_number, 510, + __kernel_version_format, __kernel_version_major, __kernel_version_minor, __kernel_version_lower, __kernel_version_suffix); - sprintf(buf, "%s %s %s %s %s %s\n", + snprintf(buf, 1000, "%s %s %s %s %s %s\n", __kernel_name, version_number, __kernel_version_codename, @@ -444,9 +414,9 @@ static uint32_t version_func(fs_node_t *node, uint64_t offset, uint32_t size, ui return size; } -static uint32_t compiler_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t compiler_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char buf[1024]; - sprintf(buf, "%s\n", __kernel_compiler_version); + snprintf(buf, 1000, "%s\n", __kernel_compiler_version); size_t _bsize = strlen(buf); if (offset > _bsize) return 0; @@ -466,18 +436,18 @@ static void mount_recurse(char * buf, tree_node_t * node, size_t height) { char * c = tmp; /* Indent output */ for (uint32_t i = 0; i < height; ++i) { - c += sprintf(c, " "); + c += snprintf(c, 5, " "); } /* Get the current process */ struct vfs_entry * fnode = (struct vfs_entry *)node->value; /* Print the process name */ if (fnode->file) { - c += sprintf(c, "%s → %s 0x%x (%s, %s)", fnode->name, fnode->device, fnode->file, fnode->fs_type, fnode->file->name); + c += snprintf(c, 100, "%s → %s %p (%s, %s)", fnode->name, fnode->device, (void*)fnode->file, fnode->fs_type, fnode->file->name); } else { - c += sprintf(c, "%s → (empty)", fnode->name); + c += snprintf(c, 100, "%s → (empty)", fnode->name); } /* Linefeed */ - sprintf(buf+strlen(buf),"%s\n",tmp); + snprintf(buf+strlen(buf), 100, "%s\n",tmp); free(tmp); foreach(child, node->children) { /* Recursively print the children */ @@ -485,7 +455,7 @@ static void mount_recurse(char * buf, tree_node_t * node, size_t height) { } } -static uint32_t mounts_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t mounts_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char * buf = malloc(4096); buf[0] = '\0'; @@ -504,7 +474,8 @@ static uint32_t mounts_func(fs_node_t *node, uint64_t offset, uint32_t size, uin return size; } -static uint32_t modules_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t modules_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { +#if 0 list_t * hash_keys = hashmap_keys(modules_get_list()); char * buf = malloc(hash_keys->length * 512); unsigned int soffset = 0; @@ -544,17 +515,19 @@ static uint32_t modules_func(fs_node_t *node, uint64_t offset, uint32_t size, ui memcpy(buffer, buf + offset, size); free(buf); return size; +#endif + return 0; } extern hashmap_t * fs_types; /* from kernel/fs/vfs.c */ -static uint32_t filesystems_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t filesystems_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { list_t * hash_keys = hashmap_keys(fs_types); char * buf = malloc(hash_keys->length * 512); unsigned int soffset = 0; foreach(_key, hash_keys) { char * key = (char *)_key->value; - soffset += sprintf(&buf[soffset], "%s\n", key); + soffset += snprintf(&buf[soffset], 100, "%s\n", key); } free(hash_keys); @@ -570,15 +543,10 @@ static uint32_t filesystems_func(fs_node_t *node, uint64_t offset, uint32_t size return size; } -static uint32_t loader_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t loader_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char * buf = malloc(512); - if (mboot_ptr->flags & MULTIBOOT_FLAG_LOADER) { - sprintf(buf, "%s\n", mboot_ptr->boot_loader_name); - } else { - buf[0] = '\n'; - buf[1] = '\0'; - } + snprintf(buf, 511, "%s\n", arch_get_loader()); size_t _bsize = strlen(buf); if (offset > _bsize) { @@ -592,31 +560,32 @@ static uint32_t loader_func(fs_node_t *node, uint64_t offset, uint32_t size, uin return size; } -extern char * get_irq_handler(int irq, int chain); - -static uint32_t irq_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +#ifdef __x86_64__ +#include +#include +static uint64_t irq_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { char * buf = malloc(4096); unsigned int soffset = 0; for (int i = 0; i < 16; ++i) { - soffset += sprintf(&buf[soffset], "irq %d: ", i); + soffset += snprintf(&buf[soffset], 100, "irq %d: ", i); for (int j = 0; j < 4; ++j) { - char * t = get_irq_handler(i, j); + const char * t = get_irq_handler(i, j); if (!t) break; - soffset += sprintf(&buf[soffset], "%s%s", j ? "," : "", t); + soffset += snprintf(&buf[soffset], 100, "%s%s", j ? "," : "", t); } - soffset += sprintf(&buf[soffset], "\n"); + soffset += snprintf(&buf[soffset], 100, "\n"); } outportb(0x20, 0x0b); outportb(0xa0, 0x0b); - soffset += sprintf(&buf[soffset], "isr=0x%4x\n", (inportb(0xA0) << 8) | inportb(0x20)); + soffset += snprintf(&buf[soffset], 100, "isr=0x%04x\n", (inportb(0xA0) << 8) | inportb(0x20)); outportb(0x20, 0x0a); outportb(0xa0, 0x0a); - soffset += sprintf(&buf[soffset], "irr=0x%4x\n", (inportb(0xA0) << 8) | inportb(0x20)); + soffset += snprintf(&buf[soffset], 100, "irr=0x%04x\n", (inportb(0xA0) << 8) | inportb(0x20)); - soffset += sprintf(&buf[soffset], "imr=0x%4x\n", (inportb(0xA1) << 8) | inportb(0x21)); + soffset += snprintf(&buf[soffset], 100, "imr=0x%04x\n", (inportb(0xA1) << 8) | inportb(0x21)); size_t _bsize = strlen(buf); if (offset > _bsize) { @@ -642,7 +611,7 @@ static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, struct _pci_buf * b = extra; - b->offset += sprintf(b->buffer + b->offset, "%2x:%2x.%d (%4x, %4x:%4x)\n", + b->offset += snprintf(b->buffer + b->offset, 100, "%02x:%02x.%d (%04x, %04x:%04x)\n", (int)pci_extract_bus(device), (int)pci_extract_slot(device), (int)pci_extract_func(device), @@ -650,17 +619,17 @@ static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, vendorid, deviceid); - b->offset += sprintf(b->buffer + b->offset, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4)); - b->offset += sprintf(b->buffer + b->offset, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4)); - b->offset += sprintf(b->buffer + b->offset, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4)); - b->offset += sprintf(b->buffer + b->offset, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4)); - b->offset += sprintf(b->buffer + b->offset, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); - b->offset += sprintf(b->buffer + b->offset, " BAR5: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); + b->offset += snprintf(b->buffer + b->offset, 100, " BAR0: 0x%08x", pci_read_field(device, PCI_BAR0, 4)); + b->offset += snprintf(b->buffer + b->offset, 100, " BAR1: 0x%08x", pci_read_field(device, PCI_BAR1, 4)); + b->offset += snprintf(b->buffer + b->offset, 100, " BAR2: 0x%08x", pci_read_field(device, PCI_BAR2, 4)); + b->offset += snprintf(b->buffer + b->offset, 100, " BAR3: 0x%08x", pci_read_field(device, PCI_BAR3, 4)); + b->offset += snprintf(b->buffer + b->offset, 100, " BAR4: 0x%08x", pci_read_field(device, PCI_BAR4, 4)); + b->offset += snprintf(b->buffer + b->offset, 100, " BAR5: 0x%08x\n", pci_read_field(device, PCI_BAR5, 4)); - b->offset += sprintf(b->buffer + b->offset, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); - b->offset += sprintf(b->buffer + b->offset, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); - b->offset += sprintf(b->buffer + b->offset, " Interrupt: %d", pci_get_interrupt(device)); - b->offset += sprintf(b->buffer + b->offset, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2)); + b->offset += snprintf(b->buffer + b->offset, 100, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); + b->offset += snprintf(b->buffer + b->offset, 100, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); + b->offset += snprintf(b->buffer + b->offset, 100, " Interrupt: %d", pci_get_interrupt(device)); + b->offset += snprintf(b->buffer + b->offset, 100, " Status: 0x%04x\n", pci_read_field(device, PCI_STATUS, 2)); } static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { @@ -668,7 +637,7 @@ static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, vo (*count)++; } -static uint32_t pci_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t pci_func(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { size_t count = 0; pci_scan(&scan_count, -1, &count); @@ -688,6 +657,7 @@ static uint32_t pci_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_ free(b.buffer); return size; } +#endif static struct procfs_entry std_entries[] = { {-1, "cpuinfo", cpuinfo_func}, @@ -700,17 +670,19 @@ static struct procfs_entry std_entries[] = { {-8, "modules", modules_func}, {-9, "filesystems", filesystems_func}, {-10,"loader", loader_func}, +#ifdef __x86_64__ {-11,"irq", irq_func}, {-12,"pat", pat_func}, {-13,"pci", pci_func}, +#endif }; static list_t * extended_entries = NULL; -static int next_id = 0; +static long next_id = 0; int procfs_install(struct procfs_entry * entry) { if (!extended_entries) { - extended_entries = list_create(); + extended_entries = list_create("procfs entries",NULL); next_id = -PROCFS_STANDARD_ENTRIES - 1; } @@ -720,7 +692,7 @@ int procfs_install(struct procfs_entry * entry) { return 0; } -static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_procfs_root(fs_node_t *node, uint64_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); @@ -778,8 +750,6 @@ static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { int i = index + 1; - debug_print(NOTICE, "%d %d %d", i, index, PROCFS_STANDARD_ENTRIES); - pid_t pid = 0; foreach(lnode, process_list) { @@ -798,7 +768,7 @@ static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); out->ino = pid; - sprintf(out->name, "%d", pid); + snprintf(out->name, 100, "%d", pid); return out; } @@ -806,7 +776,7 @@ static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { static int readlink_self(fs_node_t * node, char * buf, size_t size) { char tmp[30]; size_t req; - sprintf(tmp, "/proc/%d", current_process->id); + snprintf(tmp, 100, "/proc/%d", this_core->current_process->id); req = strlen(tmp) + 1; if (size < req) { @@ -901,16 +871,10 @@ static fs_node_t * procfs_create(void) { return fnode; } -int procfs_initialize(void) { +void procfs_initialize(void) { /* TODO Move this to some sort of config */ vfs_mount("/proc", procfs_create()); - debug_print_vfs_tree(); - return 0; + //debug_print_vfs_tree(); } -int procfs_finalize(void) { - return 0; -} - -MODULE_DEF(procfs, procfs_initialize, procfs_finalize); diff --git a/kernel/fs/ramdisk.c b/kernel/vfs/ramdisk.c similarity index 58% rename from kernel/fs/ramdisk.c rename to kernel/vfs/ramdisk.c index 9fc78858..bffe7c91 100644 --- a/kernel/fs/ramdisk.c +++ b/kernel/vfs/ramdisk.c @@ -1,26 +1,37 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/ramdisk.c + * @brief VFS wrapper for physical memory blocks. + * + * Allows raw physical memory blocks provided by the loader to be + * used like a block file. Used to provide multiboot payloads + * as /dev/ram* files. + * + * Note that the ramdisk driver really does deal with physical + * memory addresses, not virtual address, and once a block of + * pages has been handed over to the ramdisk driver it is owned + * by the ramdisk driver which may mark those pages as available + * (via an ioctl request). + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * Ramdisk driver. - * - * Provide raw block access to files loaded into kernel memory. + * Copyright (C) 2014-2021 K. Lange */ -#include -#include -#include -#include +#include +#include +#include #include -#include +#include +#include +#include -static uint32_t read_ramdisk(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer); -static uint32_t write_ramdisk(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer); +static uint64_t read_ramdisk(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer); +static uint64_t write_ramdisk(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer); static void open_ramdisk(fs_node_t *node, unsigned int flags); static void close_ramdisk(fs_node_t *node); -static uint32_t read_ramdisk(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t read_ramdisk(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { if (offset > node->length) { return 0; @@ -31,12 +42,12 @@ static uint32_t read_ramdisk(fs_node_t *node, uint64_t offset, uint32_t size, ui size = i; } - memcpy(buffer, (void *)(node->inode + (uintptr_t)offset), size); + memcpy(buffer, (void *)((uintptr_t)mmu_map_from_physical(node->inode) + (uintptr_t)offset), size); return size; } -static uint32_t write_ramdisk(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t write_ramdisk(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { if (offset > node->length) { return 0; } @@ -46,7 +57,7 @@ static uint32_t write_ramdisk(fs_node_t *node, uint64_t offset, uint32_t size, u size = i; } - memcpy((void *)(node->inode + (uintptr_t)offset), buffer, size); + memcpy((void *)((uintptr_t)mmu_map_from_physical(node->inode) + (uintptr_t)offset), buffer, size); return size; } @@ -61,7 +72,7 @@ static void close_ramdisk(fs_node_t * node) { static int ioctl_ramdisk(fs_node_t * node, int request, void * argp) { switch (request) { case 0x4001: - if (current_process->user != 0) { + if (this_core->current_process->user != 0) { return -EPERM; } else { /* Clear all of the memory used by this ramdisk */ @@ -71,7 +82,7 @@ static int ioctl_ramdisk(fs_node_t * node, int request, void * argp) { node->length -= node->length % 0x1000; } for (uintptr_t i = node->inode; i < (node->inode + node->length); i += 0x1000) { - clear_frame(i); + mmu_frame_clear(i); } } /* Mark the file length as 0 */ @@ -81,13 +92,14 @@ static int ioctl_ramdisk(fs_node_t * node, int request, void * argp) { default: return -EINVAL; } + return -1; } static fs_node_t * ramdisk_device_create(int device_number, uintptr_t location, size_t size) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); fnode->inode = location; - sprintf(fnode->name, "ram%d", device_number); + snprintf(fnode->name, 10, "ram%d", device_number); fnode->uid = 0; fnode->gid = 0; fnode->mask = 0770; @@ -106,7 +118,7 @@ fs_node_t * ramdisk_mount(uintptr_t location, size_t size) { fs_node_t * ramdisk = ramdisk_device_create(last_device_number, location, size); if (ramdisk) { char tmp[64]; - sprintf(tmp, "/dev/%s", ramdisk->name); + snprintf(tmp, 63, "/dev/%s", ramdisk->name); vfs_mount(tmp, ramdisk); last_device_number += 1; return ramdisk; @@ -114,3 +126,4 @@ fs_node_t * ramdisk_mount(uintptr_t location, size_t size) { return NULL; } + diff --git a/kernel/vfs/random.c b/kernel/vfs/random.c new file mode 100644 index 00000000..6eaf09a9 --- /dev/null +++ b/kernel/vfs/random.c @@ -0,0 +1,56 @@ +/** + * @file kernel/vfs/random.c + * @brief Bad RNG. + * + * Provides a terrible little xorshift random number generator. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014-2018 K. Lange + */ +#include +#include +#include + +static uint32_t rand(void) { + static uint32_t x = 123456789; + static uint32_t y = 362436069; + static uint32_t z = 521288629; + static uint32_t w = 88675123; + + uint32_t t; + + t = x ^ (x << 11); + x = y; y = z; z = w; + return w = w ^ (w >> 19) ^ t ^ (t >> 8); +} + +static uint64_t read_random(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { + size_t s = 0; + while (s < size) { + buffer[s] = rand() % 0xFF; + s++; + } + return size; +} + +static fs_node_t * random_device_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "random"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0444; + fnode->length = 1024; + fnode->flags = FS_CHARDEVICE; + fnode->read = read_random; + return fnode; +} + +void random_initialize(void) { + vfs_mount("/dev/random", random_device_create()); + vfs_mount("/dev/urandom", random_device_create()); +} + diff --git a/modules/tarfs.c b/kernel/vfs/tarfs.c similarity index 91% rename from modules/tarfs.c rename to kernel/vfs/tarfs.c index b156f548..d8bda010 100644 --- a/modules/tarfs.c +++ b/kernel/vfs/tarfs.c @@ -1,21 +1,19 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/tarfs.c + * @brief Read-only filesystem driver for ustar archives. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2018 K. Lange - * - * tarfs - Allows read-only mounting of ustar archives */ -#include #include -#include -#include -#include -#include +#include #include #include -#include -#include +#include +#include #define TARFS_LOG_LEVEL WARNING @@ -136,7 +134,7 @@ static int count_slashes(char * string) { return i; } -static struct dirent * readdir_tar_root(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_tar_root(fs_node_t *node, uint64_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); @@ -200,7 +198,7 @@ static struct dirent * readdir_tar_root(fs_node_t *node, uint32_t index) { return NULL; } -static uint32_t read_tarfs(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { +static uint64_t read_tarfs(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t * buffer) { struct tarfs * self = node->device; struct ustar * file = malloc(sizeof(struct ustar)); ustar_from_offset(self, node->inode, file); @@ -216,7 +214,7 @@ static uint32_t read_tarfs(fs_node_t * node, uint64_t offset, uint32_t size, uin return read_fs(self->device, offset + node->inode + 512, size, buffer); } -static struct dirent * readdir_tarfs(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_tarfs(fs_node_t *node, uint64_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); @@ -307,7 +305,7 @@ static fs_node_t * finddir_tarfs(fs_node_t *node, char *name) { /* Append name */ strncat(my_filename, name, strlen(name)); if (strlen(my_filename) > 255) { - debug_print(CRITICAL, "what"); + printf("tarfs: critical: what?"); } unsigned int offset = node->inode; @@ -346,13 +344,13 @@ static int readlink_tarfs(fs_node_t * node, char * buf, size_t size) { ustar_from_offset(self, node->inode, file); if (size < strlen(file->link) + 1) { - debug_print(INFO, "Requested read size was only %d, need %d.", size, strlen(file->link)+1); + //debug_print(INFO, "Requested read size was only %d, need %d.", size, strlen(file->link)+1); memcpy(buf, file->link, size-1); buf[size-1] = '\0'; free(file); return size-1; } else { - debug_print(INFO, "Reading link target is [%s]", file->link); + //debug_print(INFO, "Reading link target is [%s]", file->link); memcpy(buf, file->link, strlen(file->link) + 1); free(file); return strlen(file->link); @@ -380,7 +378,7 @@ static fs_node_t * file_from_ustar(struct tarfs * self, struct ustar * file, uns fs->readdir = readdir_tarfs; fs->finddir = finddir_tarfs; } else if (file->type[0] == '1') { - debug_print(ERROR, "Hardlink detected"); + //debug_print(ERROR, "Hardlink detected"); /* go through file and find target, reassign inode to point to that */ } else if (file->type[0] == '2') { fs->flags = FS_SYMLINK; @@ -447,20 +445,22 @@ static int ustar_from_offset(struct tarfs * self, unsigned int offset, struct us return 1; } -static fs_node_t * tar_mount(char * device, char * mount_path) { +static fs_node_t * tar_mount(const char * device, const char * mount_path) { char * arg = strdup(device); char * argv[10]; int argc = tokenize(arg, ",", argv); if (argc > 1) { - debug_print(WARNING, "tarfs driver takes no options"); + //debug_print(WARNING, "tarfs driver takes no options"); + printf("tarfs got unexpected mount arguments: %s\n", device); } fs_node_t * dev = kopen(argv[0], 0); free(arg); /* Shouldn't need the filename or args anymore */ if (!dev) { - debug_print(ERROR, "failed to open %s", device); + //debug_print(ERROR, "failed to open %s", device); + printf("tarfs could not open target device\n"); return NULL; } @@ -485,14 +485,8 @@ static fs_node_t * tar_mount(char * device, char * mount_path) { return root; } -static int init(void) { +int tarfs_register_init(void) { vfs_register("tar", tar_mount); return 0; } -static int fini(void) { - return 0; -} - -MODULE_DEF(tarfs, init, fini); - diff --git a/modules/tmpfs.c b/kernel/vfs/tmpfs.c similarity index 74% rename from modules/tmpfs.c rename to kernel/vfs/tmpfs.c index 0d094d1b..1867d31e 100644 --- a/modules/tmpfs.c +++ b/kernel/vfs/tmpfs.c @@ -1,17 +1,27 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/tmpfs.c + * @brief In-memory read-write filesystem. + * + * Generally provides the filesystem for "migrated" live CDs, + * as well as /tmp and /var. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange + * Copyright (C) 2014-2021 K. Lange */ -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include #include +#include +#include +#include +#include /* 4KB */ #define BLOCKSIZE 0x1000 @@ -47,7 +57,7 @@ static struct tmpfs_file * tmpfs_file_new(char * name) { t->ctime = t->atime; t->blocks = malloc(t->pointers * sizeof(char *)); for (size_t i = 0; i < t->pointers; ++i) { - t->blocks[i] = NULL; + t->blocks[i] = 0; } spin_unlock(tmpfs_lock); @@ -56,28 +66,24 @@ static struct tmpfs_file * tmpfs_file_new(char * name) { static int symlink_tmpfs(fs_node_t * parent, char * target, char * name) { struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; - debug_print(NOTICE, "Creating TMPFS file (symlink) %s in %s", name, d->name); spin_lock(tmpfs_lock); foreach(f, d->files) { struct tmpfs_file * t = (struct tmpfs_file *)f->value; if (!strcmp(name, t->name)) { spin_unlock(tmpfs_lock); - debug_print(WARNING, "... already exists."); return -EEXIST; /* Already exists */ } } spin_unlock(tmpfs_lock); - debug_print(NOTICE, "... creating a new file (symlink)."); struct tmpfs_file * t = tmpfs_file_new(name); t->type = TMPFS_TYPE_LINK; - debug_print(NOTICE, "symlink target is [%s]", target); t->target = strdup(target); t->mask = 0777; - t->uid = current_process->user; - t->gid = current_process->user; + t->uid = this_core->current_process->user; + t->gid = this_core->current_process->user; spin_lock(tmpfs_lock); list_insert(d->files, t); @@ -89,17 +95,15 @@ static int symlink_tmpfs(fs_node_t * parent, char * target, char * name) { static int readlink_tmpfs(fs_node_t * node, char * buf, size_t size) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); if (t->type != TMPFS_TYPE_LINK) { - debug_print(WARNING, "Not a symlink? Very confused!"); + printf("tmpfs: not a symlink?\n"); return -1; } if (size < strlen(t->target) + 1) { - debug_print(INFO, "Requested read size was only %d, need %d.", size, strlen(t->target)+1); memcpy(buf, t->target, size-1); buf[size-1] = '\0'; return size-2; } else { - debug_print(INFO, "Reading link target is [%s]", t->target); memcpy(buf, t->target, strlen(t->target) + 1); return strlen(t->target); } @@ -117,7 +121,7 @@ static struct tmpfs_dir * tmpfs_dir_new(char * name, struct tmpfs_dir * parent) d->atime = now(); d->mtime = d->atime; d->ctime = d->atime; - d->files = list_create(); + d->files = list_create("tmpfs directory entries",d); spin_unlock(tmpfs_lock); return d; @@ -125,23 +129,20 @@ static struct tmpfs_dir * tmpfs_dir_new(char * name, struct tmpfs_dir * parent) static void tmpfs_file_free(struct tmpfs_file * t) { if (t->type == TMPFS_TYPE_LINK) { - debug_print(ERROR, "uh, what"); + printf("tmpfs: bad link free?\n"); free(t->target); } for (size_t i = 0; i < t->block_count; ++i) { - clear_frame((uintptr_t)t->blocks[i] * 0x1000); + mmu_frame_clear((uintptr_t)t->blocks[i] * 0x1000); } } static void tmpfs_file_blocks_embiggen(struct tmpfs_file * t) { t->pointers *= 2; - debug_print(INFO, "Embiggening file %s to %d blocks", t->name, t->pointers); t->blocks = realloc(t->blocks, sizeof(char *) * t->pointers); } static char * tmpfs_file_getset_block(struct tmpfs_file * t, size_t blockid, int create) { - debug_print(INFO, "Reading block %d from file %s", blockid, t->name); - spin_lock(tmpfs_page_lock); if (create) { @@ -150,61 +151,59 @@ static char * tmpfs_file_getset_block(struct tmpfs_file * t, size_t blockid, int tmpfs_file_blocks_embiggen(t); } while (blockid >= t->block_count) { - debug_print(INFO, "Allocating block %d for file %s", blockid, t->name); - uintptr_t index = first_frame(); - set_frame(index * 0x1000); - t->blocks[t->block_count] = (char*)index; + uintptr_t index = mmu_allocate_a_frame(); + t->blocks[t->block_count] = index; t->block_count += 1; } spin_unlock(tmpfs_lock); } else { if (blockid >= t->block_count) { - debug_print(ERROR, "This will probably end badly."); + printf("tmpfs: not enough blocks?\n"); return NULL; } } - debug_print(INFO, "Using block %d->0x%x (of %d) on file %s", blockid, t->blocks[blockid], t->block_count, t->name); - page_t * page = get_page((uintptr_t)buf_space,0,current_directory); - page->rw = 1; - page->user = 0; - page->frame = (uintptr_t)t->blocks[blockid]; - page->present = 1; - invalidate_tables_at((uintptr_t)buf_space); + union PML * page = mmu_get_page((uintptr_t)buf_space,0); + /* This should be map_address? */ + page->bits.writable = 1; + page->bits.user = 0; + page->bits.page = (uintptr_t)t->blocks[blockid]; + page->bits.present = 1; + page->bits.size = 0; + mmu_invalidate((uintptr_t)buf_space); return (char *)buf_space; } -static uint32_t read_tmpfs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t read_tmpfs(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); t->atime = now(); - uint32_t end; + uint64_t end; if (offset + size > t->length) { end = t->length; } else { end = offset + size; } - debug_print(INFO, "reading from %d to %d", offset, end); - uint32_t start_block = offset / BLOCKSIZE; - uint32_t end_block = end / BLOCKSIZE; - uint32_t end_size = end - end_block * BLOCKSIZE; - uint32_t size_to_read = end - offset; + uint64_t start_block = offset / BLOCKSIZE; + uint64_t end_block = end / BLOCKSIZE; + uint64_t end_size = end - end_block * BLOCKSIZE; + uint64_t size_to_read = end - offset; if (start_block == end_block && offset == end) return 0; if (start_block == end_block) { void *buf = tmpfs_file_getset_block(t, start_block, 0); - memcpy(buffer, (uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), size_to_read); + memcpy(buffer, (uint8_t *)(((uintptr_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), size_to_read); spin_unlock(tmpfs_page_lock); return size_to_read; } else { - uint32_t block_offset; - uint32_t blocks_read = 0; + uint64_t block_offset; + uint64_t blocks_read = 0; for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { if (block_offset == start_block) { void *buf = tmpfs_file_getset_block(t, block_offset, 0); - memcpy(buffer, (uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), BLOCKSIZE - (offset % BLOCKSIZE)); + memcpy(buffer, (uint8_t *)(((uint64_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), BLOCKSIZE - (offset % BLOCKSIZE)); spin_unlock(tmpfs_page_lock); } else { void *buf = tmpfs_file_getset_block(t, block_offset, 0); @@ -221,33 +220,33 @@ static uint32_t read_tmpfs(fs_node_t *node, uint64_t offset, uint32_t size, uint return size_to_read; } -static uint32_t write_tmpfs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t write_tmpfs(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); t->atime = now(); t->mtime = t->atime; - uint32_t end; + uint64_t end; if (offset + size > t->length) { t->length = offset + size; } end = offset + size; - uint32_t start_block = offset / BLOCKSIZE; - uint32_t end_block = end / BLOCKSIZE; - uint32_t end_size = end - end_block * BLOCKSIZE; - uint32_t size_to_read = end - offset; + uint64_t start_block = offset / BLOCKSIZE; + uint64_t end_block = end / BLOCKSIZE; + uint64_t end_size = end - end_block * BLOCKSIZE; + uint64_t size_to_read = end - offset; if (start_block == end_block) { void *buf = tmpfs_file_getset_block(t, start_block, 1); - memcpy((uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), buffer, size_to_read); + memcpy((uint8_t *)(((uint64_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), buffer, size_to_read); spin_unlock(tmpfs_page_lock); return size_to_read; } else { - uint32_t block_offset; - uint32_t blocks_read = 0; + uint64_t block_offset; + uint64_t blocks_read = 0; for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { if (block_offset == start_block) { void *buf = tmpfs_file_getset_block(t, block_offset, 1); - memcpy((uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), buffer, BLOCKSIZE - (offset % BLOCKSIZE)); + memcpy((uint8_t *)(((uint64_t)buf) + ((uintptr_t)offset % BLOCKSIZE)), buffer, BLOCKSIZE - (offset % BLOCKSIZE)); spin_unlock(tmpfs_page_lock); } else { void *buf = tmpfs_file_getset_block(t, block_offset, 1); @@ -276,8 +275,6 @@ static int chmod_tmpfs(fs_node_t * node, int mode) { static int chown_tmpfs(fs_node_t * node, int uid, int gid) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); - debug_print(INFO, "chown(..., %d, %d)", uid, gid); - t->uid = uid; t->gid = gid; @@ -286,9 +283,8 @@ static int chown_tmpfs(fs_node_t * node, int uid, int gid) { static void truncate_tmpfs(fs_node_t * node) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); - debug_print(INFO, "Truncating file %s", t->name); for (size_t i = 0; i < t->block_count; ++i) { - clear_frame((uintptr_t)t->blocks[i] * 0x1000); + mmu_frame_clear((uintptr_t)t->blocks[i] * 0x1000); t->blocks[i] = 0; } t->block_count = 0; @@ -298,7 +294,6 @@ static void truncate_tmpfs(fs_node_t * node) { static void open_tmpfs(fs_node_t * node, unsigned int flags) { struct tmpfs_file * t = (struct tmpfs_file *)(node->device); - debug_print(INFO, "---- Opened TMPFS file %s with flags 0x%x ----", t->name, flags); t->atime = now(); } @@ -343,11 +338,9 @@ static fs_node_t * tmpfs_from_link(struct tmpfs_file * t) { return fnode; } -static struct dirent * readdir_tmpfs(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_tmpfs(fs_node_t *node, uint64_t index) { struct tmpfs_dir * d = (struct tmpfs_dir *)node->device; - uint32_t i = 0; - - debug_print(NOTICE, "tmpfs - readdir id=%d", index); + uint64_t i = 0; if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); @@ -374,7 +367,7 @@ static struct dirent * readdir_tmpfs(fs_node_t *node, uint32_t index) { struct tmpfs_file * t = (struct tmpfs_file *)f->value; struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); - out->ino = (uint32_t)t; + out->ino = (uint64_t)t; strcpy(out->name, t->name); return out; } else { @@ -443,24 +436,21 @@ static int create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) { if (!name) return -EINVAL; struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; - debug_print(NOTICE, "Creating TMPFS file %s in %s", name, d->name); spin_lock(tmpfs_lock); foreach(f, d->files) { struct tmpfs_file * t = (struct tmpfs_file *)f->value; if (!strcmp(name, t->name)) { spin_unlock(tmpfs_lock); - debug_print(WARNING, "... already exists."); return -EEXIST; /* Already exists */ } } spin_unlock(tmpfs_lock); - debug_print(NOTICE, "... creating a new file."); struct tmpfs_file * t = tmpfs_file_new(name); t->mask = permission; - t->uid = current_process->user; - t->gid = current_process->user; + t->uid = this_core->current_process->user; + t->gid = this_core->current_process->user; spin_lock(tmpfs_lock); list_insert(d->files, t); @@ -474,24 +464,21 @@ static int mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) { if (!strlen(name)) return -EINVAL; struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; - debug_print(NOTICE, "Creating TMPFS directory %s (in %s)", name, d->name); spin_lock(tmpfs_lock); foreach(f, d->files) { struct tmpfs_file * t = (struct tmpfs_file *)f->value; if (!strcmp(name, t->name)) { spin_unlock(tmpfs_lock); - debug_print(WARNING, "... already exists."); return -EEXIST; /* Already exists */ } } spin_unlock(tmpfs_lock); - debug_print(NOTICE, "... creating a new directory."); struct tmpfs_dir * out = tmpfs_dir_new(name, d); out->mask = permission; - out->uid = current_process->user; - out->gid = current_process->user; + out->uid = this_core->current_process->user; + out->gid = this_core->current_process->user; spin_lock(tmpfs_lock); list_insert(d->files, out); @@ -540,7 +527,7 @@ fs_node_t * tmpfs_create(char * name) { return tmpfs_from_dir(tmpfs_root); } -fs_node_t * tmpfs_mount(char * device, char * mount_path) { +fs_node_t * tmpfs_mount(const char * device, const char * mount_path) { char * arg = strdup(device); char * argv[10]; int argc = tokenize(arg, ",", argv); @@ -549,7 +536,7 @@ fs_node_t * tmpfs_mount(char * device, char * mount_path) { if (argc > 1) { if (strlen(argv[1]) < 3) { - debug_print(WARNING, "ignoring bad permission option for tmpfs"); + printf("tmpfs: ignoring bad permission option for tmpfs\n"); } else { int mode = ((argv[1][0] - '0') << 6) | ((argv[1][1] - '0') << 3) | @@ -558,20 +545,12 @@ fs_node_t * tmpfs_mount(char * device, char * mount_path) { } } - free(arg); + //free(arg); return fs; } -static int tmpfs_initialize(void) { - - buf_space = (void*)kvmalloc(BLOCKSIZE); - +void tmpfs_register_init(void) { + buf_space = (void*)valloc(BLOCKSIZE); vfs_register("tmpfs", tmpfs_mount); - - return 0; -} -static int tmpfs_finalize(void) { - return 0; } -MODULE_DEF(tmpfs, tmpfs_initialize, tmpfs_finalize); diff --git a/kernel/fs/tty.c b/kernel/vfs/tty.c similarity index 90% rename from kernel/fs/tty.c rename to kernel/vfs/tty.c index 1cf19c9e..7d912d04 100644 --- a/kernel/fs/tty.c +++ b/kernel/vfs/tty.c @@ -1,22 +1,34 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/tty.c + * @brief PTY driver. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2013-2018 K. Lange + * Copyright (C) 2013-2021 K. Lange */ -#include -#include +#include +#include +#include #include -#include +#include #include #include #include -#include - +#include +#include +#include +#include #include #include +#include #define TTY_BUFFER_SIZE 4096 +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +extern void ptr_validate(void * ptr, const char * syscall); +#define validate(o) ptr_validate(o,"ioctl") + static int _pty_counter = 0; static hashmap_t * _pty_index = NULL; static fs_node_t * _pty_dir = NULL; @@ -246,7 +258,7 @@ void tty_input_process(pty_t * pty, uint8_t c) { static void tty_fill_name(pty_t * pty, char * out) { ((char*)out)[0] = '\0'; - sprintf((char*)out, "/dev/pts/%d", pty->name); + snprintf((char*)out, 100, "/dev/pts/%zd", pty->name); } int pty_ioctl(pty_t * pty, int request, void * argp) { @@ -266,7 +278,7 @@ int pty_ioctl(pty_t * pty, int request, void * argp) { return 0; case IOCTLTTYLOGIN: /* Set the user id of the login user */ - if (current_process->user != 0) return -EPERM; + if (this_core->current_process->user != 0) return -EPERM; if (!argp) return -EINVAL; validate(argp); pty->slave->uid = *(int*)argp; @@ -294,7 +306,6 @@ int pty_ioctl(pty_t * pty, int request, void * argp) { if (!argp) return -EINVAL; validate(argp); pty->fg_proc = *(pid_t *)argp; - debug_print(NOTICE, "Setting PTY group to %d", pty->fg_proc); return 0; case TIOCGPGRP: if (!argp) return -EINVAL; @@ -317,13 +328,13 @@ int pty_ioctl(pty_t * pty, int request, void * argp) { } } -uint32_t read_pty_master(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t read_pty_master(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { pty_t * pty = (pty_t *)node->device; /* Standard pipe read */ return ring_buffer_read(pty->out, size, buffer); } -uint32_t write_pty_master(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t write_pty_master(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { pty_t * pty = (pty_t *)node->device; size_t l = 0; @@ -340,7 +351,7 @@ void close_pty_master(fs_node_t * node) { return; } -uint32_t read_pty_slave(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t read_pty_slave(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { pty_t * pty = (pty_t *)node->device; if (pty->tios.c_lflag & ICANON) { @@ -354,7 +365,7 @@ uint32_t read_pty_slave(fs_node_t * node, uint64_t offset, uint32_t size, uint8 } } -uint32_t write_pty_slave(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t write_pty_slave(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { pty_t * pty = (pty_t *)node->device; size_t l = 0; @@ -432,8 +443,8 @@ fs_node_t * pty_master_create(pty_t * pty) { memset(fnode, 0x00, sizeof(fs_node_t)); fnode->name[0] = '\0'; - sprintf(fnode->name, "pty master"); - fnode->uid = current_process->user; + snprintf(fnode->name, 100, "pty master"); + fnode->uid = this_core->current_process->user; fnode->gid = 0; fnode->mask = 0666; fnode->flags = FS_PIPE; @@ -461,8 +472,8 @@ fs_node_t * pty_slave_create(pty_t * pty) { memset(fnode, 0x00, sizeof(fs_node_t)); fnode->name[0] = '\0'; - sprintf(fnode->name, "pty slave"); - fnode->uid = current_process->user; + snprintf(fnode->name, 100, "pty slave"); + fnode->uid = this_core->current_process->user; fnode->gid = 0; fnode->mask = 0620; fnode->flags = FS_CHARDEVICE; @@ -494,9 +505,9 @@ static int isatty(fs_node_t * node) { static int readlink_dev_tty(fs_node_t * node, char * buf, size_t size) { pty_t * pty = NULL; - for (unsigned int i = 0; i < ((current_process->fds->length < 3) ? current_process->fds->length : 3); ++i) { - if (isatty(current_process->fds->entries[i])) { - pty = (pty_t *)current_process->fds->entries[i]->device; + for (unsigned int i = 0; i < ((this_core->current_process->fds->length < 3) ? this_core->current_process->fds->length : 3); ++i) { + if (isatty(this_core->current_process->fds->entries[i])) { + pty = (pty_t *)this_core->current_process->fds->entries[i]->device; break; } } @@ -504,7 +515,7 @@ static int readlink_dev_tty(fs_node_t * node, char * buf, size_t size) { char tmp[30]; size_t req; if (!pty) { - sprintf(tmp, "/dev/null"); + snprintf(tmp, 100, "/dev/null"); } else { pty->fill_name(pty, tmp); } @@ -541,7 +552,7 @@ static fs_node_t * create_dev_tty(void) { return fnode; } -static struct dirent * readdir_pty(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_pty(fs_node_t *node, uint64_t index) { if (index == 0) { struct dirent * out = malloc(sizeof(struct dirent)); memset(out, 0x00, sizeof(struct dirent)); @@ -576,7 +587,7 @@ static struct dirent * readdir_pty(fs_node_t *node, uint32_t index) { memset(out, 0x00, sizeof(struct dirent)); out->ino = out_pty->name; out->name[0] = '\0'; - sprintf(out->name, "%d", out_pty->name); + snprintf(out->name, 100, "%zd", out_pty->name); return out; } else { return NULL; @@ -587,8 +598,8 @@ static fs_node_t * finddir_pty(fs_node_t * node, char * name) { if (!name) return NULL; if (strlen(name) < 1) return NULL; - int c = 0; - for (int i = 0; name[i]; ++i) { + intptr_t c = 0; + for (intptr_t i = 0; name[i]; ++i) { if (name[i] < '0' || name[i] > '9') { return NULL; } @@ -598,7 +609,6 @@ static fs_node_t * finddir_pty(fs_node_t * node, char * name) { pty_t * _pty = hashmap_get(_pty_index, (void*)c); if (!_pty) { - debug_print(ERROR, "Invalid PTY number: %d\n", c); return NULL; } diff --git a/kernel/fs/unixpipe.c b/kernel/vfs/unixpipe.c similarity index 78% rename from kernel/fs/unixpipe.c rename to kernel/vfs/unixpipe.c index e566a37d..e4bbc897 100644 --- a/kernel/fs/unixpipe.c +++ b/kernel/vfs/unixpipe.c @@ -1,15 +1,23 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/unixpipe.c + * @brief Implementation of Unix pipes. + * + * Provides for unidirectional communication between processes. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange + * Copyright (C) 2014-2021 K. Lange */ -#include -#include -#include -#include +#include #include +#include +#include #include +#include +#include +#include #include #define UNIX_PIPE_BUFFER 512 @@ -28,7 +36,7 @@ static void close_complete(struct unix_pipe * self) { ring_buffer_destroy(self->buffer); } -static uint32_t read_unixpipe(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t read_unixpipe(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { struct unix_pipe * self = node->device; size_t read = 0; @@ -46,14 +54,14 @@ static uint32_t read_unixpipe(fs_node_t * node, uint64_t offset, uint32_t size, return read; } -static uint32_t write_unixpipe(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t write_unixpipe(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t *buffer) { struct unix_pipe * self = node->device; size_t written = 0; while (written < size) { if (self->read_closed) { /* SIGPIPE to current process */ - send_signal(getpid(), SIGPIPE, 1); + send_signal(this_core->current_process->id, SIGPIPE, 1); return written; } @@ -67,12 +75,8 @@ static uint32_t write_unixpipe(fs_node_t * node, uint64_t offset, uint32_t size, static void close_read_pipe(fs_node_t * node) { struct unix_pipe * self = node->device; - debug_print(NOTICE, "Closing read end of pipe."); - self->read_closed = 1; - if (self->write_closed) { - debug_print(NOTICE, "Both ends now closed, should clean up."); - } else { + if (!self->write_closed) { ring_buffer_interrupt(self->buffer); } } @@ -80,12 +84,8 @@ static void close_read_pipe(fs_node_t * node) { static void close_write_pipe(fs_node_t * node) { struct unix_pipe * self = node->device; - debug_print(NOTICE, "Closing write end of pipe."); - self->write_closed = 1; - if (self->read_closed) { - debug_print(NOTICE, "Both ends now closed, should clean up."); - } else { + if (!self->read_closed) { ring_buffer_interrupt(self->buffer); if (!ring_buffer_unread(self->buffer)) { ring_buffer_alert_waiters(self->buffer); @@ -118,8 +118,8 @@ int make_unix_pipe(fs_node_t ** pipes) { memset(pipes[0], 0, sizeof(fs_node_t)); memset(pipes[1], 0, sizeof(fs_node_t)); - sprintf(pipes[0]->name, "[pipe:read]"); - sprintf(pipes[1]->name, "[pipe:write]"); + snprintf(pipes[0]->name, 100, "[pipe:read]"); + snprintf(pipes[1]->name, 100, "[pipe:write]"); pipes[0]->mask = 0666; pipes[1]->mask = 0666; diff --git a/kernel/fs/vfs.c b/kernel/vfs/vfs.c similarity index 85% rename from kernel/fs/vfs.c rename to kernel/vfs/vfs.c index 6dcbab55..91cf4716 100644 --- a/kernel/fs/vfs.c +++ b/kernel/vfs/vfs.c @@ -1,21 +1,29 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/vfs.c + * @brief Virtual file system. + * + * Provides the high-level generic operations for the VFS. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange + * Copyright (C) 2011-2021 K. Lange * Copyright (C) 2014 Lioncash * Copyright (C) 2012 Tianyi Wang - * - * Virtual File System - * */ -#include -#include +#include +#include +#include #include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include #define MAX_SYMLINK_DEPTH 8 #define MAX_SYMLINK_SIZE 4096 @@ -25,21 +33,26 @@ fs_node_t * fs_root = NULL; /* Pointer to the root mount fs_node (must be some f hashmap_t * fs_types = NULL; +#define MIN(l,r) ((l) < (r) ? (l) : (r)) +#define MAX(l,r) ((l) > (r) ? (l) : (r)) + +#define debug_print(x, ...) do { if (0) {printf("vfs.c [%s] ", #x); printf(__VA_ARGS__); printf("\n"); } } while (0) + int has_permission(fs_node_t * node, int permission_bit) { if (!node) return 0; - if (current_process->user == 0 && permission_bit != 01) { /* even root needs exec to exec */ + if (this_core->current_process->user == 0 && permission_bit != 01) { /* even root needs exec to exec */ return 1; } - uint32_t permissions = node->mask; + uint64_t permissions = node->mask; uint8_t user_perm = (permissions >> 6) & 07; //uint8_t group_perm = (permissions >> 3) & 07; uint8_t other_perm = (permissions) & 07; - if (current_process->user == node->uid) { + if (this_core->current_process->user == node->uid) { return (permission_bit & user_perm); /* TODO group permissions? */ } else { @@ -48,7 +61,7 @@ int has_permission(fs_node_t * node, int permission_bit) { } -static struct dirent * readdir_mapper(fs_node_t *node, uint32_t index) { +static struct dirent * readdir_mapper(fs_node_t *node, uint64_t index) { tree_node_t * d = (tree_node_t *)node->device; if (!d) return NULL; @@ -98,7 +111,7 @@ static fs_node_t * vfs_mapper(void) { } /** - * selectcheck_fs: Check if a read from this file would block. + * @brief Check if a read from this file would block. */ int selectcheck_fs(fs_node_t * node) { if (!node) return -ENOENT; @@ -111,7 +124,7 @@ int selectcheck_fs(fs_node_t * node) { } /** - * selectwait_fs: Inform a node that it should alert the current_process. + * @brief Inform a node that it should alert the current_process. */ int selectwait_fs(fs_node_t * node, void * process) { if (!node) return -ENOENT; @@ -124,7 +137,7 @@ int selectwait_fs(fs_node_t * node, void * process) { } /** - * read_fs: Read a file system node based on its underlying type. + * @brief Read a file system node based on its underlying type. * * @param node Node to read * @param offset Offset into the node data to read from @@ -132,11 +145,11 @@ int selectwait_fs(fs_node_t * node, void * process) { * @param buffer A buffer to copy of the read data into * @returns Bytes read */ -uint32_t read_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t read_fs(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { if (!node) return -ENOENT; if (node->read) { - uint32_t ret = node->read(node, offset, size, buffer); + uint64_t ret = node->read(node, offset, size, buffer); return ret; } else { return -EINVAL; @@ -144,7 +157,7 @@ uint32_t read_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffe } /** - * write_fs: Write a file system node based on its underlying type. + * @brief Write a file system node based on its underlying type. * * @param node Node to write to * @param offset Offset into the node data to write to @@ -152,11 +165,11 @@ uint32_t read_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffe * @param buffer A buffer to copy from * @returns Bytes written */ -uint32_t write_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +uint64_t write_fs(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { if (!node) return -ENOENT; if (node->write) { - uint32_t ret = node->write(node, offset, size, buffer); + uint64_t ret = node->write(node, offset, size, buffer); return ret; } else { return -EROFS; @@ -164,7 +177,7 @@ uint32_t write_fs(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buff } /** - * truncate_fs: set the size of a file to 9 + * @brief set the size of a file to 9 * * @param node File to resize */ @@ -186,7 +199,7 @@ void vfs_lock(fs_node_t * node) { } /** - * open_fs: Open a file system node. + * @brief Open a file system node. * * @param node Node to open * @param flags Same as open, specifies read/write/append/truncate @@ -207,12 +220,12 @@ void open_fs(fs_node_t *node, unsigned int flags) { } /** - * close_fs: Close a file system node + * @brief Close a file system node * * @param node Node to close */ void close_fs(fs_node_t *node) { - assert(node != fs_root && "Attempted to close the filesystem root. kablooey"); + //assert(node != fs_root && "Attempted to close the filesystem root. kablooey"); if (!node) { debug_print(WARNING, "Double close? This isn't an fs_node."); @@ -224,7 +237,7 @@ void close_fs(fs_node_t *node) { spin_lock(tmp_refcount_lock); node->refcount--; if (node->refcount == 0) { - debug_print(NOTICE, "Node refcount [%s] is now 0: %d", node->name, node->refcount); + debug_print(NOTICE, "Node refcount [%s] is now 0: %ld", node->name, node->refcount); if (node->close) { node->close(node); @@ -236,7 +249,10 @@ void close_fs(fs_node_t *node) { } /** - * chmod_fs + * @brief Change permissions for a file system node. + * + * @param node Node to change permissions for + * @param mode New mode bits */ int chmod_fs(fs_node_t *node, int mode) { if (node->chmod) { @@ -246,7 +262,7 @@ int chmod_fs(fs_node_t *node, int mode) { } /** - * chown_fs + * @brief Change ownership for a file system node. */ int chown_fs(fs_node_t *node, int uid, int gid) { if (node->chown) { @@ -256,13 +272,13 @@ int chown_fs(fs_node_t *node, int uid, int gid) { } /** - * readdir_fs: Read a directory for the requested index + * @brief Read a directory for the requested index * * @param node Directory to read * @param index Offset to look for * @returns A dirent object. */ -struct dirent *readdir_fs(fs_node_t *node, uint32_t index) { +struct dirent *readdir_fs(fs_node_t *node, uint64_t index) { if (!node) return NULL; if ((node->flags & FS_DIRECTORY) && node->readdir) { @@ -274,7 +290,7 @@ struct dirent *readdir_fs(fs_node_t *node, uint32_t index) { } /** - * finddir_fs: Find the requested file in the directory and return an fs_node for it + * @brief Find the requested file in the directory and return an fs_node for it * * @param node Directory to search * @param name File to look for @@ -288,13 +304,13 @@ fs_node_t *finddir_fs(fs_node_t *node, char *name) { return ret; } else { debug_print(WARNING, "Node passed to finddir_fs isn't a directory!"); - debug_print(WARNING, "node = 0x%x, name = %s", node, name); + debug_print(WARNING, "node = %p, name = %s", (void*)node, name); return (fs_node_t *)NULL; } } /** - * ioctl_fs: Control Device + * @brief Control Device * * @param node Device node to control * @param request Device-specific request code @@ -321,11 +337,11 @@ int ioctl_fs(fs_node_t *node, int request, void * argp) { int create_file_fs(char *name, uint16_t permission) { fs_node_t * parent; - char *cwd = (char *)(current_process->wd_name); + char *cwd = (char *)(this_core->current_process->wd_name); char *path = canonicalize_path(cwd, name); - char * parent_path = malloc(strlen(path) + 4); - sprintf(parent_path, "%s/..", path); + char * parent_path = malloc(strlen(path) + 5); + snprintf(parent_path, strlen(path) + 4, "%s/..", path); char * f_path = path + strlen(path) - 1; while (f_path > path) { @@ -371,11 +387,11 @@ int create_file_fs(char *name, uint16_t permission) { int unlink_fs(char * name) { fs_node_t * parent; - char *cwd = (char *)(current_process->wd_name); + char *cwd = (char *)(this_core->current_process->wd_name); char *path = canonicalize_path(cwd, name); - char * parent_path = malloc(strlen(path) + 4); - sprintf(parent_path, "%s/..", path); + char * parent_path = malloc(strlen(path) + 5); + snprintf(parent_path, strlen(path) + 4, "%s/..", path); char * f_path = path + strlen(path) - 1; while (f_path > path) { @@ -420,15 +436,15 @@ int unlink_fs(char * name) { int mkdir_fs(char *name, uint16_t permission) { fs_node_t * parent; - char *cwd = (char *)(current_process->wd_name); + char *cwd = (char *)(this_core->current_process->wd_name); char *path = canonicalize_path(cwd, name); if (!name || !strlen(name)) { return -EINVAL; } - char * parent_path = malloc(strlen(path) + 4); - sprintf(parent_path, "%s/..", path); + char * parent_path = malloc(strlen(path) + 5); + snprintf(parent_path, strlen(path) + 4, "%s/..", path); char * f_path = path + strlen(path) - 1; while (f_path > path) { @@ -498,11 +514,11 @@ fs_node_t *clone_fs(fs_node_t *source) { int symlink_fs(char * target, char * name) { fs_node_t * parent; - char *cwd = (char *)(current_process->wd_name); + char *cwd = (char *)(this_core->current_process->wd_name); char *path = canonicalize_path(cwd, name); - char * parent_path = malloc(strlen(path) + 4); - sprintf(parent_path, "%s/..", path); + char * parent_path = malloc(strlen(path) + 5); + snprintf(parent_path, strlen(path) + 4, "%s/..", path); char * f_path = path + strlen(path) - 1; while (f_path > path) { @@ -536,7 +552,7 @@ int symlink_fs(char * target, char * name) { return ret; } -int readlink_fs(fs_node_t *node, char * buf, uint32_t size) { +int readlink_fs(fs_node_t *node, char * buf, uint64_t size) { if (!node) return -ENOENT; if (node->readlink) { @@ -548,15 +564,15 @@ int readlink_fs(fs_node_t *node, char * buf, uint32_t size) { /** - * canonicalize_path: Canonicalize a path. + * @brief Canonicalize a path. * * @param cwd Current working directory * @param input Path to append or canonicalize on * @returns An absolute path string */ -char *canonicalize_path(char *cwd, char *input) { +char *canonicalize_path(const char *cwd, const char *input) { /* This is a stack-based canonicalizer; we use a list as a stack */ - list_t *out = list_create(); + list_t *out = list_create("vfs canonicalize_path working memory",input); /* * If we have a relative path, we need to canonicalize @@ -680,13 +696,13 @@ void vfs_install(void) { fs_types = hashmap_create(5); } -int vfs_register(char * name, vfs_mount_callback callback) { +int vfs_register(const char * name, vfs_mount_callback callback) { if (hashmap_get(fs_types, name)) return 1; hashmap_set(fs_types, name, (void *)(uintptr_t)callback); return 0; } -int vfs_mount_type(char * type, char * arg, char * mountpoint) { +int vfs_mount_type(const char * type, const char * arg, const char * mountpoint) { vfs_mount_callback t = (vfs_mount_callback)(uintptr_t)hashmap_get(fs_types, type); if (!t) { @@ -705,17 +721,17 @@ int vfs_mount_type(char * type, char * arg, char * mountpoint) { ent->device = strdup(arg); } - debug_print(NOTICE, "Mounted %s[%s] to %s: 0x%x", type, arg, mountpoint, n); + debug_print(NOTICE, "Mounted %s[%s] to %s: %p", type, arg, mountpoint, (void*)n); debug_print_vfs_tree(); return 0; } -//volatile uint8_t tmp_vfs_lock = 0; static spin_lock_t tmp_vfs_lock = { 0 }; /** - * vfs_mount - Mount a file system to the specified path. + * @brief Mount a file system to the specified path. * + * Mounts a file system node to a given base path. * For example, if we have an EXT2 filesystem with a root node * of ext2_root and we want to mount it to /, we would run * vfs_mount("/", ext2_root); - or, if we have a procfs node, @@ -724,7 +740,7 @@ static spin_lock_t tmp_vfs_lock = { 0 }; * * Paths here must be absolute. */ -void * vfs_mount(char * path, fs_node_t * local_root) { +void * vfs_mount(const char * path, fs_node_t * local_root) { if (!fs_tree) { debug_print(ERROR, "VFS hasn't been initialized, you can't mount things yet!"); return NULL; @@ -812,9 +828,9 @@ void * vfs_mount(char * path, fs_node_t * local_root) { return ret_val; } -void map_vfs_directory(char * c) { +void map_vfs_directory(const char * c) { fs_node_t * f = vfs_mapper(); - struct vfs_entry * e = vfs_mount(c, f); + struct vfs_entry * e = vfs_mount((char*)c, f); if (!strcmp(c, "/")) { f->device = fs_tree->root; } else { @@ -831,15 +847,15 @@ void debug_print_vfs_tree_node(tree_node_t * node, size_t height) { char * c = tmp; /* Indent output */ for (uint32_t i = 0; i < height; ++i) { - c += sprintf(c, " "); + c += snprintf(c, 3, " "); } /* Get the current process */ struct vfs_entry * fnode = (struct vfs_entry *)node->value; /* Print the process name */ if (fnode->file) { - c += sprintf(c, "%s → %s 0x%x (%s, %s)", fnode->name, fnode->device, fnode->file, fnode->fs_type, fnode->file->name); + c += snprintf(c, 100, "%s → %s %p (%s, %s)", fnode->name, fnode->device, (void*)fnode->file, fnode->fs_type, fnode->file->name); } else { - c += sprintf(c, "%s → (empty)", fnode->name); + c += snprintf(c, 100, "%s → (empty)", fnode->name); } /* Linefeed */ debug_print(NOTICE, "%s", tmp); @@ -912,7 +928,7 @@ fs_node_t *get_mount_point(char * path, unsigned int path_depth, char **outpath, -fs_node_t *kopen_recur(char *filename, uint32_t flags, uint32_t symlink_depth, char *relative_to) { +fs_node_t *kopen_recur(const char *filename, uint64_t flags, uint64_t symlink_depth, char *relative_to) { /* Simple sanity checks that we actually have a file system */ if (!filename) { return NULL; @@ -940,7 +956,7 @@ fs_node_t *kopen_recur(char *filename, uint32_t flags, uint32_t symlink_depth, c /* Otherwise, we need to break the path up and start searching */ char *path_offset = path; - uint32_t path_depth = 0; + uint64_t path_depth = 0; while (path_offset < path + path_len) { /* Find each PATH_SEPARATOR */ if (*path_offset == PATH_SEPARATOR) { @@ -1069,7 +1085,7 @@ fs_node_t *kopen_recur(char *filename, uint32_t flags, uint32_t symlink_depth, c } /** - * kopen: Open a file by name. + * @brief Open a file by name. * * Explore the file system tree to find the appropriate node for * for a given path. The path can be relative to the working directory @@ -1079,9 +1095,9 @@ fs_node_t *kopen_recur(char *filename, uint32_t flags, uint32_t symlink_depth, c * @param flags Flag bits for read/write mode. * @returns A file system node element that the caller can free. */ -fs_node_t *kopen(char *filename, uint32_t flags) { +fs_node_t *kopen(const char *filename, uint64_t flags) { debug_print(NOTICE, "kopen(%s)", filename); - return kopen_recur(filename, flags, 0, (char *)(current_process->wd_name)); + return kopen_recur(filename, flags, 0, (char *)(this_core->current_process->wd_name)); } diff --git a/modules/zero.c b/kernel/vfs/zero.c similarity index 70% rename from modules/zero.c rename to kernel/vfs/zero.c index f6da35bc..9c79958d 100644 --- a/modules/zero.c +++ b/kernel/vfs/zero.c @@ -1,21 +1,24 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab +/** + * @file kernel/vfs/zero.c + * @brief /dev/null and /dev/zero provider. + * + * @copyright * This file is part of ToaruOS and is released under the terms * of the NCSA / University of Illinois License - see LICENSE.md * Copyright (C) 2014-2018 K. Lange - * - * Null Device - * */ -#include -#include -#include +#include +#include +#include +#include +#include -static uint32_t read_null(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t read_null(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { return 0; } -static uint32_t write_null(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t write_null(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { return 0; } @@ -27,12 +30,12 @@ static void close_null(fs_node_t * node) { return; } -static uint32_t read_zero(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t read_zero(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { memset(buffer, 0x00, size); return 1; } -static uint32_t write_zero(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { +static uint64_t write_zero(fs_node_t *node, uint64_t offset, uint64_t size, uint8_t *buffer) { return 0; } @@ -82,15 +85,8 @@ static fs_node_t * zero_device_create(void) { return fnode; } -static int zero_initialize(void) { +void zero_initialize(void) { vfs_mount("/dev/null", null_device_create()); vfs_mount("/dev/zero", zero_device_create()); - return 0; } -static int zero_finalize(void) { - return 0; -} - - -MODULE_DEF(zero, zero_initialize, zero_finalize); diff --git a/modules/lfbvideo.c b/kernel/video/lfbvideo.c similarity index 50% rename from modules/lfbvideo.c rename to kernel/video/lfbvideo.c index b91cb296..b3c296d0 100644 --- a/modules/lfbvideo.c +++ b/kernel/video/lfbvideo.c @@ -1,31 +1,33 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange +/** + * @file kernel/video/lfbvideo.c + * @brief Shared linear framebuffer drivers for qemu/bochs/vbox, vmware, + * and platforms that can modeset in the bootloader. * - * Generic linear framebuffer driver. - * - * Supports several cases: - * - Bochs/QEMU/VirtualBox "Bochs VBE" with modesetting. - * - VMware SVGA with modesetting. - * - Linear framebuffers set by the bootloader with no modesetting. + * Detects a small set of video devices that can be configured with simple + * port writes and provides a runtime modesetting API for them. For other + * devices, provides framebuffer mapping and resolution querying for modes + * that have been preconfigured by the bootloader. */ - -#include -#include -#include +#include #include -#include +#include +#include #include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include -#define PREFERRED_W 1024 -#define PREFERRED_H 768 +/* FIXME: Not sure what to do with this; ifdef around it? */ +#include + +static int PREFERRED_W = 1440; +static int PREFERRED_H = 900; #define PREFERRED_VY 4096 #define PREFERRED_B 32 @@ -35,10 +37,11 @@ uint16_t lfb_resolution_y = 0; uint16_t lfb_resolution_b = 0; uint32_t lfb_resolution_s = 0; uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000; +size_t lfb_memsize = 0xFF0000; const char * lfb_driver_name = NULL; -static fs_node_t * lfb_device = NULL; -static int lfb_init(char * c); +fs_node_t * lfb_device = NULL; +static int lfb_init(const char * c); /* Where to send display size change signals */ static pid_t display_change_recipient = 0; @@ -52,11 +55,13 @@ void lfb_set_resolution(uint16_t x, uint16_t y) { lfb_resolution_impl(x,y); if (display_change_recipient) { send_signal(display_change_recipient, SIGWINEVENT, 1); - debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient); } } } +extern void ptr_validate(void * ptr, const char * syscall); +#define validate(o) ptr_validate(o,"ioctl") + /** * Framebuffer control ioctls. * Used by the compositor to get display sizes and by the @@ -87,11 +92,25 @@ static int ioctl_vid(fs_node_t * node, int request, void * argp) { case IO_VID_ADDR: /* Get framebuffer address - TODO: map the framebuffer? */ validate(argp); - *((uintptr_t *)argp) = (uintptr_t)lfb_vid_memory; + { + uintptr_t lfb_user_offset; + if (*(uintptr_t*)argp == 0) { + /* Pick an address and map it */ + lfb_user_offset = 0x100000000; /* at 4GiB seems good */ + } else { + validate((void*)(*(uintptr_t*)argp)); + lfb_user_offset = *(uintptr_t*)argp; + } + for (uintptr_t i = 0; i < lfb_memsize; i += 0x1000) { + union PML * page = mmu_get_page(lfb_user_offset + i, MMU_GET_MAKE); + mmu_frame_map_address(page,MMU_FLAG_WRITABLE|MMU_FLAG_WC,((uintptr_t)(lfb_vid_memory) & 0xFFFFFFFF) + i); + } + *((uintptr_t *)argp) = lfb_user_offset; + } return 0; case IO_VID_SIGNAL: /* ioctl to register for a signal (vid device change? idk) on display change */ - display_change_recipient = getpid(); + display_change_recipient = this_core->current_process->id; return 0; case IO_VID_SET: /* Initiate mode setting */ @@ -103,7 +122,7 @@ static int ioctl_vid(fs_node_t * node, int request, void * argp) { memcpy(argp, lfb_driver_name, strlen(lfb_driver_name)); return 0; case IO_VID_REINIT: - if (current_process->user != 0) { + if (this_core->current_process->user != 0) { return -EPERM; } validate(argp); @@ -111,13 +130,14 @@ static int ioctl_vid(fs_node_t * node, int request, void * argp) { default: return -EINVAL; } + return -EINVAL; } /* Framebuffer device file initializer */ static fs_node_t * lfb_video_device_create(void /* TODO */) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); - sprintf(fnode->name, "fb0"); /* TODO */ + snprintf(fnode->name, 100, "fb0"); /* TODO */ fnode->length = 0; fnode->flags = FS_BLOCKDEVICE; /* Framebuffers are block devices */ fnode->mask = 0660; /* Only accessible to root user/group */ @@ -125,113 +145,17 @@ static fs_node_t * lfb_video_device_create(void /* TODO */) { return fnode; } -/** - * Framebuffer fatal error presentation. - * - * This is called by a kernel hook to render fatal error messages - * (panic / oops / bsod) to the graphraical framebuffer. Mostly, - * that means the "out of memory" error. Bescause this is a fatal - * error condition, we don't care much about speed, so we can do - * silly things like ready from the framebuffer, which we do to - * produce a vignetting and desaturation effect. - */ -static int vignette_at(int x, int y) { - int amount = 0; - int level = 100; - if (x < level) amount += (level - x); - if (x > lfb_resolution_x - level) amount += (level - (lfb_resolution_x - x)); - if (y < level) amount += (level - y); - if (y > lfb_resolution_y - level) amount += (level - (lfb_resolution_y - y)); - return amount; -} - -#include "../apps/terminal-font.h" - -/* XXX Why is this not defined in the font header... */ -#define char_height 20 -#define char_width 9 - -/* Set point in framebuffer */ -static void set_point(int x, int y, uint32_t value) { - uint32_t * disp = (uint32_t *)lfb_vid_memory; - uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x]; - *cell = value; -} - -/* Draw text on framebuffer */ -static void write_char(int x, int y, int val, uint32_t color) { - if (val > 128) { - val = 4; - } - uint16_t * c = large_font[val]; - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - if (c[i] & (1 << (15-j))) { - set_point(x+j,y+i,color); - } - } - } -} - -#define _RED(color) ((color & 0x00FF0000) / 0x10000) -#define _GRE(color) ((color & 0x0000FF00) / 0x100) -#define _BLU(color) ((color & 0x000000FF) / 0x1) -#define _ALP(color) ((color & 0xFF000000) / 0x1000000) -static void lfb_video_panic(char ** msgs) { - /* Desaturate the display */ - uint32_t * disp = (uint32_t *)lfb_vid_memory; - for (int y = 0; y < lfb_resolution_y; y++) { - for (int x = 0; x < lfb_resolution_x; x++) { - uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x]; - - int r = _RED(*cell); - int g = _GRE(*cell); - int b = _BLU(*cell); - - int l = 3 * r + 6 * g + 1 * b; - r = (l) / 10; - g = (l) / 10; - b = (l) / 10; - - r = r > 255 ? 255 : r; - g = g > 255 ? 255 : g; - b = b > 255 ? 255 : b; - - int amount = vignette_at(x,y); - r = (r - amount < 0) ? 0 : r - amount; - g = (g - amount < 0) ? 0 : g - amount; - b = (b - amount < 0) ? 0 : b - amount; - - *cell = 0xFF000000 + ((0xFF & r) * 0x10000) + ((0xFF & g) * 0x100) + ((0xFF & b) * 0x1); - } - } - - /* Now print the message, divided on line feeds, into the center of the screen */ - int num_entries = 0; - for (char ** m = msgs; *m; m++, num_entries++); - int y = (lfb_resolution_y - (num_entries * char_height)) / 2; - for (char ** message = msgs; *message; message++) { - int x = (lfb_resolution_x - (strlen(*message) * char_width)) / 2; - for (char * c = *message; *c; c++) { - write_char(x+1, y+1, *c, 0xFF000000); - write_char(x, y, *c, 0xFFFF0000); - x += char_width; - } - y += char_height; - } -} - -static uint32_t framebuffer_func(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { +static uint64_t framebuffer_func(fs_node_t * node, uint64_t offset, uint64_t size, uint8_t * buffer) { char * buf = malloc(4096); if (lfb_driver_name) { - sprintf(buf, + snprintf(buf, 4095, "Driver:\t%s\n" "XRes:\t%d\n" "YRes:\t%d\n" "BitsPerPixel:\t%d\n" "Stride:\t%d\n" - "Address:\t0x%x\n", + "Address:\t%p\n", lfb_driver_name, lfb_resolution_x, lfb_resolution_y, @@ -239,7 +163,7 @@ static uint32_t framebuffer_func(fs_node_t * node, uint64_t offset, uint32_t siz lfb_resolution_s, lfb_vid_memory); } else { - sprintf(buf, "Driver:\tnone\n"); + snprintf(buf, 20, "Driver:\tnone\n"); } size_t _bsize = strlen(buf); @@ -264,13 +188,8 @@ static struct procfs_entry framebuffer_entry = { static void finalize_graphics(const char * driver) { lfb_driver_name = driver; lfb_device->length = lfb_resolution_s * lfb_resolution_y; /* Size is framebuffer size in bytes */ - debug_video_crash = lfb_video_panic; - int (*procfs_install)(struct procfs_entry *) = (int (*)(struct procfs_entry *))(uintptr_t)hashmap_get(modules_get_symbols(),"procfs_install"); - - if (procfs_install) { - procfs_install(&framebuffer_entry); - } + procfs_install(&framebuffer_entry); } /* Bochs support {{{ */ @@ -280,7 +199,7 @@ static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra (v == 0x10de && d == 0x0a20)) { uintptr_t t = pci_read_field(device, PCI_BAR0, 4); if (t > 0) { - *((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0); + *((uint8_t **)extra) = mmu_map_from_physical(t & 0xFFFFFFF0); } } } @@ -318,8 +237,6 @@ static void bochs_set_resolution(uint16_t x, uint16_t y) { } static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) { - uint32_t vid_memsize; - debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller..."); outports(0x1CE, 0x00); uint16_t i = inports(0x1CF); @@ -336,99 +253,38 @@ static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) lfb_resolution_impl = &bochs_set_resolution; if (!lfb_vid_memory) { - debug_print(ERROR, "Failed to locate video memory."); + printf("failed to locate video memory\n"); return; } - /* Enable the higher memory */ - uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; - for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { - page_t * p = get_page(i, 1, kernel_directory); - dma_frame(p, 0, 1, i); - p->pat = 1; - p->writethrough = 1; - p->cachedisable = 1; - } - outports(0x1CE, 0x0a); i = inports(0x1CF); if (i > 1) { - vid_memsize = (uint32_t)i * 64 * 1024; + lfb_memsize = (uint32_t)i * 64 * 1024; } else { - vid_memsize = inportl(0x1CF); - } - debug_print(WARNING, "Video memory size is 0x%x", vid_memsize); - for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + vid_memsize; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + lfb_memsize = inportl(0x1CF); } finalize_graphics("bochs"); } +extern struct multiboot * mboot_struct; + static void graphics_install_preset(uint16_t w, uint16_t h) { - if (!(mboot_ptr && (mboot_ptr->flags & (1 << 12)))) { - debug_print(ERROR, "Failed to locate preset video memory - missing multiboot header."); - return; - } - /* Extract framebuffer information from multiboot */ - lfb_vid_memory = (void *)mboot_ptr->framebuffer_addr; - lfb_resolution_x = mboot_ptr->framebuffer_width; - lfb_resolution_y = mboot_ptr->framebuffer_height; - lfb_resolution_s = mboot_ptr->framebuffer_pitch; + lfb_vid_memory = mmu_map_from_physical(mboot_struct->framebuffer_addr); + lfb_resolution_x = mboot_struct->framebuffer_width; + lfb_resolution_y = mboot_struct->framebuffer_height; + lfb_resolution_s = mboot_struct->framebuffer_pitch; lfb_resolution_b = 32; - - debug_print(WARNING, "Mode was set by bootloader: %dx%d bpp should be 32, framebuffer is at 0x%x", w, h, (uintptr_t)lfb_vid_memory); - - for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + w * h * 4; i += 0x1000) { - page_t * p = get_page(i, 1, kernel_directory); - dma_frame(p, 0, 1, i); - p->pat = 1; - p->writethrough = 1; - p->cachedisable = 1; - } finalize_graphics("preset"); } -static void graphics_install_kludge(uint16_t w, uint16_t h) { - uint32_t * herp = (uint32_t *)0xA0000; - herp[0] = 0xA5ADFACE; - herp[1] = 0xFAF42943; - - for (int i = 2; i < 1000; i += 2) { - herp[i] = 0xFF00FF00; - herp[i+1] = 0x00FF00FF; +static void check_multiboot(void) { + if ((mboot_struct->flags & MULTIBOOT_FLAG_FB) && (mboot_struct->framebuffer_width)) { + PREFERRED_W = mboot_struct->framebuffer_width; + PREFERRED_H = mboot_struct->framebuffer_height; } - - for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) { - /* Enable the higher memory */ - for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { - dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); - } - - /* Go find it */ - for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) { - if (((uintptr_t *)x)[0] == 0xA5ADFACE && ((uintptr_t *)x)[1] == 0xFAF42943) { - lfb_vid_memory = (uint8_t *)x; - debug_print(INFO, "Had to futz around, but found video memory at 0x%x", lfb_vid_memory); - goto mem_found; - } - } - } -mem_found: - lfb_resolution_x = w; - lfb_resolution_y = h; - lfb_resolution_s = w * 4; - lfb_resolution_b = 32; - - for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + w * h * 4; i += 0x1000) { - page_t * p = get_page(i, 1, kernel_directory); - dma_frame(p, 0, 1, i); - p->pat = 1; - p->writethrough = 1; - p->cachedisable = 1; - } - finalize_graphics("kludge"); } #define SVGA_IO_BASE (vmware_io) @@ -485,32 +341,23 @@ static void graphics_install_vmware(uint16_t w, uint16_t h) { pci_scan(vmware_scan_pci, -1, &vmware_io); if (!vmware_io) { - debug_print(ERROR, "No vmware device found?"); + printf("vmware video, but no device found?\n"); return; } else { - debug_print(WARNING, "vmware io base: 0x%x", vmware_io); + printf("vmware io base: %p\n", (void*)(uintptr_t)vmware_io); } vmware_set_resolution(w,h); lfb_resolution_impl = &vmware_set_resolution; - uint32_t fb_addr = vmware_read(SVGA_REG_FB_START); - debug_print(WARNING, "vmware fb address: 0x%x", fb_addr); + uintptr_t fb_addr = vmware_read(SVGA_REG_FB_START); + printf("vmware fb address: %p\n", (void*)fb_addr); - uint32_t fb_size = vmware_read(15); + size_t fb_size = vmware_read(15); - debug_print(WARNING, "vmware fb size: 0x%x", fb_size); + printf("vmware fb size: 0x%lx\n", fb_size); - lfb_vid_memory = (uint8_t *)fb_addr; - - uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; - for (uintptr_t i = fb_offset; i <= fb_offset + fb_size; i += 0x1000) { - page_t * p = get_page(i, 1, kernel_directory); - dma_frame(p, 0, 1, i); - p->pat = 1; - p->writethrough = 1; - p->cachedisable = 1; - } + lfb_vid_memory = mmu_map_from_physical(fb_addr); finalize_graphics("vmware"); } @@ -535,13 +382,14 @@ static void auto_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) } } -static int lfb_init(char * c) { +static int lfb_init(const char * c) { char * arg = strdup(c); char * argv[10]; int argc = tokenize(arg, ",", argv); uint16_t x, y; if (argc < 3) { + check_multiboot(); x = PREFERRED_W; y = PREFERRED_H; } else { @@ -552,7 +400,6 @@ static int lfb_init(char * c) { int ret_val = 0; if (!strcmp(argv[0], "auto")) { /* Attempt autodetection */ - debug_print(NOTICE, "Automatically detecting display driver..."); struct disp_mode mode = {x,y,0}; pci_scan(auto_scan_pci, -1, &mode); if (!mode.set) { @@ -567,11 +414,7 @@ static int lfb_init(char * c) { } else if (!strcmp(argv[0],"preset")) { /* Set by bootloader (UEFI) */ graphics_install_preset(x,y); - } else if (!strcmp(argv[0],"kludge")) { - /* Old hack to find vid memory from the VGA window */ - graphics_install_kludge(x,y); } else { - debug_print(WARNING, "Unrecognized video adapter: %s", argv[0]); ret_val = 1; } @@ -579,26 +422,11 @@ static int lfb_init(char * c) { return ret_val; } -static int init(void) { - - if (mboot_ptr->vbe_mode_info) { - lfb_vid_memory = (uint8_t *)((vbe_info_t *)(mboot_ptr->vbe_mode_info))->physbase; - } - +int framebuffer_initialize(void) { lfb_device = lfb_video_device_create(); + lfb_init(args_present("vid") ? args_value("vid") : "auto"); vfs_mount("/dev/fb0", lfb_device); - char * c; - if ((c = args_value("vid"))) { - debug_print(NOTICE, "Video mode requested: %s", c); - lfb_init(c); - } - return 0; } -static int fini(void) { - return 0; -} - -MODULE_DEF(lfbvideo, init, fini); diff --git a/kuroko b/kuroko index 567a0037..d859ac50 160000 --- a/kuroko +++ b/kuroko @@ -1 +1 @@ -Subproject commit 567a0037319fb8d65a990aa31de3a6051bd91cd4 +Subproject commit d859ac50928f2f3be54b3308a56c9284ff5c7bc5 diff --git a/lib/decorations.c b/lib/decorations.c index cb49c431..de9a56bc 100644 --- a/lib/decorations.c +++ b/lib/decorations.c @@ -254,7 +254,7 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { case YUTANI_MSG_WINDOW_MOUSE_EVENT: { struct yutani_msg_window_mouse_event * me = (void*)m->data; - yutani_window_t * window = hashmap_get(yctx->windows, (void*)me->wid); + yutani_window_t * window = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid); struct decor_bounds bounds; decor_get_bounds(window, &bounds); if (!window) return 0; diff --git a/lib/graphics.c b/lib/graphics.c index ed1ac95a..304d1457 100644 --- a/lib/graphics.c +++ b/lib/graphics.c @@ -96,6 +96,7 @@ static int framebuffer_fd = 0; gfx_context_t * init_graphics_fullscreen() { gfx_context_t * out = malloc(sizeof(gfx_context_t)); out->clips = NULL; + out->buffer = NULL; if (!framebuffer_fd) { framebuffer_fd = open("/dev/fb0", 0, 0); @@ -770,8 +771,8 @@ uint32_t getBilinearFilteredPixelColor(sprite_t * tex, double u, double v) { int y = floor(v); if (x >= tex->width) return 0; if (y >= tex->height) return 0; - if (x <= 0) return 0; - if (y <= 0) return 0; + if (x < 0) return 0; + if (y < 0) return 0; double u_ratio = u - x; double v_ratio = v - y; double u_o = 1 - u_ratio; @@ -946,10 +947,10 @@ void draw_rounded_rectangle(gfx_context_t * ctx, int32_t x, int32_t y, uint16_t } GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), c); - GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c); + if (_z >= 0) GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c); _x = x + radius - i - 1; GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), c); - GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c); + if (_z >= 0) GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), c); } } } @@ -989,10 +990,10 @@ void draw_rounded_rectangle_pattern(gfx_context_t * ctx, int32_t x, int32_t y, u double alpha = (j_max - (double)j); GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), pattern(_x,_y,alpha,extra)); - GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), pattern(_x,_z,alpha,extra)); + if (_z >= 0) GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), pattern(_x,_z,alpha,extra)); _x = x + radius - i - 1; GFX(ctx, _x, _y) = alpha_blend_rgba(GFX(ctx, _x, _y), pattern(_x,_y,alpha,extra)); - GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), pattern(_x,_z,alpha,extra)); + if (_z >= 0) GFX(ctx, _x, _z) = alpha_blend_rgba(GFX(ctx, _x, _z), pattern(_x,_z,alpha,extra)); } } } diff --git a/lib/hashmap.c b/lib/hashmap.c index 5307efa3..a0fec5bd 100644 --- a/lib/hashmap.c +++ b/lib/hashmap.c @@ -28,11 +28,11 @@ void * hashmap_string_dupe(void * key) { } unsigned int hashmap_int_hash(void * key) { - return (unsigned int)key; + return (uintptr_t)key; } int hashmap_int_comp(void * a, void * b) { - return (int)a == (int)b; + return (uintptr_t)a == (uintptr_t)b; } void * hashmap_int_dupe(void * key) { diff --git a/lib/jpeg.c b/lib/jpeg.c index f643afe4..4ca32b22 100644 --- a/lib/jpeg.c +++ b/lib/jpeg.c @@ -135,8 +135,12 @@ static void baseline_dct(FILE * f, int len) { fread(&dct, sizeof(struct dct), 1, f); /* Read image dimensions, each as big-endian 16-bit values */ - swap16(&dct.height); - swap16(&dct.width); + uint16_t h = dct.height; + uint16_t w = dct.width; + swap16(&h); + swap16(&w); + dct.height = h; + dct.width = w; /* We read 7 bytes */ len -= sizeof(struct dct); diff --git a/lib/menu.c b/lib/menu.c index 51154ba7..6a4bceda 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -134,7 +134,7 @@ void _menu_activate_MenuEntry_Normal(struct MenuEntry * self, int flags) { list_t * menu_keys = hashmap_keys(menu_windows); hovered_menu = NULL; foreach(_key, menu_keys) { - yutani_window_t * window = hashmap_get(menu_windows, (void*)_key->value); + yutani_window_t * window = hashmap_get(menu_windows, (void*)(uintptr_t)_key->value); if (window) { struct MenuList * menu = window->user_data; menu_definitely_close(menu); @@ -546,7 +546,7 @@ void menu_show(struct MenuList * menu, yutani_t * yctx) { _menu_redraw(menu_window, yctx, menu); - hashmap_set(menu_windows, (void*)menu_window->wid, menu_window); + hashmap_set(menu_windows, (void*)(uintptr_t)menu_window->wid, menu_window); } void menu_show_at(struct MenuList * menu, yutani_window_t * parent, int x, int y) { @@ -603,7 +603,7 @@ int menu_definitely_close(struct MenuList * menu) { yutani_wid_t wid = menu->window->wid; yutani_close(menu->window->ctx, menu->window); menu->window = NULL; - hashmap_remove(menu_windows, (void*)wid); + hashmap_remove(menu_windows, (void*)(uintptr_t)wid); return 0; } @@ -622,7 +622,7 @@ int menu_leave(struct MenuList * menu) { /* Get all menus */ list_t * menu_keys = hashmap_keys(menu_windows); foreach(_key, menu_keys) { - yutani_window_t * window = hashmap_get(menu_windows, (void *)_key->value); + yutani_window_t * window = hashmap_get(menu_windows, (void *)(uintptr_t)_key->value); if (window) { struct MenuList * menu = window->user_data; if (!hovered_menu || (menu != hovered_menu->child && !menu_has_eventual_child(menu, hovered_menu))) { @@ -816,8 +816,8 @@ int menu_process_event(yutani_t * yctx, yutani_msg_t * m) { case YUTANI_MSG_KEY_EVENT: { struct yutani_msg_key_event * me = (void*)m->data; - if (hashmap_has(menu_windows, (void*)me->wid)) { - yutani_window_t * window = hashmap_get(menu_windows, (void *)me->wid); + if (hashmap_has(menu_windows, (void*)(uintptr_t)me->wid)) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)(uintptr_t)me->wid); struct MenuList * menu = window->user_data; menu_key_action(menu, me); } @@ -826,8 +826,8 @@ int menu_process_event(yutani_t * yctx, yutani_msg_t * m) { case YUTANI_MSG_WINDOW_MOUSE_EVENT: { struct yutani_msg_window_mouse_event * me = (void*)m->data; - if (hashmap_has(menu_windows, (void*)me->wid)) { - yutani_window_t * window = hashmap_get(menu_windows, (void *)me->wid); + if (hashmap_has(menu_windows, (void*)(uintptr_t)me->wid)) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)(uintptr_t)me->wid); struct MenuList * menu = window->user_data; if (me->new_x >= 0 && me->new_x < (int)window->width && me->new_y >= 0 && me->new_y < (int)window->height) { if (hovered_menu != menu) { @@ -851,8 +851,8 @@ int menu_process_event(yutani_t * yctx, yutani_msg_t * m) { case YUTANI_MSG_WINDOW_FOCUS_CHANGE: { struct yutani_msg_window_focus_change * me = (void*)m->data; - if (hashmap_has(menu_windows, (void*)me->wid)) { - yutani_window_t * window = hashmap_get(menu_windows, (void *)me->wid); + if (hashmap_has(menu_windows, (void*)(uintptr_t)me->wid)) { + yutani_window_t * window = hashmap_get(menu_windows, (void *)(uintptr_t)me->wid); struct MenuList * menu = window->user_data; if (!me->focused) { /* XXX leave menu */ @@ -898,7 +898,7 @@ void menu_bar_render(struct menu_bar * self, gfx_context_t * ctx) { } while (_entries->title) { int w = string_width(_entries->title) + 10; - if ((self->active_menu && hashmap_has(menu_get_windows_hash(), (void*)self->active_menu_wid)) && _entries == self->active_entry) { + if ((self->active_menu && hashmap_has(menu_get_windows_hash(), (void*)(uintptr_t)self->active_menu_wid)) && _entries == self->active_entry) { for (int y = _y; y < _y + MENU_BAR_HEIGHT; ++y) { for (int x = offset + 2; x < offset + 2 + w; ++x) { GFX(ctx, x, y) = rgb(93,163,236); @@ -959,7 +959,7 @@ int menu_bar_mouse_event(yutani_t * yctx, yutani_window_t * window, struct menu_ if (x >= offset && x < offset + w) { if (me->command == YUTANI_MOUSE_EVENT_CLICK || _close_enough(me)) { menu_bar_show_menu(yctx, window, self,offset,_entries); - } else if (self->active_menu && hashmap_has(menu_get_windows_hash(), (void*)self->active_menu_wid) && _entries != self->active_entry) { + } else if (self->active_menu && hashmap_has(menu_get_windows_hash(), (void*)(uintptr_t)self->active_menu_wid) && _entries != self->active_entry) { menu_definitely_close(self->active_menu); menu_bar_show_menu(yctx, window, self,offset,_entries); } diff --git a/lib/pex.c b/lib/pex.c index e398370f..fa7d6cc7 100644 --- a/lib/pex.c +++ b/lib/pex.c @@ -19,7 +19,7 @@ #include -size_t pex_send(FILE * sock, unsigned int rcpt, size_t size, char * blob) { +size_t pex_send(FILE * sock, uintptr_t rcpt, size_t size, char * blob) { assert(size <= MAX_PACKET_SIZE); pex_header_t * broadcast = malloc(sizeof(pex_header_t) + size); broadcast->target = rcpt; diff --git a/lib/rline.c b/lib/rline.c index 0c48aecf..08125634 100644 --- a/lib/rline.c +++ b/lib/rline.c @@ -364,6 +364,10 @@ static const char * COLOR_GREEN = "@2"; static const char * COLOR_ESCAPE = "@2"; static const char * COLOR_SEARCH_FG = "@0"; static const char * COLOR_SEARCH_BG = "@3"; +static const char * COLOR_ERROR_FG = "@9"; +static const char * COLOR_ERROR_BG = "@9"; +static const char * COLOR_BOLD = "@9"; +static const char * COLOR_LINK = "@9"; /** * Themes are selected from the $RLINE_THEME @@ -385,6 +389,10 @@ static void rline_exp_load_colorscheme_default(void) { COLOR_ESCAPE = "@12"; COLOR_SEARCH_FG = "@0"; COLOR_SEARCH_BG = "@13"; + COLOR_ERROR_FG = "@17"; + COLOR_ERROR_BG = "@1"; + COLOR_BOLD = "@9"; + COLOR_LINK = "@14"; } static void rline_exp_load_colorscheme_sunsmoke(void) { @@ -403,6 +411,10 @@ static void rline_exp_load_colorscheme_sunsmoke(void) { COLOR_ESCAPE = "2;113;203;173"; COLOR_SEARCH_FG = "5;234"; COLOR_SEARCH_BG = "5;226"; + COLOR_ERROR_FG = "5;15"; + COLOR_ERROR_BG = "5;196"; + COLOR_BOLD = "2;230;230;230;1"; + COLOR_LINK = "2;51;162;230;4"; } /** @@ -523,44 +535,11 @@ void paintNHex(struct syntax_state * state, int n) { } } -void paint_krk_string(struct syntax_state * state, int type) { - /* Assumes you came in from a check of charat() == '"' */ - paint(1, FLAG_STRING); - while (charat() != -1) { - if (charat() == '\\' && nextchar() == type) { - paint(2, FLAG_ESCAPE); - } else if (charat() == type) { - paint(1, FLAG_STRING); - return; - } else if (charat() == '\\') { - if (nextchar() == 'x') { - paintNHex(state, 2); - } else if (nextchar() == 'u') { - paintNHex(state, 4); - } else if (nextchar() == 'U') { - paintNHex(state, 8); - } else if (nextchar() >= '0' && nextchar() <= '7') { - paint(2, FLAG_ESCAPE); - if (charat() >= '0' && charat() <= '7') { - paint(1, FLAG_ESCAPE); - if (charat() >= '0' && charat() <= '7') { - paint(1, FLAG_ESCAPE); - } - } - } else { - paint(2, FLAG_ESCAPE); - } - } else { - paint(1, FLAG_STRING); - } - } -} - char * syn_krk_keywords[] = { "and","class","def","else","for","if","in","import","del", "let","not","or","return","while","try","except","raise", "continue","break","as","from","elif","lambda","with","is", - "pass","assert","yield","finally", + "pass","assert","yield","finally","async","await", NULL }; @@ -573,6 +552,7 @@ char * syn_krk_types[] = { "print","set","any","all","bool","ord","chr","hex","oct","filter", "sorted","bytes","getattr","sum","min","max","id","hash","map","bin", "enumerate","zip","setattr","property","staticmethod","classmethod", + "issubclass","hasattr","delattr","NotImplemented", NULL }; @@ -583,12 +563,83 @@ char * syn_krk_special[] = { }; char * syn_krk_exception[] = { - "TypeError","ArgumentError","IndexError","KeyError","AttributeError", - "NameError","ImportError","IOError","ValueError","KeyboardInterrupt", - "ZeroDivisionError","SyntaxError","Exception", + "Exception", "TypeError", "ArgumentError", "IndexError", "KeyError", + "AttributeError", "NameError", "ImportError", "IOError", "ValueError", + "KeyboardInterrupt", "ZeroDivisionError", "NotImplementedError", "SyntaxError", + "AssertionError", NULL }; +void paint_krk_string_shared(struct syntax_state * state, int type, int isFormat, int isTriple) { + if (charat() == '\\') { + if (nextchar() == 'x') { + paintNHex(state, 2); + } else if (nextchar() == 'u') { + paintNHex(state, 4); + } else if (nextchar() == 'U') { + paintNHex(state, 8); + } else if (nextchar() >= '0' && nextchar() <= '7') { + paint(2, FLAG_ESCAPE); + if (charat() >= '0' && charat() <= '7') { + paint(1, FLAG_ESCAPE); + if (charat() >= '0' && charat() <= '7') { + paint(1, FLAG_ESCAPE); + } + } + } else { + paint(2, FLAG_ESCAPE); + } + } else if (isFormat && charat() == '{') { + paint(1, FLAG_ESCAPE); + if (charat() == '}') { + state->i--; + paint(2, FLAG_ERROR); /* Can't do that. */ + } else { + int x = 0; + while (charat() != -1) { + if (charat() == '{') { + x++; + } else if (charat() == '}') { + if (x == 0) { + paint(1, FLAG_ESCAPE); + break; + } + x--; + } else if (charat() == type && !isTriple) { + while (charat() != -1) { + paint(1, FLAG_ERROR); + } + return; + } else if (find_keywords(state, syn_krk_keywords, FLAG_ESCAPE, c_keyword_qualifier)) { + continue; + } else if (lastchar() != '.' && find_keywords(state, syn_krk_types, FLAG_TYPE, c_keyword_qualifier)) { + continue; + } else if (find_keywords(state, syn_krk_exception, FLAG_PRAGMA, c_keyword_qualifier)) { + continue; + } + paint(1, FLAG_NUMERAL); + } + } + } else { + paint(1, FLAG_STRING); + } +} + +void paint_krk_string(struct syntax_state * state, int type, int isFormat) { + /* Assumes you came in from a check of charat() == '"' */ + paint(1, FLAG_STRING); + while (charat() != -1) { + if (charat() == '\\' && nextchar() == type) { + paint(2, FLAG_ESCAPE); + } else if (charat() == type) { + paint(1, FLAG_STRING); + return; + } else { + paint_krk_string_shared(state,type,isFormat,0); + } + } +} + int paint_krk_numeral(struct syntax_state * state) { if (charat() == '0' && (nextchar() == 'x' || nextchar() == 'X')) { paint(2, FLAG_NUMERAL); @@ -609,16 +660,18 @@ int paint_krk_numeral(struct syntax_state * state) { return 0; } -int paint_krk_triple_string(struct syntax_state * state, int type) { +int paint_krk_triple_string(struct syntax_state * state, int type, int isFormat) { while (charat() != -1) { - if (charat() == type) { + if (charat() == '\\' && nextchar() == type) { + paint(2, FLAG_ESCAPE); + } else if (charat() == type) { paint(1, FLAG_STRING); if (charat() == type && nextchar() == type) { paint(2, FLAG_STRING); return 0; } } else { - paint(1, FLAG_STRING); + paint_krk_string_shared(state,type,isFormat,1); } } return (type == '"') ? 1 : 2; /* continues */ @@ -635,12 +688,13 @@ int syn_krk_calculate(struct syntax_state * state) { while (c_keyword_qualifier(charat())) paint(1, FLAG_TYPE); return 0; } else if (charat() == '"' || charat() == '\'') { + int isFormat = (lastchar() == 'f'); if (nextchar() == charat() && charrel(2) == charat()) { int type = charat(); paint(3, FLAG_STRING); - return paint_krk_triple_string(state, type); + return paint_krk_triple_string(state, type, isFormat); } else { - paint_krk_string(state, charat()); + paint_krk_string(state, charat(), isFormat); } return 0; } else if (find_keywords(state, syn_krk_keywords, FLAG_KEYWORD, c_keyword_qualifier)) { @@ -659,10 +713,11 @@ int syn_krk_calculate(struct syntax_state * state) { return 0; } break; + /* rline doesn't support multiline editing anyway */ case 1: - return paint_krk_triple_string(state, '"'); + return paint_krk_triple_string(state, '"', 0); case 2: - return paint_krk_triple_string(state, '\''); + return paint_krk_triple_string(state, '\'', 0); } return -1; } @@ -1034,6 +1089,22 @@ int syn_py_calculate(struct syntax_state * state) { } return -1; } + +void * rline_exp_for_python(void * _stdin, void * _stdout, char * prompt) { + + rline_exp_set_prompts(prompt, "", strlen(prompt), 0); + + char * buf = malloc(1024); + memset(buf, 0, 1024); + + rline_exp_set_syntax("python"); + rline_exit_string = ""; + rline(buf, 1024); + rline_history_insert(strdup(buf)); + rline_scroll = 0; + + return buf; +} #endif void rline_redraw(rline_context_t * context) { @@ -1068,10 +1139,10 @@ static const char * flag_to_color(int _flag) { return COLOR_GREEN; case FLAG_DIFFMINUS: return COLOR_RED; -// case FLAG_BOLD: -// return COLOR_BOLD; -// case FLAG_LINK: -// return COLOR_LINK; + case FLAG_BOLD: + return COLOR_BOLD; + case FLAG_LINK: + return COLOR_LINK; case FLAG_ESCAPE: return COLOR_ESCAPE; default: @@ -1345,6 +1416,9 @@ static void render_line(void) { } else if (c.flags == FLAG_NOTICE) { set_colors(COLOR_SEARCH_FG, COLOR_SEARCH_BG); was_searching = 1; + } else if (c.flags == FLAG_ERROR) { + set_colors(COLOR_ERROR_FG, COLOR_ERROR_BG); + was_searching = 1; /* co-opting this should work... */ } else if (was_searching) { fprintf(stdout,"\033[0m"); set_colors(color, COLOR_BG); @@ -1426,6 +1500,7 @@ static void render_line(void) { } } + printf("\033[0m"); set_colors(COLOR_FG, COLOR_BG); if (show_right_side && prompt_right_width) { @@ -1690,7 +1765,7 @@ void redraw_matching_paren(int col) { void highlight_matching_paren(void) { int col = -1; - if (is_paren(the_line->text[column].codepoint)) { + if (column < the_line->actual && is_paren(the_line->text[column].codepoint)) { find_matching_paren(&col, 0); } else if (column > 0 && is_paren(the_line->text[column-1].codepoint)) { find_matching_paren(&col, 1); @@ -1809,14 +1884,16 @@ static void history_previous(void) { * Cycle to next history entry */ static void history_next(void) { - if (rline_scroll > 1) { + if (rline_scroll >= 1) { + unsigned char * buf; + if (rline_scroll > 1) buf = (unsigned char *)rline_history_prev(rline_scroll-1); + else buf = (unsigned char *)temp_buffer; rline_scroll--; /* Copy in from history */ the_line->actual = 0; column = 0; loading = 1; - unsigned char * buf = (unsigned char *)rline_history_prev(rline_scroll); uint32_t istate = 0, c = 0; for (unsigned int i = 0; i < strlen((char *)buf); ++i) { if (!decode(&istate, &c, buf[i])) { @@ -1824,21 +1901,6 @@ static void history_next(void) { } } loading = 0; - } else if (rline_scroll == 1) { - /* Copy in from temp */ - rline_scroll = 0; - - the_line->actual = 0; - column = 0; - loading = 1; - char * buf = temp_buffer; - uint32_t istate = 0, c = 0; - for (unsigned int i = 0; i < strlen(buf); ++i) { - if (!decode(&istate, &c, buf[i])) { - insert_char(c); - } - } - loading = 0; } /* Set cursor at end */ column = the_line->actual; diff --git a/lib/sdf.c b/lib/sdf.c index b9b6e3e7..b77c1db2 100644 --- a/lib/sdf.c +++ b/lib/sdf.c @@ -206,14 +206,14 @@ int draw_sdf_string_stroke(gfx_context_t * ctx, int32_t x, int32_t y, const char sprite_t * tmp; spin_lock(&_sdf_lock); - if (!hashmap_has(_font_cache, (void *)(scale_height | (font << 16)))) { + if (!hashmap_has(_font_cache, (void *)(uintptr_t)(scale_height | (font << 16)))) { tmp = create_sprite(scale * _font_data->width, scale * _font_data->height, ALPHA_OPAQUE); gfx_context_t * t = init_graphics_sprite(tmp); draw_sprite_scaled(t, _font_data, 0, 0, tmp->width, tmp->height); free(t); - hashmap_set(_font_cache, (void *)(scale_height | (font << 16)), tmp); + hashmap_set(_font_cache, (void *)(uintptr_t)(scale_height | (font << 16)), tmp); } else { - tmp = hashmap_get(_font_cache, (void *)(scale_height | (font << 16))); + tmp = hashmap_get(_font_cache, (void *)(uintptr_t)(scale_height | (font << 16))); } uint32_t state = 0; diff --git a/lib/termemu.c b/lib/termemu.c index 28266856..1aecfb9c 100644 --- a/lib/termemu.c +++ b/lib/termemu.c @@ -431,7 +431,7 @@ static void _ansi_put(term_state_t * s, char c) { break; case ANSI_DSR: { - char out[24]; + char out[27]; sprintf(out, "\033[%d;%dR", callbacks->get_csr_y() + 1, callbacks->get_csr_x() + 1); callbacks->input_buffer_stuff(out); } diff --git a/lib/yutani.c b/lib/yutani.c index 2cb56ef7..bf60547c 100644 --- a/lib/yutani.c +++ b/lib/yutani.c @@ -81,7 +81,7 @@ static void _handle_internal(yutani_t * y, yutani_msg_t * out) { case YUTANI_MSG_WINDOW_MOVE: { struct yutani_msg_window_move * wm = (void *)out->data; - yutani_window_t * win = hashmap_get(y->windows, (void *)wm->wid); + yutani_window_t * win = hashmap_get(y->windows, (void *)(uintptr_t)wm->wid); if (win) { win->x = wm->x; win->y = wm->y; @@ -91,7 +91,7 @@ static void _handle_internal(yutani_t * y, yutani_msg_t * out) { case YUTANI_MSG_RESIZE_OFFER: { struct yutani_msg_window_resize * wr = (void *)out->data; - yutani_window_t * win = hashmap_get(y->windows, (void *)wr->wid); + yutani_window_t * win = hashmap_get(y->windows, (void *)(uintptr_t)wr->wid); if (win) { win->decorator_flags &= ~(DECOR_FLAG_TILED); win->decorator_flags |= (wr->flags & YUTANI_RESIZE_TILED) << 2; @@ -575,7 +575,7 @@ yutani_window_t * yutani_window_create_flags(yutani_t * y, int width, int height win->ctx = y; free(mm); - hashmap_set(y->windows, (void*)win->wid, win); + hashmap_set(y->windows, (void*)(uintptr_t)win->wid, win); char key[1024]; YUTANI_SHMKEY(y->server_ident, key, 1024, win); @@ -635,7 +635,7 @@ void yutani_close(yutani_t * y, yutani_window_t * win) { shm_release(key); } - hashmap_remove(y->windows, (void*)win->wid); + hashmap_remove(y->windows, (void*)(uintptr_t)win->wid); free(win); } diff --git a/libc/arch/x86_64/crt0.S b/libc/arch/x86_64/crt0.S new file mode 100644 index 00000000..b83d5ea8 --- /dev/null +++ b/libc/arch/x86_64/crt0.S @@ -0,0 +1,8 @@ +.global _start + +_start: + movq $main, %rcx + and $0xFFFFFFFFFFFFFFF0, %rsp + call pre_main /* call pre_main */ + + diff --git a/libc/crti.S b/libc/arch/x86_64/crti.S similarity index 56% rename from libc/crti.S rename to libc/arch/x86_64/crti.S index 4f649f31..226013e3 100644 --- a/libc/crti.S +++ b/libc/arch/x86_64/crti.S @@ -1,9 +1,11 @@ .global _init .section .init _init: - push %ebp + push %rbp + movq %rsp, %rbp .global _fini .section .fini _fini: - push %ebp + push %rbp + movq %rsp, %rbp diff --git a/libc/crtn.S b/libc/arch/x86_64/crtn.S similarity index 66% rename from libc/crtn.S rename to libc/arch/x86_64/crtn.S index aa67ce13..3cf67235 100644 --- a/libc/crtn.S +++ b/libc/arch/x86_64/crtn.S @@ -1,7 +1,8 @@ .section .init - pop %ebp + pop %rbp ret .section .fini - pop %ebp + pop %rbp ret + diff --git a/libc/arch/x86_64/math.c b/libc/arch/x86_64/math.c new file mode 100644 index 00000000..203c5103 --- /dev/null +++ b/libc/arch/x86_64/math.c @@ -0,0 +1,84 @@ +#include + +double ceil(double x) { + if (x == 0.0) return x; + + double out; + asm volatile ( + "frndint\n" + : "=t"(out) : "0"(x) + ); + if (out < x) return out + 1.0; + return out; +} + +double floor(double x) { + if (x == 0.0) return x; + + double out; + asm volatile ( + "frndint\n" + : "=t"(out) : "0"(x) + ); + if (out > x) return out - 1.0; + return out; +} + +double pow(double x, double y) { + double out; + asm volatile ( + "fyl2x;" + "fld %%st;" + "frndint;" + "fsub %%st,%%st(1);" + "fxch;" + "fchs;" + "f2xm1;" + "fld1;" + "faddp;" + "fxch;" + "fld1;" + "fscale;" + "fstp %%st(1);" + "fmulp;" : "=t"(out) : "0"(x),"u"(y) : "st(1)" ); + return out; +} + +double fmod(double x, double y) { + long double out; + asm volatile ( + "1: fprem;" /* Partial remainder */ + " fnstsw %%ax;" /* store status word */ + " sahf;" /* store AX (^ FPU status) into flags */ + " jp 1b;" /* jump back to 1 above if parity flag==1 */ + : "=t"(out) : "0"(x), "u"(y) : "ax", "cc"); + return out; +} + +double tan(double x) { + double out; + double _x = x; + double one; + asm volatile ( + "fldl %2\n" + "fptan\n" + "fstpl %1\n" + "fstpl %0\n" + : "=m"(out), "=m"(one) : "m"(_x) + ); + return out; +} + +double atan2(double y, double x) { + double out; + double _x = x; + double _y = y; + asm volatile ( + "fldl %1\n" + "fldl %2\n" + "fpatan\n" + "fstpl %0\n" + : "=m"(out) : "m"(_y), "m"(_x) + ); + return out; +} diff --git a/libc/string/memcpy.c b/libc/arch/x86_64/memcpy.c similarity index 100% rename from libc/string/memcpy.c rename to libc/arch/x86_64/memcpy.c diff --git a/libc/string/memset.c b/libc/arch/x86_64/memset.c similarity index 62% rename from libc/string/memset.c rename to libc/arch/x86_64/memset.c index e8b33c60..3d9c00b6 100644 --- a/libc/string/memset.c +++ b/libc/arch/x86_64/memset.c @@ -3,8 +3,8 @@ void * memset(void * dest, int c, size_t n) { asm volatile("cld; rep stosb" : "=c"((int){0}) - : "D"(dest), "a"(c), "c"(n) - : "flags", "memory"); + : "rdi"(dest), "a"(c), "c"(n) + : "flags", "memory", "rdi"); return dest; } diff --git a/libc/arch/x86_64/setjmp.c b/libc/arch/x86_64/setjmp.c new file mode 100644 index 00000000..153c7011 --- /dev/null +++ b/libc/arch/x86_64/setjmp.c @@ -0,0 +1,40 @@ +#include + + +__attribute__((naked)) +__attribute__((returns_twice)) +int setjmp(jmp_buf env) { + asm volatile ( + "leaq 8(%%rsp), %%rax\n" /* Return address into rax */ + "movq %%rax, 0(%%rdi)\n" /* jmp_buf[0] = rsp */ + "movq %%rbp, 8(%%rdi)\n" /* jmp_buf[1] = rbp */ + "movq (%%rsp), %%rax\n" + "movq %%rax, 16(%%rdi)\n" /* jmp_buf[2] = return address */ + "movq %%rbx, 24(%%rdi)\n" /* jmp_buf[3] = rbx */ + "movq %%r12, 32(%%rdi)\n" /* jmp_buf[4] = r12 */ + "movq %%r13, 40(%%rdi)\n" /* jmp_buf[5] = r12 */ + "movq %%r14, 48(%%rdi)\n" /* jmp_buf[6] = r12 */ + "movq %%r15, 56(%%rdi)\n" /* jmp_buf[7] = r12 */ + "xor %%rax, %%rax\n" /* return 0 */ + "retq" + :::"memory" + ); +} + +__attribute__((naked)) +__attribute__((noreturn)) +void longjmp(jmp_buf env, int val) { + asm volatile ( + "movq 0(%%rdi), %%rsp\n" + "movq 8(%%rdi), %%rbp\n" + "movq 24(%%rdi), %%rbx\n" + "movq 32(%%rdi), %%r12\n" + "movq 40(%%rdi), %%r13\n" + "movq 48(%%rdi), %%r14\n" + "movq 56(%%rdi), %%r15\n" + "movq %%rsi, %%rax\n" + "jmpq *16(%%rdi)\n" + :::"memory" + ); +} + diff --git a/libc/crt0.S b/libc/crt0.S deleted file mode 100644 index acc81470..00000000 --- a/libc/crt0.S +++ /dev/null @@ -1,7 +0,0 @@ -.global _start - -_start: - pop %eax - push $main - call pre_main - diff --git a/libc/ctype/_ctype.c b/libc/ctype/_ctype.c index 5e44c1b7..b18ba922 100644 --- a/libc/ctype/_ctype.c +++ b/libc/ctype/_ctype.c @@ -1,6 +1,6 @@ #include -char _ctype_[256]= { +unsigned char _ctype_[256]= { _C, _C, _C, _C, _C, _C, _C, _C, _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, diff --git a/libc/ioctl/ioctl.c b/libc/ioctl/ioctl.c index 87ec0856..67adff8b 100644 --- a/libc/ioctl/ioctl.c +++ b/libc/ioctl/ioctl.c @@ -32,11 +32,11 @@ int tcdrain(int i) { } int tcflow(int fd, int arg) { - return ioctl(fd, TCXONC, (void*)arg); + return ioctl(fd, TCXONC, (void*)(uintptr_t)arg); } int tcflush(int fd, int arg) { - return ioctl(fd, TCFLSH, (void*)arg); + return ioctl(fd, TCFLSH, (void*)(uintptr_t)arg); } pid_t tcgetsid(int fd) { @@ -45,7 +45,7 @@ pid_t tcgetsid(int fd) { } int tcsendbreak(int fd, int arg) { - return ioctl(fd, TCSBRK, (void*)arg); + return ioctl(fd, TCSBRK, (void*)(uintptr_t)arg); } int tcgetattr(int fd, struct termios * tio) { diff --git a/libc/main.c b/libc/main.c index ad73906b..091ed813 100644 --- a/libc/main.c +++ b/libc/main.c @@ -33,8 +33,11 @@ void _exit(int val){ extern void __make_tls(void); +static int __libc_init_called = 0; + __attribute__((constructor)) static void _libc_init(void) { + __libc_init_called = 1; __make_tls(); __stdio_init_buffers(); @@ -95,10 +98,19 @@ static void _libc_init(void) { _argv_0 = __get_argv()[0]; } -void pre_main(int (*main)(int,char**), int argc, char * argv[]) { +void pre_main(int argc, char * argv[], char ** envp, int (*main)(int,char**)) { if (!__get_argv()) { /* Statically loaded, must set __argv so __get_argv() works */ __argv = argv; + /* Run our initializers, because I'm pretty sure the kernel didn't... */ + if (!__libc_init_called) { + extern uintptr_t __init_array_start; + extern uintptr_t __init_array_end; + for (uintptr_t * constructor = &__init_array_start; constructor < &__init_array_end; ++constructor) { + void (*constr)(void) = (void*)*constructor; + constr(); + } + } } _init(); exit(main(argc, argv)); diff --git a/libc/math/math.c b/libc/math/math.c index 27800f00..b856b300 100644 --- a/libc/math/math.c +++ b/libc/math/math.c @@ -14,55 +14,10 @@ double exp(double x) { return pow(2.71828182846, x); } -double ceil(double x) { - if (x == 0.0) return x; - - double out; - asm volatile ( - "frndint\n" - : "=t"(out) : "0"(x) - ); - if (out < x) return out + 1.0; - return out; -} - -double floor(double x) { - if (x == 0.0) return x; - - double out; - asm volatile ( - "frndint\n" - : "=t"(out) : "0"(x) - ); - if (out > x) return out - 1.0; - return out; -} - int abs(int j) { return (j < 0 ? -j : j); } -double pow(double x, double y) { - MATH; - double out; - asm volatile ( - "fyl2x;" - "fld %%st;" - "frndint;" - "fsub %%st,%%st(1);" - "fxch;" - "fchs;" - "f2xm1;" - "fld1;" - "faddp;" - "fxch;" - "fld1;" - "fscale;" - "fstp %%st(1);" - "fmulp;" : "=t"(out) : "0"(x),"u"(y) : "st(1)" ); - return out; -} - double fabs(double x) { MATH; return __builtin_fabs(x); @@ -72,19 +27,6 @@ float fabsf(float x) { return fabs(x); } -double fmod(double x, double y) { - MATH; - - long double out; - asm volatile ( - "1: fprem;" /* Partial remainder */ - " fnstsw %%ax;" /* store status word */ - " sahf;" /* store AX (^ FPU status) into flags */ - " jp 1b;" /* jump back to 1 above if parity flag==1 */ - : "=t"(out) : "0"(x), "u"(y) : "ax", "cc"); - return out; -} - double sqrt(double x) { MATH; return __builtin_sqrt(x); @@ -481,36 +423,6 @@ double cos(double x) { return sin(x + 3.141592654 / 2.0); } -double tan(double x) { - MATH; - float out; - float _x = x; - float one; - asm volatile ( - "fld %2\n" - "fptan\n" - "fstp %1\n" - "fstp %0\n" - : "=m"(out), "=m"(one) : "m"(_x) - ); - return out; -} - -double atan2(double y, double x) { - MATH; - float out; - float _x = x; - float _y = y; - asm volatile ( - "fld %1\n" - "fld %2\n" - "fpatan\n" - "fstp %0\n" - : "=m"(out) : "m"(_y), "m"(_x) - ); - return out; -} - double atan(double x) { return atan2(x,1.0); } diff --git a/libc/pthread/pthread.c b/libc/pthread/pthread.c index c5a86b2a..a03227c5 100644 --- a/libc/pthread/pthread.c +++ b/libc/pthread/pthread.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -30,12 +31,13 @@ struct pthread { void * arg; }; -void * ___tls_get_addr(void* input) { +void * __tls_get_addr(void* input) { return NULL; } void __make_tls(void) { - char * tlsSpace = calloc(1,4096); + char * tlsSpace = valloc(4096); + memset(tlsSpace, 0x0, 4096); char ** tlsSelf = (char **)(tlsSpace + 4096 - sizeof(char *)); *tlsSelf = (char*)tlsSelf; sysfunc(TOARU_SYS_FUNC_SETGSBASE, (char*[]){(char*)tlsSelf}); @@ -126,7 +128,7 @@ int pthread_join(pthread_t thread, void **retval) { int status; int result = waitpid(thread.id, &status, 0); if (retval) { - *retval = (void*)status; + *retval = (void*)(uintptr_t)status; } return result; } diff --git a/libc/setjmp.S b/libc/setjmp.S deleted file mode 100644 index 83c121e6..00000000 --- a/libc/setjmp.S +++ /dev/null @@ -1,64 +0,0 @@ -.global setjmp -.type setjmp, STT_FUNC -setjmp: - - pushl %ebp - movl %esp,%ebp - - pushl %edi - movl 8(%ebp),%edi - - movl %eax,0 (%edi) - movl %ebx,4 (%edi) - movl %ecx,8 (%edi) - movl %edx,12 (%edi) - movl %esi,16 (%edi) - - movl -4 (%ebp),%eax - movl %eax,20 (%edi) - - movl 0 (%ebp),%eax - movl %eax,24 (%edi) - - movl %esp,%eax - addl $12,%eax - movl %eax,28 (%edi) - - movl 4 (%ebp),%eax - movl %eax,32 (%edi) - - popl %edi - movl $0,%eax - leave - ret - -.global longjmp -.type longjmp, STT_FUNC -longjmp: - pushl %ebp - movl %esp,%ebp - - movl 8(%ebp),%edi /* get jmp_buf */ - movl 12(%ebp),%eax /* store retval in j->eax */ - testl %eax,%eax - jne 0f - incl %eax -0: - movl %eax,0(%edi) - - movl 24(%edi),%ebp - - /*__CLI */ - movl 28(%edi),%esp - - pushl 32(%edi) - - movl 0 (%edi),%eax - movl 4 (%edi),%ebx - movl 8 (%edi),%ecx - movl 12(%edi),%edx - movl 16(%edi),%esi - movl 20(%edi),%edi - /*__STI */ - - ret diff --git a/libc/signal/kill.c b/libc/signal/kill.c index 9bd062dd..ef29b33f 100644 --- a/libc/signal/kill.c +++ b/libc/signal/kill.c @@ -3,9 +3,9 @@ #include #include -DEFN_SYSCALL2(send_signal, SYS_KILL, uint32_t, uint32_t); +DEFN_SYSCALL2(kill, SYS_KILL, int, int); int kill(int pid, int sig) { - __sets_errno(syscall_send_signal(pid, sig)); + __sets_errno(syscall_kill(pid, sig)); } diff --git a/libc/signal/signal.c b/libc/signal/signal.c index fe94660a..99d494cb 100644 --- a/libc/signal/signal.c +++ b/libc/signal/signal.c @@ -2,7 +2,7 @@ #include #include -DEFN_SYSCALL2(signal, SYS_SIGNAL, uint32_t, void *); +DEFN_SYSCALL2(signal, SYS_SIGNAL, int, void *); /* XXX This syscall interface is screwy, doesn't allow for good errno handling */ sighandler_t signal(int signum, sighandler_t handler) { diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 341efc16..f4dfc428 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -121,7 +121,6 @@ static size_t print_hex(unsigned long long value, unsigned int width, int (*call */ size_t xvasprintf(int (*callback)(void *, char), void * userData, const char * fmt, va_list args) { char * s; - int precision = -1; size_t written = 0; for (const char *f = fmt; *f; f++) { if (*f != '%') { @@ -135,6 +134,7 @@ size_t xvasprintf(int (*callback)(void *, char), void * userData, const char * f int big = 0; int alt = 0; int always_sign = 0; + int precision = -1; while (1) { if (*f == '-') { align = 0; @@ -238,7 +238,7 @@ size_t xvasprintf(int (*callback)(void *, char), void * userData, const char * f break; case 'p': alt = 1; - if (sizeof(void*) == sizeof(long long)) big = 2; + if (sizeof(void*) == sizeof(long long)) big = 2; /* fallthrough */ case 'X': case 'x': /* Hexadecimal number */ { diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index 8d195d35..54758d90 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -143,7 +143,7 @@ static size_t write_bytes(FILE * f, char * buf, size_t len) { size_t newBytes = 0; while (len > 0) { f->write_buf[f->written++] = *buf; - if (f->written == (size_t)f->bufsiz || *buf == '\n') { + if (f->written == (size_t)f->wbufsiz || *buf == '\n') { fflush(f); } newBytes++; @@ -174,7 +174,7 @@ static size_t read_bytes(FILE * f, char * out, size_t len) { if (f->offset == f->bufsiz) { f->offset = 0; } - f->last_read_start = syscall_lseek(f->fd, 0, SEEK_CUR); + f->last_read_start = syscall_seek(f->fd, 0, SEEK_CUR); ssize_t r = read(fileno(f), &f->read_buf[f->offset], f->bufsiz - f->offset); if (r < 0) { //fprintf(stderr, "error condition\n"); @@ -389,7 +389,7 @@ int fseek(FILE * stream, long offset, int whence) { stream->ungetc = -1; stream->eof = 0; - int resp = syscall_lseek(stream->fd,offset,whence); + int resp = syscall_seek(stream->fd,offset,whence); if (resp < 0) { errno = -resp; return -1; @@ -412,7 +412,7 @@ long ftell(FILE * stream) { stream->available = 0; stream->ungetc = -1; stream->eof = 0; - long resp = syscall_lseek(stream->fd, 0, SEEK_CUR); + long resp = syscall_seek(stream->fd, 0, SEEK_CUR); if (resp < 0) { errno = -resp; return -1; diff --git a/libc/stdlib/malloc.c b/libc/stdlib/malloc.c index 40858211..f690ccd3 100644 --- a/libc/stdlib/malloc.c +++ b/libc/stdlib/malloc.c @@ -116,8 +116,13 @@ * Defines for often-used integral values * related to our binning and paging strategy. */ +#ifdef __x86_64__ +#define NUM_BINS 10U /* Number of bins, total, under 64-bit. */ +#define SMALLEST_BIN_LOG 3U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */ +#else #define NUM_BINS 11U /* Number of bins, total, under 32-bit. */ #define SMALLEST_BIN_LOG 2U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */ +#endif #define BIG_BIN (NUM_BINS - 1) /* Index for the big bin, (NUM_BINS - 1) */ #define SMALLEST_BIN (1UL << SMALLEST_BIN_LOG) /* Size of the smallest bin. */ @@ -996,8 +1001,7 @@ static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size) */ void *ptr = klmalloc(nmemb * size); - if (__builtin_expect(ptr != NULL, 1)) - memset(ptr,0x00,nmemb * size); + if (ptr) memset(ptr,0x00,nmemb * size); return ptr; } /* }}} */ diff --git a/libc/stdlib/putenv.c b/libc/stdlib/putenv.c index df7dc659..64c5111c 100644 --- a/libc/stdlib/putenv.c +++ b/libc/stdlib/putenv.c @@ -45,7 +45,7 @@ int unsetenv(const char * str) { int putenv(char * string) { - char name[strlen(string)]; + char name[strlen(string)+1]; strcpy(name, string); char * c = strchr(name, '='); if (!c) { diff --git a/libc/stdlib/rand.c b/libc/stdlib/rand.c index d8928b2c..281fdb94 100644 --- a/libc/stdlib/rand.c +++ b/libc/stdlib/rand.c @@ -12,7 +12,7 @@ int rand(void) { t = x ^ (x << 11); x = y; y = z; z = w; - return abs(w = w ^ (w >> 19) ^ t ^ (t >> 8)); + return w = w ^ (w >> 19) ^ t ^ (t >> 8); } void srand(unsigned int seed) { diff --git a/libc/string/str.c b/libc/string/str.c index 5c864d22..ef665833 100644 --- a/libc/string/str.c +++ b/libc/string/str.c @@ -348,8 +348,7 @@ long atol(const char * s) { } switch (*s) { case '-': - neg = 1; - /* Fallthrough is intentional here */ + neg = 1; /* fallthrough */ case '+': s++; } @@ -370,8 +369,7 @@ int atoi(const char * s) { } switch (*s) { case '-': - neg = 1; - /* Fallthrough is intentional here */ + neg = 1; /* fallthrough */ case '+': s++; } diff --git a/libc/sys/network.c b/libc/sys/network.c index 28eef78e..cb109d0e 100644 --- a/libc/sys/network.c +++ b/libc/sys/network.c @@ -1,6 +1,7 @@ /* * socket methods (mostly unimplemented) */ +#include #include #include #include @@ -11,66 +12,98 @@ #include #include +#include +#include -static struct hostent _out_host = {0}; -static struct in_addr * _out_host_vector[2] = {NULL, NULL}; -static struct in_addr * _out_host_aliases[1] = {NULL}; -static uint32_t _out_addr; - -#define UNIMPLEMENTED fprintf(stderr, "[libnetwork] Unimplemented: %s\n", __FUNCTION__) - -struct hostent * gethostbyname(const char * name) { - if (_out_host.h_name) free(_out_host.h_name); - _out_host.h_name = strdup(name); - int fd = open("/dev/net",O_RDONLY); - void * args[2] = {(void *)name,&_out_addr}; - int ret = ioctl(fd, 0x5000, args); - close(fd); - if (ret) return NULL; - - _out_host_vector[0] = (struct in_addr *)&_out_addr; - _out_host.h_aliases = (char **)&_out_host_aliases; - _out_host.h_addrtype = AF_INET; - _out_host.h_addr_list = (char**)_out_host_vector; - _out_host.h_length = sizeof(uint32_t); - return &_out_host; -} +DEFN_SYSCALL3(socket, SYS_SOCKET, int, int, int); +DEFN_SYSCALL5(setsockopt, SYS_SETSOCKOPT, int,int,int,const void*,size_t); +DEFN_SYSCALL3(bind, SYS_BIND, int,const void*,size_t); +DEFN_SYSCALL4(accept, SYS_ACCEPT, int,void*,size_t*,int); +DEFN_SYSCALL2(listen, SYS_LISTEN, int,int); +DEFN_SYSCALL3(connect, SYS_CONNECT, int,const void*,size_t); +DEFN_SYSCALL5(getsockopt, SYS_GETSOCKOPT, int,int,int,void*,size_t*); +DEFN_SYSCALL3(recv, SYS_RECV, int,void*,int); +DEFN_SYSCALL3(send, SYS_SEND, int,const void*,int); +DEFN_SYSCALL2(shutdown, SYS_SHUTDOWN, int, int); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - UNIMPLEMENTED; - return -1; + __sets_errno(syscall_connect(sockfd,addr,addrlen)); } /* All of these should just be reads. */ ssize_t recv(int sockfd, void *buf, size_t len, int flags) { - UNIMPLEMENTED; - return -1; + struct iovec _iovec = { + buf, len + }; + struct msghdr _header = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = &_iovec, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + return recvmsg(sockfd, &_header, flags); } ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { - UNIMPLEMENTED; - return -1; + struct iovec _iovec = { + buf, len + }; + struct msghdr _header = { + .msg_name = src_addr, + .msg_namelen = addrlen ? *addrlen : 0, + .msg_iov = &_iovec, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + ssize_t result = recvmsg(sockfd, &_header, flags); + if (addrlen) *addrlen = _header.msg_namelen; + return result; } ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) { - UNIMPLEMENTED; - return -1; + __sets_errno(syscall_recv(sockfd,msg,flags)); } ssize_t send(int sockfd, const void *buf, size_t len, int flags) { - UNIMPLEMENTED; - return len; + struct iovec _iovec = { + (void*)buf, len + }; + struct msghdr _header = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = &_iovec, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + return sendmsg(sockfd, &_header, flags); } ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - UNIMPLEMENTED; - return len; + struct iovec _iovec = { + (void*)buf, len + }; + struct msghdr _header = { + .msg_name = (void*)dest_addr, + .msg_namelen = addrlen, + .msg_iov = &_iovec, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + return sendmsg(sockfd, &_header, flags); } ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) { - UNIMPLEMENTED; - return -1; + __sets_errno(syscall_send(sockfd,msg,flags)); } int socket(int domain, int type, int protocol) { - UNIMPLEMENTED; - return -1; + /* Thin wrapper around a new system call, I guess. */ + __sets_errno(syscall_socket(domain,type,protocol)); } uint32_t htonl(uint32_t hostlong) { @@ -90,40 +123,50 @@ uint16_t ntohs(uint16_t netshort) { } int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - UNIMPLEMENTED; - return -1; + __sets_errno(syscall_bind(sockfd,addr,addrlen)); } int accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen) { - UNIMPLEMENTED; - return -1; + __sets_errno(syscall_accept(sockfd,addr,addrlen,0)); +} + +int accept4(int sockfd, struct sockaddr * addr, socklen_t * addrlen, int flags) { + __sets_errno(syscall_accept(sockfd,addr,addrlen,flags)); } int listen(int sockfd, int backlog) { - UNIMPLEMENTED; - return -1; + __sets_errno(syscall_listen(sockfd,backlog)); } +int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { + __sets_errno(syscall_getsockopt(sockfd,level,optname,optval,optlen)); +} + +int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { + __sets_errno(syscall_setsockopt(sockfd,level,optname,optval,optlen)); +} + +int shutdown(int sockfd, int how) { + __sets_errno(syscall_shutdown(sockfd,how)); +} + +#define UNIMPLEMENTED fprintf(stderr, "[libnetwork] Unimplemented: %s\n", __FUNCTION__) + int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { UNIMPLEMENTED; return -1; } int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - return -1; -} - -int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { UNIMPLEMENTED; return -1; } -int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { +struct hostent * gethostbyname(const char * name) { + /* This formerly called into the kernel network device to perform + * DNS lookups, but we're going to resolve directly with a UDP DNS + * client with timeouts and everything, right here in the libc... */ UNIMPLEMENTED; - return -1; + return NULL; } -int shutdown(int sockfd, int how) { - UNIMPLEMENTED; - return -1; -} diff --git a/libc/sys/sysfunc.c b/libc/sys/sysfunc.c index 69ade1e2..023bfc87 100644 --- a/libc/sys/sysfunc.c +++ b/libc/sys/sysfunc.c @@ -3,8 +3,8 @@ #include #include -DEFN_SYSCALL2(system_function, SYS_SYSFUNC, int, char **); +DEFN_SYSCALL2(sysfunc, SYS_SYSFUNC, int, char **); extern int sysfunc(int command, char ** args) { - __sets_errno(syscall_system_function(command, args)); + __sets_errno(syscall_sysfunc(command, args)); } diff --git a/libc/unistd/fstat.c b/libc/unistd/fstat.c index 5a2b27cd..26ce40b3 100644 --- a/libc/unistd/fstat.c +++ b/libc/unistd/fstat.c @@ -4,8 +4,8 @@ #include #include -DEFN_SYSCALL2(fstat, SYS_STAT, int, void *); +DEFN_SYSCALL2(stat, SYS_STAT, int, void *); int fstat(int file, struct stat *st) { - __sets_errno(syscall_fstat(file, st)); + __sets_errno(syscall_stat(file, st)); } diff --git a/libc/unistd/lseek.c b/libc/unistd/lseek.c index 00596139..fc8108ec 100644 --- a/libc/unistd/lseek.c +++ b/libc/unistd/lseek.c @@ -3,9 +3,9 @@ #include #include -DEFN_SYSCALL3(lseek, SYS_SEEK, int, int, int); +DEFN_SYSCALL3(seek, SYS_SEEK, int, long, int); off_t lseek(int file, off_t ptr, int dir) { - __sets_errno(syscall_lseek(file,ptr,dir)); + __sets_errno(syscall_seek(file,ptr,dir)); } diff --git a/libc/unistd/pathconf.c b/libc/unistd/pathconf.c new file mode 100644 index 00000000..add68e6b --- /dev/null +++ b/libc/unistd/pathconf.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +long pathconf(const char *path, int name) { + switch (name) { + case _PC_PATH_MAX: + return PATH_MAX; + default: + errno = EINVAL; + return -1; + } +} diff --git a/libc/unistd/read.c b/libc/unistd/read.c index 2fda4c76..00a63642 100644 --- a/libc/unistd/read.c +++ b/libc/unistd/read.c @@ -3,8 +3,8 @@ #include #include -DEFN_SYSCALL3(read, SYS_READ, int, char *, int); +DEFN_SYSCALL3(read, SYS_READ, int, char *, size_t); -int read(int file, void *ptr, size_t len) { +ssize_t read(int file, void *ptr, size_t len) { __sets_errno(syscall_read(file,ptr,len)); } diff --git a/libc/unistd/sleep.c b/libc/unistd/sleep.c index a2938f38..021fb804 100644 --- a/libc/unistd/sleep.c +++ b/libc/unistd/sleep.c @@ -1,7 +1,7 @@ #include unsigned int sleep(unsigned int seconds) { - syscall_nanosleep(seconds, 0); + syscall_sleep(seconds, 0); return 0; } diff --git a/libc/unistd/stat.c b/libc/unistd/stat.c index 03fcd28a..9543a5d3 100644 --- a/libc/unistd/stat.c +++ b/libc/unistd/stat.c @@ -4,11 +4,11 @@ #include #include -DEFN_SYSCALL2(stat, SYS_STATF, char *, void *); +DEFN_SYSCALL2(statf, SYS_STATF, char *, void *); DEFN_SYSCALL2(lstat, SYS_LSTAT, char *, void *); int stat(const char *file, struct stat *st){ - int ret = syscall_stat((char *)file, (void *)st); + int ret = syscall_statf((char *)file, (void *)st); if (ret >= 0) { return ret; } else { diff --git a/libc/unistd/usleep.c b/libc/unistd/usleep.c index 5c3920d0..3a3dc8d6 100644 --- a/libc/unistd/usleep.c +++ b/libc/unistd/usleep.c @@ -2,10 +2,10 @@ #include #include -DEFN_SYSCALL2(nanosleep, SYS_SLEEP, unsigned long, unsigned long); +DEFN_SYSCALL2(sleep, SYS_SLEEP, unsigned long, unsigned long); int usleep(useconds_t usec) { - syscall_nanosleep((usec / 10000) / 1000, (usec / 10000) % 1000); + syscall_sleep((usec / 10000) / 1000, (usec / 10000) % 1000); return 0; } diff --git a/libc/unistd/write.c b/libc/unistd/write.c index 5ebbb9ad..9c2af20b 100644 --- a/libc/unistd/write.c +++ b/libc/unistd/write.c @@ -3,7 +3,7 @@ #include #include -DEFN_SYSCALL3(write, SYS_WRITE, int, char *, int); +DEFN_SYSCALL3(write, SYS_WRITE, int, char *, size_t); ssize_t write(int file, const void *ptr, size_t len) { __sets_errno(syscall_write(file,(char *)ptr,len)); diff --git a/linker/link.ld b/linker/link.ld index d0cc55ae..6d7434a0 100644 --- a/linker/link.ld +++ b/linker/link.ld @@ -30,11 +30,15 @@ SECTIONS *(.bss) } - .eh_frame BLOCK(4K) : ALIGN(4K) - { + .eh_frame BLOCK(4K) : ALIGN(4K) { *(.eh_frame) } + .init_array : { + PROVIDE_HIDDEN (__init_array_start = .); + PROVIDE_HIDDEN (__init_array_end = .); + } + end = .; /DISCARD/ : diff --git a/linker/linker.c b/linker/linker.c index a404f168..3accc54d 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -1,9 +1,6 @@ -/* vim: ts=4 sw=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016-2018 Kevin Lange - * - * ELF Dynamic Linker/Loader +/** + * @file linker/linker.c + * @brief ELF Dynamic Linker/Loader * * Loads ELF executables and links them at runtime to their * shared library dependencies. @@ -18,6 +15,11 @@ * * However, it's sufficient for our purposes, and works well enough * to load Python C modules. + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016-2021 K. Lange */ #include #include @@ -87,16 +89,16 @@ typedef struct elf_object { FILE * file; /* Full copy of the header. */ - Elf32_Header header; + Elf64_Header header; char * dyn_string_table; size_t dyn_string_table_size; - Elf32_Sym * dyn_symbol_table; + Elf64_Sym * dyn_symbol_table; size_t dyn_symbol_table_size; - Elf32_Dyn * dynamic; - Elf32_Word * dyn_hash; + Elf64_Dyn * dynamic; + Elf64_Word * dyn_hash; void (*init)(void); void (**init_array)(void); @@ -204,7 +206,7 @@ static elf_t * open_object(const char * path) { object->file = f; /* Read the header */ - size_t r = fread(&object->header, sizeof(Elf32_Header), 1, object->file); + size_t r = fread(&object->header, sizeof(Elf64_Header), 1, object->file); /* Header failed to read? */ if (!r) { @@ -233,11 +235,11 @@ static elf_t * open_object(const char * path) { /* Calculate the size of an object file by examining its phdrs */ static size_t object_calculate_size(elf_t * object) { - uintptr_t base_addr = 0xFFFFFFFF; + uintptr_t base_addr = (uintptr_t)-1; uintptr_t end_addr = 0x0; size_t headers = 0; while (headers < object->header.e_phnum) { - Elf32_Phdr phdr; + Elf64_Phdr phdr; /* Read the phdr */ fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET); @@ -266,7 +268,7 @@ static size_t object_calculate_size(elf_t * object) { } /* If base_addr is still -1, then no valid phdrs were found, and the object has no loaded size. */ - if (base_addr == 0xFFFFFFFF) return 0; + if (base_addr == (uintptr_t)-1) return 0; return end_addr - base_addr; } @@ -279,7 +281,7 @@ static uintptr_t object_load(elf_t * object, uintptr_t base) { size_t headers = 0; while (headers < object->header.e_phnum) { - Elf32_Phdr phdr; + Elf64_Phdr phdr; /* Read the phdr */ fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET); @@ -312,7 +314,7 @@ static uintptr_t object_load(elf_t * object, uintptr_t base) { case PT_DYNAMIC: { /* Keep a reference to the dynamic section, which is actually loaded by a PT_LOAD normally. */ - object->dynamic = (Elf32_Dyn *)(base + phdr.p_vaddr); + object->dynamic = (Elf64_Dyn *)(base + phdr.p_vaddr); } break; default: @@ -330,32 +332,32 @@ static int object_postload(elf_t * object) { /* If there is a dynamic table, parse it. */ if (object->dynamic) { - Elf32_Dyn * table; + Elf64_Dyn * table; /* Locate string tables */ table = object->dynamic; while (table->d_tag) { switch (table->d_tag) { - case 4: - object->dyn_hash = (Elf32_Word *)(object->base + table->d_un.d_ptr); + case DT_HASH: + object->dyn_hash = (Elf64_Word *)(object->base + table->d_un.d_ptr); object->dyn_symbol_table_size = object->dyn_hash[1]; break; - case 5: /* Dynamic String Table */ + case DT_STRTAB: object->dyn_string_table = (char *)(object->base + table->d_un.d_ptr); break; - case 6: /* Dynamic Symbol Table */ - object->dyn_symbol_table = (Elf32_Sym *)(object->base + table->d_un.d_ptr); + case DT_SYMTAB: + object->dyn_symbol_table = (Elf64_Sym *)(object->base + table->d_un.d_ptr); break; - case 10: /* Size of string table */ + case DT_STRSZ: /* Size of string table */ object->dyn_string_table_size = table->d_un.d_val; break; - case 12: /* DT_INIT - initialization function */ + case DT_INIT: /* DT_INIT - initialization function */ object->init = (void (*)(void))(table->d_un.d_ptr + object->base); break; - case 25: /* DT_INIT_ARRAY - array of constructors */ + case DT_INIT_ARRAY: /* DT_INIT_ARRAY - array of constructors */ object->init_array = (void (**)(void))(table->d_un.d_ptr + object->base); break; - case 27: /* DT_INIT_ARRAYSZ - size of the table of constructors */ + case DT_INIT_ARRAYSZ: /* DT_INIT_ARRAYSZ - size of the table of constructors */ object->init_array_size = table->d_un.d_val / sizeof(uintptr_t); break; } @@ -391,6 +393,7 @@ static int need_symbol_for_type(unsigned char type) { case 6: case 7: case 14: + case R_X86_64_TPOFF64: return 1; default: return 0; @@ -402,7 +405,7 @@ static int object_relocate(elf_t * object) { /* If there is a dynamic symbol table, load symbols */ if (object->dyn_symbol_table) { - Elf32_Sym * table = object->dyn_symbol_table; + Elf64_Sym * table = object->dyn_symbol_table; size_t i = 0; while (i < object->dyn_symbol_table_size) { char * symname = (char *)((uintptr_t)object->dyn_string_table + table->st_name); @@ -421,18 +424,20 @@ static int object_relocate(elf_t * object) { /* Find relocation table */ for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) { - Elf32_Shdr shdr; + Elf64_Shdr shdr; /* Load section header */ fseek(object->file, object->header.e_shoff + x, SEEK_SET); fread(&shdr, object->header.e_shentsize, 1, object->file); /* Relocation table found */ - if (shdr.sh_type == 9) { - Elf32_Rel * table = (Elf32_Rel *)(shdr.sh_addr + object->base); + if (shdr.sh_type == SHT_REL) { + TRACE_LD("Found a REL section, this is not handled."); + } else if (shdr.sh_type == SHT_RELA) { + Elf64_Rela * table = (Elf64_Rela *)(shdr.sh_addr + object->base); while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) { - unsigned int symbol = ELF32_R_SYM(table->r_info); - unsigned char type = ELF32_R_TYPE(table->r_info); - Elf32_Sym * sym = &object->dyn_symbol_table[symbol]; + unsigned int symbol = ELF64_R_SYM(table->r_info); + unsigned int type = ELF64_R_TYPE(table->r_info); + Elf64_Sym * sym = &object->dyn_symbol_table[symbol]; /* If we need symbol for this, get it. */ char * symname = NULL; @@ -450,6 +455,41 @@ static int object_relocate(elf_t * object) { /* Relocations, symbol lookups, etc. */ switch (type) { + case R_X86_64_GLOB_DAT: /* 6 */ + if (symname && hashmap_has(glob_dat, symname)) { + x = (uintptr_t)hashmap_get(glob_dat, symname); + } /* fallthrough */ + case R_X86_64_JUMP_SLOT: /* 7 */ + memcpy((void*)(table->r_offset + object->base), &x, sizeof(uintptr_t)); + break; + case R_X86_64_RELATIVE: /* 8*/ + x = object->base; + x += table->r_addend; + //*((ssize_t *)(table->r_offset + object->base)); + memcpy((void*)(table->r_offset + object->base), &x, sizeof(uintptr_t)); + break; + case R_X86_64_64: /* 1 */ + x += table->r_addend; + memcpy((void*)(table->r_offset + object->base), &x, sizeof(uintptr_t)); + break; + case R_X86_64_COPY: /* 5 */ + memcpy((void *)(table->r_offset + object->base), (void *)x, sym->st_size); + break; + case R_X86_64_TPOFF64: + x = *((ssize_t *)(table->r_offset + object->base)); + if (!hashmap_has(tls_map, symname)) { + if (!sym->st_size) { + fprintf(stderr, "Haven't placed %s in static TLS yet but don't know its size?\n", symname); + } + current_tls_offset += sym->st_size; /* TODO alignment restrictions */ + hashmap_set(tls_map, symname, (void*)(current_tls_offset)); + x -= current_tls_offset; + } else { + x -= (size_t)hashmap_get(tls_map, symname); + } + memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t)); + break; +#if 0 case 6: /* GLOB_DAT */ if (symname && hashmap_has(glob_dat, symname)) { x = (uintptr_t)hashmap_get(glob_dat, symname); @@ -488,6 +528,7 @@ static int object_relocate(elf_t * object) { } memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t)); break; +#endif default: TRACE_LD("Unknown relocation type: %d", type); } @@ -504,18 +545,31 @@ static int object_relocate(elf_t * object) { static void object_find_copy_relocations(elf_t * object) { for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) { - Elf32_Shdr shdr; + Elf64_Shdr shdr; fseek(object->file, object->header.e_shoff + x, SEEK_SET); fread(&shdr, object->header.e_shentsize, 1, object->file); /* Relocation table found */ - if (shdr.sh_type == 9) { - Elf32_Rel * table = (Elf32_Rel *)(shdr.sh_addr + object->base); + if (shdr.sh_type == SHT_REL) { + Elf64_Rel * table = (Elf64_Rel *)(shdr.sh_addr + object->base); while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) { - unsigned char type = ELF32_R_TYPE(table->r_info); - if (type == 5) { - unsigned int symbol = ELF32_R_SYM(table->r_info); - Elf32_Sym * sym = &object->dyn_symbol_table[symbol]; + unsigned int type = ELF64_R_TYPE(table->r_info); + if (type == R_X86_64_COPY) { + unsigned int symbol = ELF64_R_SYM(table->r_info); + Elf64_Sym * sym = &object->dyn_symbol_table[symbol]; + char * symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name); + hashmap_set(glob_dat, symname, (void *)table->r_offset); + } + table++; + } + } + if (shdr.sh_type == SHT_RELA) { + Elf64_Rela * table = (Elf64_Rela *)(shdr.sh_addr + object->base); + while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) { + unsigned int type = ELF64_R_TYPE(table->r_info); + if (type == R_X86_64_COPY) { + unsigned int symbol = ELF64_R_SYM(table->r_info); + Elf64_Sym * sym = &object->dyn_symbol_table[symbol]; char * symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name); hashmap_set(glob_dat, symname, (void *)table->r_offset); } @@ -533,7 +587,7 @@ static void * object_find_symbol(elf_t * object, const char * symbol_name) { return NULL; } - Elf32_Sym * table = object->dyn_symbol_table; + Elf64_Sym * table = object->dyn_symbol_table; size_t i = 0; while (i < object->dyn_symbol_table_size) { if (!strcmp(symbol_name, (char *)((uintptr_t)object->dyn_string_table + table->st_name))) { @@ -736,7 +790,6 @@ ld_exports_t ld_builtin_exports[] = { }; int main(int argc, char * argv[]) { - if (argc < 2) { fprintf(stderr, "ld.so - dynamic binary loader\n" @@ -760,7 +813,7 @@ int main(int argc, char * argv[]) { /* Enable tracing if requested */ char * trace_ld_env = getenv("LD_DEBUG"); - if ((trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes")))) { + if (trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes"))) { __trace_ld = 1; } @@ -912,7 +965,7 @@ nope: _malloc_minimum = 0x40000000; /* Jump to the entry for the main object */ - TRACE_LD("Jumping to entry point"); + TRACE_LD("Jumping to entry point 0x%lx", main_obj->header.e_entry); entry_point_t entry = (entry_point_t)main_obj->header.e_entry; entry(argc-arg_offset,argv+arg_offset,environ); diff --git a/modules/README.md b/modules/README.md deleted file mode 100644 index a92692e1..00000000 --- a/modules/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# Kernel Modules - -The Toaru kernel supports loadable modules which provide most of the device driver support. - -A simple module requires a load and unload method, which are exposed along with a module -name through the `MODULE_DEF` macro available from ``. - -```c -#include - -static int load(void) { - /* Run on module installation */ - return 0; -} - -static int unload(void) { - /* Clean up for removal */ - return 0; -} - -MODULE_DEF(example_mod, load, unload); -``` - -## Module Dependencies - -If your module depends on another module being loaded, list each dependency using the `MODULE_DEPENDS` macro: - -```c -MODULE_DEF(extension_mod, load, unload); -MODULE_DEPENDS(example_mod); -``` - -Currently, dependencies are tested at load time, but the kernel will not load dependencies for you. - -Dependency lists can be parsed by external tools to ensure modules are properly linked. - -## Kernel Functions - -All non-static kernel functions are available for use in modules. -For example, the logging functions may be used: - -```c -#include -#include - -static int load(void) { - debug_print(WARNING, "Hello, world."); - return 0; -} - -static int unload(void) { - return 0; -} - -MODULE_DEF(printing_mod, load, unload); -``` - -## Background Tasks - -Device drivers, such as those for network devices, may want to create a background process to manage tasks. -This can be done through the `create_kernel_tasklet` interface at device startup. - -```c -#include -#include - -static void tasklet_run(void * data, char * name) { - /* Perform tasklet activities */ - while (1) { - do_thing(); - } -} - -static int load(void) { - create_kernel_tasklet(tasklet_run, "[demo-tasklet]", NULL); - return 0; -} - -static int unload(void) { - /* Maybe clean up your tasklet here. */ - return 0; -} - -MODULE_DEF(tasklet_mod, load, unload); -``` - -## Caveats - -- Currently, unloading modules is not supported. -- Modules which are expected to be loaded at runtime should be very careful of memory allocations they make, as they happen in a context which may not be shared with other processes. If you wish to make use of memory mappings, ensure that you are creating a new kernel tasklet to perform work. Attempting to access mapped memory from an interrupt handler or a device driver may not be possible if it was mapped at module installation. - diff --git a/modules/ata.c b/modules/ata.c deleted file mode 100644 index 3c7054e6..00000000 --- a/modules/ata.c +++ /dev/null @@ -1,895 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * ATA Disk Driver - * - * Provides raw block access to an (Parallel) ATA drive. - */ - -#include -#include -#include -#include -#include -#include - -/* TODO: Move this to mod/ata.h */ -#include - -#include - -static char ata_drive_char = 'a'; -static int cdrom_number = 0; -static uint32_t ata_pci = 0x00000000; -static list_t * atapi_waiter; -static int atapi_in_progress = 0; - -typedef union { - uint8_t command_bytes[12]; - uint16_t command_words[6]; -} atapi_command_t; - -/* 8086:7010 */ -static void find_ata_pci(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if ((vendorid == 0x8086) && (deviceid == 0x7010 || deviceid == 0x7111)) { - *((uint32_t *)extra) = device; - } -} - -typedef struct { - uintptr_t offset; - uint16_t bytes; - uint16_t last; -} prdt_t; - -struct ata_device { - int io_base; - int control; - int slave; - int is_atapi; - ata_identify_t identity; - prdt_t * dma_prdt; - uintptr_t dma_prdt_phys; - uint8_t * dma_start; - uintptr_t dma_start_phys; - uint32_t bar4; - uint32_t atapi_lba; - uint32_t atapi_sector_size; -}; - -static struct ata_device ata_primary_master = {.io_base = 0x1F0, .control = 0x3F6, .slave = 0}; -static struct ata_device ata_primary_slave = {.io_base = 0x1F0, .control = 0x3F6, .slave = 1}; -static struct ata_device ata_secondary_master = {.io_base = 0x170, .control = 0x376, .slave = 0}; -static struct ata_device ata_secondary_slave = {.io_base = 0x170, .control = 0x376, .slave = 1}; - -//static volatile uint8_t ata_lock = 0; -static spin_lock_t ata_lock = { 0 }; - -/* TODO support other sector sizes */ -#define ATA_SECTOR_SIZE 512 - -static void ata_device_read_sector(struct ata_device * dev, uint64_t lba, uint8_t * buf); -static void ata_device_read_sector_atapi(struct ata_device * dev, uint64_t lba, uint8_t * buf); -static void ata_device_write_sector_retry(struct ata_device * dev, uint64_t lba, uint8_t * buf); -static uint32_t read_ata(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer); -static uint32_t write_ata(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer); -static void open_ata(fs_node_t *node, unsigned int flags); -static void close_ata(fs_node_t *node); - -static uint64_t ata_max_offset(struct ata_device * dev) { - uint64_t sectors = dev->identity.sectors_48; - if (!sectors) { - /* Fall back to sectors_28 */ - sectors = dev->identity.sectors_28; - } - - return sectors * ATA_SECTOR_SIZE; -} - -static uint64_t atapi_max_offset(struct ata_device * dev) { - uint64_t max_sector = dev->atapi_lba; - - if (!max_sector) return 0; - - return (max_sector + 1) * dev->atapi_sector_size; -} - -static uint32_t read_ata(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - - struct ata_device * dev = (struct ata_device *)node->device; - -#if 0 - debug_print(ERROR, "ATA read at offset 0x%8x%8x", (uint32_t)(offset >> 32), (uint32_t)(offset & 0xFFFFFFFF)); - debug_print(ERROR, "read size is 0x%8x", size); -#endif - - unsigned int start_block = offset / ATA_SECTOR_SIZE; - unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; - - unsigned int x_offset = 0; - - - if (offset > ata_max_offset(dev)) { - return 0; - } - - if (offset + size > ata_max_offset(dev)) { - unsigned int i = ata_max_offset(dev) - offset; - size = i; - } - - if (offset % ATA_SECTOR_SIZE || size < ATA_SECTOR_SIZE) { - unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); - if (prefix_size > size) prefix_size = size; - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, start_block, (uint8_t *)tmp); - - memcpy(buffer, (void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_SECTOR_SIZE)), prefix_size); - - free(tmp); - - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { - unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, end_block, (uint8_t *)tmp); - - memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size); - - free(tmp); - - end_block--; - } - - while (start_block <= end_block) { - ata_device_read_sector(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += ATA_SECTOR_SIZE; - start_block++; - } - - return size; -} - -static uint32_t read_atapi(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - - struct ata_device * dev = (struct ata_device *)node->device; - - unsigned int start_block = offset / dev->atapi_sector_size; - unsigned int end_block = (offset + size - 1) / dev->atapi_sector_size; - - unsigned int x_offset = 0; - - if (offset > atapi_max_offset(dev)) { - return 0; - } - - if (offset + size > atapi_max_offset(dev)) { - unsigned int i = atapi_max_offset(dev) - offset; - size = i; - } - - if (offset % dev->atapi_sector_size || size < dev->atapi_sector_size) { - unsigned int prefix_size = (dev->atapi_sector_size - (offset % dev->atapi_sector_size)); - if (prefix_size > size) prefix_size = size; - char * tmp = malloc(dev->atapi_sector_size); - ata_device_read_sector_atapi(dev, start_block, (uint8_t *)tmp); - - memcpy(buffer, (void *)((uintptr_t)tmp + ((uintptr_t)offset % dev->atapi_sector_size)), prefix_size); - - free(tmp); - - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % dev->atapi_sector_size && start_block <= end_block) { - unsigned int postfix_size = (offset + size) % dev->atapi_sector_size; - char * tmp = malloc(dev->atapi_sector_size); - ata_device_read_sector_atapi(dev, end_block, (uint8_t *)tmp); - - memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size); - - free(tmp); - - end_block--; - } - - while (start_block <= end_block) { - ata_device_read_sector_atapi(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += dev->atapi_sector_size; - start_block++; - } - - return size; -} - - -static uint32_t write_ata(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - struct ata_device * dev = (struct ata_device *)node->device; - - unsigned int start_block = offset / ATA_SECTOR_SIZE; - unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; - - unsigned int x_offset = 0; - -#if 0 - debug_print(ERROR, "ATA write at offset 0x%8x%8x", (uint32_t)(offset >> 32), (uint32_t)(offset & 0xFFFFFFFF)); - debug_print(ERROR, "write size is 0x%8x", size); - debug_print(ERROR, "some data from buf: [%2x %2x %2x %2x]", buffer[0], buffer[1], buffer[2], buffer[3]); -#endif - - if (offset > ata_max_offset(dev)) { - return 0; - } - - if (offset + size > ata_max_offset(dev)) { - unsigned int i = ata_max_offset(dev) - offset; - size = i; - } - - if (offset % ATA_SECTOR_SIZE) { - unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); - - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, start_block, (uint8_t *)tmp); - - debug_print(NOTICE, "Writing first block"); - - memcpy((void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_SECTOR_SIZE)), buffer, prefix_size); - ata_device_write_sector_retry(dev, start_block, (uint8_t *)tmp); - - free(tmp); - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { - unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; - - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, end_block, (uint8_t *)tmp); - - debug_print(NOTICE, "Writing last block"); - - memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), postfix_size); - - ata_device_write_sector_retry(dev, end_block, (uint8_t *)tmp); - - free(tmp); - end_block--; - } - - while (start_block <= end_block) { - ata_device_write_sector_retry(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += ATA_SECTOR_SIZE; - start_block++; - } - - return size; -} - -static void open_ata(fs_node_t * node, unsigned int flags) { - return; -} - -static void close_ata(fs_node_t * node) { - return; -} - -static fs_node_t * atapi_device_create(struct ata_device * device) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - sprintf(fnode->name, "cdrom%d", cdrom_number); - fnode->device = device; - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0664; - fnode->length = atapi_max_offset(device); - fnode->flags = FS_BLOCKDEVICE; - fnode->read = read_atapi; - fnode->write = NULL; /* no write support */ - fnode->open = open_ata; - fnode->close = close_ata; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->ioctl = NULL; /* TODO, identify, etc? */ - return fnode; -} - - -static fs_node_t * ata_device_create(struct ata_device * device) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - sprintf(fnode->name, "atadev%d", ata_drive_char - 'a'); - fnode->device = device; - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0660; - fnode->length = ata_max_offset(device); /* TODO */ - fnode->flags = FS_BLOCKDEVICE; - fnode->read = read_ata; - fnode->write = write_ata; - fnode->open = open_ata; - fnode->close = close_ata; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->ioctl = NULL; /* TODO, identify, etc? */ - return fnode; -} - -static void ata_io_wait(struct ata_device * dev) { - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); -} - -static int ata_status_wait(struct ata_device * dev, int timeout) { - int status; - if (timeout > 0) { - int i = 0; - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY && (i < timeout)) i++; - } else { - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY); - } - return status; -} - -static int ata_wait(struct ata_device * dev, int advanced) { - uint8_t status = 0; - - ata_io_wait(dev); - - status = ata_status_wait(dev, -1); - - if (advanced) { - status = inportb(dev->io_base + ATA_REG_STATUS); - if (status & ATA_SR_ERR) return 1; - if (status & ATA_SR_DF) return 1; - if (!(status & ATA_SR_DRQ)) return 1; - } - - return 0; -} - -static void ata_soft_reset(struct ata_device * dev) { - outportb(dev->control, 0x04); - ata_io_wait(dev); - outportb(dev->control, 0x00); -} - -static int ata_irq_handler(struct regs *r) { - inportb(ata_primary_master.io_base + ATA_REG_STATUS); - if (atapi_in_progress) { - wakeup_queue(atapi_waiter); - } - irq_ack(14); - return 1; -} - -static int ata_irq_handler_s(struct regs *r) { - inportb(ata_secondary_master.io_base + ATA_REG_STATUS); - if (atapi_in_progress) { - wakeup_queue(atapi_waiter); - } - irq_ack(15); - return 1; -} - -static void ata_device_init(struct ata_device * dev) { - - debug_print(NOTICE, "Initializing IDE device on bus %d", dev->io_base); - - outportb(dev->io_base + 1, 1); - outportb(dev->control, 0); - - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - ata_io_wait(dev); - - int status = inportb(dev->io_base + ATA_REG_COMMAND); - debug_print(INFO, "Device status: %d", status); - - ata_wait(dev, 0); - - uint16_t * buf = (uint16_t *)&dev->identity; - - for (int i = 0; i < 256; ++i) { - buf[i] = inports(dev->io_base); - } - - uint8_t * ptr = (uint8_t *)&dev->identity.model; - for (int i = 0; i < 39; i+=2) { - uint8_t tmp = ptr[i+1]; - ptr[i+1] = ptr[i]; - ptr[i] = tmp; - } - - dev->is_atapi = 0; - - debug_print(NOTICE, "Device Name: %s", dev->identity.model); - debug_print(NOTICE, "Sectors (48): %d", (uint32_t)dev->identity.sectors_48); - debug_print(NOTICE, "Sectors (24): %d", dev->identity.sectors_28); - - debug_print(NOTICE, "Setting up DMA..."); - dev->dma_prdt = (void *)kvmalloc_p(sizeof(prdt_t) * 1, &dev->dma_prdt_phys); - dev->dma_start = (void *)kvmalloc_p(4096, &dev->dma_start_phys); - - debug_print(NOTICE, "Putting prdt at 0x%x (0x%x phys)", dev->dma_prdt, dev->dma_prdt_phys); - debug_print(NOTICE, "Putting prdt[0] at 0x%x (0x%x phys)", dev->dma_start, dev->dma_start_phys); - - dev->dma_prdt[0].offset = dev->dma_start_phys; - dev->dma_prdt[0].bytes = 512; - dev->dma_prdt[0].last = 0x8000; - - debug_print(NOTICE, "ATA PCI device ID: 0x%x", ata_pci); - - uint16_t command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); - debug_print(NOTICE, "COMMAND register before: 0x%4x", command_reg); - if (command_reg & (1 << 2)) { - debug_print(NOTICE, "Bus mastering already enabled."); - } else { - command_reg |= (1 << 2); /* bit 2 */ - debug_print(NOTICE, "Enabling bus mastering..."); - pci_write_field(ata_pci, PCI_COMMAND, 4, command_reg); - command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); - debug_print(NOTICE, "COMMAND register after: 0x%4x", command_reg); - } - - dev->bar4 = pci_read_field(ata_pci, PCI_BAR4, 4); - debug_print(NOTICE, "BAR4: 0x%x", dev->bar4); - - if (dev->bar4 & 0x00000001) { - dev->bar4 = dev->bar4 & 0xFFFFFFFC; - } else { - debug_print(WARNING, "? ATA bus master registers are /usually/ I/O ports.\n"); - return; /* No DMA because we're not sure what to do here */ - } - -#if 0 - pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 0xFE); - if (pci_read_field(ata_pci, PCI_INTERRUPT_LINE, 1) == 0xFE) { - /* needs assignment */ - pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 14); - } -#endif - -} - -static int atapi_device_init(struct ata_device * dev) { - - dev->is_atapi = 1; - - outportb(dev->io_base + 1, 1); - outportb(dev->control, 0); - - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); - ata_io_wait(dev); - - int status = inportb(dev->io_base + ATA_REG_COMMAND); - debug_print(INFO, "Device status: %d", status); - - ata_wait(dev, 0); - - uint16_t * buf = (uint16_t *)&dev->identity; - - for (int i = 0; i < 256; ++i) { - buf[i] = inports(dev->io_base); - } - - uint8_t * ptr = (uint8_t *)&dev->identity.model; - for (int i = 0; i < 39; i+=2) { - uint8_t tmp = ptr[i+1]; - ptr[i+1] = ptr[i]; - ptr[i] = tmp; - } - - debug_print(NOTICE, "Device Name: %s", dev->identity.model); - - /* Detect medium */ - atapi_command_t command; - command.command_bytes[0] = 0x25; - command.command_bytes[1] = 0; - command.command_bytes[2] = 0; - command.command_bytes[3] = 0; - command.command_bytes[4] = 0; - command.command_bytes[5] = 0; - command.command_bytes[6] = 0; - command.command_bytes[7] = 0; - command.command_bytes[8] = 0; /* bit 0 = PMI (0, last sector) */ - command.command_bytes[9] = 0; /* control */ - command.command_bytes[10] = 0; - command.command_bytes[11] = 0; - - uint16_t bus = dev->io_base; - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_LBA1, 0x08); - outportb(bus + ATA_REG_LBA2, 0x08); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); - - /* poll */ - int timeout = 100; - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error; - if (timeout-- < 100) goto atapi_timeout; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - } - - for (int i = 0; i < 6; ++i) { - outports(bus, command.command_words[i]); - } - - /* poll */ - timeout = 100; - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_read; - if (timeout-- < 100) goto atapi_timeout; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - if ((status & ATA_SR_DRQ)) break; - } - - uint16_t data[4]; - - for (int i = 0; i < 4; ++i) { - data[i] = inports(bus); - } - -#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) - uint32_t lba, blocks;; - memcpy(&lba, &data[0], sizeof(uint32_t)); - lba = htonl(lba); - memcpy(&blocks, &data[2], sizeof(uint32_t)); - blocks = htonl(blocks); - - dev->atapi_lba = lba; - dev->atapi_sector_size = blocks; - - if (!lba) return 1; - - debug_print(WARNING, "Finished! LBA = %x; block length = %x", lba, blocks); - return 0; - -atapi_error_read: - debug_print(ERROR, "ATAPI error; no medium?"); - return 1; - -atapi_error: - debug_print(ERROR, "ATAPI early error; unsure"); - return 1; - -atapi_timeout: - debug_print(ERROR, "ATAPI device timeout, ignoring."); - return 1; -} - -static int ata_device_detect(struct ata_device * dev) { - ata_soft_reset(dev); - ata_io_wait(dev); - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - ata_status_wait(dev, 10000); - - unsigned char cl = inportb(dev->io_base + ATA_REG_LBA1); /* CYL_LO */ - unsigned char ch = inportb(dev->io_base + ATA_REG_LBA2); /* CYL_HI */ - - debug_print(NOTICE, "Device detected: 0x%2x 0x%2x", cl, ch); - if (cl == 0xFF && ch == 0xFF) { - /* Nothing here */ - return 0; - } - if ((cl == 0x00 && ch == 0x00) || - (cl == 0x3C && ch == 0xC3)) { - /* Parallel ATA device, or emulated SATA */ - - char devname[64]; - sprintf((char *)&devname, "/dev/hd%c", ata_drive_char); - fs_node_t * node = ata_device_create(dev); - vfs_mount(devname, node); - ata_device_init(dev); - node->length = ata_max_offset(dev); - - ata_drive_char++; - return 1; - } else if ((cl == 0x14 && ch == 0xEB) || - (cl == 0x69 && ch == 0x96)) { - debug_print(WARNING, "Detected ATAPI device at io-base 0x%3x, control 0x%3x, slave %d", dev->io_base, dev->control, dev->slave); - - char devname[64]; - sprintf((char *)&devname, "/dev/cdrom%d", cdrom_number); - - if (atapi_device_init(dev)) { - return 0; - } - fs_node_t * node = atapi_device_create(dev); - vfs_mount(devname, node); - - cdrom_number++; - - return 2; - } - - /* TODO: ATAPI, SATA, SATAPI */ - return 0; -} - -static void ata_device_read_sector(struct ata_device * dev, uint64_t lba, uint8_t * buf) { - uint16_t bus = dev->io_base; - uint8_t slave = dev->slave; - - if (dev->is_atapi) return; - -#if 0 - debug_print(ERROR, "Request to read sector %8x%8x", - (uint32_t)(lba >> 32), - (uint32_t)(lba & 0xFFFFFFFF)); -#endif - - spin_lock(ata_lock); - -#if 0 - int errors = 0; -try_again: -#endif - - ata_wait(dev, 0); - - /* Stop */ - outportb(dev->bar4, 0x00); - - /* Set the PRDT */ - outportl(dev->bar4 + 0x04, dev->dma_prdt_phys); - - /* Enable error, irq status */ - outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); - - /* set read */ - outportb(dev->bar4, 0x08); - - IRQ_ON; - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if (!(status & ATA_SR_BSY)) break; - } - - outportb(bus + ATA_REG_CONTROL, 0x00); - outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4); - ata_io_wait(dev); - outportb(bus + ATA_REG_FEATURES, 0x00); - - outportb(bus + ATA_REG_SECCOUNT0, 0); - outportb(bus + ATA_REG_LBA0, (lba & 0xff000000) >> 24); - outportb(bus + ATA_REG_LBA1, (lba & 0xff00000000) >> 32); - outportb(bus + ATA_REG_LBA2, (lba & 0xff0000000000) >> 40); - - outportb(bus + ATA_REG_SECCOUNT0, 1); - outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); - outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); - outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - - //outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_PIO); -#if 1 - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - } -#endif - outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_DMA_EXT); - - ata_io_wait(dev); - - outportb(dev->bar4, 0x08 | 0x01); - - while (1) { - int status = inportb(dev->bar4 + 0x02); - int dstatus = inportb(dev->io_base + ATA_REG_STATUS); - if (!(status & 0x04)) { - continue; - } - if (!(dstatus & ATA_SR_BSY)) { - break; - } - } - IRQ_OFF; - -#if 0 - if (ata_wait(dev, 1)) { - debug_print(WARNING, "Error during ATA read of lba block %d", lba); - errors++; - if (errors > 4) { - debug_print(WARNING, "-- Too many errors trying to read this block. Bailing."); - spin_unlock(ata_lock); - return; - } - goto try_again; - } -#endif - - /* Copy from DMA buffer to output buffer. */ - memcpy(buf, dev->dma_start, 512); - - /* Inform device we are done. */ - outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); - -#if 0 - int size = 256; - inportsm(bus,buf,size); - ata_wait(dev, 0); - outportb(bus + ATA_REG_CONTROL, 0x02); -#endif - spin_unlock(ata_lock); -} - -static void ata_device_read_sector_atapi(struct ata_device * dev, uint64_t lba, uint8_t * buf) { - - if (!dev->is_atapi) return; - - uint16_t bus = dev->io_base; - spin_lock(ata_lock); - - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_LBA1, dev->atapi_sector_size & 0xFF); - outportb(bus + ATA_REG_LBA2, dev->atapi_sector_size >> 8); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); - - /* poll */ - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; - } - - atapi_in_progress = 1; - - - atapi_command_t command; - command.command_bytes[0] = 0xA8; - command.command_bytes[1] = 0; - command.command_bytes[2] = (lba >> 0x18) & 0xFF; - command.command_bytes[3] = (lba >> 0x10) & 0xFF; - command.command_bytes[4] = (lba >> 0x08) & 0xFF; - command.command_bytes[5] = (lba >> 0x00) & 0xFF; - command.command_bytes[6] = 0; - command.command_bytes[7] = 0; - command.command_bytes[8] = 0; /* bit 0 = PMI (0, last sector) */ - command.command_bytes[9] = 1; /* control */ - command.command_bytes[10] = 0; - command.command_bytes[11] = 0; - - for (int i = 0; i < 6; ++i) { - outports(bus, command.command_words[i]); - } - - /* Wait */ - sleep_on(atapi_waiter); - - atapi_in_progress = 0; - - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; - } - - uint16_t size_to_read = inportb(bus + ATA_REG_LBA2) << 8; - size_to_read = size_to_read | inportb(bus + ATA_REG_LBA1); - - - inportsm(bus,buf,size_to_read/2); - - while (1) { - uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); - if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; - if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; - } - -atapi_error_on_read_setup: - spin_unlock(ata_lock); - -} - -static void ata_device_write_sector(struct ata_device * dev, uint64_t lba, uint8_t * buf) { - uint16_t bus = dev->io_base; - uint8_t slave = dev->slave; - -#if 0 - debug_print(ERROR, "Request to write sector %8x%8x", - (uint32_t)(lba >> 32), - (uint32_t)(lba & 0xFFFFFFFF)); - debug_print(ERROR, "Some data from buf: [%2x %2x %2x %2x]", buf[0], buf[1], buf[2], buf[3]); -#endif - - spin_lock(ata_lock); - - outportb(bus + ATA_REG_CONTROL, 0x02); - - ata_wait(dev, 0); - outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4); - ata_wait(dev, 0); - - outportb(bus + ATA_REG_FEATURES, 0x00); - - outportb(bus + ATA_REG_SECCOUNT0, 0); - outportb(bus + ATA_REG_LBA0, (lba & 0xff000000) >> 24); - outportb(bus + ATA_REG_LBA1, (lba & 0xff00000000) >> 32); - outportb(bus + ATA_REG_LBA2, (lba & 0xff0000000000) >> 40); - - outportb(bus + ATA_REG_SECCOUNT0, 1); - outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); - outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); - outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - - outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT); - ata_wait(dev, 0); - int size = ATA_SECTOR_SIZE / 2; - outportsm(bus,buf,size); - outportb(bus + 0x07, ATA_CMD_CACHE_FLUSH); - ata_wait(dev, 0); - spin_unlock(ata_lock); -} - -static int buffer_compare(uint32_t * ptr1, uint32_t * ptr2, size_t size) { - assert(!(size % 4)); - size_t i = 0; - while (i < size) { - if (*ptr1 != *ptr2) return 1; - ptr1++; - ptr2++; - i += sizeof(uint32_t); - } - return 0; -} - -static void ata_device_write_sector_retry(struct ata_device * dev, uint64_t lba, uint8_t * buf) { - uint64_t sectors = dev->identity.sectors_48; - if (lba >= sectors) return; - uint8_t * read_buf = malloc(ATA_SECTOR_SIZE); - do { - ata_device_write_sector(dev, lba, buf); - ata_device_read_sector(dev, lba, read_buf); - } while (buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); - free(read_buf); -} - -static int ata_initialize(void) { - /* Detect drives and mount them */ - - /* Locate ATA device via PCI */ - pci_scan(&find_ata_pci, -1, &ata_pci); - - irq_install_handler(14, ata_irq_handler, "ide master"); - irq_install_handler(15, ata_irq_handler_s, "ide slave"); - - atapi_waiter = list_create(); - - ata_device_detect(&ata_primary_master); - ata_device_detect(&ata_primary_slave); - ata_device_detect(&ata_secondary_master); - ata_device_detect(&ata_secondary_slave); - - return 0; -} - -static int ata_finalize(void) { - - return 0; -} - -MODULE_DEF(ata, ata_initialize, ata_finalize); diff --git a/modules/ataold.c b/modules/ataold.c deleted file mode 100644 index 070b3fa8..00000000 --- a/modules/ataold.c +++ /dev/null @@ -1,408 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * ATA Disk Driver - * - * Provides raw block access to an (Parallel) ATA drive. - */ - -#include -#include -#include -#include -#include - -/* TODO: Move this to mod/ata.h */ -#include - -static char ata_drive_char = 'a'; - -struct ata_device { - int io_base; - int control; - int slave; - ata_identify_t identity; -}; - -//static volatile uint8_t ata_lock = 0; -static spin_lock_t ata_lock = { 0 }; - -/* TODO support other sector sizes */ -#define ATA_SECTOR_SIZE 512 - -static void ata_device_read_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf); -static void ata_device_write_sector_retry(struct ata_device * dev, uint32_t lba, uint8_t * buf); - -static uint64_t ata_max_offset(struct ata_device * dev) { - uint64_t sectors = dev->identity.sectors_48; - if (!sectors) { - /* Fall back to sectors_28 */ - sectors = dev->identity.sectors_28; - } - - return sectors * ATA_SECTOR_SIZE; -} - -static uint32_t read_ata(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - - struct ata_device * dev = (struct ata_device *)node->device; - - unsigned int start_block = offset / ATA_SECTOR_SIZE; - unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; - - unsigned int x_offset = 0; - - if (offset > ata_max_offset(dev)) { - return 0; - } - - if (offset + size > ata_max_offset(dev)) { - unsigned int i = ata_max_offset(dev) - offset; - size = i; - } - - if (offset % ATA_SECTOR_SIZE) { - unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, start_block, (uint8_t *)tmp); - - memcpy(buffer, (void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_SECTOR_SIZE)), prefix_size); - - free(tmp); - - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % ATA_SECTOR_SIZE && start_block < end_block) { - unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, end_block, (uint8_t *)tmp); - - memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size); - - free(tmp); - - end_block--; - } - - while (start_block <= end_block) { - ata_device_read_sector(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += ATA_SECTOR_SIZE; - start_block++; - } - - return size; -} - -static uint32_t write_ata(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - struct ata_device * dev = (struct ata_device *)node->device; - - unsigned int start_block = offset / ATA_SECTOR_SIZE; - unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; - - unsigned int x_offset = 0; - - if (offset > ata_max_offset(dev)) { - return 0; - } - - if (offset + size > ata_max_offset(dev)) { - unsigned int i = ata_max_offset(dev) - offset; - size = i; - } - - if (offset % ATA_SECTOR_SIZE) { - unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); - - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, start_block, (uint8_t *)tmp); - - debug_print(NOTICE, "Writing first block"); - - memcpy((void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_SECTOR_SIZE)), buffer, prefix_size); - ata_device_write_sector_retry(dev, start_block, (uint8_t *)tmp); - - free(tmp); - x_offset += prefix_size; - start_block++; - } - - if ((offset + size) % ATA_SECTOR_SIZE && start_block < end_block) { - unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; - - char * tmp = malloc(ATA_SECTOR_SIZE); - ata_device_read_sector(dev, end_block, (uint8_t *)tmp); - - debug_print(NOTICE, "Writing last block"); - - memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), postfix_size); - - ata_device_write_sector_retry(dev, end_block, (uint8_t *)tmp); - - free(tmp); - end_block--; - } - - while (start_block <= end_block) { - ata_device_write_sector_retry(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); - x_offset += ATA_SECTOR_SIZE; - start_block++; - } - - return size; -} - -static void open_ata(fs_node_t * node, unsigned int flags) { - return; -} - -static void close_ata(fs_node_t * node) { - return; -} - -static fs_node_t * ata_device_create(struct ata_device * device) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - sprintf(fnode->name, "atadev%d", ata_drive_char - 'a'); - fnode->device = device; - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0660; - fnode->length = ata_max_offset(device); /* TODO */ - fnode->flags = FS_BLOCKDEVICE; - fnode->read = read_ata; - fnode->write = write_ata; - fnode->open = open_ata; - fnode->close = close_ata; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->ioctl = NULL; /* TODO, identify, etc? */ - return fnode; -} - -static void ata_io_wait(struct ata_device * dev) { - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); - inportb(dev->io_base + ATA_REG_ALTSTATUS); -} - -static int ata_status_wait(struct ata_device * dev, int timeout) { - int status; - if (timeout > 0) { - int i = 0; - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY && (i < timeout)) i++; - } else { - while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY); - } - return status; -} - -static int ata_wait(struct ata_device * dev, int advanced) { - uint8_t status = 0; - - ata_io_wait(dev); - - status = ata_status_wait(dev, -1); - - if (advanced) { - status = inportb(dev->io_base + ATA_REG_STATUS); - if (status & ATA_SR_ERR) return 1; - if (status & ATA_SR_DF) return 1; - if (!(status & ATA_SR_DRQ)) return 1; - } - - return 0; -} - -static void ata_soft_reset(struct ata_device * dev) { - outportb(dev->control, 0x04); - ata_io_wait(dev); - outportb(dev->control, 0x00); -} - -static void ata_device_init(struct ata_device * dev) { - - debug_print(NOTICE, "Initializing IDE device on bus %d", dev->io_base); - - outportb(dev->io_base + 1, 1); - outportb(dev->control, 0); - - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - - outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - ata_io_wait(dev); - - int status = inportb(dev->io_base + ATA_REG_COMMAND); - debug_print(INFO, "Device status: %d", status); - - ata_wait(dev, 0); - - uint16_t * buf = (uint16_t *)&dev->identity; - - for (int i = 0; i < 256; ++i) { - buf[i] = inports(dev->io_base); - } - - uint8_t * ptr = (uint8_t *)&dev->identity.model; - for (int i = 0; i < 39; i+=2) { - uint8_t tmp = ptr[i+1]; - ptr[i+1] = ptr[i]; - ptr[i] = tmp; - } - - debug_print(NOTICE, "Device Name: %s", dev->identity.model); - debug_print(NOTICE, "Sectors (48): %d", (uint32_t)dev->identity.sectors_48); - debug_print(NOTICE, "Sectors (24): %d", dev->identity.sectors_28); - - outportb(dev->io_base + ATA_REG_CONTROL, 0x02); -} - -static int ata_device_detect(struct ata_device * dev) { - ata_soft_reset(dev); - ata_io_wait(dev); - outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); - ata_io_wait(dev); - ata_status_wait(dev, 10000); - - unsigned char cl = inportb(dev->io_base + ATA_REG_LBA1); /* CYL_LO */ - unsigned char ch = inportb(dev->io_base + ATA_REG_LBA2); /* CYL_HI */ - - debug_print(NOTICE, "Device detected: 0x%2x 0x%2x", cl, ch); - if (cl == 0xFF && ch == 0xFF) { - /* Nothing here */ - return 0; - } - if ((cl == 0x00 && ch == 0x00) || - (cl == 0x3C && ch == 0xC3)) { - /* Parallel ATA device, or emulated SATA */ - - char devname[64]; - sprintf((char *)&devname, "/dev/hd%c", ata_drive_char); - fs_node_t * node = ata_device_create(dev); - vfs_mount(devname, node); - ata_drive_char++; - - ata_device_init(dev); - - return 1; - } - - /* TODO: ATAPI, SATA, SATAPI */ - return 0; -} - -static void ata_device_read_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf) { - uint16_t bus = dev->io_base; - uint8_t slave = dev->slave; - - spin_lock(ata_lock); - - int errors = 0; -try_again: - outportb(bus + ATA_REG_CONTROL, 0x02); - - ata_wait(dev, 0); - - outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_SECCOUNT0, 1); - outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); - outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); - outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_PIO); - - if (ata_wait(dev, 1)) { - debug_print(WARNING, "Error during ATA read of lba block %d", lba); - errors++; - if (errors > 4) { - debug_print(WARNING, "-- Too many errors trying to read this block. Bailing."); - spin_unlock(ata_lock); - return; - } - goto try_again; - } - - int size = 256; - inportsm(bus,buf,size); - ata_wait(dev, 0); - spin_unlock(ata_lock); -} - -static void ata_device_write_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf) { - uint16_t bus = dev->io_base; - uint8_t slave = dev->slave; - - spin_lock(ata_lock); - - outportb(bus + ATA_REG_CONTROL, 0x02); - - ata_wait(dev, 0); - outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); - ata_wait(dev, 0); - - outportb(bus + ATA_REG_FEATURES, 0x00); - outportb(bus + ATA_REG_SECCOUNT0, 0x01); - outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); - outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); - outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); - ata_wait(dev, 0); - int size = ATA_SECTOR_SIZE / 2; - outportsm(bus,buf,size); - outportb(bus + 0x07, ATA_CMD_CACHE_FLUSH); - ata_wait(dev, 0); - spin_unlock(ata_lock); -} - -static int buffer_compare(uint32_t * ptr1, uint32_t * ptr2, size_t size) { - assert(!(size % 4)); - size_t i = 0; - while (i < size) { - if (*ptr1 != *ptr2) return 1; - ptr1++; - ptr2++; - i += sizeof(uint32_t); - } - return 0; -} - -static void ata_device_write_sector_retry(struct ata_device * dev, uint32_t lba, uint8_t * buf) { - uint8_t * read_buf = malloc(ATA_SECTOR_SIZE); - IRQ_OFF; - do { - ata_device_write_sector(dev, lba, buf); - ata_device_read_sector(dev, lba, read_buf); - } while (buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); - IRQ_RES; - free(read_buf); -} - -static struct ata_device ata_primary_master = {.io_base = 0x1F0, .control = 0x3F6, .slave = 0}; -static struct ata_device ata_primary_slave = {.io_base = 0x1F0, .control = 0x3F6, .slave = 1}; -static struct ata_device ata_secondary_master = {.io_base = 0x170, .control = 0x376, .slave = 0}; -static struct ata_device ata_secondary_slave = {.io_base = 0x170, .control = 0x376, .slave = 1}; - - -static int ata_initialize(void) { - /* Detect drives and mount them */ - - ata_device_detect(&ata_primary_master); - ata_device_detect(&ata_primary_slave); - ata_device_detect(&ata_secondary_master); - ata_device_detect(&ata_secondary_slave); - - return 0; -} - -static int ata_finalize(void) { - - return 0; -} - -MODULE_DEF(ata_legacy, ata_initialize, ata_finalize); diff --git a/modules/debug_sh.c b/modules/debug_sh.c deleted file mode 100644 index e8fa98cb..00000000 --- a/modules/debug_sh.c +++ /dev/null @@ -1,754 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * Kernel Debug Shell - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -/* - * just call read_fs honestly, I don't care anymore - */ -int debug_shell_readline(fs_node_t * dev, char * linebuf, int max) { - int r = read_fs(dev, 0, max, (uint8_t *)linebuf); - if (r <= 0) return -1; - if (r && linebuf[r-1] == '\n') { - linebuf[r-1] = '\0'; - return r-1; - } - return r; -} - -/* - * Tasklet for running a userspace application. - */ -static void debug_shell_run_sh(void * data, char * name) { - - char * argv[] = { - data, - NULL - }; - int argc = 0; - while (argv[argc]) { - argc++; - } - char * env[] = { - "LD_LIBRARY_PATH=/lib", - NULL - }; - system(argv[0], argc, argv, env); /* Run shell */ - - task_exit(42); -} - -static hashmap_t * shell_commands_map = NULL; - -/* - * Shell commands - */ -static int shell_create_userspace_shell(fs_node_t * tty, int argc, char * argv[]) { - int pid = create_kernel_tasklet(debug_shell_run_sh, "[[k-sh]]", "/bin/sh"); - fprintf(tty, "Shell started with pid = %d\n", pid); - int status; - waitpid(pid,&status,0); - return status; -} - -static int shell_replace_login(fs_node_t * tty, int argc, char * argv[]) { - /* We need to fork to get a clean task space */ - create_kernel_tasklet(debug_shell_run_sh, "[[k-sh]]", "/bin/login"); - /* Then exit the shell process */ - task_exit(0); - /* unreachable */ - return 0; -} - -static int shell_echo(fs_node_t * tty, int argc, char * argv[]) { - for (int i = 1; i < argc; ++i) { - fprintf(tty, "%s ", argv[i]); - } - fprintf(tty, "\n"); - return 0; -} - -static int dumb_strcmp(void * a, void *b) { - return strcmp(a, b); -} - -static void dumb_sort(void ** list, size_t length, int (*compare)(void*,void*)) { - for (unsigned int i = 0; i < length-1; ++i) { - for (unsigned int j = 0; j < length-1; ++j) { - if (compare(list[j], list[j+1]) > 0) { - void * t = list[j+1]; - list[j+1] = list[j]; - list[j] = t; - } - } - } -} - -static void print_spaces(fs_node_t * tty, int num_spaces) { - for (int i = 0; i < num_spaces; ++i) { - fprintf(tty, " "); - } -} - -static int shell_help(fs_node_t * tty, int argc, char * argv[]) { - list_t * hash_keys = hashmap_keys(shell_commands_map); - - char ** keys = malloc(sizeof(char *) * hash_keys->length); - - unsigned int i = 0; - unsigned int max_width = 0; - - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - keys[i] = key; - i++; - if (strlen(key) > max_width) { - max_width = strlen(key); - } - } - - dumb_sort((void **)keys, hash_keys->length, &dumb_strcmp); - - for (i = 0; i < hash_keys->length; ++i) { - struct shell_command * c = hashmap_get(shell_commands_map, keys[i]); - fprintf(tty, "\033[1;32m%s\033[0m ", c->name); - print_spaces(tty, max_width- strlen(c->name)); - fprintf(tty, "- %s\n", c->description); - } - - free(keys); - list_free(hash_keys); - free(hash_keys); - - return 0; -} - -static int shell_cd(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 2) { - return 1; - } - char * newdir = argv[1]; - char * path = canonicalize_path(current_process->wd_name, newdir); - fs_node_t * chd = kopen(path, 0); - if (chd) { - if ((chd->flags & FS_DIRECTORY) == 0) { - return 1; - } - close_fs(chd); - free(current_process->wd_name); - current_process->wd_name = malloc(strlen(path) + 1); - memcpy(current_process->wd_name, path, strlen(path) + 1); - return 0; - } else { - return 1; - } -} - -static int shell_ls(fs_node_t * tty, int argc, char * argv[]) { - fs_node_t * wd; - if (argc < 2) { - wd = kopen(current_process->wd_name, 0); - } else { - wd = kopen(argv[1], 0); - } - uint32_t index = 0; - struct dirent * kentry = readdir_fs(wd, index); - while (kentry) { - fprintf(tty, "%s\n", kentry->name); - free(kentry); - - index++; - kentry = readdir_fs(wd, index); - } - close_fs(wd); - return 0; -} - -static int shell_cat(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 2) { - fprintf(tty, "Usage: cat \n"); - return 1; - } - - fs_node_t * node = kopen(argv[1], 0); - if (!node) { - fprintf(tty, "Could not open %s.\n", argv[1]); - return 1; - } - -#define CHUNK_SIZE 4096 - uint8_t * buf = malloc(CHUNK_SIZE); - memset(buf, 0, CHUNK_SIZE); - size_t offset = 0; - while (1) { - size_t r = read_fs(node, offset, CHUNK_SIZE, buf); - if (!r) break; - write_fs(tty, 0, r, buf); - offset += r; - } - - close_fs(node); - return 0; -} - -static int shell_log(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 2) { - fprintf(tty, "Log level is currently %d.\n", debug_level); - fprintf(tty, "Serial logging is %s.\n", !!debug_file ? "enabled" : "disabled"); - fprintf(tty, "Usage: log [on|off] []\n"); - } else { - if (!strcmp(argv[1], "direct")) { - debug_file = kopen("/dev/ttyS0", 0); - if (argc > 2) { - debug_level = atoi(argv[2]); - } - } else if (!strcmp(argv[1], "on")) { - debug_file = tty; - if (argc > 2) { - debug_level = atoi(argv[2]); - } - } else if (!strcmp(argv[1], "off")) { - debug_file = NULL; - } - } - return 0; -} - -static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - - fs_node_t * tty = extra; - - fprintf(tty, "%2x:%2x.%d (%4x, %4x:%4x)\n", - (int)pci_extract_bus(device), - (int)pci_extract_slot(device), - (int)pci_extract_func(device), - (int)pci_find_type(device), - vendorid, - deviceid); - - fprintf(tty, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4)); - fprintf(tty, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4)); - fprintf(tty, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4)); - fprintf(tty, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4)); - fprintf(tty, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); - fprintf(tty, " BAR5: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); - - fprintf(tty, " IRQ Line: %d", pci_read_field(device, 0x3C, 1)); - fprintf(tty, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1)); - fprintf(tty, " Interrupt: %d", pci_get_interrupt(device)); - fprintf(tty, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2)); -} - -static int shell_pci(fs_node_t * tty, int argc, char * argv[]) { - pci_scan(&scan_hit_list, -1, tty); - return 0; -} - -static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) { - *((uint32_t *)extra) = device; - } -} -static int shell_frob_piix(fs_node_t * tty, int argc, char * argv[]) { - uint32_t pci_isa = 0; - pci_scan(&find_isa_bridge, -1, &pci_isa); - if (pci_isa) { - fprintf(tty, "PCI-to-ISA interrupt mappings by line:\n"); - for (int i = 0; i < 4; ++i) { - fprintf(tty, "Line %d: 0x%2x\n", i+1, pci_read_field(pci_isa, 0x60+i, 1)); - } - } - return 0; -} - -static int shell_uid(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 2) { - fprintf(tty, "uid=%d\n", current_process->user); - } else { - current_process->user = atoi(argv[1]); - } - return 0; -} - -char * special_thing = "I am a string from the kernel.\n"; - -static int shell_mod(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 2) { - fprintf(tty, "%s: expected argument\n", argv[0]); - return 1; - } - fs_node_t * file = kopen(argv[1], 0); - if (!file) { - fprintf(tty, "%s: Error loading module '%s': File not found\n", argv[0], argv[1]); - return 1; - } - close_fs(file); - - module_data_t * mod_info = module_load(argv[1]); - if (!mod_info) { - fprintf(tty, "%s: Error loading module '%s'\n", argv[0], argv[1]); - return 1; - } - - fprintf(tty, "Module '%s' loaded at 0x%x\n", mod_info->mod_info->name, mod_info->bin_data); - - return 0; -} - -static int shell_symbols(fs_node_t * tty, int argc, char * argv[]) { - - if (argc > 1 && !strcmp(argv[1],"--all")) { - list_t * hash_keys = hashmap_keys(modules_get_symbols()); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - uintptr_t a = (uintptr_t)hashmap_get(modules_get_symbols(), key); - fprintf(tty, "0x%x - %s\n", a, key); - } - free(hash_keys); - } else { - - extern char kernel_symbols_start[]; - extern char kernel_symbols_end[]; - - struct ksym { - uintptr_t addr; - char name[]; - } * k = (void*)&kernel_symbols_start; - - while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { - fprintf(tty, "0x%x - %s\n", k->addr, k->name); - k = (void *)((uintptr_t)k + sizeof(uintptr_t) + strlen(k->name) + 1); - } - } - - return 0; -} - -static int shell_print(fs_node_t * tty, int argc, char * argv[]) { - - if (argc < 3) { - fprintf(tty, "print format_string symbol_name\n"); - return 1; - } - - char * format = argv[1]; - char * symbol = argv[2]; - int deref = 0; - - if (symbol[0] == '*') { - symbol = &symbol[1]; - deref = 1; - } - - void * addr = hashmap_get(modules_get_symbols(),symbol); - if (!addr) return 1; - - if (deref) { - fprintf(tty, format, addr); - } else { - fprintf(tty, format, *((uintptr_t *)addr)); - } - fprintf(tty, "\n"); - - return 0; -} - -static int shell_call(fs_node_t * tty, int argc, char * argv[]) { - - if (argc < 2) { - fprintf(tty, "call function_name\n"); - return 1; - } - - char * symbol = argv[1]; - - void (*addr)(void) = (void (*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),symbol); - if (!addr) return 1; - - addr(); - - return 0; -} - -static int shell_modules(fs_node_t * tty, int argc, char * argv[]) { - list_t * hash_keys = hashmap_keys(modules_get_list()); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - module_data_t * mod_info = hashmap_get(modules_get_list(), key); - - fprintf(tty, "0x%x {.init=0x%x, .fini=0x%x} %s", - mod_info->bin_data, - mod_info->mod_info->initialize, - mod_info->mod_info->finalize, - mod_info->mod_info->name); - - if (mod_info->deps) { - unsigned int i = 0; - fprintf(tty, " Deps: "); - while (i < mod_info->deps_length) { - fprintf(tty, "%s ", &mod_info->deps[i]); - i += strlen(&mod_info->deps[i]) + 1; - } - } - - fprintf(tty, "\n"); - } - free(hash_keys); - - return 0; -} - -static int shell_rdtsc(fs_node_t * tty, int argc, char * argv[]) { - uint64_t x; - asm volatile ("rdtsc" : "=A" (x)); - - fprintf(tty, "0x%x%x\n", (uint32_t)(x >> 32), (uint32_t)(x & 0xFFFFFFFF)); - - return 0; -} - -static int shell_mhz(fs_node_t * tty, int argc, char * argv[]) { - - uint64_t x, y; - - asm volatile ("rdtsc" : "=A" (x)); - - unsigned long s, ss; - relative_time(1, 0, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - asm volatile ("rdtsc" : "=A" (y)); - - uint64_t diff = y - x; - uint32_t f = diff >> 15; - uint32_t mhz = f / 30; - - fprintf(tty, "%d MHz\n", mhz); - - return 0; -} - -/* - * Determine the size of a smart terminal that we don't have direct - * termios access to. This is done by sending a cursor-move command - * that will put the cursor into the lower right corner and then - * requesting the cursor position report. We then read and parse - * the position report. In the case where the terminal on the other - * end is actually dumb, we end up waiting for some input and - * then timing out. - * TODO with asyncio support, the timeout should actually work. - * consider also using an alarm (which I also don't have) - */ -static void divine_size(fs_node_t * dev, int * width, int * height) { - char tmp[100]; - int read = 0; - unsigned long start_tick = timer_ticks; - memset(tmp, 0, sizeof(tmp)); - /* Move cursor, Request position, Reset cursor */ - fprintf(dev, "\033[1000;1000H\033[6n\033[H"); - while (1) { - char buf[1]; - int r = read_fs(dev, 0, 1, (unsigned char *)buf); - if (r > 0) { - if (buf[0] != 'R') { - if (read > 1) { - tmp[read-2] = buf[0]; - } - read++; - } else { - break; - } - } - if (timer_ticks - start_tick >= 2) { - /* - * We've timed out. This will only be triggered - * when we eventually receive something, though - */ - *width = 80; - *height = 23; - /* Clear and return */ - fprintf(dev, "\033[J"); - return; - } - } - /* Clear */ - fprintf(dev, "\033[J"); - /* Break up the result into two strings */ - - for (unsigned int i = 0; i < strlen(tmp); i++) { - if (tmp[i] == ';') { - tmp[i] = '\0'; - break; - } - } - char * h = (char *)((uintptr_t)tmp + strlen(tmp)+1); - /* And then parse it into numbers */ - *height = atoi(tmp); - *width = atoi(h); -} - -static int shell_divinesize(fs_node_t * tty, int argc, char * argv[]) { - struct winsize size = {0,0,0,0}; - - /* Attempt to divine the terminal size. Changing the window size after this will do bad things */ - int width, height; - divine_size(tty, &width, &height); - - fprintf(tty, "Identified size: %d x %d\n", width, height); - - size.ws_row = height; - size.ws_col = width; - - ioctl_fs(tty, TIOCSWINSZ, &size); - - return 0; -} - -static int shell_fix_mouse(fs_node_t * tty, int argc, char * argv[]) { - - fs_node_t * mouse = kopen("/dev/mouse", 0); - if (mouse) { - ioctl_fs(mouse, 1, NULL); - close_fs(mouse); - } - - return 0; -} - -static int shell_mount(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 4) { - fprintf(tty, "Usage: %s type device mountpoint\n", argv[0]); - return 1; - } - - return -vfs_mount_type(argv[1], argv[2], argv[3]); -} - -static int shell_exit(fs_node_t * tty, int argc, char * argv[]) { - kexit(0); - return 0; -} - -static int shell_cursor_off(fs_node_t * tty, int argc, char * argv[]) { - outportb(0x3D4, 14); - outportb(0x3D5, 0xFF); - outportb(0x3D4, 15); - outportb(0x3D5, 0xFF); - return 0; -} - -extern pid_t trace_pid; -static int shell_debug_pid(fs_node_t * tty, int argc, char * argv[]) { - trace_pid = atoi(argv[1]); - return 0; -} - -extern hashmap_t * kernel_args_map; -static int shell_set(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 3) { - fprintf(tty, "set KEY VALUE\n"); - return 1; - } - hashmap_set(kernel_args_map, argv[1], strdup(argv[2])); - return 0; -} - -static int shell_coax_irq(fs_node_t * tty, int argc, char * argv[]) { - if (argc < 2) { - fprintf(tty, "coax-irq IRQ\n"); - return 1; - } - - irq_ack(atoi(argv[1])); - - return 0; -} - -static struct shell_command shell_commands[] = { - {"shell", &shell_create_userspace_shell, - "Runs a userspace shell on this tty."}, - {"login", &shell_replace_login, - "Replace the debug shell with /bin/login."}, - {"echo", &shell_echo, - "Prints arguments."}, - {"help", &shell_help, - "Prints a list of possible shell commands and their descriptions."}, - {"cd", &shell_cd, - "Change current directory."}, - {"ls", &shell_ls, - "List files in current or other directory."}, - {"cat", &shell_cat, - "Read a file to the console."}, - {"log", &shell_log, - "Configure serial debug logging."}, - {"pci", &shell_pci, - "Print PCI devices, as well as their names and BARs."}, - {"uid", &shell_uid, - "Change the effective user id of the shell."}, - {"mod", &shell_mod, - "[testing] Module loading."}, - {"symbols", &shell_symbols, - "Dump symbol table."}, - {"debug_pid", &shell_debug_pid, - "Set pid to trace syscalls for."}, - {"print", &shell_print, - "[dangerous] Print the value of a symbol using a format string."}, - {"call", &shell_call, - "[dangerous] Call a function by name."}, - {"modules", &shell_modules, - "Print names and addresses of all loaded modules."}, - {"divine-size", &shell_divinesize, - "Attempt to discover TTY size of serial."}, - {"fix-mouse", &shell_fix_mouse, - "Attempt to reset mouse device."}, - {"mount", &shell_mount, - "Mount a filesystemp."}, - {"rdtsc", &shell_rdtsc, - "Read the TSC, if available."}, - {"mhz", &shell_mhz, - "Use TSC to determine clock speed."}, - {"cursor-off", &shell_cursor_off, - "Disable VGA text mode cursor."}, - {"exit", &shell_exit, - "Quit the shell."}, - {"piix", &shell_frob_piix, - "frob piix"}, - {"set", &shell_set, - "set kcmdline flag"}, - {"coax-irq", &shell_coax_irq, - "force ack an irq"}, - {NULL, NULL, NULL} -}; - -void debug_shell_install(struct shell_command * sh) { - hashmap_set(shell_commands_map, sh->name, sh); -} - -/* - * A TTY object to pass to the tasklets for handling - * serial-tty interaction. This probably shouldn't - * be done as tasklets - TTYs should just be able - * to wrap existing fs_nodes themselves, but that's - * a problem for another day. - */ -struct tty_o { - fs_node_t * node; - fs_node_t * tty; -}; - -static void debug_shell_actual(void * data, char * name) { - - current_process->image.entry = 0; - fs_node_t * tty = (fs_node_t *)current_process->fds->entries[1]; - - /* Our prompt will include the version number of the current kernel */ - char version_number[1024]; - sprintf(version_number, __kernel_version_format, - __kernel_version_major, - __kernel_version_minor, - __kernel_version_lower, - __kernel_version_suffix); - - /* Initialize the shell commands map */ - int retval = 0; - - while (1) { - char command[512]; - - /* Print out the prompt */ - if (retval) { - fprintf(tty, "\033[1;34m%s-%s \033[1;31m%d\033[1;34m %s#\033[0m ", __kernel_name, version_number, retval, current_process->wd_name); - } else { - fprintf(tty, "\033[1;34m%s-%s %s#\033[0m ", __kernel_name, version_number, current_process->wd_name); - } - - /* Read a line */ - if (debug_shell_readline(current_process->fds->entries[0], command, 511) < 0) { - kexit(0); - } - - char * arg = strdup(command); - char * argv[1024]; /* Command tokens (space-separated elements) */ - int argc = tokenize(arg, " ", argv); - - if (!argc) continue; - - /* Parse the command string */ - struct shell_command * sh = hashmap_get(shell_commands_map, argv[0]); - if (sh) { - retval = sh->function(tty, argc, argv); - } else { - fprintf(tty, "Unrecognized command: %s\n", argv[0]); - } - - free(arg); - } - -} - -/* - * Tasklet for managing the kernel serial console. - * This is basically a very simple shell, with access - * to some internal kernel commands, and (eventually) - * debugging routines. - */ -static void debug_shell_run(void * data, char * name) { - fs_node_t * tty = kopen("/dev/ttyS0", 0); - - int fd = process_append_fd((process_t *)current_process, tty); - current_process->fds->modes[fd] = 03; /* rw */ - process_move_fd((process_t *)current_process, fd, 0); - process_move_fd((process_t *)current_process, fd, 1); - process_move_fd((process_t *)current_process, fd, 2); - - debug_shell_actual(tty, name); -} - -int debug_shell_start(void) { - /* Setup shell commands */ - shell_commands_map = hashmap_create(10); - struct shell_command * sh = &shell_commands[0]; - while (sh->name) { - hashmap_set(shell_commands_map, sh->name, sh); - sh++; - } - - debug_hook = debug_shell_actual; - - if (args_present("kdebug")) { - int i = create_kernel_tasklet(debug_shell_run, "[kttydebug]", NULL); - debug_print(NOTICE, "Started tasklet with pid=%d", i); - } - - return 0; -} - -int debug_shell_stop(void) { - debug_print(NOTICE, "Tried to unload debug shell, but debug shell has no real shutdown routine. Don't do that!"); - return 0; -} - -MODULE_DEF(debugshell, debug_shell_start, debug_shell_stop); -MODULE_DEPENDS(serial); diff --git a/modules/dospart.c b/modules/dospart.c deleted file mode 100644 index f9043fe7..00000000 --- a/modules/dospart.c +++ /dev/null @@ -1,130 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include - -#define SECTORSIZE 512 - -static mbr_t mbr; - -struct dos_partition_entry { - fs_node_t * device; - partition_t partition; -}; - -static uint32_t read_part(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - struct dos_partition_entry * device = (struct dos_partition_entry *)node->device; - - if (offset > device->partition.sector_count * SECTORSIZE) { - debug_print(WARNING, "Read beyond partition!"); - return 0; - } - - if (offset + size > device->partition.sector_count * SECTORSIZE) { - size = device->partition.sector_count * SECTORSIZE - offset; - debug_print(WARNING, "Tried to read past end of partition, clamped to %d", size); - } - - return read_fs(device->device, offset + device->partition.lba_first_sector * SECTORSIZE, size, buffer); -} - -static uint32_t write_part(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - struct dos_partition_entry * device = (struct dos_partition_entry *)node->device; - - if (offset > device->partition.sector_count * SECTORSIZE) { - return 0; - } - - if (offset + size > device->partition.sector_count * SECTORSIZE) { - size = device->partition.sector_count * SECTORSIZE - offset; - } - - return write_fs(device->device, offset + device->partition.lba_first_sector * SECTORSIZE, size, buffer); -} - -static void open_part(fs_node_t * node, unsigned int flags) { - return; -} - -static void close_part(fs_node_t * node) { - return; -} - -static fs_node_t * dospart_device_create(int i, fs_node_t * dev, partition_t * part) { - - vfs_lock(dev); - - struct dos_partition_entry * device = malloc(sizeof(struct dos_partition_entry)); - memcpy(&device->partition, part, sizeof(partition_t)); - device->device = dev; - - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - sprintf(fnode->name, "dospart%d", i); - fnode->device = device; - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0660; - fnode->length = device->partition.sector_count * SECTORSIZE; /* TODO */ - fnode->flags = FS_BLOCKDEVICE; - fnode->read = read_part; - fnode->write = write_part; - fnode->open = open_part; - fnode->close = close_part; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->ioctl = NULL; /* TODO, identify, etc? */ - return fnode; -} - -static int read_partition_map(char * name) { - fs_node_t * device = kopen(name, 0); - if (!device) return 1; - - read_fs(device, 0, SECTORSIZE, (uint8_t *)&mbr); - - if (mbr.signature[0] == 0x55 && mbr.signature[1] == 0xAA) { - debug_print(INFO, "Partition table found."); - - for (int i = 0; i < 4; ++i) { - if (mbr.partitions[i].status & 0x80) { - debug_print(NOTICE, "Partition #%d: @%d+%d", i+1, mbr.partitions[i].lba_first_sector, mbr.partitions[i].sector_count); - fs_node_t * node = dospart_device_create(i, device, &mbr.partitions[i]); - - char tmp[64]; - sprintf(tmp, "%s%d", name, i); - vfs_mount(tmp, node); - } else { - debug_print(NOTICE, "Partition #%d: inactive", i+1); - } - } - } else { - debug_print(NOTICE, "No partition table on %s", name); - } - - return 0; -} - -static int dospart_initialize(void) { - for (char l = 'a'; l < 'z'; ++l) { - char name[64]; - sprintf(name, "/dev/hd%c", l); - if (read_partition_map(name)) { - break; - } - } - return 0; -} - -static int dospart_finalize(void) { - return 0; -} - -MODULE_DEF(dospart, dospart_initialize, dospart_finalize); diff --git a/modules/e1000.c b/modules/e1000.c deleted file mode 100644 index 2bc49a97..00000000 --- a/modules/e1000.c +++ /dev/null @@ -1,480 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2017-2018 K. Lange - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define E1000_LOG_LEVEL NOTICE - -static uint32_t e1000_device_pci = 0x00000000; -static int e1000_irq = 0; -static uintptr_t mem_base = 0; -static int has_eeprom = 0; -static uint8_t mac[6]; -static int rx_index = 0; -static int tx_index = 0; - -static list_t * net_queue = NULL; -static spin_lock_t net_queue_lock = { 0 }; -static list_t * rx_wait; - -static uint32_t mmio_read32(uintptr_t addr) { - return *((volatile uint32_t*)(addr)); -} -static void mmio_write32(uintptr_t addr, uint32_t val) { - (*((volatile uint32_t*)(addr))) = val; -} - -static void write_command(uint16_t addr, uint32_t val) { - mmio_write32(mem_base + addr, val); -} - -static uint32_t read_command(uint16_t addr) { - return mmio_read32(mem_base + addr); -} - -#define E1000_NUM_RX_DESC 32 -#define E1000_NUM_TX_DESC 8 - -struct rx_desc { - volatile uint64_t addr; - volatile uint16_t length; - volatile uint16_t checksum; - volatile uint8_t status; - volatile uint8_t errors; - volatile uint16_t special; -} __attribute__((packed)); /* this looks like it should pack fine as-is */ - -struct tx_desc { - volatile uint64_t addr; - volatile uint16_t length; - volatile uint8_t cso; - volatile uint8_t cmd; - volatile uint8_t status; - volatile uint8_t css; - volatile uint16_t special; -} __attribute__((packed)); - -static uint8_t * rx_virt[E1000_NUM_RX_DESC]; -static uint8_t * tx_virt[E1000_NUM_TX_DESC]; -static struct rx_desc * rx; -static struct tx_desc * tx; -static uintptr_t rx_phys; -static uintptr_t tx_phys; - -static void enqueue_packet(void * buffer) { - spin_lock(net_queue_lock); - list_insert(net_queue, buffer); - spin_unlock(net_queue_lock); -} - -static struct ethernet_packet * dequeue_packet(void) { - while (!net_queue->length) { - sleep_on(rx_wait); - } - - spin_lock(net_queue_lock); - node_t * n = list_dequeue(net_queue); - void* value = n->value; - free(n); - spin_unlock(net_queue_lock); - - return value; -} - -static uint8_t* get_mac() { - return mac; -} - -#define E1000_REG_CTRL 0x0000 -#define E1000_REG_STATUS 0x0008 -#define E1000_REG_EEPROM 0x0014 -#define E1000_REG_CTRL_EXT 0x0018 - -#define E1000_REG_RCTRL 0x0100 -#define E1000_REG_RXDESCLO 0x2800 -#define E1000_REG_RXDESCHI 0x2804 -#define E1000_REG_RXDESCLEN 0x2808 -#define E1000_REG_RXDESCHEAD 0x2810 -#define E1000_REG_RXDESCTAIL 0x2818 - -#define E1000_REG_TCTRL 0x0400 -#define E1000_REG_TXDESCLO 0x3800 -#define E1000_REG_TXDESCHI 0x3804 -#define E1000_REG_TXDESCLEN 0x3808 -#define E1000_REG_TXDESCHEAD 0x3810 -#define E1000_REG_TXDESCTAIL 0x3818 - -#define E1000_REG_RXADDR 0x5400 - -#define RCTL_EN (1 << 1) /* Receiver Enable */ -#define RCTL_SBP (1 << 2) /* Store Bad Packets */ -#define RCTL_UPE (1 << 3) /* Unicast Promiscuous Enabled */ -#define RCTL_MPE (1 << 4) /* Multicast Promiscuous Enabled */ -#define RCTL_LPE (1 << 5) /* Long Packet Reception Enable */ -#define RCTL_LBM_NONE (0 << 6) /* No Loopback */ -#define RCTL_LBM_PHY (3 << 6) /* PHY or external SerDesc loopback */ -#define RTCL_RDMTS_HALF (0 << 8) /* Free Buffer Threshold is 1/2 of RDLEN */ -#define RTCL_RDMTS_QUARTER (1 << 8) /* Free Buffer Threshold is 1/4 of RDLEN */ -#define RTCL_RDMTS_EIGHTH (2 << 8) /* Free Buffer Threshold is 1/8 of RDLEN */ -#define RCTL_MO_36 (0 << 12) /* Multicast Offset - bits 47:36 */ -#define RCTL_MO_35 (1 << 12) /* Multicast Offset - bits 46:35 */ -#define RCTL_MO_34 (2 << 12) /* Multicast Offset - bits 45:34 */ -#define RCTL_MO_32 (3 << 12) /* Multicast Offset - bits 43:32 */ -#define RCTL_BAM (1 << 15) /* Broadcast Accept Mode */ -#define RCTL_VFE (1 << 18) /* VLAN Filter Enable */ -#define RCTL_CFIEN (1 << 19) /* Canonical Form Indicator Enable */ -#define RCTL_CFI (1 << 20) /* Canonical Form Indicator Bit Value */ -#define RCTL_DPF (1 << 22) /* Discard Pause Frames */ -#define RCTL_PMCF (1 << 23) /* Pass MAC Control Frames */ -#define RCTL_SECRC (1 << 26) /* Strip Ethernet CRC */ - -#define RCTL_BSIZE_256 (3 << 16) -#define RCTL_BSIZE_512 (2 << 16) -#define RCTL_BSIZE_1024 (1 << 16) -#define RCTL_BSIZE_2048 (0 << 16) -#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) -#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) -#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) - -#define TCTL_EN (1 << 1) /* Transmit Enable */ -#define TCTL_PSP (1 << 3) /* Pad Short Packets */ -#define TCTL_CT_SHIFT 4 /* Collision Threshold */ -#define TCTL_COLD_SHIFT 12 /* Collision Distance */ -#define TCTL_SWXOFF (1 << 22) /* Software XOFF Transmission */ -#define TCTL_RTLC (1 << 24) /* Re-transmit on Late Collision */ - -#define CMD_EOP (1 << 0) /* End of Packet */ -#define CMD_IFCS (1 << 1) /* Insert FCS */ -#define CMD_IC (1 << 2) /* Insert Checksum */ -#define CMD_RS (1 << 3) /* Report Status */ -#define CMD_RPS (1 << 4) /* Report Packet Sent */ -#define CMD_VLE (1 << 6) /* VLAN Packet Enable */ -#define CMD_IDE (1 << 7) /* Interrupt Delay Enable */ - -static int eeprom_detect(void) { - - write_command(E1000_REG_EEPROM, 1); - - for (int i = 0; i < 100000 && !has_eeprom; ++i) { - uint32_t val = read_command(E1000_REG_EEPROM); - if (val & 0x10) has_eeprom = 1; - } - - return 0; -} - -static uint16_t eeprom_read(uint8_t addr) { - uint32_t temp = 0; - write_command(E1000_REG_EEPROM, 1 | ((uint32_t)(addr) << 8)); - while (!((temp = read_command(E1000_REG_EEPROM)) & (1 << 4))); - return (uint16_t)((temp >> 16) & 0xFFFF); -} - - -static void find_e1000(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if ((vendorid == 0x8086) && (deviceid == 0x100e || deviceid == 0x1004 || deviceid == 0x100f || deviceid == 0x10ea)) { - *((uint32_t *)extra) = device; - } -} - -static void write_mac(void) { - - uint32_t low; - uint32_t high; - - memcpy(&low, &mac[0], 4); - memcpy(&high,&mac[4], 2); - memset((uint8_t *)&high + 2, 0, 2); - high |= 0x80000000; - - write_command(E1000_REG_RXADDR + 0, low); - write_command(E1000_REG_RXADDR + 4, high); -} - -static void read_mac(void) { - if (has_eeprom) { - uint32_t t; - t = eeprom_read(0); - mac[0] = t & 0xFF; - mac[1] = t >> 8; - t = eeprom_read(1); - mac[2] = t & 0xFF; - mac[3] = t >> 8; - t = eeprom_read(2); - mac[4] = t & 0xFF; - mac[5] = t >> 8; - } else { - uint8_t * mac_addr = (uint8_t *)(mem_base + E1000_REG_RXADDR); - for (int i = 0; i < 6; ++i) { - mac[i] = mac_addr[i]; - } - } -} - -static int irq_handler(struct regs *r) { - - uint32_t status = read_command(0xc0); - - if (!status) { - return 0; - } - - irq_ack(e1000_irq); - - if (status & 0x04) { - /* Start link */ - debug_print(E1000_LOG_LEVEL, "start link"); - } else if (status & 0x10) { - /* ?? */ - } else if (status & ((1 << 6) | (1 << 7))) { - /* receive packet */ - do { - rx_index = read_command(E1000_REG_RXDESCTAIL); - if (rx_index == (int)read_command(E1000_REG_RXDESCHEAD)) return 1; - rx_index = (rx_index + 1) % E1000_NUM_RX_DESC; - if (rx[rx_index].status & 0x01) { - uint8_t * pbuf = (uint8_t *)rx_virt[rx_index]; - uint16_t plen = rx[rx_index].length; - - void * packet = malloc(plen); - memcpy(packet, pbuf, plen); - - rx[rx_index].status = 0; - - enqueue_packet(packet); - - write_command(E1000_REG_RXDESCTAIL, rx_index); - } else { - break; - } - } while (1); - wakeup_queue(rx_wait); - } - - return 1; -} - -static void send_packet(uint8_t* payload, size_t payload_size) { - tx_index = read_command(E1000_REG_TXDESCTAIL); - debug_print(E1000_LOG_LEVEL,"sending packet 0x%x, %d desc[%d]", payload, payload_size, tx_index); - - memcpy(tx_virt[tx_index], payload, payload_size); - tx[tx_index].length = payload_size; - tx[tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS; - tx[tx_index].status = 0; - - tx_index = (tx_index + 1) % E1000_NUM_TX_DESC; - write_command(E1000_REG_TXDESCTAIL, tx_index); -} - -static void init_rx(void) { - - write_command(E1000_REG_RXDESCLO, rx_phys); - write_command(E1000_REG_RXDESCHI, 0); - - write_command(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(struct rx_desc)); - - write_command(E1000_REG_RXDESCHEAD, 0); - write_command(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1); - - rx_index = 0; - - write_command(E1000_REG_RCTRL, - RCTL_EN | - (read_command(E1000_REG_RCTRL) & (~((1 << 17) | (1 << 16))))); - -} - -static void init_tx(void) { - - - write_command(E1000_REG_TXDESCLO, tx_phys); - write_command(E1000_REG_TXDESCHI, 0); - - write_command(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(struct tx_desc)); - - write_command(E1000_REG_TXDESCHEAD, 0); - write_command(E1000_REG_TXDESCTAIL, 0); - - tx_index = 0; - - write_command(E1000_REG_TCTRL, - TCTL_EN | - TCTL_PSP | - read_command(E1000_REG_TCTRL)); -} - - -static void e1000_init(void * data, char * name) { - - debug_print(E1000_LOG_LEVEL, "enabling bus mastering"); - uint16_t command_reg = pci_read_field(e1000_device_pci, PCI_COMMAND, 2); - command_reg |= (1 << 2); - command_reg |= (1 << 0); - pci_write_field(e1000_device_pci, PCI_COMMAND, 2, command_reg); - - debug_print(E1000_LOG_LEVEL, "mem base: 0x%x", mem_base); - - eeprom_detect(); - debug_print(E1000_LOG_LEVEL, "has_eeprom = %d", has_eeprom); - read_mac(); - write_mac(); - - debug_print(E1000_LOG_LEVEL, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - unsigned long s, ss; - - uint32_t ctrl = read_command(E1000_REG_CTRL); - /* reset phy */ - write_command(E1000_REG_CTRL, ctrl | (0x80000000)); - read_command(E1000_REG_STATUS); - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - /* reset mac */ - write_command(E1000_REG_CTRL, ctrl | (0x04000000)); - read_command(E1000_REG_STATUS); - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - /* Reload EEPROM */ - write_command(E1000_REG_CTRL, ctrl | (0x00002000)); - read_command(E1000_REG_STATUS); - relative_time(0, 20, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - - /* initialize */ - write_command(E1000_REG_CTRL, ctrl | (1 << 26)); - - /* wait */ - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - debug_print(E1000_LOG_LEVEL, "back from sleep"); - - uint32_t status = read_command(E1000_REG_CTRL); - status |= (1 << 5); /* set auto speed detection */ - status |= (1 << 6); /* set link up */ - status &= ~(1 << 3); /* unset link reset */ - status &= ~(1UL << 31UL); /* unset phy reset */ - status &= ~(1 << 7); /* unset invert loss-of-signal */ - write_command(E1000_REG_CTRL, status); - - /* Disables flow control */ - write_command(0x0028, 0); - write_command(0x002c, 0); - write_command(0x0030, 0); - write_command(0x0170, 0); - - /* Unset flow control */ - status = read_command(E1000_REG_CTRL); - status &= ~(1 << 30); - write_command(E1000_REG_CTRL, status); - - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - net_queue = list_create(); - rx_wait = list_create(); - - e1000_irq = pci_get_interrupt(e1000_device_pci); - - irq_install_handler(e1000_irq, irq_handler, "e1000"); - - debug_print(E1000_LOG_LEVEL, "Binding interrupt %d", e1000_irq); - - for (int i = 0; i < 128; ++i) { - write_command(0x5200 + i * 4, 0); - } - - for (int i = 0; i < 64; ++i) { - write_command(0x4000 + i * 4, 0); - } - -#if 0 - /* This would rewrite the MAC address... */ - write_command(0x5400, *(uint32_t*)(&mac[0])); - write_command(0x5404, *(uint16_t*)(&mac[4])); - write_command(0x5404, read_command(0x5404) | (1 << 31)); -#endif - - write_command(E1000_REG_RCTRL, (1 << 4)); - - init_rx(); - init_tx(); - - /* Twiddle interrupts */ - write_command(0x00D0, 0xFF); - write_command(0x00D8, 0xFF); - write_command(0x00D0,(1 << 2) | (1 << 6) | (1 << 7) | (1 << 1) | (1 << 0)); - - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - int link_is_up = (read_command(E1000_REG_STATUS) & (1 << 1)); - debug_print(E1000_LOG_LEVEL,"e1000 done. has_eeprom = %d, link is up = %d, irq=%d", has_eeprom, link_is_up, e1000_irq); - - init_netif_funcs(get_mac, dequeue_packet, send_packet, "Intel E1000"); -} - -static int init(void) { - pci_scan(&find_e1000, -1, &e1000_device_pci); - - if (!e1000_device_pci) { - debug_print(E1000_LOG_LEVEL, "No e1000 device found."); - return 1; - } - - /* This seems to always be memory mapped on important devices. */ - mem_base = pci_read_field(e1000_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0; - - for (size_t x = 0; x < 0x10000; x += 0x1000) { - uintptr_t addr = (mem_base & 0xFFFFF000) + x; - dma_frame(get_page(addr, 1, kernel_directory), 1, 1, addr); - } - - rx = (void*)kvmalloc_p(sizeof(struct rx_desc) * E1000_NUM_RX_DESC + 16, &rx_phys); - - for (int i = 0; i < E1000_NUM_RX_DESC; ++i) { - rx_virt[i] = (void*)kvmalloc_p(8192 + 16, (uint32_t *)&rx[i].addr); - debug_print(E1000_LOG_LEVEL, "rx[%d] 0x%x → 0x%x", i, rx_virt[i], (uint32_t)rx[i].addr); - rx[i].status = 0; - } - - tx = (void*)kvmalloc_p(sizeof(struct tx_desc) * E1000_NUM_TX_DESC + 16, &tx_phys); - - for (int i = 0; i < E1000_NUM_TX_DESC; ++i) { - tx_virt[i] = (void*)kvmalloc_p(8192+16, (uint32_t *)&tx[i].addr); - debug_print(E1000_LOG_LEVEL, "tx[%d] 0x%x → 0x%x", i, tx_virt[i], (uint32_t)tx[i].addr); - tx[i].status = 0; - tx[i].cmd = (1 << 0); - } - - - create_kernel_tasklet(e1000_init, "[e1000]", NULL); - - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(e1000, init, fini); -MODULE_DEPENDS(net); diff --git a/modules/ext2.c b/modules/ext2.c deleted file mode 100644 index 5190d043..00000000 --- a/modules/ext2.c +++ /dev/null @@ -1,1660 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define EXT2_BGD_BLOCK 2 - -#define E_SUCCESS 0 -#define E_BADBLOCK 1 -#define E_NOSPACE 2 -#define E_BADPARENT 3 - -#undef _symlink -#define _symlink(inode) ((char *)(inode)->block) - -/* - * EXT2 filesystem object - */ -typedef struct { - ext2_superblock_t * superblock; /* Device superblock, contains important information */ - ext2_bgdescriptor_t * block_groups; /* Block Group Descriptor / Block groups */ - fs_node_t * root_node; /* Root FS node (attached to mountpoint) */ - - fs_node_t * block_device; /* Block device node XXX unused */ - - unsigned int block_size; /* Size of one block */ - unsigned int pointers_per_block; /* Number of pointers that fit in a block */ - unsigned int inodes_per_group; /* Number of inodes in a "group" */ - unsigned int block_group_count; /* Number of blocks groups */ - - ext2_disk_cache_entry_t * disk_cache; /* Dynamically allocated array of cache entries */ - unsigned int cache_entries; /* Size of ->disk_cache */ - unsigned int cache_time; /* "timer" that increments with each cache read/write */ - - spin_lock_t lock; /* Synchronization lock point */ - - uint8_t bgd_block_span; - uint8_t bgd_offset; - unsigned int inode_size; - - uint8_t * cache_data; - - int flags; -} ext2_fs_t; - -#define EXT2_FLAG_NOCACHE 0x0001 - -/* - * These macros were used in the original toaru ext2 driver. - * They make referring to some of the core parts of the drive a bit easier. - */ -#define BGDS (this->block_group_count) -#define SB (this->superblock) -#define BGD (this->block_groups) -#define RN (this->root_node) -#define DC (this->disk_cache) - -/* - * These macros deal with the block group descriptor bitmap - */ -#define BLOCKBIT(n) (bg_buffer[((n) >> 3)] & (1 << (((n) % 8)))) -#define BLOCKBYTE(n) (bg_buffer[((n) >> 3)]) -#define SETBIT(n) (1 << (((n) % 8))) - -static uint32_t node_from_file(ext2_fs_t * this, ext2_inodetable_t *inode, ext2_dir_t *direntry, fs_node_t *fnode); -static uint32_t ext2_root(ext2_fs_t * this, ext2_inodetable_t *inode, fs_node_t *fnode); -static ext2_inodetable_t * read_inode(ext2_fs_t * this, uint32_t inode); -static void refresh_inode(ext2_fs_t * this, ext2_inodetable_t * inodet, uint32_t inode); -static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, uint32_t index); -static fs_node_t * finddir_ext2(fs_node_t *node, char *name); -static unsigned int allocate_block(ext2_fs_t * this); - -/** - * ext2->get_cache_time Increment and return the current cache time - * - * @returns Current cache time - */ -static unsigned int get_cache_time(ext2_fs_t * this) { - return this->cache_time++; -} - -/** - * ext2->cache_flush_dirty Flush dirty cache entry to the disk. - * - * @param ent_no Cache entry to dump - * @returns Error code or E_SUCCESS - */ -static int cache_flush_dirty(ext2_fs_t * this, unsigned int ent_no) { - write_fs(this->block_device, (DC[ent_no].block_no) * this->block_size, this->block_size, (uint8_t *)(DC[ent_no].block)); - DC[ent_no].dirty = 0; - - return E_SUCCESS; -} - -/** - * ext2->rewrite_superblock Rewrite the superblock. - * - * Superblocks are a bit different from other blocks, as they are always in the same place, - * regardless of what the filesystem block size is. This doesn't work well with our setup, - * so we need to special-case it. - */ -static int rewrite_superblock(ext2_fs_t * this) { - write_fs(this->block_device, 1024, sizeof(ext2_superblock_t), (uint8_t *)SB); - return E_SUCCESS; -} - -/** - * ext2->read_block Read a block from the block device associated with this filesystem. - * - * The read block will be copied into the buffer pointed to by `buf`. - * - * @param block_no Number of block to read. - * @param buf Where to put the data read. - * @returns Error code or E_SUCCESS - */ -static int read_block(ext2_fs_t * this, unsigned int block_no, uint8_t * buf) { - /* 0 is an invalid block number. So is anything beyond the total block count, but we can't check that. */ - if (!block_no) { - return E_BADBLOCK; - } - - /* This operation requires the filesystem lock to be obtained */ - spin_lock(this->lock); - - /* We can make reads without a cache in place. */ - if (!DC) { - /* In such cases, we read directly from the block device */ - read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)buf); - /* We are done, release the lock */ - spin_unlock(this->lock); - /* And return SUCCESS */ - return E_SUCCESS; - } - - /* - * Search the cache for this entry - * We'll look for the oldest entry, too. - */ - int oldest = -1; - unsigned int oldest_age = UINT32_MAX; - for (unsigned int i = 0; i < this->cache_entries; ++i) { - if (DC[i].block_no == block_no) { - /* We found it! Update usage times */ - DC[i].last_use = get_cache_time(this); - /* Read the block */ - memcpy(buf, DC[i].block, this->block_size); - /* Release the lock */ - spin_unlock(this->lock); - /* Success! */ - return E_SUCCESS; - } - if (DC[i].last_use < oldest_age) { - /* We found an older block, remember this. */ - oldest = i; - oldest_age = DC[i].last_use; - } - } - - /* - * At this point, we did not find this block in the cache. - * We are going to replace the oldest entry with this new one. - */ - - /* We'll start by flushing the block if it was dirty. */ - if (DC[oldest].dirty) { - cache_flush_dirty(this, oldest); - } - - /* Then we'll read the new one */ - read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)DC[oldest].block); - - /* And copy the results to the output buffer */ - memcpy(buf, DC[oldest].block, this->block_size); - - /* And update the cache entry to point to the new block */ - DC[oldest].block_no = block_no; - DC[oldest].last_use = get_cache_time(this); - DC[oldest].dirty = 0; - - /* Release the lock */ - spin_unlock(this->lock); - - /* And return success */ - return E_SUCCESS; -} - -/** - * ext2->write_block Write a block to the block device. - * - * @param block_no Block to write - * @param buf Data in the block - * @returns Error code or E_SUCCESSS - */ -static int write_block(ext2_fs_t * this, unsigned int block_no, uint8_t *buf) { - if (!block_no) { - debug_print(ERROR, "Attempted to write to block #0. Enable tracing and retry this operation."); - debug_print(ERROR, "Your file system is most likely corrupted now."); - return E_BADBLOCK; - } - - /* This operation requires the filesystem lock */ - spin_lock(this->lock); - - if (!DC) { - write_fs(this->block_device, block_no * this->block_size, this->block_size, buf); - spin_unlock(this->lock); - return E_SUCCESS; - } - - /* Find the entry in the cache */ - int oldest = -1; - unsigned int oldest_age = UINT32_MAX; - for (unsigned int i = 0; i < this->cache_entries; ++i) { - if (DC[i].block_no == block_no) { - /* We found it. Update the cache entry */ - DC[i].last_use = get_cache_time(this); - DC[i].dirty = 1; - memcpy(DC[i].block, buf, this->block_size); - spin_unlock(this->lock); - return E_SUCCESS; - } - if (DC[i].last_use < oldest_age) { - /* Keep track of the oldest entry */ - oldest = i; - oldest_age = DC[i].last_use; - } - } - - /* We did not find this element in the cache, so make room. */ - if (DC[oldest].dirty) { - /* Flush the oldest entry */ - cache_flush_dirty(this, oldest); - } - - /* Update the entry */ - memcpy(DC[oldest].block, buf, this->block_size); - DC[oldest].block_no = block_no; - DC[oldest].last_use = get_cache_time(this); - DC[oldest].dirty = 1; - - /* Release the lock */ - spin_unlock(this->lock); - - /* We're done. */ - return E_SUCCESS; -} - -static unsigned int ext2_sync(ext2_fs_t * this) { - if (!this->disk_cache) return 0; - - /* This operation requires the filesystem lock */ - spin_lock(this->lock); - - /* Flush each cache entry. */ - for (unsigned int i = 0; i < this->cache_entries; ++i) { - if (DC[i].dirty) { - cache_flush_dirty(this, i); - } - } - - /* Release the lock */ - spin_unlock(this->lock); - - return 0; -} - -/** - * ext2->set_block_number Set the "real" block number for a given "inode" block number. - * - * @param inode Inode to operate on - * @param iblock Block offset within the inode - * @param rblock Real block number - * @returns Error code or E_SUCCESS - */ -static unsigned int set_block_number(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int iblock, unsigned int rblock) { - - unsigned int p = this->pointers_per_block; - - /* We're going to do some crazy math in a bit... */ - unsigned int a, b, c, d, e, f, g; - - uint8_t * tmp; - - if (iblock < EXT2_DIRECT_BLOCKS) { - inode->block[iblock] = rblock; - return E_SUCCESS; - } else if (iblock < EXT2_DIRECT_BLOCKS + p) { - /* XXX what if inode->block[EXT2_DIRECT_BLOCKS] isn't set? */ - if (!inode->block[EXT2_DIRECT_BLOCKS]) { - unsigned int block_no = allocate_block(this); - if (!block_no) return E_NOSPACE; - inode->block[EXT2_DIRECT_BLOCKS] = block_no; - write_inode(this, inode, inode_no); - } - tmp = malloc(this->block_size); - read_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp); - - ((uint32_t *)tmp)[iblock - EXT2_DIRECT_BLOCKS] = rblock; - write_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp); - - free(tmp); - return E_SUCCESS; - } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p) { - a = iblock - EXT2_DIRECT_BLOCKS; - b = a - p; - c = b / p; - d = b - c * p; - - if (!inode->block[EXT2_DIRECT_BLOCKS+1]) { - unsigned int block_no = allocate_block(this); - if (!block_no) return E_NOSPACE; - inode->block[EXT2_DIRECT_BLOCKS+1] = block_no; - write_inode(this, inode, inode_no); - } - - tmp = malloc(this->block_size); - read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp); - - if (!((uint32_t *)tmp)[c]) { - unsigned int block_no = allocate_block(this); - if (!block_no) goto no_space_free; - ((uint32_t *)tmp)[c] = block_no; - write_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp); - } - - uint32_t nblock = ((uint32_t *)tmp)[c]; - read_block(this, nblock, (uint8_t *)tmp); - - ((uint32_t *)tmp)[d] = rblock; - write_block(this, nblock, (uint8_t *)tmp); - - free(tmp); - return E_SUCCESS; - } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p + p) { - a = iblock - EXT2_DIRECT_BLOCKS; - b = a - p; - c = b - p * p; - d = c / (p * p); - e = c - d * p * p; - f = e / p; - g = e - f * p; - - if (!inode->block[EXT2_DIRECT_BLOCKS+2]) { - unsigned int block_no = allocate_block(this); - if (!block_no) return E_NOSPACE; - inode->block[EXT2_DIRECT_BLOCKS+2] = block_no; - write_inode(this, inode, inode_no); - } - - tmp = malloc(this->block_size); - read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp); - - if (!((uint32_t *)tmp)[d]) { - unsigned int block_no = allocate_block(this); - if (!block_no) goto no_space_free; - ((uint32_t *)tmp)[d] = block_no; - write_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp); - } - - uint32_t nblock = ((uint32_t *)tmp)[d]; - read_block(this, nblock, (uint8_t *)tmp); - - if (!((uint32_t *)tmp)[f]) { - unsigned int block_no = allocate_block(this); - if (!block_no) goto no_space_free; - ((uint32_t *)tmp)[f] = block_no; - write_block(this, nblock, (uint8_t *)tmp); - } - - nblock = ((uint32_t *)tmp)[f]; - read_block(this, nblock, (uint8_t *)tmp); - - ((uint32_t *)tmp)[g] = nblock; - write_block(this, nblock, (uint8_t *)tmp); - - free(tmp); - return E_SUCCESS; - } - - debug_print(CRITICAL, "EXT2 driver tried to write to a block number that was too high (%d)", rblock); - return E_BADBLOCK; -no_space_free: - free(tmp); - return E_NOSPACE; -} - -/** - * ext2->get_block_number Given an inode block number, get the real block number. - * - * @param inode Inode to operate on - * @param iblock Block offset within the inode - * @returns Real block number - */ -static unsigned int get_block_number(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int iblock) { - - unsigned int p = this->pointers_per_block; - - /* We're going to do some crazy math in a bit... */ - unsigned int a, b, c, d, e, f, g; - - uint8_t * tmp; - - if (iblock < EXT2_DIRECT_BLOCKS) { - return inode->block[iblock]; - } else if (iblock < EXT2_DIRECT_BLOCKS + p) { - /* XXX what if inode->block[EXT2_DIRECT_BLOCKS] isn't set? */ - tmp = malloc(this->block_size); - read_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp); - - unsigned int out = ((uint32_t *)tmp)[iblock - EXT2_DIRECT_BLOCKS]; - free(tmp); - return out; - } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p) { - a = iblock - EXT2_DIRECT_BLOCKS; - b = a - p; - c = b / p; - d = b - c * p; - - tmp = malloc(this->block_size); - read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp); - - uint32_t nblock = ((uint32_t *)tmp)[c]; - read_block(this, nblock, (uint8_t *)tmp); - - unsigned int out = ((uint32_t *)tmp)[d]; - free(tmp); - return out; - } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p + p) { - a = iblock - EXT2_DIRECT_BLOCKS; - b = a - p; - c = b - p * p; - d = c / (p * p); - e = c - d * p * p; - f = e / p; - g = e - f * p; - - tmp = malloc(this->block_size); - read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp); - - uint32_t nblock = ((uint32_t *)tmp)[d]; - read_block(this, nblock, (uint8_t *)tmp); - - nblock = ((uint32_t *)tmp)[f]; - read_block(this, nblock, (uint8_t *)tmp); - - unsigned int out = ((uint32_t *)tmp)[g]; - free(tmp); - return out; - } - - debug_print(CRITICAL, "EXT2 driver tried to read to a block number that was too high (%d)", iblock); - - return 0; -} - -static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, uint32_t index) { - uint32_t group = index / this->inodes_per_group; - if (group > BGDS) { - return E_BADBLOCK; - } - - uint32_t inode_table_block = BGD[group].inode_table; - index -= group * this->inodes_per_group; - uint32_t block_offset = ((index - 1) * this->inode_size) / this->block_size; - uint32_t offset_in_block = (index - 1) - block_offset * (this->block_size / this->inode_size); - - ext2_inodetable_t *inodet = malloc(this->block_size); - /* Read the current table block */ - read_block(this, inode_table_block + block_offset, (uint8_t *)inodet); - memcpy((uint8_t *)((uint32_t)inodet + offset_in_block * this->inode_size), inode, this->inode_size); - write_block(this, inode_table_block + block_offset, (uint8_t *)inodet); - free(inodet); - - return E_SUCCESS; -} - -static unsigned int allocate_block(ext2_fs_t * this) { - unsigned int block_no = 0; - unsigned int block_offset = 0; - unsigned int group = 0; - uint8_t * bg_buffer = malloc(this->block_size); - - for (unsigned int i = 0; i < BGDS; ++i) { - if (BGD[i].free_blocks_count > 0) { - read_block(this, BGD[i].block_bitmap, (uint8_t *)bg_buffer); - while (BLOCKBIT(block_offset)) { - ++block_offset; - } - block_no = block_offset + SB->blocks_per_group * i; - group = i; - break; - } - } - - if (!block_no) { - debug_print(CRITICAL, "No available blocks, disk is out of space!"); - free(bg_buffer); - return 0; - } - - debug_print(WARNING, "allocating block #%d (group %d)", block_no, group); - - BLOCKBYTE(block_offset) |= SETBIT(block_offset); - write_block(this, BGD[group].block_bitmap, (uint8_t *)bg_buffer); - - BGD[group].free_blocks_count--; - for (int i = 0; i < this->bgd_block_span; ++i) { - write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); - } - - SB->free_blocks_count--; - rewrite_superblock(this); - - memset(bg_buffer, 0x00, this->block_size); - write_block(this, block_no, bg_buffer); - - free(bg_buffer); - - return block_no; - -} - - -/** - * ext2->allocate_inode_block Allocate a block in an inode. - * - * @param inode Inode to operate on - * @param inode_no Number of the inode (this is not part of the struct) - * @param block Block within inode to allocate - * @returns Error code or E_SUCCESS - */ -static int allocate_inode_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int block) { - debug_print(NOTICE, "Allocating block #%d for inode #%d", block, inode_no); - unsigned int block_no = allocate_block(this); - - if (!block_no) return E_NOSPACE; - - set_block_number(this, inode, inode_no, block, block_no); - - unsigned int t = (block + 1) * (this->block_size / 512); - if (inode->blocks < t) { - debug_print(NOTICE, "Setting inode->blocks to %d = (%d fs blocks)", t, t / (this->block_size / 512)); - inode->blocks = t; - } - write_inode(this, inode, inode_no); - - return E_SUCCESS; -} - -/** - * ext2->inode_read_block - * - * @param inode - * @param no - * @param block - * @parma buf - * @returns Real block number for reference. - */ -static unsigned int inode_read_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int block, uint8_t * buf) { - - if (block >= inode->blocks / (this->block_size / 512)) { - memset(buf, 0x00, this->block_size); - debug_print(WARNING, "Tried to read an invalid block. Asked for %d (0-indexed), but inode only has %d!", block, inode->blocks / (this->block_size / 512)); - return 0; - } - - unsigned int real_block = get_block_number(this, inode, block); - read_block(this, real_block, buf); - - return real_block; -} - -/** - * ext2->inode_write_block - */ -static unsigned int inode_write_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int block, uint8_t * buf) { - if (block >= inode->blocks / (this->block_size / 512)) { - debug_print(WARNING, "Attempting to write beyond the existing allocated blocks for this inode."); - debug_print(WARNING, "Inode %d, Block %d", inode_no, block); - } - - debug_print(WARNING, "clearing and allocating up to required blocks (block=%d, %d)", block, inode->blocks); - char * empty = NULL; - while (block >= inode->blocks / (this->block_size / 512)) { - allocate_inode_block(this, inode, inode_no, inode->blocks / (this->block_size / 512)); - refresh_inode(this, inode, inode_no); - } - if (empty) free(empty); - debug_print(WARNING, "... done"); - - unsigned int real_block = get_block_number(this, inode, block); - debug_print(WARNING, "Writing virtual block %d for inode %d maps to real block %d", block, inode_no, real_block); - - write_block(this, real_block, buf); - return real_block; -} - -/** - * ext2->create_entry - * - * @returns Error code or E_SUCCESS - */ -static int create_entry(fs_node_t * parent, char * name, uint32_t inode) { - ext2_fs_t * this = (ext2_fs_t *)parent->device; - - ext2_inodetable_t * pinode = read_inode(this,parent->inode); - if (((pinode->mode & EXT2_S_IFDIR) == 0) || (name == NULL)) { - debug_print(WARNING, "Attempted to allocate an inode in a parent that was not a directory."); - return E_BADPARENT; - } - - debug_print(WARNING, "Creating a directory entry for %s pointing to inode %d.", name, inode); - - /* okay, how big is it... */ - - debug_print(WARNING, "We need to append %d bytes to the direcotry.", sizeof(ext2_dir_t) + strlen(name)); - - unsigned int rec_len = sizeof(ext2_dir_t) + strlen(name); - rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; - - debug_print(WARNING, "Our directory entry looks like this:"); - debug_print(WARNING, " inode = %d", inode); - debug_print(WARNING, " rec_len = %d", rec_len); - debug_print(WARNING, " name_len = %d", strlen(name)); - debug_print(WARNING, " file_type = %d", 0); - debug_print(WARNING, " name = %s", name); - - debug_print(WARNING, "The inode size is marked as: %d", pinode->size); - debug_print(WARNING, "Block size is %d", this->block_size); - - uint8_t * block = malloc(this->block_size); - uint8_t block_nr = 0; - uint32_t dir_offset = 0; - uint32_t total_offset = 0; - int modify_or_replace = 0; - ext2_dir_t *previous; - - inode_read_block(this, pinode, block_nr, block); - while (total_offset < pinode->size) { - if (dir_offset >= this->block_size) { - block_nr++; - dir_offset -= this->block_size; - inode_read_block(this, pinode, block_nr, block); - } - ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); - - unsigned int sreclen = d_ent->name_len + sizeof(ext2_dir_t); - sreclen += (sreclen % 4) ? (4 - (sreclen % 4)) : 0; - - { - char f[d_ent->name_len+1]; - memcpy(f, d_ent->name, d_ent->name_len); - f[d_ent->name_len] = 0; - debug_print(WARNING, " * file: %s", f); - } - debug_print(WARNING, " rec_len: %d", d_ent->rec_len); - debug_print(WARNING, " type: %d", d_ent->file_type); - debug_print(WARNING, " namel: %d", d_ent->name_len); - debug_print(WARNING, " inode: %d", d_ent->inode); - - if (d_ent->rec_len != sreclen && total_offset + d_ent->rec_len == pinode->size) { - debug_print(WARNING, " - should be %d, but instead points to end of block", sreclen); - debug_print(WARNING, " - we've hit the end, should change this pointer"); - - dir_offset += sreclen; - total_offset += sreclen; - - modify_or_replace = 1; /* Modify */ - previous = d_ent; - - break; - } - - if (d_ent->inode == 0) { - modify_or_replace = 2; /* Replace */ - } - - dir_offset += d_ent->rec_len; - total_offset += d_ent->rec_len; - } - - if (!modify_or_replace) { - debug_print(WARNING, "That's odd, this shouldn't have happened, we made it all the way here without hitting our two end conditions?"); - } - - if (modify_or_replace == 1) { - debug_print(WARNING, "The last node in the list is a real node, we need to modify it."); - - if (dir_offset + rec_len >= this->block_size) { - debug_print(WARNING, "Need to allocate more space, bail!"); - free(block); - return E_NOSPACE; - } else { - unsigned int sreclen = previous->name_len + sizeof(ext2_dir_t); - sreclen += (sreclen % 4) ? (4 - (sreclen % 4)) : 0; - previous->rec_len = sreclen; - debug_print(WARNING, "Set previous node rec_len to %d", sreclen); - } - - } else if (modify_or_replace == 2) { - debug_print(WARNING, "The last node in the list is a fake node, we'll replace it."); - } - - debug_print(WARNING, " total_offset = 0x%x", total_offset); - debug_print(WARNING, " dir_offset = 0x%x", dir_offset); - ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); - - d_ent->inode = inode; - d_ent->rec_len = this->block_size - dir_offset; - d_ent->name_len = strlen(name); - d_ent->file_type = 0; /* This is unused */ - memcpy(d_ent->name, name, strlen(name)); - - inode_write_block(this, pinode, parent->inode, block_nr, block); - - free(block); - free(pinode); - - - return E_NOSPACE; -} - -static unsigned int allocate_inode(ext2_fs_t * this) { - uint32_t node_no = 0; - uint32_t node_offset = 0; - uint32_t group = 0; - uint8_t * bg_buffer = malloc(this->block_size); - - for (unsigned int i = 0; i < BGDS; ++i) { - if (BGD[i].free_inodes_count > 0) { - debug_print(NOTICE, "Group %d has %d free inodes.", i, BGD[i].free_inodes_count); - read_block(this, BGD[i].inode_bitmap, (uint8_t *)bg_buffer); - while (BLOCKBIT(node_offset)) { - node_offset++; - } - node_no = node_offset + i * this->inodes_per_group + 1; - group = i; - break; - } - } - if (!node_no) { - debug_print(ERROR, "Ran out of inodes!"); - return 0; - } - - BLOCKBYTE(node_offset) |= SETBIT(node_offset); - - write_block(this, BGD[group].inode_bitmap, (uint8_t *)bg_buffer); - free(bg_buffer); - - BGD[group].free_inodes_count--; - for (int i = 0; i < this->bgd_block_span; ++i) { - write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); - } - - SB->free_inodes_count--; - rewrite_superblock(this); - - return node_no; -} - -static int mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) { - if (!name) return -EINVAL; - - ext2_fs_t * this = parent->device; - - /* first off, check if it exists */ - fs_node_t * check = finddir_ext2(parent, name); - if (check) { - debug_print(WARNING, "A file by this name already exists: %s", name); - free(check); - return -EEXIST; - } - - /* Allocate an inode for it */ - unsigned int inode_no = allocate_inode(this); - ext2_inodetable_t * inode = read_inode(this,inode_no); - - /* Set the access and creation times to now */ - inode->atime = now(); - inode->ctime = inode->atime; - inode->mtime = inode->atime; - inode->dtime = 0; /* This inode was never deleted */ - - /* Empty the file */ - memset(inode->block, 0x00, sizeof(inode->block)); - inode->blocks = 0; - inode->size = 0; /* empty */ - - /* Assign it to root */ - inode->uid = current_process->user; /* user */ - inode->gid = current_process->user; - - /* misc */ - inode->faddr = 0; - inode->links_count = 2; /* There's the parent's pointer to us, and our pointer to us. */ - inode->flags = 0; - inode->osd1 = 0; - inode->generation = 0; - inode->file_acl = 0; - inode->dir_acl = 0; - - /* File mode */ - inode->mode = EXT2_S_IFDIR; - inode->mode |= 0xFFF & permission; - - /* Write the osd blocks to 0 */ - memset(inode->osd2, 0x00, sizeof(inode->osd2)); - - /* Write out inode changes */ - write_inode(this, inode, inode_no); - - /* Now append the entry to the parent */ - create_entry(parent, name, inode_no); - - inode->size = this->block_size; - write_inode(this, inode, inode_no); - - uint8_t * tmp = malloc(this->block_size); - ext2_dir_t * t = malloc(12); - memset(t, 0, 12); - t->inode = inode_no; - t->rec_len = 12; - t->name_len = 1; - t->name[0] = '.'; - memcpy(&tmp[0], t, 12); - t->inode = parent->inode; - t->name_len = 2; - t->name[1] = '.'; - t->rec_len = this->block_size - 12; - memcpy(&tmp[12], t, 12); - free(t); - - inode_write_block(this, inode, inode_no, 0, tmp); - - free(inode); - free(tmp); - - /* Update parent link count */ - ext2_inodetable_t * pinode = read_inode(this, parent->inode); - pinode->links_count++; - write_inode(this, pinode, parent->inode); - free(pinode); - - /* Update directory count in block group descriptor */ - uint32_t group = inode_no / this->inodes_per_group; - BGD[group].used_dirs_count++; - for (int i = 0; i < this->bgd_block_span; ++i) { - write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); - } - - ext2_sync(this); - - return 0; -} - -static int create_ext2(fs_node_t * parent, char * name, uint16_t permission) { - if (!name) return -EINVAL; - - ext2_fs_t * this = parent->device; - - /* first off, check if it exists */ - fs_node_t * check = finddir_ext2(parent, name); - if (check) { - debug_print(WARNING, "A file by this name already exists: %s", name); - free(check); - return -EEXIST; - } - - /* Allocate an inode for it */ - unsigned int inode_no = allocate_inode(this); - ext2_inodetable_t * inode = read_inode(this,inode_no); - - /* Set the access and creation times to now */ - inode->atime = now(); - inode->ctime = inode->atime; - inode->mtime = inode->atime; - inode->dtime = 0; /* This inode was never deleted */ - - /* Empty the file */ - memset(inode->block, 0x00, sizeof(inode->block)); - inode->blocks = 0; - inode->size = 0; /* empty */ - - /* Assign it to root */ - inode->uid = current_process->user; /* user */ - inode->gid = current_process->user; - - /* misc */ - inode->faddr = 0; - inode->links_count = 1; /* The one we're about to create. */ - inode->flags = 0; - inode->osd1 = 0; - inode->generation = 0; - inode->file_acl = 0; - inode->dir_acl = 0; - - /* File mode */ - /* TODO: Use the mask from `permission` */ - inode->mode = EXT2_S_IFREG; - inode->mode |= 0xFFF & permission; - - /* Write the osd blocks to 0 */ - memset(inode->osd2, 0x00, sizeof(inode->osd2)); - - /* Write out inode changes */ - write_inode(this, inode, inode_no); - - /* Now append the entry to the parent */ - create_entry(parent, name, inode_no); - - free(inode); - - ext2_sync(this); - - return 0; -} - -static int chmod_ext2(fs_node_t * node, int mode) { - ext2_fs_t * this = node->device; - - ext2_inodetable_t * inode = read_inode(this,node->inode); - - inode->mode = (inode->mode & 0xFFFFF000) | mode; - - write_inode(this, inode, node->inode); - - ext2_sync(this); - - return 0; -} - -/** - * direntry_ext2 - */ -static ext2_dir_t * direntry_ext2(ext2_fs_t * this, ext2_inodetable_t * inode, uint32_t no, uint32_t index) { - uint8_t *block = malloc(this->block_size); - uint8_t block_nr = 0; - inode_read_block(this, inode, block_nr, block); - uint32_t dir_offset = 0; - uint32_t total_offset = 0; - uint32_t dir_index = 0; - - while (total_offset < inode->size && dir_index <= index) { - ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); - - if (d_ent->inode != 0 && dir_index == index) { - ext2_dir_t *out = malloc(d_ent->rec_len); - memcpy(out, d_ent, d_ent->rec_len); - free(block); - return out; - } - - dir_offset += d_ent->rec_len; - total_offset += d_ent->rec_len; - - if (d_ent->inode) { - dir_index++; - } - - if (dir_offset >= this->block_size) { - block_nr++; - dir_offset -= this->block_size; - inode_read_block(this, inode, block_nr, block); - } - } - - free(block); - return NULL; -} - -/** - * finddir_ext2 - */ -static fs_node_t * finddir_ext2(fs_node_t *node, char *name) { - - ext2_fs_t * this = (ext2_fs_t *)node->device; - - ext2_inodetable_t *inode = read_inode(this,node->inode); - assert(inode->mode & EXT2_S_IFDIR); - uint8_t * block = malloc(this->block_size); - ext2_dir_t *direntry = NULL; - uint8_t block_nr = 0; - inode_read_block(this, inode, block_nr, block); - uint32_t dir_offset = 0; - uint32_t total_offset = 0; - - while (total_offset < inode->size) { - if (dir_offset >= this->block_size) { - block_nr++; - dir_offset -= this->block_size; - inode_read_block(this, inode, block_nr, block); - } - ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); - - if (d_ent->inode == 0 || strlen(name) != d_ent->name_len) { - dir_offset += d_ent->rec_len; - total_offset += d_ent->rec_len; - - continue; - } - - char *dname = malloc(sizeof(char) * (d_ent->name_len + 1)); - memcpy(dname, &(d_ent->name), d_ent->name_len); - dname[d_ent->name_len] = '\0'; - if (!strcmp(dname, name)) { - free(dname); - direntry = malloc(d_ent->rec_len); - memcpy(direntry, d_ent, d_ent->rec_len); - break; - } - free(dname); - - dir_offset += d_ent->rec_len; - total_offset += d_ent->rec_len; - } - free(inode); - if (!direntry) { - free(block); - return NULL; - } - fs_node_t *outnode = malloc(sizeof(fs_node_t)); - memset(outnode, 0, sizeof(fs_node_t)); - - inode = read_inode(this, direntry->inode); - - if (!node_from_file(this, inode, direntry, outnode)) { - debug_print(CRITICAL, "Oh dear. Couldn't allocate the outnode?"); - } - - free(direntry); - free(inode); - free(block); - return outnode; -} - -static int unlink_ext2(fs_node_t * node, char * name) { - /* XXX this is a very bad implementation */ - ext2_fs_t * this = (ext2_fs_t *)node->device; - - ext2_inodetable_t *inode = read_inode(this,node->inode); - assert(inode->mode & EXT2_S_IFDIR); - uint8_t * block = malloc(this->block_size); - ext2_dir_t *direntry = NULL; - uint8_t block_nr = 0; - inode_read_block(this, inode, block_nr, block); - uint32_t dir_offset = 0; - uint32_t total_offset = 0; - - while (total_offset < inode->size) { - if (dir_offset >= this->block_size) { - block_nr++; - dir_offset -= this->block_size; - inode_read_block(this, inode, block_nr, block); - } - ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); - - if (d_ent->inode == 0 || strlen(name) != d_ent->name_len) { - dir_offset += d_ent->rec_len; - total_offset += d_ent->rec_len; - - continue; - } - - char *dname = malloc(sizeof(char) * (d_ent->name_len + 1)); - memcpy(dname, &(d_ent->name), d_ent->name_len); - dname[d_ent->name_len] = '\0'; - if (!strcmp(dname, name)) { - free(dname); - direntry = d_ent; - break; - } - free(dname); - - dir_offset += d_ent->rec_len; - total_offset += d_ent->rec_len; - } - free(inode); - if (!direntry) { - free(block); - return -ENOENT; - } - - direntry->inode = 0; - - inode_write_block(this, inode, node->inode, block_nr, block); - free(block); - - ext2_sync(this); - - return 0; -} - - -static void refresh_inode(ext2_fs_t * this, ext2_inodetable_t * inodet, uint32_t inode) { - uint32_t group = inode / this->inodes_per_group; - if (group > BGDS) { - return; - } - uint32_t inode_table_block = BGD[group].inode_table; - inode -= group * this->inodes_per_group; // adjust index within group - uint32_t block_offset = ((inode - 1) * this->inode_size) / this->block_size; - uint32_t offset_in_block = (inode - 1) - block_offset * (this->block_size / this->inode_size); - - uint8_t * buf = malloc(this->block_size); - - read_block(this, inode_table_block + block_offset, buf); - - ext2_inodetable_t *inodes = (ext2_inodetable_t *)buf; - - memcpy(inodet, (uint8_t *)((uint32_t)inodes + offset_in_block * this->inode_size), this->inode_size); - - free(buf); -} - -/** - * read_inode - */ -static ext2_inodetable_t * read_inode(ext2_fs_t * this, uint32_t inode) { - ext2_inodetable_t *inodet = malloc(this->inode_size); - refresh_inode(this, inodet, inode); - return inodet; -} - -static uint32_t read_ext2(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - ext2_fs_t * this = (ext2_fs_t *)node->device; - ext2_inodetable_t * inode = read_inode(this, node->inode); - uint32_t end; - if (inode->size == 0) return 0; - if (offset + size > inode->size) { - end = inode->size; - } else { - end = offset + size; - } - uint32_t start_block = offset / this->block_size; - uint32_t end_block = end / this->block_size; - uint32_t end_size = end - end_block * this->block_size; - uint32_t size_to_read = end - offset; - - uint8_t * buf = malloc(this->block_size); - if (start_block == end_block) { - inode_read_block(this, inode, start_block, buf); - memcpy(buffer, (uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % this->block_size)), size_to_read); - } else { - uint32_t block_offset; - uint32_t blocks_read = 0; - for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { - if (block_offset == start_block) { - inode_read_block(this, inode, block_offset, buf); - memcpy(buffer, (uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % this->block_size)), this->block_size - (offset % this->block_size)); - } else { - inode_read_block(this, inode, block_offset, buf); - memcpy(buffer + this->block_size * blocks_read - (offset % this->block_size), buf, this->block_size); - } - } - if (end_size) { - inode_read_block(this, inode, end_block, buf); - memcpy(buffer + this->block_size * blocks_read - (offset % this->block_size), buf, end_size); - } - } - free(inode); - free(buf); - return size_to_read; -} - -static uint32_t write_inode_buffer(ext2_fs_t * this, ext2_inodetable_t * inode, uint32_t inode_number, uint64_t offset, uint32_t size, uint8_t *buffer) { - uint32_t end = offset + size; - if (end > inode->size) { - inode->size = end; - write_inode(this, inode, inode_number); - } - - uint32_t start_block = offset / this->block_size; - uint32_t end_block = end / this->block_size; - uint32_t end_size = end - end_block * this->block_size; - uint32_t size_to_read = end - offset; - uint8_t * buf = malloc(this->block_size); - if (start_block == end_block) { - inode_read_block(this, inode, start_block, buf); - memcpy((uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % this->block_size)), buffer, size_to_read); - inode_write_block(this, inode, inode_number, start_block, buf); - } else { - uint32_t block_offset; - uint32_t blocks_read = 0; - for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { - if (block_offset == start_block) { - int b = inode_read_block(this, inode, block_offset, buf); - memcpy((uint8_t *)(((uint32_t)buf) + ((uintptr_t)offset % this->block_size)), buffer, this->block_size - (offset % this->block_size)); - inode_write_block(this, inode, inode_number, block_offset, buf); - if (!b) { - refresh_inode(this, inode, inode_number); - } - } else { - int b = inode_read_block(this, inode, block_offset, buf); - memcpy(buf, buffer + this->block_size * blocks_read - (offset % this->block_size), this->block_size); - inode_write_block(this, inode, inode_number, block_offset, buf); - if (!b) { - refresh_inode(this, inode, inode_number); - } - } - } - if (end_size) { - inode_read_block(this, inode, end_block, buf); - memcpy(buf, buffer + this->block_size * blocks_read - (offset % this->block_size), end_size); - inode_write_block(this, inode, inode_number, end_block, buf); - } - } - free(buf); - return size_to_read; -} - -static uint32_t write_ext2(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - ext2_fs_t * this = (ext2_fs_t *)node->device; - ext2_inodetable_t * inode = read_inode(this, node->inode); - - uint32_t rv = write_inode_buffer(this, inode, node->inode, offset, size, buffer); - free(inode); - return rv; -} - -static void truncate_ext2(fs_node_t * node) { - ext2_fs_t * this = node->device; - ext2_inodetable_t * inode = read_inode(this,node->inode); - inode->size = 0; - write_inode(this, inode, node->inode); -} - -static void open_ext2(fs_node_t *node, unsigned int flags) { - /* Nothing to do here */ -} - -static void close_ext2(fs_node_t *node) { - /* Nothing to do here */ -} - - -/** - * readdir_ext2 - */ -static struct dirent * readdir_ext2(fs_node_t *node, uint32_t index) { - - ext2_fs_t * this = (ext2_fs_t *)node->device; - - ext2_inodetable_t *inode = read_inode(this, node->inode); - assert(inode->mode & EXT2_S_IFDIR); - ext2_dir_t *direntry = direntry_ext2(this, inode, node->inode, index); - if (!direntry) { - free(inode); - return NULL; - } - struct dirent *dirent = malloc(sizeof(struct dirent)); - memcpy(&dirent->name, &direntry->name, direntry->name_len); - dirent->name[direntry->name_len] = '\0'; - dirent->ino = direntry->inode; - free(direntry); - free(inode); - return dirent; -} - -static int symlink_ext2(fs_node_t * parent, char * target, char * name) { - if (!name) return -EINVAL; - - ext2_fs_t * this = parent->device; - - /* first off, check if it exists */ - fs_node_t * check = finddir_ext2(parent, name); - if (check) { - debug_print(WARNING, "A file by this name already exists: %s", name); - free(check); - return -EEXIST; /* this should probably have a return value... */ - } - - /* Allocate an inode for it */ - unsigned int inode_no = allocate_inode(this); - ext2_inodetable_t * inode = read_inode(this,inode_no); - - /* Set the access and creation times to now */ - inode->atime = now(); - inode->ctime = inode->atime; - inode->mtime = inode->atime; - inode->dtime = 0; /* This inode was never deleted */ - - /* Empty the file */ - memset(inode->block, 0x00, sizeof(inode->block)); - inode->blocks = 0; - inode->size = 0; /* empty */ - - /* Assign it to current user */ - inode->uid = current_process->user; - inode->gid = current_process->user; - - /* misc */ - inode->faddr = 0; - inode->links_count = 1; /* The one we're about to create. */ - inode->flags = 0; - inode->osd1 = 0; - inode->generation = 0; - inode->file_acl = 0; - inode->dir_acl = 0; - - inode->mode = EXT2_S_IFLNK; - - /* I *think* this is what you're supposed to do with symlinks */ - inode->mode |= 0777; - - /* Write the osd blocks to 0 */ - memset(inode->osd2, 0x00, sizeof(inode->osd2)); - - size_t target_len = strlen(target); - int embedded = target_len <= 60; // sizeof(_symlink(inode)); - if (embedded) { - memcpy(_symlink(inode), target, target_len); - inode->size = target_len; - } - - /* Write out inode changes */ - write_inode(this, inode, inode_no); - - /* Now append the entry to the parent */ - create_entry(parent, name, inode_no); - - - /* If we didn't embed it in the inode just use write_inode_buffer to finish the job */ - if (!embedded) { - write_inode_buffer(parent->device, inode, inode_no, 0, target_len, (uint8_t *)target); - } - free(inode); - - ext2_sync(this); - - return 0; -} - -static int readlink_ext2(fs_node_t * node, char * buf, size_t size) { - ext2_fs_t * this = (ext2_fs_t *)node->device; - ext2_inodetable_t * inode = read_inode(this, node->inode); - size_t read_size = inode->size < size ? inode->size : size; - if (inode->size > 60) { //sizeof(_symlink(inode))) { - read_ext2(node, 0, read_size, (uint8_t *)buf); - } else { - memcpy(buf, _symlink(inode), read_size); - } - - /* Believe it or not, we actually aren't supposed to include the nul in the length. */ - if (read_size < size) { - buf[read_size] = '\0'; - } - - free(inode); - return read_size; -} - - - -static uint32_t node_from_file(ext2_fs_t * this, ext2_inodetable_t *inode, ext2_dir_t *direntry, fs_node_t *fnode) { - if (!fnode) { - /* You didn't give me a node to write into, go **** yourself */ - return 0; - } - /* Information from the direntry */ - fnode->device = (void *)this; - fnode->inode = direntry->inode; - memcpy(&fnode->name, &direntry->name, direntry->name_len); - fnode->name[direntry->name_len] = '\0'; - /* Information from the inode */ - fnode->uid = inode->uid; - fnode->gid = inode->gid; - fnode->length = inode->size; - fnode->mask = inode->mode & 0xFFF; - fnode->nlink = inode->links_count; - /* File Flags */ - fnode->flags = 0; - if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) { - fnode->flags |= FS_FILE; - fnode->read = read_ext2; - fnode->write = write_ext2; - fnode->create = NULL; - fnode->mkdir = NULL; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->symlink = NULL; - fnode->readlink = NULL; - fnode->truncate = truncate_ext2; - } - if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) { - fnode->flags |= FS_DIRECTORY; - fnode->create = create_ext2; - fnode->mkdir = mkdir_ext2; - fnode->readdir = readdir_ext2; - fnode->finddir = finddir_ext2; - fnode->unlink = unlink_ext2; - fnode->write = NULL; - fnode->symlink = symlink_ext2; - fnode->readlink = NULL; - } - if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) { - fnode->flags |= FS_BLOCKDEVICE; - } - if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) { - fnode->flags |= FS_CHARDEVICE; - } - if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) { - fnode->flags |= FS_PIPE; - } - if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) { - fnode->flags |= FS_SYMLINK; - fnode->read = NULL; - fnode->write = NULL; - fnode->create = NULL; - fnode->mkdir = NULL; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->readlink = readlink_ext2; - } - - fnode->atime = inode->atime; - fnode->mtime = inode->mtime; - fnode->ctime = inode->ctime; - debug_print(INFO, "file a/m/c times are %d/%d/%d", fnode->atime, fnode->mtime, fnode->ctime); - - fnode->chmod = chmod_ext2; - fnode->open = open_ext2; - fnode->close = close_ext2; - fnode->ioctl = NULL; - return 1; -} - -static uint32_t ext2_root(ext2_fs_t * this, ext2_inodetable_t *inode, fs_node_t *fnode) { - if (!fnode) { - return 0; - } - /* Information for root dir */ - fnode->device = (void *)this; - fnode->inode = 2; - fnode->name[0] = '/'; - fnode->name[1] = '\0'; - /* Information from the inode */ - fnode->uid = inode->uid; - fnode->gid = inode->gid; - fnode->length = inode->size; - fnode->mask = inode->mode & 0xFFF; - fnode->nlink = inode->links_count; - /* File Flags */ - fnode->flags = 0; - if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) { - debug_print(CRITICAL, "Root appears to be a regular file."); - debug_print(CRITICAL, "This is probably very, very wrong."); - return 0; - } - if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) { - } else { - debug_print(CRITICAL, "Root doesn't appear to be a directory."); - debug_print(CRITICAL, "This is probably very, very wrong."); - - debug_print(ERROR, "Other useful information:"); - debug_print(ERROR, "%d", inode->uid); - debug_print(ERROR, "%d", inode->gid); - debug_print(ERROR, "%d", inode->size); - debug_print(ERROR, "%d", inode->mode); - debug_print(ERROR, "%d", inode->links_count); - - return 0; - } - if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) { - fnode->flags |= FS_BLOCKDEVICE; - } - if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) { - fnode->flags |= FS_CHARDEVICE; - } - if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) { - fnode->flags |= FS_PIPE; - } - if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) { - fnode->flags |= FS_SYMLINK; - } - - fnode->atime = inode->atime; - fnode->mtime = inode->mtime; - fnode->ctime = inode->ctime; - - fnode->flags |= FS_DIRECTORY; - fnode->read = NULL; - fnode->write = NULL; - fnode->chmod = chmod_ext2; - fnode->open = open_ext2; - fnode->close = close_ext2; - fnode->readdir = readdir_ext2; - fnode->finddir = finddir_ext2; - fnode->ioctl = NULL; - fnode->create = create_ext2; - fnode->mkdir = mkdir_ext2; - fnode->unlink = unlink_ext2; - return 1; -} - -static fs_node_t * mount_ext2(fs_node_t * block_device, int flags) { - - debug_print(NOTICE, "Mounting ext2 file system..."); - ext2_fs_t * this = malloc(sizeof(ext2_fs_t)); - - memset(this, 0x00, sizeof(ext2_fs_t)); - - this->flags = flags; - - this->block_device = block_device; - this->block_size = 1024; - vfs_lock(this->block_device); - - SB = malloc(this->block_size); - - debug_print(INFO, "Reading superblock..."); - read_block(this, 1, (uint8_t *)SB); - if (SB->magic != EXT2_SUPER_MAGIC) { - debug_print(ERROR, "... not an EXT2 filesystem? (magic didn't match, got 0x%x)", SB->magic); - return NULL; - } - this->inode_size = SB->inode_size; - if (SB->inode_size == 0) { - this->inode_size = 128; - } - this->block_size = 1024 << SB->log_block_size; - this->cache_entries = 10240; - if (this->block_size > 2048) { - this->cache_entries /= 4; - } - debug_print(INFO, "bs=%d, cache entries=%d", this->block_size, this->cache_entries); - this->pointers_per_block = this->block_size / 4; - debug_print(INFO, "Log block size = %d -> %d", SB->log_block_size, this->block_size); - BGDS = SB->blocks_count / SB->blocks_per_group; - if (SB->blocks_per_group * BGDS < SB->blocks_count) { - BGDS += 1; - } - this->inodes_per_group = SB->inodes_count / BGDS; - - if (!(this->flags & EXT2_FLAG_NOCACHE)) { - debug_print(INFO, "Allocating cache..."); - DC = malloc(sizeof(ext2_disk_cache_entry_t) * this->cache_entries); - this->cache_data = malloc(this->block_size * this->cache_entries); - memset(this->cache_data, 0, this->block_size * this->cache_entries); - for (uint32_t i = 0; i < this->cache_entries; ++i) { - DC[i].block_no = 0; - DC[i].dirty = 0; - DC[i].last_use = 0; - DC[i].block = this->cache_data + i * this->block_size; - if (i % 128 == 0) { - debug_print(INFO, "Allocated cache block #%d", i+1); - } - } - debug_print(INFO, "Allocated cache."); - } else { - DC = NULL; - debug_print(NOTICE, "ext2 cache is disabled (nocache)"); - } - - // load the block group descriptors - this->bgd_block_span = sizeof(ext2_bgdescriptor_t) * BGDS / this->block_size + 1; - BGD = malloc(this->block_size * this->bgd_block_span); - - debug_print(INFO, "bgd_block_span = %d", this->bgd_block_span); - - this->bgd_offset = 2; - - if (this->block_size > 1024) { - this->bgd_offset = 1; - } - - for (int i = 0; i < this->bgd_block_span; ++i) { - read_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); - } - -#ifdef DEBUG_BLOCK_DESCRIPTORS - char * bg_buffer = malloc(this->block_size * sizeof(char)); - for (uint32_t i = 0; i < BGDS; ++i) { - debug_print(INFO, "Block Group Descriptor #%d @ %d", i, this->bgd_offset + i * SB->blocks_per_group); - debug_print(INFO, "\tBlock Bitmap @ %d", BGD[i].block_bitmap); { - debug_print(INFO, "\t\tExamining block bitmap at %d", BGD[i].block_bitmap); - read_block(this, BGD[i].block_bitmap, (uint8_t *)bg_buffer); - uint32_t j = 0; - while (BLOCKBIT(j)) { - ++j; - } - debug_print(INFO, "\t\tFirst free block in group is %d", j + BGD[i].block_bitmap - 2); - } - debug_print(INFO, "\tInode Bitmap @ %d", BGD[i].inode_bitmap); { - debug_print(INFO, "\t\tExamining inode bitmap at %d", BGD[i].inode_bitmap); - read_block(this, BGD[i].inode_bitmap, (uint8_t *)bg_buffer); - uint32_t j = 0; - while (BLOCKBIT(j)) { - ++j; - } - debug_print(INFO, "\t\tFirst free inode in group is %d", j + this->inodes_per_group * i + 1); - } - debug_print(INFO, "\tInode Table @ %d", BGD[i].inode_table); - debug_print(INFO, "\tFree Blocks = %d", BGD[i].free_blocks_count); - debug_print(INFO, "\tFree Inodes = %d", BGD[i].free_inodes_count); - } - free(bg_buffer); -#endif - - ext2_inodetable_t *root_inode = read_inode(this, 2); - RN = (fs_node_t *)malloc(sizeof(fs_node_t)); - if (!ext2_root(this, root_inode, RN)) { - return NULL; - } - debug_print(NOTICE, "Mounted EXT2 disk, root VFS node is at 0x%x", RN); - return RN; -} - -fs_node_t * ext2_fs_mount(char * device, char * mount_path) { - - char * arg = strdup(device); - char * argv[10]; - int argc = tokenize(arg, ",", argv); - - fs_node_t * dev = kopen(argv[0], 0); - if (!dev) { - debug_print(ERROR, "failed to open %s", device); - return NULL; - } - - int flags = 0; - - for (int i = 1; i < argc; ++i) { - if (!strcmp(argv[i],"nocache")) { - flags |= EXT2_FLAG_NOCACHE; - } else { - debug_print(WARNING, "Unrecognized option to ext2 driver: %s", argv[i]); - } - } - - fs_node_t * fs = mount_ext2(dev, flags); - - free(arg); - return fs; -} - -int ext2_initialize(void) { - - vfs_register("ext2", ext2_fs_mount); - - return 0; -} - -int ext2_finalize(void) { - - return 0; -} - -MODULE_DEF(ext2, ext2_initialize, ext2_finalize); - diff --git a/modules/hda.c b/modules/hda.c deleted file mode 100644 index 83620b06..00000000 --- a/modules/hda.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Experimental Intel High-Definition Audio "driver" - */ - -#include -#include -#include -#include - -struct hda_device { - uint32_t pci_device; -}; - -static struct hda_device _device; - -static void find_hda(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - - struct hda_device * hda = extra; - - if ((vendorid == 0x8086) && (deviceid == 0x2668)) { - hda->pci_device = device; - } - -} - -DEFINE_SHELL_FUNCTION(hda_test, "[debug] Intel HDA experiments") { - - if (!_device.pci_device) { - fprintf(tty, "No HDA device found.\n"); - return 1; - } - fprintf(tty, "HDA audio device is at 0x%x.\n", _device.pci_device); - - return 0; -} - -static int init(void) { - BIND_SHELL_FUNCTION(hda_test); - pci_scan(&find_hda, -1, &_device); - if (!_device.pci_device) { - return 1; - } - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(hda, init, fini); -MODULE_DEPENDS(debugshell); diff --git a/modules/iso9660.c b/modules/iso9660.c deleted file mode 100644 index 047c7e28..00000000 --- a/modules/iso9660.c +++ /dev/null @@ -1,509 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016-2018 K. Lange - * - * ISO 9660 filesystem driver (for CDs) - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define ISO_SECTOR_SIZE 2048 - -#define FLAG_HIDDEN 0x01 -#define FLAG_DIRECTORY 0x02 -#define FLAG_ASSOCIATED 0x04 -#define FLAG_EXTENDED 0x08 -#define FLAG_PERMISSIONS 0x10 -#define FLAG_CONTINUES 0x80 - -typedef struct { - fs_node_t * block_device; - uint32_t block_size; - hashmap_t * cache; - list_t * lru; -} iso_9660_fs_t; - -typedef struct { - char year[4]; - char month[2]; - char day[2]; - char hour[2]; - char minute[2]; - char second[2]; - char hundredths[2]; - int8_t timezone; -} __attribute__((packed)) iso_9660_datetime_t; - -typedef struct { - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t minute; - uint8_t second; - int8_t timezone; -} __attribute__((packed)) iso_9660_rec_date_t; - -typedef struct { - uint8_t length; - uint8_t ext_length; - - uint32_t extent_start_LSB; - uint32_t extent_start_MSB; - - uint32_t extent_length_LSB; - uint32_t extent_length_MSB; - - iso_9660_rec_date_t record_date; - - uint8_t flags; - uint8_t interleave_units; - uint8_t interleave_gap; - - uint16_t volume_seq_LSB; - uint16_t volume_seq_MSB; - - uint8_t name_len; - char name[]; -} __attribute__((packed)) iso_9660_directory_entry_t; - -typedef struct { - uint8_t type; /* 0x01 */ - char id[5]; /* CD001 */ - - uint8_t version; - uint8_t _unused0; - - char system_id[32]; - char volume_id[32]; - - uint8_t _unused1[8]; - - uint32_t volume_space_LSB; - uint32_t volume_space_MSB; - - uint8_t _unused2[32]; - - uint16_t volume_set_LSB; - uint16_t volume_set_MSB; - - uint16_t volume_seq_LSB; - uint16_t volume_seq_MSB; - - uint16_t logical_block_size_LSB; - uint16_t logical_block_size_MSB; - - uint32_t path_table_size_LSB; - uint32_t path_table_size_MSB; - - uint32_t path_table_LSB; - uint32_t optional_path_table_LSB; - - uint32_t path_table_MSB; - uint32_t optional_path_table_MSB; - - /* iso_9660_directory_entry_t */ - char root[34]; - - char volume_set_id[128]; - char volume_publisher[128]; - char data_preparer[128]; - char application_id[128]; - - char copyright_file[38]; - char abstract_file[36]; - char bibliographic_file[37]; - - iso_9660_datetime_t creation; - iso_9660_datetime_t modification; - iso_9660_datetime_t expiration; - iso_9660_datetime_t effective; - - uint8_t file_structure_version; - uint8_t _unused_3; - - char application_use[]; -} __attribute__((packed)) iso_9660_volume_descriptor_t; - -static void file_from_dir_entry(iso_9660_fs_t * this, size_t sector, iso_9660_directory_entry_t * dir, size_t offset, fs_node_t * fs); - -#define CACHE_SIZE 64 - -static void read_sector(iso_9660_fs_t * this, uint32_t sector_id, char * buffer) { - if (this->cache) { - void * sector_id_v = (void *)sector_id; - if (hashmap_has(this->cache, sector_id_v)) { - memcpy(buffer,hashmap_get(this->cache, sector_id_v), this->block_size); - - node_t * me = list_find(this->lru, sector_id_v); - list_delete(this->lru, me); - list_append(this->lru, me); - - } else { - if (this->lru->length > CACHE_SIZE) { - node_t * l = list_dequeue(this->lru); - free(hashmap_get(this->cache, l->value)); - hashmap_remove(this->cache, l->value); - free(l); - } - read_fs(this->block_device, sector_id * this->block_size, this->block_size, (uint8_t *)buffer); - char * buf = malloc(this->block_size); - memcpy(buf, buffer, this->block_size); - hashmap_set(this->cache, sector_id_v, buf); - list_insert(this->lru, sector_id_v); - } - } else { - read_fs(this->block_device, sector_id * this->block_size, this->block_size, (uint8_t *)buffer); - } -} - -static void inplace_lower(char * string) { - while (*string) { - if (*string >= 'A' && *string <= 'Z') { - *string += ('a' - 'A'); - } - string++; - } -} - -static void open_iso(fs_node_t *node, unsigned int flags) { - /* Nothing to do here */ -} - -static void close_iso(fs_node_t *node) { - /* Nothing to do here */ -} - -static struct dirent * readdir_iso(fs_node_t *node, uint32_t index) { - if (index == 0) { - struct dirent * out = malloc(sizeof(struct dirent)); - memset(out, 0x00, sizeof(struct dirent)); - out->ino = 0; - strcpy(out->name, "."); - return out; - } - - if (index == 1) { - struct dirent * out = malloc(sizeof(struct dirent)); - memset(out, 0x00, sizeof(struct dirent)); - out->ino = 0; - strcpy(out->name, ".."); - return out; - } - - iso_9660_fs_t * this = node->device; - char * buffer = malloc(this->block_size); - read_sector(this, node->inode, buffer); - iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)(buffer + node->impl); - - debug_print(INFO, "[iso] Reading directory for readdir; sector = %d, offset = %d", node->inode, node->impl); - - uint8_t * root_data = malloc(root_entry->extent_length_LSB); - uint8_t * offset = root_data; - size_t sector_offset = 0; - size_t length_to_read = root_entry->extent_length_LSB; - while (length_to_read) { - read_sector(this, root_entry->extent_start_LSB + sector_offset, (char*)offset); - if (length_to_read >= this->block_size) { - offset += this->block_size; - sector_offset += 1; - length_to_read -= this->block_size; - } else { - break; - } - } - - debug_print(INFO, "[iso] Done, want index = %d", index); - - /* Examine directory */ - offset = root_data; - - unsigned int i = 0; - struct dirent *dirent = malloc(sizeof(struct dirent)); - fs_node_t * out = malloc(sizeof(fs_node_t)); - memset(dirent, 0, sizeof(struct dirent)); - while (1) { - iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)offset; - if (dir->length == 0) { - debug_print(INFO, "dir->length = %d", dir->length); - if ((size_t)(offset - root_data) < root_entry->extent_length_LSB) { - offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); - goto try_again; - } - break; - } - if (!(dir->flags & FLAG_HIDDEN)) { - debug_print(INFO, "[iso] Found file %d", i); - if (i == index) { - file_from_dir_entry(this, (root_entry->extent_start_LSB)+(offset - root_data)/this->block_size, dir, (offset - root_data) % this->block_size, out); - memcpy(&dirent->name, out->name, strlen(out->name)+1); - dirent->ino = out->inode; - goto cleanup; - } - i += 1; - } - offset += dir->length; -try_again: - if ((size_t)(offset - root_data) > root_entry->extent_length_LSB) break; - } - - debug_print(INFO, "offset = %x; root_data = %x; extent = %x", offset, root_data, root_entry->extent_length_LSB); - - free(dirent); - dirent = NULL; - -cleanup: - free(root_data); - free(buffer); - free(out); - return dirent; -} - -static uint32_t read_iso(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { - iso_9660_fs_t * this = node->device; - char * tmp = malloc(this->block_size); - read_sector(this, node->inode, tmp); - iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)(tmp + node->impl); - - uint32_t end; - /* We can do this in a single underlying read to the filesystem */ - if (offset + size > root_entry->extent_length_LSB) { - end = root_entry->extent_length_LSB; - } else { - end = offset + size; - } - uint32_t size_to_read = end - offset; - - read_fs(this->block_device, root_entry->extent_start_LSB * this->block_size + offset, size_to_read, (uint8_t *)buffer); - - free(tmp); - return size_to_read; -} - -static fs_node_t * finddir_iso(fs_node_t *node, char *name) { - iso_9660_fs_t * this = node->device; - char * buffer = malloc(this->block_size); - read_sector(this, node->inode, buffer); - iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)(buffer + node->impl); - - uint8_t * root_data = malloc(root_entry->extent_length_LSB); - uint8_t * offset = root_data; - size_t sector_offset = 0; - size_t length_to_read = root_entry->extent_length_LSB; - while (length_to_read) { - read_sector(this, root_entry->extent_start_LSB + sector_offset, (char*)offset); - if (length_to_read >= this->block_size) { - offset += this->block_size; - sector_offset += 1; - length_to_read -= this->block_size; - } else { - break; - } - } - - /* Examine directory */ - offset = root_data; - - fs_node_t * out = malloc(sizeof(fs_node_t)); - while (1) { - iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)offset; - if (dir->length == 0) { - if ((size_t)(offset - root_data) < root_entry->extent_length_LSB) { - offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); - goto try_next_finddir; - } - break; - } - if (!(dir->flags & FLAG_HIDDEN)) { - memset(out, 0, sizeof(fs_node_t)); - file_from_dir_entry(this, (root_entry->extent_start_LSB)+(offset - root_data)/this->block_size, dir, (offset - root_data) % this->block_size, out); - - if (!strcmp(out->name, name)) { - goto cleanup; /* found it */ - } - - } - offset += dir->length; -try_next_finddir: - if ((size_t)(offset - root_data) > root_entry->extent_length_LSB) break; - } - - free(out); - out = NULL; - -cleanup: - free(root_data); - free(buffer); - return out; -} - -static void file_from_dir_entry(iso_9660_fs_t * this, size_t sector, iso_9660_directory_entry_t * dir, size_t offset, fs_node_t * fs) { - fs->device = this; - fs->inode = sector; /* Sector the file is in */ - fs->impl = offset; /* Offset */ - - char * file_name = malloc(dir->name_len + 1); - memcpy(file_name, dir->name, dir->name_len); - file_name[dir->name_len] = 0; - inplace_lower(file_name); - char * dot = strchr(file_name, '.'); - if (!dot) { - /* It's a directory. */ - } else { - char * ext = dot + 1; - char * semi = strchr(ext, ';'); - if (semi) { - *semi = 0; - } - if (strlen(ext) == 0) { - *dot = 0; - } else { - char * derp = ext; - while (*derp == '.') derp++; - if (derp != ext) { - memmove(ext, derp, strlen(derp)+1); - } - } - } - memcpy(fs->name, file_name, strlen(file_name)+1); - free(file_name); - - fs->uid = 0; - fs->gid = 0; - fs->length = dir->extent_length_LSB; - fs->mask = 0555; - fs->nlink = 0; /* Unsupported */ - if (dir->flags & FLAG_DIRECTORY) { - fs->flags = FS_DIRECTORY; - fs->readdir = readdir_iso; - fs->finddir = finddir_iso; - } else { - fs->flags = FS_FILE; - fs->read = read_iso; - } - /* Other things not supported */ - /* TODO actually get these from the CD into Unix time */ - fs->atime = now(); - fs->mtime = now(); - fs->ctime = now(); - - fs->open = open_iso; - fs->close = close_iso; -} - -static fs_node_t * iso_fs_mount(char * device, char * mount_path) { - char * arg = strdup(device); - char * argv[10]; - int argc = tokenize(arg, ",", argv); - - fs_node_t * dev = kopen(argv[0], 0); - if (!dev) { - debug_print(ERROR, "failed to open %s", device); - return NULL; - } - - int cache = 1; - - for (int i = 1; i < argc; ++i) { - if (!strcmp(argv[i],"nocache")) { - cache = 0; - } else { - debug_print(WARNING, "Unrecognized option to iso driver: %s", argv[i]); - } - } - - if (!dev) { - debug_print(ERROR, "failed to open %s", argv[0]); - free(arg); - return NULL; - } - - iso_9660_fs_t * this = malloc(sizeof(iso_9660_fs_t)); - this->block_device = dev; - this->block_size = ISO_SECTOR_SIZE; - if (cache) { - this->cache = hashmap_create_int(10); - this->lru = list_create(); - } else { - this->cache = NULL; - } - - /* Probably want to put a block cache on this like EXT2 driver does; or do that in the ATAPI layer... */ - - debug_print(WARNING, "ISO 9660 file system driver mounting %s to %s", device, mount_path); - - /* Read the volume descriptors */ - uint8_t * tmp = malloc(ISO_SECTOR_SIZE); - int i = 0x10; - int found = 0; - while (1) { - read_sector(this,i,(char*)tmp); - if (tmp[0] == 0x00) { - debug_print(WARNING, " Boot Record"); - } else if (tmp[0] == 0x01) { - debug_print(WARNING, " Primary Volume Descriptor"); - found = 1; - break; - } else if (tmp[0] == 0x02) { - debug_print(WARNING, " Secondary Volume Descriptor"); - } else if (tmp[0] == 0x03) { - debug_print(WARNING, " Volume Partition Descriptor"); - } - if (tmp[0] == 0xFF) break; - i++; - } - - if (!found) { - debug_print(WARNING, "No primary volume descriptor?"); - free(arg); - return NULL; - } - - iso_9660_volume_descriptor_t * root = (iso_9660_volume_descriptor_t *)tmp; - - debug_print(WARNING, " Volume space: %d", root->volume_space_LSB); - debug_print(WARNING, " Volume set: %d", root->volume_set_LSB); - debug_print(WARNING, " Volume seq: %d", root->volume_seq_LSB); - debug_print(WARNING, " Block size: %d", root->logical_block_size_LSB); - debug_print(WARNING, " Path table size: %d", root->path_table_size_LSB); - debug_print(WARNING, " Path table loc: %d", root->path_table_LSB); - - iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)&root->root; - - debug_print(WARNING, "ISO root info:"); - debug_print(WARNING, " Entry len: %d", root_entry->length); - debug_print(WARNING, " File start: %d", root_entry->extent_start_LSB); - debug_print(WARNING, " File len: %d", root_entry->extent_length_LSB); - debug_print(WARNING, " Is a directory: %s", (root_entry->flags & FLAG_DIRECTORY) ? "yes" : "no?"); - debug_print(WARNING, " Interleave units: %d", root_entry->interleave_units); - debug_print(WARNING, " Interleave gap: %d", root_entry->interleave_gap); - debug_print(WARNING, " Volume Seq: %d", root_entry->volume_seq_LSB); - - fs_node_t * fs = malloc(sizeof(fs_node_t)); - memset(fs, 0, sizeof(fs_node_t)); - file_from_dir_entry(this, i, root_entry, 156, fs); - - free(arg); - return fs; -} - -static int init(void) { - vfs_register("iso", iso_fs_mount); - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(iso9660, init, fini); diff --git a/modules/net.c b/modules/net.c deleted file mode 100644 index 5125b51e..00000000 --- a/modules/net.c +++ /dev/null @@ -1,1678 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static hashmap_t * dns_cache; -static list_t * dns_waiters = NULL; -static uint32_t _dns_server; - -static hashmap_t *_tcp_sockets = NULL; -static hashmap_t *_udp_sockets = NULL; - -static void parse_dns_response(fs_node_t * tty, void * last_packet); -static size_t write_dns_packet(uint8_t * buffer, size_t queries_len, uint8_t * queries); -size_t write_dhcp_request(uint8_t * buffer, uint8_t * ip); -static size_t write_arp_request(uint8_t * buffer, uint32_t ip); - -static uint8_t _gateway[6] = {255,255,255,255,255,255}; - -static struct netif _netif = {0}; - -static int tasklet_pid = 0; - -uint32_t get_primary_dns(void); - -static uint32_t netif_func(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - char * buf = malloc(4096); - - struct netif * netif = &_netif; - char ip[16]; - ip_ntoa(netif->source, ip); - char dns[16]; - ip_ntoa(get_primary_dns(), dns); - char gw[16]; - ip_ntoa(netif->gateway, gw); - - if (netif->hwaddr[0] == 0 && - netif->hwaddr[1] == 0 && - netif->hwaddr[2] == 0 && - netif->hwaddr[3] == 0 && - netif->hwaddr[4] == 0 && - netif->hwaddr[5] == 0) { - - sprintf(buf, "no network\n"); - } else { - sprintf(buf, - "ip:\t%s\n" - "mac:\t%2x:%2x:%2x:%2x:%2x:%2x\n" - "device:\t%s\n" - "dns:\t%s\n" - "gateway:\t%s\n" - , - ip, - netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5], - netif->driver, - dns, - gw - ); - } - - size_t _bsize = strlen(buf); - if (offset > _bsize) { - free(buf); - return 0; - } - if (size > _bsize - offset) size = _bsize - offset; - - memcpy(buffer, buf + offset, size); - free(buf); - return size; -} - -static struct procfs_entry netif_entry = { - 0, /* filled by install */ - "netif", - netif_func, -}; - -void init_netif_funcs(get_mac_func mac_func, get_packet_func get_func, send_packet_func send_func, char * device) { - _netif.get_mac = mac_func; - _netif.get_packet = get_func; - _netif.send_packet = send_func; - _netif.driver = device; - memcpy(_netif.hwaddr, _netif.get_mac(), sizeof(_netif.hwaddr)); - - if (!netif_entry.id) { - int (*procfs_install)(struct procfs_entry *) = (int (*)(struct procfs_entry *))(uintptr_t)hashmap_get(modules_get_symbols(),"procfs_install"); - if (procfs_install) { - procfs_install(&netif_entry); - } - } - - if (!tasklet_pid) { - tasklet_pid = create_kernel_tasklet(net_handler, "[net]", NULL); - debug_print(NOTICE, "Network worker tasklet started with pid %d", tasklet_pid); - } -} - -struct netif * get_default_network_interface(void) { - return &_netif; -} - -uint32_t get_primary_dns(void) { - return _dns_server; -} - -uint32_t ip_aton(const char * in) { - char ip[16]; - char * c = ip; - uint32_t out[4]; - char * i; - memcpy(ip, in, strlen(in) < 15 ? strlen(in) + 1 : 15); - ip[15] = '\0'; - - i = (char *)lfind(c, '.'); - *i = '\0'; - out[0] = atoi(c); - c += strlen(c) + 1; - - i = (char *)lfind(c, '.'); - *i = '\0'; - out[1] = atoi(c); - c += strlen(c) + 1; - - i = (char *)lfind(c, '.'); - *i = '\0'; - out[2] = atoi(c); - c += strlen(c) + 1; - - out[3] = atoi(c); - - return ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | (out[3])); -} - -void ip_ntoa(uint32_t src_addr, char * out) { - sprintf(out, "%d.%d.%d.%d", - (src_addr & 0xFF000000) >> 24, - (src_addr & 0xFF0000) >> 16, - (src_addr & 0xFF00) >> 8, - (src_addr & 0xFF)); -} - -uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) { - uint32_t sum = 0; - uint16_t * s = (uint16_t *)p; - - /* TODO: Checksums for options? */ - for (int i = 0; i < 10; ++i) { - sum += ntohs(s[i]); - } - - if (sum > 0xFFFF) { - sum = (sum >> 16) + (sum & 0xFFFF); - } - - return ~(sum & 0xFFFF) & 0xFFFF; -} - -uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header * h, void * d, size_t payload_size) { - uint32_t sum = 0; - uint16_t * s = (uint16_t *)p; - - /* TODO: Checksums for options? */ - for (int i = 0; i < 6; ++i) { - sum += ntohs(s[i]); - if (sum > 0xFFFF) { - sum = (sum >> 16) + (sum & 0xFFFF); - } - } - - s = (uint16_t *)h; - for (int i = 0; i < 10; ++i) { - sum += ntohs(s[i]); - if (sum > 0xFFFF) { - sum = (sum >> 16) + (sum & 0xFFFF); - } - } - - uint16_t d_words = payload_size / 2; - - s = (uint16_t *)d; - for (unsigned int i = 0; i < d_words; ++i) { - sum += ntohs(s[i]); - if (sum > 0xFFFF) { - sum = (sum >> 16) + (sum & 0xFFFF); - } - } - - if (d_words * 2 != payload_size) { - uint8_t * t = (uint8_t *)d; - uint8_t tmp[2]; - tmp[0] = t[d_words * sizeof(uint16_t)]; - tmp[1] = 0; - - uint16_t * f = (uint16_t *)tmp; - - sum += ntohs(f[0]); - if (sum > 0xFFFF) { - sum = (sum >> 16) + (sum & 0xFFFF); - } - } - - return ~(sum & 0xFFFF) & 0xFFFF; -} - -static struct dirent * readdir_netfs(fs_node_t *node, uint32_t index) { - if (index == 0) { - struct dirent * out = malloc(sizeof(struct dirent)); - memset(out, 0x00, sizeof(struct dirent)); - out->ino = 0; - strcpy(out->name, "."); - return out; - } - - if (index == 1) { - struct dirent * out = malloc(sizeof(struct dirent)); - memset(out, 0x00, sizeof(struct dirent)); - out->ino = 0; - strcpy(out->name, ".."); - return out; - } - - index -= 2; - return NULL; -} - -size_t dns_name_to_normal_name(struct dns_packet * dns, size_t offset, char * buf) { - uint8_t * bytes = (uint8_t *)dns; - size_t i = 0; - - while (1) { - uint8_t c = bytes[offset]; - if (c == 0) break; - if (c >= 0xC0) { - uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1]; - i += dns_name_to_normal_name(dns, ref, &buf[i]); - return i; - } - offset++; - - for (size_t j = 0; j < c; j++) { - buf[i] = bytes[offset]; - i++; - offset++; - } - buf[i] = '.'; - i++; - buf[i] = '\0'; - } - if (i == 0) return 0; - - buf[i-1] = '\0'; - return i-1; -} - -size_t get_dns_name(char * buffer, struct dns_packet * dns, size_t offset) { - uint8_t * bytes = (uint8_t *)dns; - while (1) { - uint8_t c = bytes[offset]; - if (c == 0) { - offset++; - return offset; - } else if (c >= 0xC0) { - uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1]; - get_dns_name(buffer, dns, ref); - offset++; - offset++; - return offset; - } else { - for (int i = 0; i < c; ++i) { - *buffer = bytes[offset+1+i]; - buffer++; - *buffer = '\0'; - } - *buffer = '.'; - buffer++; - *buffer = '\0'; - offset += c + 1; - } - } -} - -size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset) { - uint8_t * bytes = (uint8_t *)dns; - while (1) { - uint8_t c = bytes[offset]; - if (c == 0) { - offset++; - return offset; - } else if (c >= 0xC0) { - uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1]; - print_dns_name(tty, dns, ref); - offset++; - offset++; - return offset; - } else { - for (int i = 0; i < c; ++i) { - fprintf(tty,"%c",bytes[offset+1+i]); - } - fprintf(tty,"."); - offset += c + 1; - } - } -} - -static int is_ip(char * name) { - - unsigned int dot_count = 0; - unsigned int t = 0; - - for (char * c = name; *c != '\0'; ++c) { - if ((*c < '0' || *c > '9') && (*c != '.')) return 0; - if (*c == '.') { - if (t > 255) return 0; - dot_count++; - t = 0; - } else { - t *= 10; - t += *c - '0'; - } - if (dot_count == 4) return 0; - } - if (dot_count != 3) return 0; - - return 1; -} - -static char read_a_byte(struct socket * stream, int * status) { - static char * foo = NULL; - static char * read_ptr = NULL; - static int have_bytes = 0; - if (!foo) foo = malloc(4096); - while (!have_bytes) { - memset(foo, 0x00, 4096); - have_bytes = net_recv(stream, (uint8_t *)foo, 4096); - if (have_bytes == 0) { - *status = 1; - return 0; - } - debug_print(WARNING, "Received %d bytes...", have_bytes); - read_ptr = foo; - } - - char ret = *read_ptr; - - have_bytes -= 1; - read_ptr++; - - return ret; -} - - -static char * fgets(char * buf, int size, struct socket * stream) { - char * x = buf; - int collected = 0; - - while (collected < size) { - - int status = 0; - - *x = read_a_byte(stream, &status); - - if (status == 1) { - return buf; - } - - collected++; - - if (*x == '\n') break; - - x++; - } - - x++; - *x = '\0'; - return buf; -} - -static void socket_alert_waiters(struct socket * sock) { - if (sock->alert_waiters) { - while (sock->alert_waiters->head) { - node_t * node = list_dequeue(sock->alert_waiters); - process_t * p = node->value; - process_alert_node(p, sock); - free(node); - } - } -} - - -static int socket_check(fs_node_t * node) { - struct socket * sock = node->device; - - if (sock->bytes_available) { - return 0; - } - - if (sock->packet_queue->length > 0) { - return 0; - } - - return 1; -} - -static int socket_wait(fs_node_t * node, void * process) { - struct socket * sock = node->device; - - if (!list_find(sock->alert_waiters, process)) { - list_insert(sock->alert_waiters, process); - } - - list_insert(((process_t *)process)->node_waits, sock); - return 0; -} - -static uint32_t socket_read(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { - /* Sleep until we have something to receive */ -#if 0 - fgets((char *)buffer, size, node->device); - return strlen((char *)buffer); -#else - return net_recv(node->device, buffer, size); -#endif -} -static uint32_t socket_write(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) { - /* Add the packet to the appropriate interface queue and send it off. */ - - net_send((struct socket *)node->device, buffer, size, 0); - return size; -} - -uint16_t next_ephemeral_port(void) { - static uint16_t next = 49152; - - if (next == 0) { - assert(0 && "All out of ephemeral ports, halting this time."); - } - - uint16_t out = next; - next++; - - if (next == 0) { - debug_print(WARNING, "Ran out of ephemeral ports - next time I'm going to bail."); - debug_print(WARNING, "You really need to implement a bitmap here."); - } - - return out; -} - -fs_node_t * socket_ipv4_tcp_create(uint32_t dest, uint16_t target_port, uint16_t source_port) { - - /* Okay, first step is to get us added to the table so we can receive syns. */ - - return NULL; - -} - -static int gethost(char * name, uint32_t * ip) { - if (is_ip(name)) { - debug_print(WARNING, " IP: %x", ip_aton(name)); - *ip = ip_aton(name); - return 0; - } else { - if (hashmap_has(dns_cache, name)) { - *ip = ip_aton(hashmap_get(dns_cache, name)); - debug_print(WARNING, " In Cache: %s → %x", name, ip); - return 0; - } else { - debug_print(WARNING, " Not in cache: %s", name); - debug_print(WARNING, " Still needs look up."); - char * xname = strdup(name); - char * queries = malloc(1024); - queries[0] = '\0'; - char * subs[10]; /* 10 is probably not the best number. */ - int argc = tokenize(xname, ".", subs); - int n = 0; - for (int i = 0; i < argc; ++i) { - debug_print(WARNING, "dns [%d]%s", strlen(subs[i]), subs[i]); - sprintf(&queries[n], "%c%s", strlen(subs[i]), subs[i]); - n += strlen(&queries[n]); - } - int c = strlen(queries) + 1; - queries[c+0] = 0x00; - queries[c+1] = 0x01; /* A */ - queries[c+2] = 0x00; - queries[c+3] = 0x01; /* IN */ - free(xname); - - debug_print(WARNING, "Querying..."); - - void * tmp = malloc(1024); - size_t packet_size = write_dns_packet(tmp, c + 4, (uint8_t *)queries); - free(queries); - - _netif.send_packet(tmp, packet_size); - free(tmp); - - /* wait for response */ - if (current_process->id != tasklet_pid) { - sleep_on(dns_waiters); - } - if (hashmap_has(dns_cache, name)) { - *ip = ip_aton(hashmap_get(dns_cache, name)); - debug_print(WARNING, " Now in cache: %s → %x", name, ip); - return 0; - } else { - if (current_process->id == tasklet_pid) { - debug_print(WARNING, "Query hasn't returned yet, but we're in the network thread, so we need to yield."); - return 2; - } - gethost(name,ip); - return 1; - } - } - } -} - -static int net_send_tcp(struct socket *socket, uint16_t flags, uint8_t * payload, uint32_t payload_size); - -static void socket_close(fs_node_t * node) { - debug_print(WARNING, "Closing socket"); - struct socket * sock = node->device; - if (sock->status == 1) return; /* already closed */ - net_send_tcp(sock, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0); - sock->status = 2; -} - -/* TODO: socket_close - TCP close; UDP... just clean us up */ -/* TODO: socket_open - idk, whatever */ - -static fs_node_t * finddir_netfs(fs_node_t * node, char * name) { - /* Should essentially find anything. */ - debug_print(WARNING, "Need to look up domain or check if is IP: %s", name); - /* Block until lookup is complete */ - - int port = 80; - char * colon; - if ((colon = strstr(name, ":"))) { - /* Port numbers */ - *colon = '\0'; - colon++; - port = atoi(colon); - } - - uint32_t ip = 0; - if (gethost(name, &ip)) return NULL; - - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - strcpy(fnode->name, name); - fnode->mask = 0666; - fnode->flags = FS_CHARDEVICE; - fnode->read = socket_read; - fnode->write = socket_write; - fnode->close = socket_close; - fnode->device = (void *)net_open(SOCK_STREAM); - fnode->selectcheck = socket_check; - fnode->selectwait = socket_wait; - - net_connect((struct socket *)fnode->device, ip, port); - - return fnode; -} - -static int ioctl_netfs(fs_node_t * node, int request, void * argp) { - switch (request) { - case 0x5000: { - /* */ - debug_print(INFO, "DNS query from userspace"); - void ** x = (void **)argp; - char * host = x[0]; - uint32_t * ip = x[1]; - /* TODO: Validate */ - return gethost(host, ip); - } - } - return 0; -} - -static size_t write_dns_packet(uint8_t * buffer, size_t queries_len, uint8_t * queries) { - size_t offset = 0; - size_t payload_size = sizeof(struct dns_packet) + queries_len; - - /* Then, let's write an ethernet frame */ - struct ethernet_packet eth_out = { - .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .destination = BROADCAST_MAC, - .type = htons(0x0800), - }; - - memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); - offset += sizeof(struct ethernet_packet); - - /* Prepare the IPv4 header */ - uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size); - uint16_t _ident = htons(1); - - struct ipv4_packet ipv4_out = { - .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */ - .dscp_ecn = 0, /* not setting either of those */ - .length = _length, - .ident = _ident, - .flags_fragment = 0, - .ttl = 0x40, - .protocol = IPV4_PROT_UDP, - .checksum = 0, /* fill this in later */ - .source = htonl(_netif.source), - .destination = htonl(_dns_server), - }; - - uint16_t checksum = calculate_ipv4_checksum(&ipv4_out); - ipv4_out.checksum = htons(checksum); - - memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet)); - offset += sizeof(struct ipv4_packet); - - uint16_t _udp_source = htons(50053); /* Use an ephemeral port */ - uint16_t _udp_destination = htons(53); - uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size); - - /* Now let's build a UDP packet */ - struct udp_packet udp_out = { - .source_port = _udp_source, - .destination_port = _udp_destination, - .length = _udp_length, - .checksum = 0, - }; - - /* XXX calculate checksum here */ - - memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet)); - offset += sizeof(struct udp_packet); - - /* DNS header */ - struct dns_packet dns_out = { - .qid = htons(0), - .flags = htons(0x0100), /* Standard query */ - .questions = htons(1), /* 1 question */ - .answers = htons(0), - .authorities = htons(0), - .additional = htons(0), - }; - - memcpy(&buffer[offset], &dns_out, sizeof(struct dns_packet)); - offset += sizeof(struct dns_packet); - - memcpy(&buffer[offset], queries, queries_len); - offset += queries_len; - - return offset; -} - -static int net_send_ether(struct socket *socket, struct netif* netif, uint16_t ether_type, void* payload, uint32_t payload_size) { - struct ethernet_packet *eth = malloc(sizeof(struct ethernet_packet) + payload_size); - memcpy(eth->source, netif->hwaddr, sizeof(eth->source)); - //memset(eth->destination, 0xFF, sizeof(eth->destination)); - memcpy(eth->destination, _gateway, sizeof(_gateway)); - eth->type = htons(ether_type); - - if (payload_size) { - memcpy(eth->payload, payload, payload_size); - } - - netif->send_packet((uint8_t*)eth, sizeof(struct ethernet_packet) + payload_size); - - free(eth); - - return 1; // yolo -} - -static int net_send_ip(struct socket *socket, int proto, void* payload, uint32_t payload_size) { - struct ipv4_packet *ipv4 = malloc(sizeof(struct ipv4_packet) + payload_size); - - uint16_t _length = htons(sizeof(struct ipv4_packet) + payload_size); - uint16_t _ident = htons(1); - - ipv4->version_ihl = ((0x4 << 4) | (0x5 << 0)); /* 4 = ipv4, 5 = no options */ - ipv4->dscp_ecn = 0; /* not setting either of those */ - ipv4->length = _length; - ipv4->ident = _ident; - ipv4->flags_fragment = 0; - ipv4->ttl = 0x40; - ipv4->protocol = proto; - ipv4->checksum = 0; // Fill in later */ - ipv4->source = htonl(_netif.source), - ipv4->destination = htonl(socket->ip); - - uint16_t checksum = calculate_ipv4_checksum(ipv4); - ipv4->checksum = htons(checksum); - - if (proto == IPV4_PROT_TCP) { - // Need to calculate TCP checksum - struct tcp_check_header check_hd = { - .source = ipv4->source, - .destination = ipv4->destination, - .zeros = 0, - .protocol = 6, - .tcp_len = htons(payload_size), - }; - - // debug_print(WARNING, "net_send_ip: Payload size: %d\n", payload_size); - struct tcp_header* tcp_hdr = (struct tcp_header*)payload; - // debug_print(WARNING, "net_send_ip: Header len htons: %d\n", TCP_HEADER_LENGTH_FLIPPED(tcp_hdr)); - size_t orig_payload_size = payload_size - TCP_HEADER_LENGTH_FLIPPED(tcp_hdr); - - uint16_t chk = calculate_tcp_checksum(&check_hd, tcp_hdr, tcp_hdr->payload, orig_payload_size); - tcp_hdr->checksum = htons(chk); - } - - if (payload) { - memcpy(ipv4->payload, payload, payload_size); - free(payload); - } - - // TODO: netif should not be a global thing. But the route should be looked up here and a netif object created/returned - int out = net_send_ether(socket, &_netif, ETHERNET_TYPE_IPV4, ipv4, sizeof(struct ipv4_packet) + payload_size); - free(ipv4); - return out; -} - -static int net_send_tcp(struct socket *socket, uint16_t flags, uint8_t * payload, uint32_t payload_size) { - struct tcp_header *tcp = malloc(sizeof(struct tcp_header) + payload_size); - - tcp->source_port = htons(socket->port_recv); - tcp->destination_port = htons(socket->port_dest); - tcp->seq_number = htonl(socket->proto_sock.tcp_socket.seq_no); - tcp->ack_number = flags & (TCP_FLAGS_ACK) ? htonl(socket->proto_sock.tcp_socket.ack_no) : 0; - tcp->flags = htons(0x5000 ^ (flags & 0xFF)); - tcp->window_size = htons(1548-54); - tcp->checksum = 0; // Fill in later - tcp->urgent = 0; - - if ((flags & 0xff) == TCP_FLAGS_SYN) { - // If only SYN set, expected ACK will be 1 despite no payload - socket->proto_sock.tcp_socket.seq_no += 1; - } else { - socket->proto_sock.tcp_socket.seq_no += payload_size; - } - - if (payload) { - memcpy(tcp->payload, payload, payload_size); - } - - return net_send_ip(socket, IPV4_PROT_TCP, tcp, sizeof(struct tcp_header) + payload_size); -} - -struct socket* net_open(uint32_t type) { - // This is a socket() call - struct socket *sock = malloc(sizeof(struct socket)); - memset(sock, 0, sizeof(struct socket)); - sock->sock_type = type; - - return sock; -} - -int net_close(struct socket* socket) { - // socket->is_connected; - socket->status = 1; /* Disconnected */ - wakeup_queue(socket->packet_wait); - socket_alert_waiters(socket); - return 1; -} - -int net_send(struct socket* socket, uint8_t* payload, size_t payload_size, int flags) { - return net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_PSH, payload, payload_size); -} - -size_t net_recv(struct socket* socket, uint8_t* buffer, size_t len) { - tcpdata_t *tcpdata = NULL; - node_t *node = NULL; - - debug_print(INFO, "0x%x [socket]", socket); - - size_t offset = 0; - size_t size_to_read = 0; - - do { - - if (socket->bytes_available) { - tcpdata = socket->current_packet; - } else { - spin_lock(socket->packet_queue_lock); - do { - if (socket->packet_queue->length > 0) { - node = list_dequeue(socket->packet_queue); - spin_unlock(socket->packet_queue_lock); - break; - } else { - if (socket->status == 1) { - spin_unlock(socket->packet_queue_lock); - debug_print(WARNING, "Socket closed, done reading."); - return 0; - } - spin_unlock(socket->packet_queue_lock); - sleep_on(socket->packet_wait); - spin_lock(socket->packet_queue_lock); - } - } while (1); - - tcpdata = node->value; - socket->bytes_available = tcpdata->payload_size; - socket->bytes_read = 0; - free(node); - } - - size_to_read = MIN(len, socket->bytes_available); - - if (tcpdata->payload != 0) { - memcpy(buffer + offset, tcpdata->payload + socket->bytes_read, size_to_read); - } - - offset += size_to_read; - - if (size_to_read < socket->bytes_available) { - socket->bytes_available -= size_to_read; - socket->bytes_read += size_to_read; - socket->current_packet = tcpdata; - } else { - socket->bytes_available = 0; - socket->current_packet = NULL; - free(tcpdata->payload); - free(tcpdata); - } - - - } while (!size_to_read); - - - return size_to_read; -} - -static void net_handle_tcp(struct tcp_header * tcp, size_t length) { - - size_t data_length = length - TCP_HEADER_LENGTH_FLIPPED(tcp); - - /* Find socket */ - if (hashmap_has(_tcp_sockets, (void *)ntohs(tcp->destination_port))) { - struct socket *socket = hashmap_get(_tcp_sockets, (void *)ntohs(tcp->destination_port)); - - if (socket->status == 2) { - debug_print(WARNING, "Received packet while connection is in 'closing' statuus"); - } - - if (socket->status == 1) { - if ((htons(tcp->flags) & TCP_FLAGS_FIN)) { - debug_print(WARNING, "TCP close sequence continues"); - return; - } - if ((htons(tcp->flags) & TCP_FLAGS_ACK)) { - debug_print(WARNING, "TCP close sequence continues"); - return; - } - debug_print(ERROR, "Socket is closed? Should send FIN. socket=0x%x flags=0x%x", socket, tcp->flags); - net_send_tcp(socket, TCP_FLAGS_FIN | TCP_FLAGS_ACK, NULL, 0); - return; - } - - if (socket->proto_sock.tcp_socket.seq_no != ntohl(tcp->ack_number)) { - // Drop packet - debug_print(WARNING, "Dropping packet. Expected ack: %d | Got ack: %d", - socket->proto_sock.tcp_socket.seq_no, ntohl(tcp->ack_number)); - return; - } - - if ((htons(tcp->flags) & TCP_FLAGS_SYN) && (htons(tcp->flags) & TCP_FLAGS_ACK)) { - socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1; - net_send_tcp(socket, TCP_FLAGS_ACK, NULL, 0); - wakeup_queue(socket->proto_sock.tcp_socket.is_connected); - } else if (htons(tcp->flags) & TCP_FLAGS_RES) { - /* Reset doesn't necessarily mean close. */ - debug_print(WARNING, "net_handle_tcp: Received RST - socket closing"); - net_close(socket); - return; - } else { - // Store a copy of the layer 5 data for a userspace recv() call - tcpdata_t *tcpdata = malloc(sizeof(tcpdata_t)); - tcpdata->payload_size = length - TCP_HEADER_LENGTH_FLIPPED(tcp); - - if (tcpdata->payload_size == 0) { - if (htons(tcp->flags) & TCP_FLAGS_FIN) { - /* We should make sure we finish sending before closing. */ - debug_print(WARNING, "net_handle_tcp: Received FIN - socket closing with SYNACK"); - socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1; - net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0); - wakeup_queue(socket->proto_sock.tcp_socket.is_connected); - net_close(socket); - } - free(tcpdata); - return; - } - - // debug_print(WARNING, "net_handle_tcp: payload length: %d\n", length); - // debug_print(WARNING, "net_handle_tcp: flipped tcp flags hdr len: %d\n", TCP_HEADER_LENGTH_FLIPPED(tcp)); - // debug_print(WARNING, "net_handle_tcp: tcpdata->payload_size: %d\n", tcpdata->payload_size); - - if (tcpdata->payload_size > 0) { - tcpdata->payload = malloc(tcpdata->payload_size); - memcpy(tcpdata->payload, tcp->payload, tcpdata->payload_size); - } else { - tcpdata->payload = NULL; - } - - socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length; - - if ((htons(tcp->flags) & TCP_FLAGS_SYN) && (htons(tcp->flags) & TCP_FLAGS_ACK) && data_length == 0) { - socket->proto_sock.tcp_socket.ack_no += 1; - } - - socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + tcpdata->payload_size; - - spin_lock(socket->packet_queue_lock); - list_insert(socket->packet_queue, tcpdata); - spin_unlock(socket->packet_queue_lock); - - // Send acknowledgement of receiving data - net_send_tcp(socket, TCP_FLAGS_ACK, NULL, 0); - - wakeup_queue(socket->packet_wait); - socket_alert_waiters(socket); - - if (htons(tcp->flags) & TCP_FLAGS_FIN) { - /* We should make sure we finish sending before closing. */ - debug_print(WARNING, "net_handle_tcp: Received FIN - socket closing with SYNACK"); - socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1; - net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0); - wakeup_queue(socket->proto_sock.tcp_socket.is_connected); - net_close(socket); - } - } - } else { - debug_print(WARNING, "net_handle_tcp: Received packet not associated with a socket!"); - } -} - -static void net_handle_udp(struct udp_packet * udp, size_t length) { - - // size_t data_length = length - sizeof(struct tcp_header); - debug_print(WARNING, "UDP response!"); - - /* Short-circuit DNS */ - if (ntohs(udp->source_port) == 53) { - debug_print(WARNING, "UDP response to DNS query!"); - parse_dns_response(debug_file, udp); - return; - } - - if (ntohs(udp->source_port) == 67) { - debug_print(WARNING, "UDP response to DHCP!"); - - { - void * tmp = malloc(1024); - size_t packet_size = write_arp_request(tmp, _netif.gateway); - _netif.send_packet(tmp, packet_size); - free(tmp); - } - - return; - } - - /* Find socket */ - if (hashmap_has(_udp_sockets, (void *)ntohs(udp->source_port))) { - /* Do the thing */ - - } else { - /* ??? */ - } - -} - -static void net_handle_ipv4(struct ipv4_packet * ipv4) { - debug_print(INFO, "net_handle_ipv4: ENTER"); - switch (ipv4->protocol) { - case IPV4_PROT_TCP: - net_handle_tcp((struct tcp_header *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet)); - break; - case IPV4_PROT_UDP: - net_handle_udp((struct udp_packet *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet)); - break; - default: - /* XXX */ - break; - } -} - -static struct ethernet_packet* net_receive(void) { - struct ethernet_packet *eth = _netif.get_packet(); - - return eth; -} - -int net_connect(struct socket* socket, uint32_t dest_ip, uint16_t dest_port) { - if (socket->sock_type == SOCK_DGRAM) { - // Can't connect UDP - return -1; - } - - memset(socket->mac, 0, sizeof(socket->mac)); // idk - socket->port_recv = next_ephemeral_port(); - socket->proto_sock.tcp_socket.is_connected = list_create(); - socket->proto_sock.tcp_socket.seq_no = 0; - socket->proto_sock.tcp_socket.ack_no = 0; - socket->proto_sock.tcp_socket.status = 0; - - socket->packet_queue = list_create(); - socket->packet_wait = list_create(); - socket->alert_waiters = list_create(); - - socket->ip = dest_ip; //ip_aton("10.255.50.206"); - socket->port_dest = dest_port; //12345; - - debug_print(WARNING, "net_connect: using ephemeral port: %d", (void*)socket->port_recv); - - hashmap_set(_tcp_sockets, (void*)socket->port_recv, socket); - - net_send_tcp(socket, TCP_FLAGS_SYN, NULL, 0); - // debug_print(WARNING, "net_connect:sent tcp SYN: %d", ret); - - // Race condition here - if net_handle_tcp runs and connects before this sleep - sleep_on(socket->proto_sock.tcp_socket.is_connected); - - return 1; -} - -static void placeholder_dhcp(void) { - debug_print(NOTICE, "Sending DHCP discover"); - void * tmp = malloc(1024); - size_t packet_size = write_dhcp_packet(tmp); - _netif.send_packet(tmp, packet_size); - free(tmp); - - while (1) { - struct ethernet_packet * eth = (struct ethernet_packet *)_netif.get_packet(); - uint16_t eth_type = ntohs(eth->type); - - debug_print(NOTICE, "Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x])", - eth->source[0], eth->source[1], eth->source[2], - eth->source[3], eth->source[4], eth->source[5], - eth->destination[0], eth->destination[1], eth->destination[2], - eth->destination[3], eth->destination[4], eth->destination[5], - eth_type); - - if (eth_type != 0x0800) { - debug_print(WARNING, "ARP packet while waiting for DHCP..."); - free(eth); - continue; - } - - - struct ipv4_packet * ipv4 = (struct ipv4_packet *)eth->payload; - uint32_t src_addr = ntohl(ipv4->source); - uint32_t dst_addr = ntohl(ipv4->destination); - uint16_t length = ntohs(ipv4->length); - - char src_ip[16]; - char dst_ip[16]; - - ip_ntoa(src_addr, src_ip); - ip_ntoa(dst_addr, dst_ip); - - debug_print(NOTICE, "IP packet [%s → %s] length=%d bytes", - src_ip, dst_ip, length); - - if (ipv4->protocol != IPV4_PROT_UDP) { - debug_print(WARNING, "Protocol: %d", ipv4->protocol); - debug_print(WARNING, "Bad packet..."); - free(eth); - continue; - } - - struct udp_packet * udp = (struct udp_packet *)ipv4->payload;; - uint16_t src_port = ntohs(udp->source_port); - uint16_t dst_port = ntohs(udp->destination_port); - uint16_t udp_len = ntohs(udp->length); - - debug_print(NOTICE, "UDP [%d → %d] length=%d bytes", - src_port, dst_port, udp_len); - - if (dst_port != 68) { - debug_print(WARNING, "Destination port: %d", dst_port); - debug_print(WARNING, "Bad packet..."); - free(eth); - continue; - } - - struct dhcp_packet * dhcp = (struct dhcp_packet *)udp->payload; - uint32_t yiaddr = ntohl(dhcp->yiaddr); - - char yiaddr_ip[16]; - ip_ntoa(yiaddr, yiaddr_ip); - debug_print(NOTICE, "DHCP Offer: %s", yiaddr_ip); - - _netif.source = yiaddr; - - debug_print(NOTICE," Scanning offer for DNS servers..."); - - size_t i = sizeof(struct dhcp_packet); - size_t j = 0; - while (i < length) { - uint8_t type = dhcp->options[j]; - uint8_t len = dhcp->options[j+1]; - uint8_t * data = &dhcp->options[j+2]; - - debug_print(NOTICE," type=%d, len=%d", type, len); - if (type == 255) { - break; - } else if (type == 6) { - /* DNS Server! */ - uint32_t dnsaddr = ntohl(*(uint32_t *)data); - char ip[16]; - ip_ntoa(dnsaddr, ip); - debug_print(NOTICE, "Found one: %s", ip); - _dns_server = dnsaddr; - } else if (type == 3) { - _netif.gateway = ntohl(*(uint32_t *)data); - } - - j += 2 + len; - i += 2 + len; - } - - debug_print(NOTICE, "Sending DHCP Request..."); - void * tmp = malloc(1024); - size_t packet_size = write_dhcp_request(tmp, (uint8_t *)&dhcp->yiaddr); - _netif.send_packet(tmp, packet_size); - free(tmp); - - free(eth); - - break; - } - -} - -struct arp { - uint16_t htype; - uint16_t proto; - - uint8_t hlen; - uint8_t plen; - - uint16_t oper; - - uint8_t sender_ha[6]; - uint32_t sender_ip; - uint8_t target_ha[6]; - uint32_t target_ip; - - uint8_t padding[18]; -} __attribute__((packed)); - -static size_t write_arp_response(uint8_t * buffer, struct arp * source) { - size_t offset = 0; - - /* Then, let's write an ethernet frame */ - struct ethernet_packet eth_out = { - .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .destination = BROADCAST_MAC, - .type = htons(0x0806), - }; - - memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); - offset += sizeof(struct ethernet_packet); - - struct arp arp_out; - - arp_out.htype = source->htype; - arp_out.proto = source->proto; - - arp_out.hlen = 6; - arp_out.plen = 4; - arp_out.oper = ntohs(2); - - arp_out.sender_ha[0] = _netif.hwaddr[0]; - arp_out.sender_ha[1] = _netif.hwaddr[1]; - arp_out.sender_ha[2] = _netif.hwaddr[2]; - arp_out.sender_ha[3] = _netif.hwaddr[3]; - arp_out.sender_ha[4] = _netif.hwaddr[4]; - arp_out.sender_ha[5] = _netif.hwaddr[5]; - arp_out.sender_ip = ntohl(_netif.source); - - arp_out.target_ha[0] = source->sender_ha[0]; - arp_out.target_ha[1] = source->sender_ha[1]; - arp_out.target_ha[2] = source->sender_ha[2]; - arp_out.target_ha[3] = source->sender_ha[3]; - arp_out.target_ha[4] = source->sender_ha[4]; - arp_out.target_ha[5] = source->sender_ha[5]; - - arp_out.target_ip = source->sender_ip; - - memcpy(&buffer[offset], &arp_out, sizeof(struct arp)); - offset += sizeof(struct arp); - - return offset; -} - -static size_t write_arp_request(uint8_t * buffer, uint32_t ip) { - size_t offset = 0; - - debug_print(WARNING, "Request ARP from gateway address %x", ip); - - /* Then, let's write an ethernet frame */ - struct ethernet_packet eth_out = { - .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .destination = BROADCAST_MAC, - .type = htons(0x0806), - }; - - memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); - offset += sizeof(struct ethernet_packet); - - struct arp arp_out; - - arp_out.htype = ntohs(1); - - debug_print(WARNING, "Request ARP from gateway address %x", ip); - arp_out.proto = ntohs(0x0800); - - arp_out.hlen = 6; - arp_out.plen = 4; - arp_out.oper = ntohs(1); - - arp_out.sender_ha[0] = _netif.hwaddr[0]; - arp_out.sender_ha[1] = _netif.hwaddr[1]; - arp_out.sender_ha[2] = _netif.hwaddr[2]; - arp_out.sender_ha[3] = _netif.hwaddr[3]; - arp_out.sender_ha[4] = _netif.hwaddr[4]; - arp_out.sender_ha[5] = _netif.hwaddr[5]; - arp_out.sender_ip = ntohl(_netif.source); - - arp_out.target_ha[0] = 0; - arp_out.target_ha[1] = 0; - arp_out.target_ha[2] = 0; - arp_out.target_ha[3] = 0; - arp_out.target_ha[4] = 0; - arp_out.target_ha[5] = 0; - - arp_out.target_ip = ntohl(ip); - - memcpy(&buffer[offset], &arp_out, sizeof(struct arp)); - offset += sizeof(struct arp); - - return offset; -} - - -static void net_handle_arp(struct ethernet_packet * eth) { - debug_print(WARNING, "ARP packet..."); - - struct arp * arp = (struct arp *)ð->payload; - - char sender_ip[16]; - char target_ip[16]; - - ip_ntoa(ntohl(arp->sender_ip), sender_ip); - ip_ntoa(ntohl(arp->target_ip), target_ip); - - debug_print(WARNING, "%2x:%2x:%2x:%2x:%2x:%2x (%s) → %2x:%2x:%2x:%2x:%2x:%2x (%s) is", - arp->sender_ha[0], - arp->sender_ha[1], - arp->sender_ha[2], - arp->sender_ha[3], - arp->sender_ha[4], - arp->sender_ha[5], - sender_ip, - arp->target_ha[0], - arp->target_ha[1], - arp->target_ha[2], - arp->target_ha[3], - arp->target_ha[4], - arp->target_ha[5], - target_ip); - - if (ntohs(arp->oper) == 1) { - - if (ntohl(arp->target_ip) == _netif.source) { - debug_print(WARNING, "That's us!"); - - { - void * tmp = malloc(1024); - size_t packet_size = write_arp_response(tmp, arp); - _netif.send_packet(tmp, packet_size); - free(tmp); - } - - } - - } else { - if (ntohl(arp->target_ip) == _netif.source) { - debug_print(WARNING, "It's a response to our query!"); - if (ntohl(arp->sender_ip) == _netif.gateway) { - _gateway[0] = arp->sender_ha[0]; - _gateway[1] = arp->sender_ha[1]; - _gateway[2] = arp->sender_ha[2]; - _gateway[3] = arp->sender_ha[3]; - _gateway[4] = arp->sender_ha[4]; - _gateway[5] = arp->sender_ha[5]; - } - } else { - debug_print(WARNING, "Response to someone else...\n"); - } - } - -} - -void net_handler(void * data, char * name) { - /* Network Packet Handler*/ - _netif.extra = NULL; - - _dns_server = ip_aton("10.0.2.3"); - - placeholder_dhcp(); - - dns_waiters = list_create(); - - _tcp_sockets = hashmap_create_int(0xFF); - _udp_sockets = hashmap_create_int(0xFF); - - while (1) { - struct ethernet_packet * eth = net_receive(); - - if (!eth) continue; - - switch (ntohs(eth->type)) { - case ETHERNET_TYPE_IPV4: - net_handle_ipv4((struct ipv4_packet *)eth->payload); - break; - case ETHERNET_TYPE_ARP: - net_handle_arp(eth); - break; - } - - free(eth); - } -} - -size_t write_dhcp_packet(uint8_t * buffer) { - size_t offset = 0; - size_t payload_size = sizeof(struct dhcp_packet); - - /* First, let's figure out how big this is supposed to be... */ - - uint8_t dhcp_options[] = { - 53, /* Message type */ - 1, /* Length: 1 */ - 1, /* Discover */ - 55, - 2, - 3, - 6, - 255, /* END */ - }; - - payload_size += sizeof(dhcp_options); - - /* Then, let's write an ethernet frame */ - struct ethernet_packet eth_out = { - .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .destination = BROADCAST_MAC, - .type = htons(0x0800), - }; - - memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); - offset += sizeof(struct ethernet_packet); - - /* Prepare the IPv4 header */ - uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size); - uint16_t _ident = htons(1); - - struct ipv4_packet ipv4_out = { - .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */ - .dscp_ecn = 0, /* not setting either of those */ - .length = _length, - .ident = _ident, - .flags_fragment = 0, - .ttl = 0x40, - .protocol = IPV4_PROT_UDP, - .checksum = 0, /* fill this in later */ - .source = htonl(ip_aton("0.0.0.0")), - .destination = htonl(ip_aton("255.255.255.255")), - }; - - uint16_t checksum = calculate_ipv4_checksum(&ipv4_out); - ipv4_out.checksum = htons(checksum); - - memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet)); - offset += sizeof(struct ipv4_packet); - - uint16_t _udp_source = htons(68); - uint16_t _udp_destination = htons(67); - uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size); - - /* Now let's build a UDP packet */ - struct udp_packet udp_out = { - .source_port = _udp_source, - .destination_port = _udp_destination, - .length = _udp_length, - .checksum = 0, - }; - - /* XXX calculate checksum here */ - - memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet)); - offset += sizeof(struct udp_packet); - - /* BOOTP headers */ - struct dhcp_packet bootp_out = { - .op = 1, - .htype = 1, - .hlen = 6, /* mac address... */ - .hops = 0, - .xid = htonl(0x1337), /* transaction id */ - .secs = 0, - .flags = 0, - - .ciaddr = 0x000000, - .yiaddr = 0x000000, - .siaddr = 0x000000, - .giaddr = 0x000000, - - .chaddr = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .sname = {0}, - .file = {0}, - .magic = htonl(DHCP_MAGIC), - }; - - memcpy(&buffer[offset], &bootp_out, sizeof(struct dhcp_packet)); - offset += sizeof(struct dhcp_packet); - - memcpy(&buffer[offset], &dhcp_options, sizeof(dhcp_options)); - offset += sizeof(dhcp_options); - - return offset; -} - -size_t write_dhcp_request(uint8_t * buffer, uint8_t * ip) { - size_t offset = 0; - size_t payload_size = sizeof(struct dhcp_packet); - - /* First, let's figure out how big this is supposed to be... */ - - uint8_t dhcp_options[] = { - 53, /* Message type */ - 1, /* Length: 1 */ - 3, /* Request */ - 50, - 4, /* requested ip */ - ip[0],ip[1],ip[2],ip[3], - 55, - 2, - 3, - 6, - 255, /* END */ - }; - - payload_size += sizeof(dhcp_options); - - /* Then, let's write an ethernet frame */ - struct ethernet_packet eth_out = { - .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .destination = BROADCAST_MAC, - .type = htons(0x0800), - }; - - memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); - offset += sizeof(struct ethernet_packet); - - /* Prepare the IPv4 header */ - uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size); - uint16_t _ident = htons(1); - - struct ipv4_packet ipv4_out = { - .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */ - .dscp_ecn = 0, /* not setting either of those */ - .length = _length, - .ident = _ident, - .flags_fragment = 0, - .ttl = 0x40, - .protocol = IPV4_PROT_UDP, - .checksum = 0, /* fill this in later */ - .source = htonl(ip_aton("0.0.0.0")), - .destination = htonl(ip_aton("255.255.255.255")), - }; - - uint16_t checksum = calculate_ipv4_checksum(&ipv4_out); - ipv4_out.checksum = htons(checksum); - - memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet)); - offset += sizeof(struct ipv4_packet); - - uint16_t _udp_source = htons(68); - uint16_t _udp_destination = htons(67); - uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size); - - /* Now let's build a UDP packet */ - struct udp_packet udp_out = { - .source_port = _udp_source, - .destination_port = _udp_destination, - .length = _udp_length, - .checksum = 0, - }; - - /* XXX calculate checksum here */ - - memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet)); - offset += sizeof(struct udp_packet); - - /* BOOTP headers */ - struct dhcp_packet bootp_out = { - .op = 1, - .htype = 1, - .hlen = 6, /* mac address... */ - .hops = 0, - .xid = htonl(0x1337), /* transaction id */ - .secs = 0, - .flags = 0, - - .ciaddr = 0x000000, - .yiaddr = 0x000000, - .siaddr = 0x000000, - .giaddr = 0x000000, - - .chaddr = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], - _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, - .sname = {0}, - .file = {0}, - .magic = htonl(DHCP_MAGIC), - }; - - memcpy(&buffer[offset], &bootp_out, sizeof(struct dhcp_packet)); - offset += sizeof(struct dhcp_packet); - - memcpy(&buffer[offset], &dhcp_options, sizeof(dhcp_options)); - offset += sizeof(dhcp_options); - - return offset; -} - - -static void parse_dns_response(fs_node_t * tty, void * last_packet) { - struct udp_packet * udp = (struct udp_packet *)last_packet; - uint16_t src_port = ntohs(udp->source_port); - uint16_t dst_port = ntohs(udp->destination_port); - uint16_t udp_len = ntohs(udp->length); - - fprintf(tty, "UDP [%d → %d] length=%d bytes\n", - src_port, dst_port, udp_len); - - struct dns_packet * dns = (struct dns_packet *)udp->payload; - uint16_t dns_questions = ntohs(dns->questions); - uint16_t dns_answers = ntohs(dns->answers); - fprintf(tty, "DNS - %d queries, %d answers\n", - dns_questions, dns_answers); - - fprintf(tty, "Queries:\n"); - int offset = sizeof(struct dns_packet); - int queries = 0; - uint8_t * bytes = (uint8_t *)dns; - while (queries < dns_questions) { - offset = print_dns_name(tty, dns, offset); - uint16_t * d = (uint16_t *)&bytes[offset]; - fprintf(tty, " - Type: %4x %4x\n", ntohs(d[0]), ntohs(d[1])); - offset += 4; - queries++; - } - - fprintf(tty, "Answers:\n"); - int answers = 0; - while (answers < dns_answers) { - char buf[1024]; - size_t ret = dns_name_to_normal_name(dns, offset, buf); - debug_print(WARNING, "%d - %s", ret, buf); - offset = print_dns_name(tty, dns, offset); - uint16_t * d = (uint16_t *)&bytes[offset]; - fprintf(tty, " - Type: %4x %4x; ", ntohs(d[0]), ntohs(d[1])); - offset += 4; - uint32_t * t = (uint32_t *)&bytes[offset]; - fprintf(tty, "TTL: %d; ", ntohl(t[0])); - offset += 4; - uint16_t * l = (uint16_t *)&bytes[offset]; - int _l = ntohs(l[0]); - fprintf(tty, "len: %d; ", _l); - offset += 2; - if (_l == 4) { - uint32_t * i = (uint32_t *)&bytes[offset]; - char ip[16]; - ip_ntoa(ntohl(i[0]), ip); - fprintf(tty, " Address: %s\n", ip); - debug_print(NOTICE, "Domain [%s] maps to [%s]", buf, ip); - if (!hashmap_has(dns_cache, buf)) { - hashmap_set(dns_cache, buf, strdup(ip)); - } - } else { - if (ntohs(d[0]) == 5) { - fprintf(tty, "CNAME: "); - char buffer[256]; - get_dns_name(buffer, dns, offset); - fprintf(tty, "%s\n", buffer); - if (strlen(buffer)) { - buffer[strlen(buffer)-1] = '\0'; - } - uint32_t addr; - if (gethost(buffer,&addr) == 2) { - debug_print(WARNING,"Can't provide a response yet, but going to query again in a moment."); - } else { - if (!hashmap_has(dns_cache, buf)) { - char ip[16]; - ip_ntoa(addr, ip); - hashmap_set(dns_cache, buf, strdup(ip)); - fprintf(tty, "resolves to %s\n", ip); - } - } - } else { - fprintf(tty, "dunno\n"); - } - } - offset += _l; - answers++; - } - - wakeup_queue(dns_waiters); -} - -static fs_node_t * netfs_create(void) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - strcpy(fnode->name, "net"); - fnode->mask = 0555; - fnode->flags = FS_DIRECTORY; - fnode->readdir = readdir_netfs; - fnode->finddir = finddir_netfs; - fnode->ioctl = ioctl_netfs; - fnode->nlink = 1; - return fnode; -} - -static int init(void) { - dns_cache = hashmap_create(10); - - hashmap_set(dns_cache, "dakko.us", strdup("104.131.140.26")); - hashmap_set(dns_cache, "toaruos.org", strdup("104.131.140.26")); - hashmap_set(dns_cache, "www.toaruos.org", strdup("104.131.140.26")); - hashmap_set(dns_cache, "www.yelp.com", strdup("104.16.57.23")); - hashmap_set(dns_cache, "s3-media2.fl.yelpcdn.com", strdup("199.27.79.175")); - hashmap_set(dns_cache, "forum.osdev.org", strdup("173.255.206.39")); - hashmap_set(dns_cache, "wolfgun.puckipedia.com", strdup("104.47.147.203")); - hashmap_set(dns_cache, "irc.freenode.net", strdup("91.217.189.42")); - hashmap_set(dns_cache, "i.imgur.com", strdup("23.235.47.193")); - - /* /dev/net/{domain|ip}/{protocol}/{port} */ - vfs_mount("/dev/net", netfs_create()); - - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(net, init, fini); diff --git a/modules/pcnet.c b/modules/pcnet.c deleted file mode 100644 index 6456c8ec..00000000 --- a/modules/pcnet.c +++ /dev/null @@ -1,375 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016-2018 K. Lange - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static list_t * net_queue = NULL; -static spin_lock_t net_queue_lock = { 0 }; -static list_t * rx_wait; - -static uint32_t pcnet_device_pci = 0x00000000; -static uint32_t pcnet_io_base = 0; -static uint32_t pcnet_mem_base = 0; -static int pcnet_irq; -static uint8_t mac[6]; - -static uint32_t pcnet_buffer_phys; -static uint8_t *pcnet_buffer_virt; - -static uint8_t * pcnet_rx_de_start; -static uint8_t * pcnet_tx_de_start; -static uint8_t * pcnet_rx_start; -static uint8_t * pcnet_tx_start; - -static uint32_t pcnet_rx_de_phys; -static uint32_t pcnet_tx_de_phys; -static uint32_t pcnet_rx_phys; -static uint32_t pcnet_tx_phys; - -static int pcnet_rx_buffer_id = 0; -static int pcnet_tx_buffer_id = 0; - -#define PCNET_DE_SIZE 16 -#define PCNET_BUFFER_SIZE 1548 -#define PCNET_RX_COUNT 32 -#define PCNET_TX_COUNT 8 - -static void find_pcnet(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if ((vendorid == 0x1022) && (deviceid == 0x2000)) { - *((uint32_t *)extra) = device; - } -} - -static void write_rap32(uint32_t value) { - outportl(pcnet_io_base + 0x14, value); -} -static void write_rap16(uint16_t value) { - outports(pcnet_io_base + 0x12, value); -} -static uint32_t read_csr32(uint32_t csr_no) { - write_rap32(csr_no); - return inportl(pcnet_io_base + 0x10); -} -static uint16_t read_csr16(uint16_t csr_no) { - write_rap32(csr_no); - return inports(pcnet_io_base + 0x10); -} -static void write_csr32(uint32_t csr_no, uint32_t value) { - write_rap32(csr_no); - outportl(pcnet_io_base + 0x10, value); -} -static void write_csr16(uint32_t csr_no, uint16_t value) { - write_rap16(csr_no); - outports(pcnet_io_base + 0x10, value); -} -static uint32_t read_bcr32(uint32_t bcr_no) { - write_rap32(bcr_no); - return inportl(pcnet_io_base + 0x1c); -} -static void write_bcr32(uint32_t bcr_no, uint32_t value) { - write_rap32(bcr_no); - outportl(pcnet_io_base + 0x1c, value); -} - -static uint32_t virt_to_phys(uint8_t * virt) { - return ((uintptr_t)virt - (uintptr_t)pcnet_buffer_virt) + pcnet_buffer_phys; -} - -static int driver_owns(uint8_t * de_table, int index) { - return (de_table[PCNET_DE_SIZE * index + 7] & 0x80) == 0; -} - -static int next_tx_index(int current_tx_index) { - int out = current_tx_index + 1; - if (out == PCNET_TX_COUNT) { - return 0; - } - return out; -} - -static int next_rx_index(int current_rx_index) { - int out = current_rx_index + 1; - if (out == PCNET_RX_COUNT) { - return 0; - } - return out; -} - -static void init_descriptor(int index, int is_tx) { - uint8_t * de_table = is_tx ? pcnet_tx_de_start : pcnet_rx_de_start; - - memset(&de_table[index * PCNET_DE_SIZE], 0, PCNET_DE_SIZE); - - uint32_t buf_addr = is_tx ? pcnet_tx_phys : pcnet_rx_phys; - *(uint32_t *)&de_table[index * PCNET_DE_SIZE] = buf_addr + index * PCNET_BUFFER_SIZE; - - uint16_t bcnt = (uint16_t)(-PCNET_BUFFER_SIZE); - bcnt &= 0x0FFF; - bcnt |= 0xF000; - *(uint16_t *)&de_table[index * PCNET_DE_SIZE + 4] = bcnt; - - if (!is_tx) { - de_table[index * PCNET_DE_SIZE + 7] = 0x80; - } -} - -static void enqueue_packet(void * buffer) { - spin_lock(net_queue_lock); - list_insert(net_queue, buffer); - spin_unlock(net_queue_lock); -} - -static struct ethernet_packet * dequeue_packet(void) { - while (!net_queue->length) { - sleep_on(rx_wait); - } - - spin_lock(net_queue_lock); - node_t * n = list_dequeue(net_queue); - void* value = n->value; - free(n); - spin_unlock(net_queue_lock); - - return value; -} - -static uint8_t* pcnet_get_mac() { - return mac; -} - -static void pcnet_send_packet(uint8_t* payload, size_t payload_size) { - if (!driver_owns(pcnet_tx_de_start, pcnet_tx_buffer_id)) { - /* sleep? */ - debug_print(ERROR, "No transmit descriptors available. Bailing."); - return; - } - if (payload_size > PCNET_BUFFER_SIZE) { - debug_print(ERROR, "Packet too big; max is %d, got %d", PCNET_BUFFER_SIZE, payload_size); - return; - } - memcpy((void *)(pcnet_tx_start + pcnet_tx_buffer_id * PCNET_BUFFER_SIZE), payload, payload_size); - - pcnet_tx_de_start[pcnet_tx_buffer_id * PCNET_DE_SIZE + 7] |= 0x3; - - uint16_t bcnt = (uint16_t)(-payload_size); - bcnt &= 0x0FFF; - bcnt |= 0xF000; - *(uint16_t *)&pcnet_tx_de_start[pcnet_tx_buffer_id * PCNET_DE_SIZE + 4] = bcnt; - - pcnet_tx_de_start[pcnet_tx_buffer_id * PCNET_DE_SIZE + 7] |= 0x80; - - write_csr32(0, read_csr32(0) | (1 << 3)); - - pcnet_tx_buffer_id = next_tx_index(pcnet_tx_buffer_id); -} - -static int pcnet_irq_handler(struct regs *r) { - - write_csr32(0, read_csr32(0) | 0x0400); - irq_ack(pcnet_irq); - - while (driver_owns(pcnet_rx_de_start, pcnet_rx_buffer_id)) { - uint16_t plen = *(uint16_t *)&pcnet_rx_de_start[pcnet_rx_buffer_id * PCNET_DE_SIZE + 8]; - - void * pbuf = (void *)(pcnet_rx_start + pcnet_rx_buffer_id * PCNET_BUFFER_SIZE); - - void * packet = malloc(plen); - memcpy(packet, pbuf, plen); - pcnet_rx_de_start[pcnet_rx_buffer_id * PCNET_DE_SIZE + 7] = 0x80; - - enqueue_packet(packet); - - pcnet_rx_buffer_id = next_rx_index(pcnet_rx_buffer_id); - } - wakeup_queue(rx_wait); - - return 1; -} - -static void pcnet_init(void * data, char * name) { - uint16_t command_reg = pci_read_field(pcnet_device_pci, PCI_COMMAND, 4) & 0xFFFF0000; - if (command_reg & (1 << 2)) { - debug_print(NOTICE, "Bus mastering already enabled.\n"); - } - command_reg |= (1 << 2); - command_reg |= (1 << 0); - pci_write_field(pcnet_device_pci, PCI_COMMAND, 4, command_reg); - - pcnet_io_base = pci_read_field(pcnet_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0; - pcnet_mem_base = pci_read_field(pcnet_device_pci, PCI_BAR1, 4) & 0xFFFFFFF0; - - pcnet_irq = pci_get_interrupt(pcnet_device_pci); - irq_install_handler(pcnet_irq, pcnet_irq_handler, "pcnet"); - - debug_print(NOTICE, "irq line: %d", pcnet_irq); - debug_print(NOTICE, "io base: 0x%x", pcnet_io_base); - - /* Read MAC from EEPROM */ - mac[0] = inportb(pcnet_io_base + 0); - mac[1] = inportb(pcnet_io_base + 1); - mac[2] = inportb(pcnet_io_base + 2); - mac[3] = inportb(pcnet_io_base + 3); - mac[4] = inportb(pcnet_io_base + 4); - mac[5] = inportb(pcnet_io_base + 5); - - /* Force reset */ - inportl(pcnet_io_base + 0x18); - inports(pcnet_io_base + 0x14); - - unsigned long s, ss; - relative_time(0, 10, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - debug_print(NOTICE, "pcnet return from sleep"); - - /* set 32-bit mode */ - outportl(pcnet_io_base + 0x10, 0); - - /* SWSTYLE to 2 */ - uint32_t csr58 = read_csr32(58); - csr58 &= 0xFFF0; - csr58 |= 2; - write_csr32(58, csr58); - - /* ASEL enable */ - uint32_t bcr2 = read_bcr32(2); - bcr2 |= 0x2; - write_bcr32(2, bcr2); - - debug_print(NOTICE, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - if (!pcnet_buffer_virt) { - debug_print(ERROR, "Failed."); - return; - } - - debug_print(WARNING, "phys: 0x%x, virt: 0x%x", pcnet_buffer_phys, pcnet_buffer_virt); - - pcnet_rx_de_start = pcnet_buffer_virt + 28; - pcnet_tx_de_start = pcnet_rx_de_start + PCNET_RX_COUNT * PCNET_DE_SIZE; - pcnet_rx_start = pcnet_tx_de_start + PCNET_TX_COUNT * PCNET_DE_SIZE; - pcnet_tx_start = pcnet_rx_start + PCNET_RX_COUNT * PCNET_BUFFER_SIZE; - - pcnet_rx_de_phys = virt_to_phys(pcnet_rx_de_start); - pcnet_tx_de_phys = virt_to_phys(pcnet_tx_de_start); - pcnet_rx_phys = virt_to_phys(pcnet_rx_start); - pcnet_tx_phys = virt_to_phys(pcnet_tx_start); - - /* set up descriptors */ - for (int i = 0; i < PCNET_RX_COUNT; i++) { - init_descriptor(i, 0); - } - - for (int i = 0; i < PCNET_TX_COUNT; i++) { - init_descriptor(i, 1); - } - - /* Set up device configuration structure */ - ((uint16_t *)&pcnet_buffer_virt[0])[0] = 0x0000; - pcnet_buffer_virt[2] = 5 << 4; /* RLEN << 4 */ - pcnet_buffer_virt[3] = 3 << 4; /* TLEN << 4 */ - pcnet_buffer_virt[4] = mac[0]; - pcnet_buffer_virt[5] = mac[1]; - pcnet_buffer_virt[6] = mac[2]; - pcnet_buffer_virt[7] = mac[3]; - pcnet_buffer_virt[8] = mac[4]; - pcnet_buffer_virt[9] = mac[5]; - - pcnet_buffer_virt[10] = 0; /* reserved */ - pcnet_buffer_virt[11] = 0; /* reserved */ - - pcnet_buffer_virt[12] = 0; - pcnet_buffer_virt[13] = 0; - pcnet_buffer_virt[14] = 0; - pcnet_buffer_virt[15] = 0; - pcnet_buffer_virt[16] = 0; - pcnet_buffer_virt[17] = 0; - pcnet_buffer_virt[18] = 0; - pcnet_buffer_virt[19] = 0; - - ((uint32_t *)&pcnet_buffer_virt[20])[0] = pcnet_rx_de_phys; - ((uint32_t *)&pcnet_buffer_virt[24])[0] = pcnet_tx_de_phys; - - /* Configure network */ - net_queue = list_create(); - rx_wait = list_create(); - - write_csr32(1, 0xFFFF & pcnet_buffer_phys); - write_csr32(2, 0xFFFF & (pcnet_buffer_phys >> 16)); - - uint32_t a = read_csr32(1); - uint32_t b = read_csr32(2); - debug_print(ERROR, "csr1 = 0x%4x csr2= 0x%4x", a, b); - - uint16_t csr3 = read_csr32(3); - if (csr3 & (1 << 10)) csr3 ^= (1 << 10); - if (csr3 & (1 << 2)) csr3 ^= (1 << 2); - csr3 |= (1 << 9); - csr3 |= (1 << 8); - write_csr32(3, csr3); /* Disable interrupt on init */ - write_csr32(4, read_csr32(4) | (1 << 1) | (1 << 12) | (1 << 14)); /* pad */ - - write_csr32(0, read_csr32(0) | (1 << 0) | (1 << 6)); /* do it */ - - uint64_t start_time; - asm volatile (".byte 0x0f, 0x31" : "=A" (start_time)); - - uint32_t status; - while (((status = read_csr32(0)) & (1 << 8)) == 0) { - uint64_t now_time; - asm volatile (".byte 0x0f, 0x31" : "=A" (now_time)); - if (now_time - start_time > 0x10000) { - debug_print(ERROR, "Could not initialize PCNet card, status is 0x%4x", status); - return; - } - } - - /* Start card */ - uint16_t csr0 = read_csr32(0); - if (csr0 & (1 << 0)) csr0 ^= (1 << 0); - if (csr0 & (1 << 2)) csr0 ^= (1 << 2); - csr0 |= (1 << 1); - write_csr32(0, csr0); - - debug_print(NOTICE, "Card start."); - - init_netif_funcs(pcnet_get_mac, dequeue_packet, pcnet_send_packet, "AMD PCnet FAST II/III"); - -} - -static int init(void) { - pci_scan(&find_pcnet, -1, &pcnet_device_pci); - - if (!pcnet_device_pci) { - debug_print(WARNING, "No PCNET device found."); - return 1; - } - - /* Initialize ring buffers */ - debug_print(WARNING, "Request a large continuous chunk of memory."); - /* This fits 32x1548 (rx) + 8x1548 (tx) + 32x16 (rx DE) + 8x16 (tx DE) */ - pcnet_buffer_virt = (void*)kvmalloc_p(0x10000, &pcnet_buffer_phys); - - create_kernel_tasklet(pcnet_init, "[pcnet]", NULL); - - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(pcnet, init, fini); -MODULE_DEPENDS(net); diff --git a/modules/pcspkr.c b/modules/pcspkr.c deleted file mode 100644 index 53a8ae52..00000000 --- a/modules/pcspkr.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include - -static void note(int length, int freq) { - - uint8_t t; - - if (length == 0) { - t = inportb(0x61) & 0xFC; - outportb(0x61, t); - return; - } - - uint32_t div = 11931800 / freq; - - outportb(0x43, 0xb6); - outportb(0x42, (uint8_t)(div)); - outportb(0x42, (uint8_t)(div >> 8)); - - t = inportb(0x61); - outportb(0x61, t | 0x3); - - if (length > 0) { - unsigned long s, ss; - relative_time(length / 1000, length % 1000, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - - t = inportb(0x61) & 0xFC; - outportb(0x61, t); - } - -} - -struct spkr { - int length; - int frequency; -}; - -static uint32_t write_spkr(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - if (!size % (sizeof(struct spkr))) { - return 0; - } - - struct spkr * s = (struct spkr *)buffer; - while ((uintptr_t)s < (uintptr_t)buffer + size) { - note(s->length, s->frequency); - s++; - } - - return (uintptr_t)s - (uintptr_t)buffer; -} - -static fs_node_t * spkr_device_create(void) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - sprintf(fnode->name, "spkr"); - fnode->mask = 0666; /* TODO need a speaker group */ - fnode->flags = FS_CHARDEVICE; - fnode->write = write_spkr; - return fnode; -} - -static int init(void) { - fs_node_t * node = spkr_device_create(); - vfs_mount("/dev/spkr", node); - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(pcspkr, init, fini); diff --git a/modules/ps2kbd.c b/modules/ps2kbd.c deleted file mode 100644 index 5693c293..00000000 --- a/modules/ps2kbd.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2011-2018 K. Lange - * - * Low-level keyboard interrupt driver. - * - * Creates a device file (keyboard_pipe) that can be read - * to retreive keyboard events. - * - */ - -#include -#include -#include -#include -#include -#include - -#define KEY_DEVICE 0x60 -#define KEY_PENDING 0x64 -#define KEY_IRQ 1 - -static fs_node_t * keyboard_pipe; - -/* - * Wait on the keyboard. - */ -static void keyboard_wait(void) { - while(inportb(KEY_PENDING) & 2); -} - -/* - * Keyboard interrupt callback - */ -static int keyboard_handler(struct regs *r) { - unsigned char scancode; - if (inportb(KEY_PENDING) & 0x01) { - scancode = inportb(KEY_DEVICE); - - write_fs(keyboard_pipe, 0, 1, (uint8_t []){scancode}); - } - - irq_ack(KEY_IRQ); - return 1; -} - -/* - * Install the keyboard driver and initialize the - * pipe device for userspace. - */ -static int keyboard_install(void) { - debug_print(NOTICE, "Initializing PS/2 keyboard driver"); - - /* Create a device pipe */ - keyboard_pipe = make_pipe(128); - - keyboard_pipe->flags = FS_CHARDEVICE; - - vfs_mount("/dev/kbd", keyboard_pipe); - - /* Install the interrupt handler */ - irq_install_handler(KEY_IRQ, keyboard_handler, "ps2 kbd"); - - return 0; -} - -static void keyboard_reset_ps2(void) { - uint8_t tmp = inportb(0x61); - outportb(0x61, tmp | 0x80); - outportb(0x61, tmp & 0x7F); - inportb(KEY_DEVICE); -} - -static int keyboard_uninstall(void) { - /* TODO */ - return 0; -} - -MODULE_DEF(ps2kbd, keyboard_install, keyboard_uninstall); diff --git a/modules/ps2mouse.c b/modules/ps2mouse.c deleted file mode 100644 index 7d7aed75..00000000 --- a/modules/ps2mouse.c +++ /dev/null @@ -1,250 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * Mouse driver - * - */ -#include -#include -#include -#include -#include -#include - -static uint8_t mouse_cycle = 0; -static uint8_t mouse_byte[4]; - -#define PACKETS_IN_PIPE 1024 -#define DISCARD_POINT 32 - -#define MOUSE_IRQ 12 - -#define MOUSE_PORT 0x60 -#define MOUSE_STATUS 0x64 -#define MOUSE_ABIT 0x02 -#define MOUSE_BBIT 0x01 -#define MOUSE_WRITE 0xD4 -#define MOUSE_F_BIT 0x20 -#define MOUSE_V_BIT 0x08 - -#define MOUSE_DEFAULT 0 -#define MOUSE_SCROLLWHEEL 1 -#define MOUSE_BUTTONS 2 - -static int8_t mouse_mode = MOUSE_DEFAULT; - -static fs_node_t * mouse_pipe; - -void (*ps2_mouse_alternate)(void) = NULL; - -static void mouse_wait(uint8_t a_type) { - uint32_t timeout = 100000; - if (!a_type) { - while (--timeout) { - if ((inportb(MOUSE_STATUS) & MOUSE_BBIT) == 1) { - return; - } - } - debug_print(INFO, "mouse timeout"); - return; - } else { - while (--timeout) { - if (!((inportb(MOUSE_STATUS) & MOUSE_ABIT))) { - return; - } - } - debug_print(INFO, "mouse timeout"); - return; - } -} - -static void mouse_write(uint8_t write) { - mouse_wait(1); - outportb(MOUSE_STATUS, MOUSE_WRITE); - mouse_wait(1); - outportb(MOUSE_PORT, write); -} - -static uint8_t mouse_read(void) { - mouse_wait(0); - char t = inportb(MOUSE_PORT); - return t; -} - -static int mouse_handler(struct regs *r) { - uint8_t status = inportb(MOUSE_STATUS); - while ((status & MOUSE_BBIT) && (status & MOUSE_F_BIT)) { - if (ps2_mouse_alternate) { - ps2_mouse_alternate(); - break; - } - int8_t mouse_in = inportb(MOUSE_PORT); - switch (mouse_cycle) { - case 0: - mouse_byte[0] = mouse_in; - if (!(mouse_in & MOUSE_V_BIT)) break; - ++mouse_cycle; - break; - case 1: - mouse_byte[1] = mouse_in; - ++mouse_cycle; - break; - case 2: - mouse_byte[2] = mouse_in; - if (mouse_mode == MOUSE_SCROLLWHEEL || mouse_mode == MOUSE_BUTTONS) { - ++mouse_cycle; - break; - } - goto finish_packet; - case 3: - mouse_byte[3] = mouse_in; - goto finish_packet; - } - goto read_next; -finish_packet: - mouse_cycle = 0; - /* We now have a full mouse packet ready to use */ - mouse_device_packet_t packet; - packet.magic = MOUSE_MAGIC; - int x = mouse_byte[1]; - int y = mouse_byte[2]; - if (x && mouse_byte[0] & (1 << 4)) { - /* Sign bit */ - x = x - 0x100; - } - if (y && mouse_byte[0] & (1 << 5)) { - /* Sign bit */ - y = y - 0x100; - } - if (mouse_byte[0] & (1 << 6) || mouse_byte[0] & (1 << 7)) { - /* Overflow */ - x = 0; - y = 0; - } - packet.x_difference = x; - packet.y_difference = y; - packet.buttons = 0; - if (mouse_byte[0] & 0x01) { - packet.buttons |= LEFT_CLICK; - } - if (mouse_byte[0] & 0x02) { - packet.buttons |= RIGHT_CLICK; - } - if (mouse_byte[0] & 0x04) { - packet.buttons |= MIDDLE_CLICK; - } - - if (mouse_mode == MOUSE_SCROLLWHEEL && mouse_byte[3]) { - if ((int8_t)mouse_byte[3] > 0) { - packet.buttons |= MOUSE_SCROLL_DOWN; - } else if ((int8_t)mouse_byte[3] < 0) { - packet.buttons |= MOUSE_SCROLL_UP; - } - } - - mouse_device_packet_t bitbucket; - while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { - read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); - } - write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); -read_next: - break; - } - irq_ack(MOUSE_IRQ); - return 1; -} - -static int ioctl_mouse(fs_node_t * node, int request, void * argp) { - if (request == 1) { - mouse_cycle = 0; - return 0; - } - return -1; -} - -static int mouse_install(void) { - debug_print(NOTICE, "Initializing PS/2 mouse interface"); - uint8_t status, result; - IRQ_OFF; - - while ((inportb(0x64) & 1)) { - inportb(0x60); - } - - mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); - mouse_wait(1); - outportb(MOUSE_STATUS, 0xA8); - mouse_read(); - mouse_wait(1); - outportb(MOUSE_STATUS, 0x20); - mouse_wait(0); - status = inportb(0x60) | 3; - mouse_wait(1); - outportb(MOUSE_STATUS, 0x60); - mouse_wait(1); - outportb(MOUSE_PORT, status); - mouse_write(0xF6); - mouse_read(); - mouse_write(0xF4); - mouse_read(); - - /* Try to enable scroll wheel (but not buttons) */ - if (!args_present("nomousescroll")) { - mouse_write(0xF2); - mouse_read(); - result = mouse_read(); - mouse_write(0xF3); - mouse_read(); - mouse_write(200); - mouse_read(); - mouse_write(0xF3); - mouse_read(); - mouse_write(100); - mouse_read(); - mouse_write(0xF3); - mouse_read(); - mouse_write(80); - mouse_read(); - mouse_write(0xF2); - mouse_read(); - result = mouse_read(); - if (result == 3) { - mouse_mode = MOUSE_SCROLLWHEEL; - } - } - - /* keyboard scancode set */ - mouse_wait(1); - outportb(MOUSE_PORT, 0xF0); - mouse_wait(1); - outportb(MOUSE_PORT, 0x02); - mouse_wait(1); - mouse_read(); - - irq_install_handler(MOUSE_IRQ, mouse_handler, "ps2 mouse"); - IRQ_RES; - - uint8_t tmp = inportb(0x61); - outportb(0x61, tmp | 0x80); - outportb(0x61, tmp & 0x7F); - inportb(MOUSE_PORT); - - while ((inportb(0x64) & 1)) { - inportb(0x60); - } - - mouse_pipe->flags = FS_CHARDEVICE; - mouse_pipe->ioctl = ioctl_mouse; - - vfs_mount("/dev/mouse", mouse_pipe); - return 0; -} - -static int mouse_uninstall(void) { - /* TODO */ - return 0; -} - -MODULE_DEF(ps2mouse, mouse_install, mouse_uninstall); diff --git a/modules/random.c b/modules/random.c deleted file mode 100644 index ced28450..00000000 --- a/modules/random.c +++ /dev/null @@ -1,66 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - * - * Provides access to the kernel RNG - * - */ - -#include -#include -#include -#include - -static uint32_t read_random(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - uint32_t s = 0; - while (s < size) { - buffer[s] = krand() % 0xFF; - s++; - } - return size; -} - -static uint32_t write_random(fs_node_t *node, uint64_t offset, uint32_t size, uint8_t *buffer) { - return size; -} - -static void open_random(fs_node_t * node, unsigned int flags) { - return; -} - -static void close_random(fs_node_t * node) { - return; -} - -static fs_node_t * random_device_create(void) { - fs_node_t * fnode = malloc(sizeof(fs_node_t)); - memset(fnode, 0x00, sizeof(fs_node_t)); - fnode->inode = 0; - strcpy(fnode->name, "random"); - fnode->uid = 0; - fnode->gid = 0; - fnode->mask = 0444; - fnode->length = 1024; - fnode->flags = FS_CHARDEVICE; - fnode->read = read_random; - fnode->write = write_random; - fnode->open = open_random; - fnode->close = close_random; - fnode->readdir = NULL; - fnode->finddir = NULL; - fnode->ioctl = NULL; - return fnode; -} - -static int random_initialize(void) { - vfs_mount("/dev/random", random_device_create()); - vfs_mount("/dev/urandom", random_device_create()); - return 0; -} - -static int random_finalize(void) { - return 0; -} - -MODULE_DEF(random, random_initialize, random_finalize); diff --git a/modules/rtl.c b/modules/rtl.c deleted file mode 100644 index 8581dc7a..00000000 --- a/modules/rtl.c +++ /dev/null @@ -1,421 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* XXX move this to ipv4? */ -extern size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset); - -static uint32_t rtl_device_pci = 0x00000000; - -static void find_rtl(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if ((vendorid == 0x10ec) && (deviceid == 0x8139)) { - *((uint32_t *)extra) = device; - } -} - -#define RTL_PORT_MAC 0x00 -#define RTL_PORT_MAR 0x08 -#define RTL_PORT_TXSTAT 0x10 -#define RTL_PORT_TXBUF 0x20 -#define RTL_PORT_RBSTART 0x30 -#define RTL_PORT_CMD 0x37 -#define RTL_PORT_RXPTR 0x38 -#define RTL_PORT_RXADDR 0x3A -#define RTL_PORT_IMR 0x3C -#define RTL_PORT_ISR 0x3E -#define RTL_PORT_TCR 0x40 -#define RTL_PORT_RCR 0x44 -#define RTL_PORT_RXMISS 0x4C -#define RTL_PORT_CONFIG 0x52 - -static list_t * net_queue = NULL; - -static spin_lock_t net_queue_lock = { 0 }; - -static int rtl_irq = 0; -static uint32_t rtl_iobase = 0; -static uint8_t * rtl_rx_buffer; -static uint8_t * rtl_tx_buffer[5]; -static uint8_t mac[6]; - -static uint8_t * last_packet = NULL; - -static uintptr_t rtl_rx_phys; -static uintptr_t rtl_tx_phys[5]; - -static uint32_t cur_rx = 0; -static int dirty_tx = 0; -static int next_tx = 0; - -static list_t * rx_wait; - -static spin_lock_t _lock; -static int next_tx_buf(void) { - int out; - spin_lock(_lock); - out = next_tx; - next_tx++; - if (next_tx == 4) { - next_tx = 0; - } - spin_unlock(_lock); - return out; -} - -void* rtl_dequeue() { - while (!net_queue->length) { - sleep_on(rx_wait); - } - - spin_lock(net_queue_lock); - node_t * n = list_dequeue(net_queue); - void* value = (struct ethernet_packet *)n->value; - free(n); - spin_unlock(net_queue_lock); - - return value; -} - -void rtl_enqueue(void * buffer) { - /* XXX size? source? */ - spin_lock(net_queue_lock); - list_insert(net_queue, buffer); - spin_unlock(net_queue_lock); -} - -uint8_t* rtl_get_mac() { - return mac; -} - -void rtl_send_packet(uint8_t* payload, size_t payload_size) { - int my_tx = next_tx_buf(); - memcpy(rtl_tx_buffer[my_tx], payload, payload_size); - - outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); - outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, payload_size); -} - -struct ethernet_packet* rtl_get_packet(void) { - return (struct ethernet_packet*)rtl_dequeue(); -} - -static int rtl_irq_handler(struct regs *r) { - uint16_t status = inports(rtl_iobase + RTL_PORT_ISR); - if (!status) { - return 0; - } - outports(rtl_iobase + RTL_PORT_ISR, status); - - irq_ack(rtl_irq); - - if (status & 0x01 || status & 0x02) { - /* Receive */ - while((inportb(rtl_iobase + RTL_PORT_CMD) & 0x01) == 0) { - int offset = cur_rx % 0x2000; - -#if 0 - uint16_t buf_addr = inports(rtl_iobase + RTL_PORT_RXADDR); - uint16_t buf_ptr = inports(rtl_iobase + RTL_PORT_RXPTR); - uint8_t cmd = inportb(rtl_iobase + RTL_PORT_CMD); -#endif - - uint32_t * buf_start = (uint32_t *)((uintptr_t)rtl_rx_buffer + offset); - uint32_t rx_status = buf_start[0]; - int rx_size = rx_status >> 16; - - if (rx_status & (0x0020 | 0x0010 | 0x0004 | 0x0002)) { - debug_print(WARNING, "rx error :("); - } else { - uint8_t * buf_8 = (uint8_t *)&(buf_start[1]); - - last_packet = malloc(rx_size); - - uintptr_t packet_end = (uintptr_t)buf_8 + rx_size; - if (packet_end > (uintptr_t)rtl_rx_buffer + 0x2000) { - size_t s = ((uintptr_t)rtl_rx_buffer + 0x2000) - (uintptr_t)buf_8; - memcpy(last_packet, buf_8, s); - memcpy((void *)((uintptr_t)last_packet + s), rtl_rx_buffer, rx_size - s); - } else { - memcpy(last_packet, buf_8, rx_size); - } - - rtl_enqueue(last_packet); - } - - cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - outports(rtl_iobase + RTL_PORT_RXPTR, cur_rx - 16); - } - wakeup_queue(rx_wait); - } - - if (status & 0x08 || status & 0x04) { - unsigned int i = inportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * dirty_tx); - (void)i; - dirty_tx++; - if (dirty_tx == 5) dirty_tx = 0; - } - - return 1; -} - -#if 0 -static void rtl_netd(void * data, char * name) { - fs_node_t * tty = data; - - { - fprintf(tty, "Sending DNS query...\n"); - uint8_t queries[] = { - 3,'i','r','c', - 8,'f','r','e','e','n','o','d','e', - 3,'n','e','t', - 0, - 0x00, 0x01, /* A */ - 0x00, 0x01, /* IN */ - }; - - int my_tx = next_tx_buf(); - size_t packet_size = write_dns_packet(rtl_tx_buffer[my_tx], sizeof(queries), queries); - - outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); - outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); - } - - sleep_on(rx_wait); - parse_dns_response(tty, last_packet); - - { - fprintf(tty, "Sending DNS query...\n"); - uint8_t queries[] = { - 7,'n','y','a','n','c','a','t', - 5,'d','a','k','k','o', - 2,'u','s', - 0, - 0x00, 0x01, /* A */ - 0x00, 0x01, /* IN */ - }; - - int my_tx = next_tx_buf(); - size_t packet_size = write_dns_packet(rtl_tx_buffer[my_tx], sizeof(queries), queries); - - outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); - outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); - } - - sleep_on(rx_wait); - parse_dns_response(tty, last_packet); - - seq_no = krand(); - - { - fprintf(tty, "Sending TCP syn\n"); - int my_tx = next_tx_buf(); - uint8_t payload[] = { 0 }; - size_t packet_size = write_tcp_packet(rtl_tx_buffer[my_tx], payload, 0, (TCP_FLAGS_SYN | DATA_OFFSET_5)); - - outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); - outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); - - seq_no += 1; - ack_no = 0; - } - - { - struct ethernet_packet * eth = net_receive(); - uint16_t eth_type = ntohs(eth->type); - - fprintf(tty, "Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x)\n", - eth->source[0], eth->source[1], eth->source[2], - eth->source[3], eth->source[4], eth->source[5], - eth->destination[0], eth->destination[1], eth->destination[2], - eth->destination[3], eth->destination[4], eth->destination[5], - eth_type); - - - struct ipv4_packet * ipv4 = (struct ipv4_packet *)eth->payload; - uint32_t src_addr = ntohl(ipv4->source); - uint32_t dst_addr = ntohl(ipv4->destination); - uint16_t length = ntohs(ipv4->length); - - char src_ip[16]; - char dst_ip[16]; - - ip_ntoa(src_addr, src_ip); - ip_ntoa(dst_addr, dst_ip); - - fprintf(tty, "IP packet [%s → %s] length=%d bytes\n", - src_ip, dst_ip, length); - - struct tcp_header * tcp = (struct tcp_header *)ipv4->payload; - - if (seq_no != ntohl(tcp->ack_number)) { - fprintf(tty, "[eth] Expected ack number of 0x%x, got 0x%x\n", - seq_no, - ntohl(tcp->ack_number)); - fprintf(tty, "[eth] Bailing...\n"); - return; - } - - ack_no = ntohl(tcp->seq_number) + 1; - free(eth); - } - - { - fprintf(tty, "Sending TCP ack\n"); - int my_tx = next_tx_buf(); - uint8_t payload[] = { 0 }; - size_t packet_size = write_tcp_packet(rtl_tx_buffer[my_tx], payload, 0, (TCP_FLAGS_ACK | DATA_OFFSET_5)); - - outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); - outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); - } - - fprintf(tty, "[eth] s-next=0x%x, r-next=0x%x\n", seq_no, ack_no); - -} -#endif - -int init_rtl(void) { - if (rtl_device_pci) { - debug_print(NOTICE, "Located an RTL 8139: 0x%x\n", rtl_device_pci); - - uint16_t command_reg = pci_read_field(rtl_device_pci, PCI_COMMAND, 4); - debug_print(NOTICE, "COMMAND register before: 0x%4x\n", command_reg); - if (command_reg & (1 << 2)) { - debug_print(NOTICE, "Bus mastering already enabled.\n"); - } else { - command_reg |= (1 << 2); /* bit 2 */ - debug_print(NOTICE, "COMMAND register after: 0x%4x\n", command_reg); - pci_write_field(rtl_device_pci, PCI_COMMAND, 4, command_reg); - command_reg = pci_read_field(rtl_device_pci, PCI_COMMAND, 4); - debug_print(NOTICE, "COMMAND register after: 0x%4x\n", command_reg); - } - - rtl_irq = pci_get_interrupt(rtl_device_pci); - debug_print(NOTICE, "Interrupt Line: %x\n", rtl_irq); - irq_install_handler(rtl_irq, rtl_irq_handler, "rtl8139"); - - uint32_t rtl_bar0 = pci_read_field(rtl_device_pci, PCI_BAR0, 4); - uint32_t rtl_bar1 = pci_read_field(rtl_device_pci, PCI_BAR1, 4); - - debug_print(NOTICE, "BAR0: 0x%8x\n", rtl_bar0); - debug_print(NOTICE, "BAR1: 0x%8x\n", rtl_bar1); - - rtl_iobase = 0x00000000; - - if (rtl_bar0 & 0x00000001) { - rtl_iobase = rtl_bar0 & 0xFFFFFFFC; - } else { - debug_print(NOTICE, "This doesn't seem right! RTL8139 should be using an I/O BAR; this looks like a memory bar."); - } - - debug_print(NOTICE, "RTL iobase: 0x%x\n", rtl_iobase); - - rx_wait = list_create(); - - debug_print(NOTICE, "Determining mac address...\n"); - for (int i = 0; i < 6; ++i) { - mac[i] = inports(rtl_iobase + RTL_PORT_MAC + i); - } - - debug_print(NOTICE, "%2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - debug_print(NOTICE, "Enabling RTL8139.\n"); - outportb(rtl_iobase + RTL_PORT_CONFIG, 0x0); - - debug_print(NOTICE, "Resetting RTL8139.\n"); - outportb(rtl_iobase + RTL_PORT_CMD, 0x10); - while ((inportb(rtl_iobase + 0x37) & 0x10) != 0) { } - - debug_print(NOTICE, "Done resetting RTL8139.\n"); - - for (int i = 0; i < 5; ++i) { - rtl_tx_buffer[i] = (void*)kvmalloc_p(0x1000, &rtl_tx_phys[i]); - for (int j = 0; j < 60; ++j) { - rtl_tx_buffer[i][j] = 0xF0; - } - } - - rtl_rx_buffer = (uint8_t *)kvmalloc_p(0x3000, &rtl_rx_phys); - memset(rtl_rx_buffer, 0x00, 0x3000); - - debug_print(NOTICE, "Buffers:\n"); - debug_print(NOTICE, " rx 0x%x [phys 0x%x and 0x%x and 0x%x]\n", rtl_rx_buffer, rtl_rx_phys, map_to_physical((uintptr_t)rtl_rx_buffer + 0x1000), map_to_physical((uintptr_t)rtl_rx_buffer + 0x2000)); - - for (int i = 0; i < 5; ++i) { - debug_print(NOTICE, " tx 0x%x [phys 0x%x]\n", rtl_tx_buffer[i], rtl_tx_phys[i]); - } - - debug_print(NOTICE, "Initializing receive buffer.\n"); - outportl(rtl_iobase + RTL_PORT_RBSTART, rtl_rx_phys); - - debug_print(NOTICE, "Enabling IRQs.\n"); - outports(rtl_iobase + RTL_PORT_IMR, - 0x8000 | /* PCI error */ - 0x4000 | /* PCS timeout */ - 0x40 | /* Rx FIFO over */ - 0x20 | /* Rx underrun */ - 0x10 | /* Rx overflow */ - 0x08 | /* Tx error */ - 0x04 | /* Tx okay */ - 0x02 | /* Rx error */ - 0x01 /* Rx okay */ - ); /* TOK, ROK */ - - debug_print(NOTICE, "Configuring transmit\n"); - outportl(rtl_iobase + RTL_PORT_TCR, - 0 - ); - - debug_print(NOTICE, "Configuring receive buffer.\n"); - outportl(rtl_iobase + RTL_PORT_RCR, - (0) | /* 8K receive */ - 0x08 | /* broadcast */ - 0x01 /* all physical */ - ); - - debug_print(NOTICE, "Enabling receive and transmit.\n"); - outportb(rtl_iobase + RTL_PORT_CMD, 0x08 | 0x04); - - debug_print(NOTICE, "Resetting rx stats\n"); - outportl(rtl_iobase + RTL_PORT_RXMISS, 0); - - net_queue = list_create(); - - debug_print(NOTICE, "Initializing netif functions\n"); - init_netif_funcs(rtl_get_mac, rtl_get_packet, rtl_send_packet, "RTL8139"); - - debug_print(NOTICE, "Back from starting the worker thread.\n"); - } else { - return -1; - } - return 0; -} - -static int init(void) { - pci_scan(&find_rtl, -1, &rtl_device_pci); - if (!rtl_device_pci) { - debug_print(NOTICE, "No RTL 8139 found"); - return 1; - } - init_rtl(); - return 0; -} - -static int fini(void) { - return 0; -} - -MODULE_DEF(rtl, init, fini); -MODULE_DEPENDS(net); diff --git a/modules/test.c b/modules/test.c new file mode 100644 index 00000000..080319c9 --- /dev/null +++ b/modules/test.c @@ -0,0 +1,21 @@ +#include + +static int init(int argc, char * argv[]) { + printf("Hello, world.\n"); + return 0; +} + +static int fini(void) { + return 0; +} + +struct Module { + const char * name; + int (*init)(int argc, char * argv[]); + int (*fini)(void); +} module_info_test = { + .name = "test", + .init = init, + .fini = fini, +}; + diff --git a/modules/usbuhci.c b/modules/usbuhci.c deleted file mode 100644 index 7cb0634f..00000000 --- a/modules/usbuhci.c +++ /dev/null @@ -1,50 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include - -static uint32_t hub_device = 0; - -static void find_usb_device(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { - if (pci_find_type(device) == 0xc03) { - int prog_if = (int)pci_read_field(device, PCI_PROG_IF, 1); - if (prog_if == 0) { - *((uint32_t *)extra)= device; - } - } -} - -DEFINE_SHELL_FUNCTION(usb, "Enumerate USB devices (UHCI)") { - - pci_scan(&find_usb_device, -1, &hub_device); - - if (!hub_device) { - fprintf(tty, "Failed to locate a UHCI controller.\n"); - return 1; - } - - fprintf(tty, "Located UHCI controller: %2x:%2x.%d\n", - (int)pci_extract_bus (hub_device), - (int)pci_extract_slot(hub_device), - (int)pci_extract_func(hub_device)); - - return 0; -} - -static int install(void) { - BIND_SHELL_FUNCTION(usb); - return 0; -} - -static int uninstall(void) { - return 0; -} - -MODULE_DEF(usbuhci, install, uninstall); -MODULE_DEPENDS(debugshell); diff --git a/modules/vgadbg.c b/modules/vgadbg.c deleted file mode 100644 index de08e767..00000000 --- a/modules/vgadbg.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include -#include - -static unsigned short * textmemptr = (unsigned short *)0xB8000; -static void placech(unsigned char c, int x, int y, int attr) { - unsigned short *where; - unsigned att = attr << 8; - where = textmemptr + (y * 80 + x); - *where = c | att; -} - -static char vga_to_ansi[] = { - 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 -}; - -static int fg = 0x07; -static int bg = 0x10; -static int cur_x = 0; -static int cur_y = 0; - -static int write_string(char * s) { - int written = 0; - while (*s) { - switch (*s) { - case '\n': - cur_x = 0; - cur_y++; - break; - case '\b': - if (cur_x > 0) cur_x--; - placech(' ', cur_x, cur_y, (vga_to_ansi[fg] & 0xF) | (vga_to_ansi[bg] << 4)); - break; - default: - placech(*s, cur_x, cur_y, (vga_to_ansi[fg] & 0xF) | (vga_to_ansi[bg] << 4)); - cur_x++; - break; - } - if (cur_x == 80) { - cur_x = 0; - cur_y++; - } - if (cur_y == 25) { - memmove(textmemptr, (textmemptr + 80), sizeof(unsigned short) * 80 * 24); - memset(textmemptr + 80 * 24, 0x00, 80 * sizeof(unsigned short)); - cur_y = 24; - } - s++; - written++; - } - return written; -} - -static void reset(void) { - fg = 0x07; - bg = 0x10; -} - -static void list_files(char * directory) { - fs_node_t * wd = kopen(directory, 0); - uint32_t index = 0; - struct dirent * kentry = readdir_fs(wd, index); - while (kentry) { - write_string(kentry->name); - write_string("\n"); - free(kentry); - - index++; - kentry = readdir_fs(wd, index); - } - close_fs(wd); -} - -static void debug_ata_wait(void) { - inportb(0x1F0 + ATA_REG_ALTSTATUS); - inportb(0x1F0 + ATA_REG_ALTSTATUS); - inportb(0x1F0 + ATA_REG_ALTSTATUS); - inportb(0x1F0 + ATA_REG_ALTSTATUS); -} - -static void debug_ata_primary(void) { - /* Reset */ - char tmp[100]; - outportb(0x3F6, 0x04); - - debug_ata_wait(); - - outportb(0x3F6, 0x00); - - debug_ata_wait(); - - outportb(0x1F0 + ATA_REG_HDDEVSEL, 0xA0); - - debug_ata_wait(); - - /* Wait on device */ - int status; - int i = 0; - while ((status = inportb(0x1F0 + ATA_REG_STATUS)) & ATA_SR_BSY) i++; - - sprintf(tmp, "Waited on status %d times\n", i); - write_string(tmp); - - unsigned char cl = inportb(0x1F0 + ATA_REG_LBA1); /* CYL_LO */ - unsigned char ch = inportb(0x1F0 + ATA_REG_LBA2); /* CYL_HI */ - - if (cl == 0xD0) { - write_string("Waiting some more...\n"); - inportb(0x1F0 + ATA_REG_ALTSTATUS); - inportb(0x1F0 + ATA_REG_ALTSTATUS); - cl = inportb(0x1F0 + ATA_REG_LBA1); /* CYL_LO */ - ch = inportb(0x1F0 + ATA_REG_LBA2); /* CYL_HI */ - } - sprintf(tmp, "ATA Primary 0x%2x 0x%2x\n", cl, ch); - write_string(tmp); - - /* Now check partitions */ - mbr_t mbr; - - fs_node_t * f = kopen("/dev/hda", 0); - - if (!f) { - write_string("Couldn't open /dev/hda\n"); - - } else { - - read_fs(f, 0, 512, (uint8_t *)&mbr); - - sprintf(tmp, "signature[0] = 0x%2x\n", mbr.signature[0]); - write_string(tmp); - sprintf(tmp, "signature[1] = 0x%2x\n", mbr.signature[1]); - write_string(tmp); - - write_string("Partitions:\n"); - - for (int i = 0; i < 4; ++i) { - if (mbr.partitions[i].status & 0x80) { - sprintf(tmp, "Partition #%d: @%d+%d\n", i+1, mbr.partitions[i].lba_first_sector, mbr.partitions[i].sector_count); - write_string(tmp); - } else { - sprintf(tmp, "Partition #%d: inactive\n", i+1); - write_string(tmp); - } - } - - } - -} - -static void tasklet(void * data, char * name) { - - write_string("Tasklet created, sleeping... _"); - - for (int i = 5; i > 0; i--) { - char tmp[3]; - sprintf(tmp, "\b%d", i); - write_string(tmp); - unsigned long s, ss; - relative_time(1, 0, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - } - - write_string("\bDone.\nReady to go.\n"); - - write_string("Here's /dev:\n"); - fg = 6; - list_files("/dev"); - reset(); - - write_string("Now let's debug the primary PATA drive:\n"); - debug_ata_primary(); - - reset(); - write_string("Here's /\n"); - fg = 6; - list_files("/"); - reset(); - - write_string("Here's /home"); - fg = 6; - list_files("/home"); - reset(); - -} - -static int vgadbg_init(void) { - - memset(textmemptr, 0x00, sizeof(unsigned short) * 80 * 25); - - write_string("VGA Text-Mode Debugger\n"); - write_string(" If you're seeing this, module loading completed successfully.\n"); - write_string(" We'll now do some checks to see what may be wrong with the system.\n"); - write_string("\n"); - - create_kernel_tasklet(tasklet, "[[vgadbg]]", NULL); - - return 0; -} - -static int vgadbg_fini(void) { - return 0; -} - -MODULE_DEF(vgadbg, vgadbg_init, vgadbg_fini); diff --git a/modules/vgalog.c b/modules/vgalog.c deleted file mode 100644 index 92fb5210..00000000 --- a/modules/vgalog.c +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../lib/termemu.c" - -static unsigned short * textmemptr = (unsigned short *)0xB8000; -static void placech(unsigned char c, int x, int y, int attr) { - unsigned short *where; - unsigned att = attr << 8; - where = textmemptr + (y * 80 + x); - *where = c | att; -} - -static char vga_to_ansi[] = { - 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 -}; - -static int current_fg = 0x07; -static int current_bg = 0x10; -static int cur_x = 0; -static int cur_y = 0; - -term_state_t * ansi_state = NULL; - -static int write_string(char * s) { - int written = 0; - while (*s) { - switch (*s) { - case '\n': - cur_x = 0; - cur_y++; - break; - case '\b': - if (cur_x > 0) cur_x--; - placech(' ', cur_x, cur_y, (vga_to_ansi[current_fg] & 0xF) | (vga_to_ansi[current_bg] << 4)); - break; - default: - placech(*s, cur_x, cur_y, (vga_to_ansi[current_fg] & 0xF) | (vga_to_ansi[current_bg] << 4)); - cur_x++; - break; - } - if (cur_x == 80) { - cur_x = 0; - cur_y++; - } - if (cur_y == 25) { - memmove(textmemptr, (textmemptr + 80), sizeof(unsigned short) * 80 * 24); - memset(textmemptr + 80 * 24, 0x00, 80 * sizeof(unsigned short)); - cur_y = 24; - } - s++; - written++; - } - return written; -} - -static void term_write(char c) { - char foo[] = {c,0}; - write_string(foo); -} - -static uint32_t vga_write(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t *buffer) { - /* XXX do some terminal processing like we did in the old days */ - size_t i = 0; - while (*buffer && i < size) { - ansi_put(ansi_state, *buffer); - buffer++; - i++; - } - return i; -} - -static fs_node_t _vga_fnode = { - .name = "vga_log", - .write = vga_write, -}; - -static void term_scroll(int how_much) { - for (int i = 0; i < how_much; ++i) { - memmove(textmemptr, (textmemptr + 80), sizeof(unsigned short) * 80 * 24); - memset(textmemptr + 80 * 24, 0x00, 80 * sizeof(unsigned short)); - } -} - -static void term_set_cell(int x, int y, uint32_t c) { - placech(c, x, y, (vga_to_ansi[current_fg] & 0xF) | (vga_to_ansi[current_bg] << 4)); -} - -static void term_set_csr(int x, int y) { - cur_x = x; - cur_y = y; -} - -static int term_get_csr_x() { - return cur_x; -} - -static int term_get_csr_y() { - return cur_y; -} - -static void term_set_csr_show(int on) { - return; -} - -static void term_set_colors(uint32_t fg, uint32_t bg) { - current_fg = fg; - current_bg = bg; -} - -static void term_redraw_cursor() { - return; -} - -static void input_buffer_stuff(char * str) { - return; -} - -static void set_title(char * c) { - /* Do nothing */ -} - -static void term_clear(int i) { - memset(textmemptr, 0x00, sizeof(unsigned short) * 80 * 25); -} - -int unsupported_int(void) { return 0; } -void unsupported(int x, int y, char * data) { } - -term_callbacks_t term_callbacks = { - term_write, - term_set_colors, - term_set_csr, - term_get_csr_x, - term_get_csr_y, - term_set_cell, - term_clear, - term_scroll, - term_redraw_cursor, - input_buffer_stuff, - set_title, - unsupported, - unsupported_int, - unsupported_int, - term_set_csr_show, - NULL, - NULL, -}; - - -static int vgadbg_init(void) { - - memset(textmemptr, 0x00, sizeof(unsigned short) * 80 * 25); - - ansi_state = ansi_init(ansi_state, 80, 25, &term_callbacks); - - debug_file = &_vga_fnode; - debug_level = 1; - - write_string("VGA Debug Logging is enabled.\n"); - - return 0; -} - -static int vgadbg_fini(void) { - return 0; -} - -MODULE_DEF(vgalog, vgadbg_init, vgadbg_fini); diff --git a/modules/vidset.c b/modules/vidset.c deleted file mode 100644 index 25bfb90e..00000000 --- a/modules/vidset.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2016-2018 K. Lange - * - * Module to provide a debug shell command to set display mode. - */ -#include -#include -#include -#include -#include -#include - -DEFINE_SHELL_FUNCTION(set_mode, "Set display mode") { - if (argc < 3) { - fprintf(tty, "set_mode \n"); - return 1; - } - int x = atoi(argv[1]); - int y = atoi(argv[2]); - fprintf(tty, "Setting mode to %dx%d.\n", x, y); - lfb_set_resolution(x,y); - return 0; -} - -static int hello(void) { - BIND_SHELL_FUNCTION(set_mode); - - return 0; -} - -static int goodbye(void) { - return 0; -} - -MODULE_DEF(vidset, hello, goodbye); -MODULE_DEPENDS(debugshell); -MODULE_DEPENDS(lfbvideo); - - diff --git a/modules/xtest.c b/modules/xtest.c deleted file mode 100644 index 46ae5e91..00000000 --- a/modules/xtest.c +++ /dev/null @@ -1,45 +0,0 @@ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * This file is part of ToaruOS and is released under the terms - * of the NCSA / University of Illinois License - see LICENSE.md - * Copyright (C) 2014-2018 K. Lange - */ -#include -#include -#include -#include -#include - -static void xtest_a(void * data, char * name) { - fs_node_t * tty = data; - - fprintf(tty, "[%s] Hello world.\n", name); - - while (1) { - fprintf(tty, "[%s] Ping.\n", name); - unsigned long s, ss; - relative_time(1, 0, &s, &ss); - sleep_until((process_t *)current_process, s, ss); - switch_task(0); - } -} - -static int hello(void) { - fs_node_t * tty = kopen("/dev/ttyS0", 0); - - fprintf(tty, "[xtest] Starting background thread...\n"); - create_kernel_tasklet(xtest_a, "xtest-a", (void *)tty); - - fprintf(tty, "[xtest] Enabling logging directly to serial...\n"); - debug_file = tty; - debug_level = 1; - - return 0; -} - -static int goodbye(void) { - return 0; -} - -MODULE_DEF(xtest, hello, goodbye); -MODULE_DEPENDS(serial); - diff --git a/util/activate.sh b/util/activate.sh index 0236be1f..31281933 100755 --- a/util/activate.sh +++ b/util/activate.sh @@ -1,6 +1,6 @@ #!/bin/bash - DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export PATH="$DIR/local/bin:$PATH" export TOOLCHAIN="$DIR" echo "$PATH" + diff --git a/util/auto-dep.krk b/util/auto-dep.krk index 319fa15b..889344f6 100755 --- a/util/auto-dep.krk +++ b/util/auto-dep.krk @@ -1,9 +1,9 @@ #!/bin/kuroko import os, kuroko, fileio -let cflags = "-O2 -g -std=gnu99 -I. -Iapps -pipe -mmmx -msse -msse2 -fplan9-extensions -Wall -Wextra -Wno-unused-parameter" +let cflags = "-O2 -g -I. -Iapps -fplan9-extensions -Wall -Wextra -Wno-unused-parameter" -def basename(path): +def basename(path: str) -> str: return path.strip('/').split('/')[-1] class Classifier: @@ -33,14 +33,10 @@ class Classifier: '': (None, '-ltoaru_textregion', ['', '','', '']), '': (None, '-ltoaru_button', ['','', '']), # Kuroko - '': (None, '-lkuroko', []), - # OPTIONAL third-party libraries, for extensions / ports - '': ('freetype2', '-lfreetype', []), - '': ('pixman-1', '-lpixman-1', []), - '': ('cairo', '-lcairo', ['', '']), + '': ('../../../kuroko/src', '-lkuroko', []), } - def __init__(self, filename): + def __init__(self, filename: str): self.export_dynamic_hint = False self.filename = filename self.includes, self.libs = self._depends() @@ -54,7 +50,7 @@ class Classifier: depends = self._calculate(depends, other) return depends - def _sort(self, depends): + def _sort(self, depends: list[str]) -> list[str]: """Sort the list of dependencies so that elements appearing first depend on elements following.""" let satisfied = [] let a = depends[:] @@ -69,7 +65,7 @@ class Classifier: a = b[:] return reversed(satisfied) - def _depends(self): + def _depends(self) -> (list[str],list[str]): """Calculate include and library dependencies.""" let lines = [] let depends = [] @@ -93,7 +89,7 @@ class Classifier: return includes, libraries -def todep(name): +def todep(name: str) -> (bool, str): """Convert a library name to an archive path or object file name.""" if name.startswith("-l"): name = name.replace("-l","",1) @@ -106,7 +102,7 @@ def todep(name): else: return (False, name) -def toheader(name): +def toheader(name: str) -> str: if name.startswith('-ltoaru_'): return name.replace('-ltoaru_','base/usr/include/toaru/') + '.h' else: @@ -132,15 +128,15 @@ if __name__ == "__main__": elif command == "--build": os.system("gcc {cflags} {extra} {includes} -o {app} {source} {libraries}".format( cflags=cflags, - app=basename(filename).replace(".c",""), + app=basename(filename).replace('.c++','').replace(".c",""), source=filename, headers=" ".join([toheader(x) for x in c.libs]), libraries=" ".join([x for x in c.libs]), includes=" ".join([x for x in c.includes if x is not None]), - extra="-Wl,--export-dynamic" if c.export_dynamic_hint else "", + extra="-rdynamic" if c.export_dynamic_hint else "", )) elif command == "--buildlib": - let libname = basename(filename).replace(".c","") + let libname = basename(filename).replace('.c++','').replace(".c","") let _libs = [x for x in c.libs if not x.startswith('-ltoaru_') or x.replace("-ltoaru_","") != libname] os.system("gcc {cflags} {includes} -shared -fPIC -olibtoaru_{lib}.so {source} {libraries}".format( cflags=cflags, @@ -152,28 +148,30 @@ if __name__ == "__main__": includes=" ".join([x for x in c.includes if x is not None]) )) elif command == "--make": - print("base/bin/{app}: {source} {headers} util/auto-dep.krk | {libraryfiles} $(LC)\n\t$(CC) $(CFLAGS) {extra} {includes} -o $@ $< {libraries}".format( - app=basename(filename).replace(".c",""), + print("base/bin/{app}: {source} {headers} util/auto-dep.krk | {libraryfiles} $(LC)\n\t{comp} {extra} {includes} -o $@ $< {libraries}".format( + app=basename(filename).replace('.c++','').replace(".c",""), source=filename, headers=" ".join([toheader(x) for x in c.libs]), libraryfiles=" ".join([todep(x)[1] for x in c.libs]), libraries=" ".join([x for x in c.libs]), includes=" ".join([x for x in c.includes if x is not None]), - extra="-Wl,--export-dynamic" if c.export_dynamic_hint else "" + comp="$(CC) $(CFLAGS)" if '.c++' not in filename else "$(CXX) $(CXXFLAGS)", + extra="-rdynamic" if c.export_dynamic_hint else "" )) elif command == "--makelib": - let libname = basename(filename).replace(".c","") + let libname = basename(filename).replace('.c++','').replace(".c","") let _libs = [x for x in c.libs if not x.startswith('-ltoaru_') or x.replace("-ltoaru_","") != libname] - print("base/lib/libtoaru_{lib}.so: {source} {headers} util/auto-dep.krk | {libraryfiles} $(LC)\n\t$(CC) $(CFLAGS) {includes} -shared -fPIC -o $@ $< {libraries}".format( + print("base/lib/libtoaru_{lib}.so: {source} {headers} util/auto-dep.krk | {libraryfiles} $(LC)\n\t{comp} {includes} -shared -fPIC -o $@ $< {libraries}".format( lib=libname, source=filename, headers=" ".join([toheader(x) for x in c.libs]), libraryfiles=" ".join([todep(x)[1] for x in _libs]), libraries=" ".join([x for x in _libs]), - includes=" ".join([x for x in c.includes if x is not None]) + includes=" ".join([x for x in c.includes if x is not None]), + comp="$(CC) $(CFLAGS)" if '.c++' not in filename else "$(CXX) $(CXXFLAGS)", )) elif command == "--makekurokomod": - let libname = basename(filename).replace(".c","").replace("module_","") + let libname = basename(filename).replace('.c++','').replace(".c","").replace("module_","") let _libs = [x for x in c.libs if not x.startswith('-ltoaru_') or x.replace("-ltoaru_","") != libname] print("base/lib/kuroko/{lib}.so: {source} {headers} util/auto-dep.krk | {libraryfiles} $(LC)\n\t$(CC) $(CFLAGS) {includes} -shared -fPIC -o $@ $< {libraries}".format( lib=libname, diff --git a/util/build-gcc.sh b/util/build-gcc.sh deleted file mode 100644 index 0cb302f3..00000000 --- a/util/build-gcc.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -$DIR/check-reqs.sh - -TARGET=i686-pc-toaru -PREFIX="$DIR/local" -TOARU_SYSROOT="$DIR/../base" - -cd "$DIR" - -mkdir -p tarballs - -pushd tarballs - if [ ! -e "binutils-2.27.tar.gz" ]; then - wget "http://ftp.gnu.org/gnu/binutils/binutils-2.27.tar.gz" - fi - if [ ! -e "gcc-6.4.0.tar.gz" ]; then - wget "http://www.netgull.com/gcc/releases/gcc-6.4.0/gcc-6.4.0.tar.gz" - fi - - if [ ! -d "binutils-2.27" ]; then - tar -xf "binutils-2.27.tar.gz" - pushd "binutils-2.27" - patch -p1 < $DIR/patches/binutils.patch > /dev/null - popd - fi - - if [ ! -d "gcc-6.4.0" ]; then - tar -xf "gcc-6.4.0.tar.gz" - pushd "gcc-6.4.0" - patch -p1 < $DIR/patches/gcc.patch > /dev/null - popd - fi -popd - -mkdir -p local -mkdir -p build -mkdir -p build/binutils -mkdir -p build/gcc - -pushd build - - unset PKG_CONFIG_LIBDIR # Just in case - - pushd binutils - $DIR/tarballs/binutils-2.27/configure --target=$TARGET --prefix=$PREFIX --with-sysroot=$TOARU_SYSROOT --disable-werror || exit 1 - make -j4 - make install - popd - - pushd gcc - $DIR/tarballs/gcc-6.4.0/configure --target=i686-pc-toaru --prefix=$PREFIX --with-sysroot=$TOARU_SYSROOT --disable-nls --enable-languages=c,c++ --disable-libssp --with-newlib || exit 1 - make all-gcc all-target-libgcc - make install-gcc install-target-libgcc - popd - -popd - - - diff --git a/util/build-in-docker.sh b/util/build-in-docker.sh index fae35815..96a497f6 100755 --- a/util/build-in-docker.sh +++ b/util/build-in-docker.sh @@ -19,7 +19,7 @@ useradd -u $NEWUID local ln -s /root/gcc_local util/local # Run make as local -runuser -u local -- make -j4 +runuser -u local -- sh -c 'make base/lib/libc.so && make -j4' # Remove the build tools rm util/local diff --git a/util/build-the-world.py b/util/build-the-world.py deleted file mode 100755 index 884f589a..00000000 --- a/util/build-the-world.py +++ /dev/null @@ -1,772 +0,0 @@ -#!/usr/bin/python3 - -import tarfile -import glob -import subprocess -import array -import struct -import os - -def BuildKernel(): - kernel_c_sources = glob.glob("kernel/*.c") + glob.glob("kernel/*/*.c") + glob.glob("kernel/*/*/*.c") - kernel_s_sources = glob.glob("kernel/*.S") - - cflags = "-O2 -std=c99 -finline-functions -ffreestanding -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format -pedantic -fno-omit-frame-pointer -D_KERNEL_ -DKERNEL_GIT_TAG=master" - - for i in kernel_c_sources: - cmd = "gcc {cflags} -nostdlib -g -c -o {obj} {src}".format( - cflags=cflags, - obj=i.replace('.c','.o'), - src=i - ) - print(cmd) - subprocess.run(cmd, shell=True) - - for i in kernel_s_sources: - cmd = "as -o {obj} {src}".format( - obj=i.replace('.S','.o'), - src=i - ) - print(cmd) - subprocess.run(cmd,shell=True) - - objects = [x.replace('.c','.o') for x in kernel_c_sources] + [x.replace('.S','.o') for x in kernel_s_sources if not x.endswith('symbols.S')] - - cmd = "gcc -T kernel/link.ld {cflags} -nostdlib -o .toaruos-kernel {objects} -lgcc".format( - cflags=cflags, - objects=' '.join(objects), - ) - print(cmd) - subprocess.run(cmd, shell=True) - - cmd = "nm -g .toaruos-kernel | generate_symbols.py > kernel/symbols.S" - print(cmd) - subprocess.run(cmd,shell=True) - - subprocess.run("rm .toaruos-kernel", shell=True) - - cmd = "as -o kernel/symbols.o kernel/symbols.S" - print(cmd) - subprocess.run(cmd,shell=True) - - cmd = "gcc -T kernel/link.ld {cflags} -nostdlib -o cdrom/kernel {objects} kernel/symbols.o -lgcc".format( - cflags=cflags, - objects=' '.join(objects), - ) - print(cmd) - subprocess.run(cmd, shell=True) - -def BuildModules(): - module_sources = glob.glob('modules/*.c') - - cflags = "-O2 -std=c99 -finline-functions -ffreestanding -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format -pedantic -fno-omit-frame-pointer -D_KERNEL_ -DKERNEL_GIT_TAG=master" - - try: - os.mkdir('cdrom/mod') - except: - pass - - for i in module_sources: - cmd = "gcc {cflags} -nostdlib -g -c -o {obj} {src}".format( - cflags=cflags, - obj=i.replace('.c','.ko').replace('modules/','cdrom/mod/'), - src=i - ) - print(cmd) - subprocess.run(cmd, shell=True) - - -class Structure(object): - - assert_size = -1 - - def __init__(self): - self.data = {} - for field in self.fields: - if len(field) > 2: - f, s, d = field - self.data[s] = d - else: - f, s = field - if f.endswith('s'): - self.data[s] = b"" - else: - self.data[s] = 0 - if self.assert_size != -1: - assert(len(self) == self.assert_size) - - def __len__(self): - return sum([struct.calcsize(f[0]) for f in self.fields]) - - def read(self, data, offset): - - def read_struct(fmt,buf,offset): - out, = struct.unpack_from(fmt,buf,offset) - return out, offset + struct.calcsize(fmt) - - o = offset - for field in self.fields: - if len(field) > 2: - f, s, _ = field - else: - f, s = field - self.data[s], o = read_struct(f, data, o) - return o - - def write(self, data, offset): - - def write_struct(fmt, buf, offset, value): - struct.pack_into(fmt, buf, offset, value) - return offset + struct.calcsize(fmt) - - o = offset - for field in self.fields: - if len(field) > 2: - f, s, _ = field - else: - f, s = field - o = write_struct(f,data,o,self.data[s]) - return o - -def read_struct(fmt,buf,offset): - out, = struct.unpack_from(fmt,buf,offset) - return out, offset + struct.calcsize(fmt) - -class FAT(object): - - def __init__(self, iso, offset): - self.iso = iso - self.offset = offset - - self.bytespersector, _ = read_struct('H', self.iso.data, offset + 11) - self.sectorspercluster, _ = read_struct('B', self.iso.data, offset + 13) - self.reservedsectors, _ = read_struct('H', self.iso.data, offset + 14) - self.numberoffats, _ = read_struct('B', self.iso.data, offset + 16) - self.numberofdirs, _ = read_struct('H', self.iso.data, offset + 17) - self.fatsize, _ = read_struct('H', self.iso.data, offset + 22) - - self.root_dir_sectors = (self.numberofdirs * 32 + (self.bytespersector - 1)) // self.bytespersector - self.first_data_sector = self.reservedsectors + (self.numberoffats * self.fatsize) + self.root_dir_sectors - self.root_sector= self.first_data_sector - self.root_dir_sectors - self.root = FATDirectory(self, self.offset + self.root_sector * self.bytespersector) - - def get_offset(self, cluster): - return self.offset + ((cluster - 2) * self.sectorspercluster + self.first_data_sector) * self.bytespersector - - def get_file(self, path): - units = path.split('/') - units = units[1:] - - me = self.root - out = None - for i in units: - for fatfile in me.list(): - if fatfile.readable_name() == i: - me = fatfile.to_dir() - out = fatfile - break - else: - return None - return out - -class FATDirectory(object): - - def __init__(self, fat, offset): - - self.fat = fat - self.offset = offset - - def list(self): - - o = self.offset - while 1: - out = FATFile(self.fat, o) - if out.name != '\0\0\0\0\0\0\0\0': - yield out - else: - break - o += out.size - - -class FATFile(object): - - def __init__(self, fat, offset): - - self.fat = fat - self.offset = offset - self.magic_long = None - self.size = 0 - self.long_name = '' - - o = self.offset - self.actual_offset = o - - self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) - - while (self.attrib & 0x0F) == 0x0F: - # Long file name entry - tmp = read_struct('10s',self.fat.iso.data,o+1)[0] - tmp += read_struct('12s',self.fat.iso.data,o+14)[0] - tmp += read_struct('4s',self.fat.iso.data,o+28)[0] - tmp = "".join([chr(x) for x in tmp[::2] if x != '\xFF']).strip('\x00') - self.long_name = tmp + self.long_name - self.size += 32 - o = self.offset + self.size - self.actual_offset = o - self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) - - o = self.offset + self.size - - self.name, o = read_struct('8s',self.fat.iso.data,o) - self.ext, o = read_struct('3s',self.fat.iso.data,o) - self.attrib, o = read_struct('B',self.fat.iso.data,o) - self.userattrib, o = read_struct('B',self.fat.iso.data,o) - self.undelete, o = read_struct('b',self.fat.iso.data,o) - self.createtime, o = read_struct('H',self.fat.iso.data,o) - self.createdate, o = read_struct('H',self.fat.iso.data,o) - self.accessdate, o = read_struct('H',self.fat.iso.data,o) - self.clusterhi, o = read_struct('H',self.fat.iso.data,o) - self.modifiedti, o = read_struct('H',self.fat.iso.data,o) - self.modifiedda, o = read_struct('H',self.fat.iso.data,o) - self.clusterlow, o = read_struct('H',self.fat.iso.data,o) - self.filesize, o = read_struct('I',self.fat.iso.data,o) - - self.name = self.name.decode('ascii') - self.ext = self.ext.decode('ascii') - - self.size += 32 - - self.cluster = (self.clusterhi << 16) + self.clusterlow - - def is_dir(self): - return bool(self.attrib & 0x10) - - def is_long(self): - return bool((self.attrib & 0x0F) == 0x0F) - - def to_dir(self): - return FATDirectory(self.fat, self.fat.get_offset(self.cluster)) - - def get_offset(self): - return self.fat.get_offset(self.cluster) - - def readable_name(self): - if self.long_name: - return self.long_name - if self.ext.strip(): - return (self.name.strip() + '.' + self.ext.strip()).lower() - else: - return self.name.strip().lower() - -def make_time(): - data = array.array('b',b'\0'*17) - struct.pack_into( - '4s2s2s2s2s2s2sb', - data, 0, - b'2018', b'11', b'14', # Year, Month, Day - b'12', b'00', b'00', # Hour, Minute, Second - b'00', # Hundreths - 0, # Offset - ) - return bytes(data) - -def make_date(): - data = array.array('b',b'\0'*7) - struct.pack_into( - 'BBBBBBb', - data, 0, - 118, 11, 14, - 12, 0, 0, - 0, - ) - return bytes(data) - -class ISOBootRecord(Structure): - assert_size = 2048 - fields = ( - ('B', 'type_code', 0), - ('5s', 'cd001', b'CD001'), - ('B', 'version', 1), - ('32s', 'boot_system_identifier'), - ('32s', 'boot_identifier'), - ('1977s', 'boot_record_data'), - ) - -class ISOElToritoBootRecord(ISOBootRecord): - assert_size = 2048 - fields = ( - ('B', 'type_code', 0), - ('5s', 'cd001', b'CD001'), - ('B', 'version', 1), - ('32s', 'boot_system_identifier',b'EL TORITO SPECIFICATION'), - ('32s', 'boot_identifier'), - ('I', 'volume_space_msb'), - ('32s', 'unused_2', b'\0'*32), - ('H', 'volume_set_size_msb', 1), - ('H', 'volume_sequence_msb', 1), - ('H', 'logical_block_size_msb', 2048), - ('I', 'path_table_size_msb'), - ('I', 'type_m_table_msb'), - ('>I', 'optional_type_m_table_msb'), - ('34s', 'root_entry_data'), - ('128s', 'volume_set_identifier', b' '*128), - ('128s', 'publisher_identifier', b' '*128), - ('128s', 'data_preparer_identifier', b' '*128), - ('128s', 'application_identifier',b' '*128), - ('38s', 'copyright_file_identifier',b' '*38), - ('36s', 'abstract_file_identifier',b' '*36), - ('37s', 'bibliographic_file_identifier',b' '*37), - ('17s', 'volume_creation_time',make_time()), - ('17s', 'volume_modification_time',make_time()), - ('17s', 'volume_expiration_time',make_time()), - ('17s', 'volume_effective_time',make_time()), - ('B', 'file_structure_version'), - ('B', 'unused_3', 0), - ('512s', 'application_data'), - ('653s', 'reserved', b'\0'*653), - ) - -class ISOVolumeDescriptorSetTerminator(Structure): - assert_size = 2048 - fields = ( - ('B', 'type_code', 0xFF), - ('5s', 'cd001', b'CD001'), - ('B', 'version', 1), - ('2041s', 'unused', b'\0'*2041) - ) - -class ISODirectoryEntry(Structure): - assert_size = 33 - fields = ( - ('B', 'length'), - ('B', 'ext_length'), - ('I', 'extent_start_msb'), - ('I', 'extent_length_msb'), - ('7s', 'record_date', make_date()), - ('B', 'flags'), - ('B', 'interleave_units'), - ('B', 'interleave_gap'), - ('H', 'volume_seq_msb'), - ('B', 'name_len'), - ) - - def set_name(self, name): - self.data['name_len'] = len(name) - self.name = name - self.data['length'] = self.assert_size + len(self.name) - if self.data['length'] % 2: - self.data['length'] += 1 - - def set_extent(self, start, length): - self.data['extent_start_lsb'] = start - self.data['extent_start_msb'] = start - self.data['extent_length_lsb'] = length - self.data['extent_length_msb'] = length - - def write(self, data, offset): - o = super(ISODirectoryEntry,self).write(data,offset) - struct.pack_into(str(len(self.name))+'s', data, o, self.name.encode('utf-8')) - return offset + self.data['length'] - -class ArbitraryData(object): - - def __init__(self, path=None, size=None): - - if path: - with open(path,'rb') as f: - tmp = f.read() - self.data = array.array('b',tmp) - elif size: - self.data = array.array('b',b'\0'*size) - else: - raise ValueError("Expected one of path or size to be set.") - - self.size = len(self.data.tobytes()) - self.actual_size = self.size - while (self.size % 2048): - self.size += 1 - - def write(self, data, offset): - struct.pack_into(str(self.size) + 's', data, offset, self.data.tobytes()) - return offset + self.size - -def make_entry(): - return b'\0'*34 - -class ISO9660(object): - - def __init__(self, from_file=None): - self.primary_volume_descriptor = ISOPrimaryVolumeDescriptor() - self.boot_record = ISOElToritoBootRecord() - self.volume_descriptor_set_terminator = ISOVolumeDescriptorSetTerminator() - self.el_torito_catalog = ElToritoCatalog() - self.allocate = 0x13 - - if from_file: - # Only for a file we produced. - with open(from_file, 'rb') as f: - tmp = f.read() - data = array.array('b', tmp) - self.primary_volume_descriptor.read(data, 0x10 * 2048) - self.boot_record.read(data, 0x11 * 2048) - self.volume_descriptor_set_terminator.read(data, 0x12 * 2048) - self.el_torito_catalog.read(data, self.boot_record.data['catalog_lba'] * 2048) - else: - # Root directory - self.root = ISODirectoryEntry() - self.root.data['flags'] = 0x02 # Directory - self.root.set_name(' ') - self.root_data = ArbitraryData(size=2048) - self.root_data.sector_offset = self.allocate_space(1) - self.root.set_extent(self.root_data.sector_offset,self.root_data.size) - - # Dummy entries - t = ISODirectoryEntry() - t.set_name('') - o = t.write(self.root_data.data, 0) - t = ISODirectoryEntry() - t.set_name('\1') - o = t.write(self.root_data.data, o) - - # Kernel - self.kernel_data = ArbitraryData(path='cdrom/kernel') - self.kernel_data.sector_offset = self.allocate_space(self.kernel_data.size // 2048) - self.kernel_entry = ISODirectoryEntry() - self.kernel_entry.set_name('KERNEL.') - self.kernel_entry.set_extent(self.kernel_data.sector_offset, self.kernel_data.actual_size) - o = self.kernel_entry.write(self.root_data.data, o) - - # Ramdisk - self.ramdisk_data = ArbitraryData(path='cdrom/ramdisk.img') - self.ramdisk_data.sector_offset = self.allocate_space(self.ramdisk_data.size // 2048) - self.ramdisk_entry = ISODirectoryEntry() - self.ramdisk_entry.set_name('RAMDISK.IMG') - self.ramdisk_entry.set_extent(self.ramdisk_data.sector_offset, self.ramdisk_data.actual_size) - o = self.ramdisk_entry.write(self.root_data.data, o) - - # Modules directory - self.mods_data = ArbitraryData(size=(2048*2)) # Just in case - self.mods_data.sector_offset = self.allocate_space(self.mods_data.size // 2048) - self.mods_entry = ISODirectoryEntry() - self.mods_entry.data['flags'] = 0x02 - self.mods_entry.set_name('MOD') - self.mods_entry.set_extent(self.mods_data.sector_offset, self.mods_data.actual_size) - o = self.mods_entry.write(self.root_data.data, o) - - self.payloads = [] - - # Modules themselves - t = ISODirectoryEntry() - t.set_name('') - o = t.write(self.mods_data.data, 0) - t = ISODirectoryEntry() - t.set_name('\1') - o = t.write(self.mods_data.data, o) - for mod_file in [ - 'cdrom/mod/ac97.ko', - 'cdrom/mod/ata.ko', - 'cdrom/mod/ataold.ko', - 'cdrom/mod/debug_sh.ko', - 'cdrom/mod/dospart.ko', - 'cdrom/mod/e1000.ko', - 'cdrom/mod/ext2.ko', - 'cdrom/mod/hda.ko', - 'cdrom/mod/iso9660.ko', - 'cdrom/mod/lfbvideo.ko', - 'cdrom/mod/net.ko', - 'cdrom/mod/packetfs.ko', - 'cdrom/mod/pcnet.ko', - 'cdrom/mod/pcspkr.ko', - 'cdrom/mod/portio.ko', - 'cdrom/mod/procfs.ko', - 'cdrom/mod/ps2kbd.ko', - 'cdrom/mod/ps2mouse.ko', - 'cdrom/mod/random.ko', - 'cdrom/mod/rtl.ko', - 'cdrom/mod/serial.ko', - 'cdrom/mod/snd.ko', - 'cdrom/mod/tmpfs.ko', - 'cdrom/mod/usbuhci.ko', - 'cdrom/mod/vbox.ko', - 'cdrom/mod/vgadbg.ko', - 'cdrom/mod/vgalog.ko', - 'cdrom/mod/vidset.ko', - 'cdrom/mod/vmware.ko', - 'cdrom/mod/xtest.ko', - 'cdrom/mod/zero.ko', - 'cdrom/mod/tarfs.ko', - ]: - payload = ArbitraryData(path=mod_file) - payload.sector_offset = self.allocate_space(payload.size // 2048) - entry = ISODirectoryEntry() - entry.set_name(mod_file.replace('cdrom/mod/','').upper()) - entry.set_extent(payload.sector_offset, payload.actual_size) - o = entry.write(self.mods_data.data, o) - self.payloads.append(payload) - - # Set up the boot catalog and records - self.el_torito_catalog.sector_offset = self.allocate_space(1) - self.boot_record.set_catalog(self.el_torito_catalog.sector_offset) - self.boot_payload = ArbitraryData(path='cdrom/boot.sys') - self.boot_payload.sector_offset = self.allocate_space(self.boot_payload.size // 2048) - self.el_torito_catalog.initial_entry.data['sector_count'] = self.boot_payload.size // 512 - self.el_torito_catalog.initial_entry.data['load_rba'] = self.boot_payload.sector_offset - #self.el_torito_catalog.section.data['sector_count'] = 0 # Expected to be 0 or 1 for "until end of CD" - #self.el_torito_catalog.section.data['load_rba'] = self.fat_payload.sector_offset - self.primary_volume_descriptor.data['root_entry_data'] = make_entry() - - def allocate_space(self, sectors): - out = self.allocate - self.allocate += sectors - return out - - def write(self, file_name): - with open(file_name, 'wb') as f: - data = array.array('b',b'\0'*(2048*self.allocate)) - self.primary_volume_descriptor.write(data,0x10 * 2048) - self.root.write(data,0x10*2048 + 156) - self.boot_record.write(data,0x11 * 2048) - self.mods_data.write(data, self.mods_data.sector_offset * 2048) - self.root_data.write(data,self.root_data.sector_offset * 2048) - self.volume_descriptor_set_terminator.write(data,0x12 * 2048) - self.el_torito_catalog.write(data,self.el_torito_catalog.sector_offset * 2048) - self.boot_payload.write(data,self.boot_payload.sector_offset * 2048) - self.kernel_data.write(data,self.kernel_data.sector_offset * 2048) - self.ramdisk_data.write(data,self.ramdisk_data.sector_offset * 2048) - #self.fat_payload.write(data,self.fat_payload.sector_offset * 2048) - for payload in self.payloads: - payload.write(data,payload.sector_offset * 2048) - data.tofile(f) - -class ElToritoValidationEntry(Structure): - assert_size = 0x20 - fields = ( - ('B','header_id',1), - ('B','platform_id',0), - ('/dev/null; then - echo "python3 is required to run build tools - 3.6 is recommended as it is needed to cross-compile itself" - RET=1 -fi - -if ! which mkfs.fat >/dev/null; then - echo "mkfs.fat is required (and should be in your PATH) to build EFI file systems" - RET=1 -fi - -if ! which mcopy >/dev/null; then - echo "mtools is required to build FAT images for EFI / hybrid ISOs" - RET=1 -fi - -if ! which xorriso >/dev/null; then - echo "xorriso is required to build ISO CD images" - RET=1 -fi - -if ! which autoconf >/dev/null; then - echo "autoconf is required to build GCC cross-compiler" - RET=1 -fi - -if ! which automake >/dev/null; then - echo "automake is required to build GCC cross-compiler" - RET=1 -fi - -if ! which wget >/dev/null; then - echo "wget is required to build GCC cross-compiler" - RET=1 -fi - -if [ ! -e /usr/lib32/crt0-efi-ia32.o ]; then - echo "gnu-efi is required to build EFI loaders" - RET=1 -fi - -if ! cpp <(echo "#include \"gmp.h\"") >/dev/null 2>/dev/null; then - echo "GMP headers are required to build GCC cross-compiler" - RET=1 -fi - -if ! cpp <(echo "#include \"mpfr.h\"") >/dev/null 2>/dev/null; then - echo "MPFR headers are required to build GCC cross-compiler" - RET=1 -fi - -if ! cpp <(echo "#include \"mpc.h\"") >/dev/null 2>/dev/null; then - echo "MPC headers are required to build GCC cross-compiler" - RET=1 -fi - -exit $RET - diff --git a/util/check.sh b/util/check.sh deleted file mode 100755 index d50a729d..00000000 --- a/util/check.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ ! -e "$DIR/local/bin/i686-pc-toaru-gcc" ]; then - echo -n "n"; - exit 1; -else - echo -n "y"; - exit 0; -fi diff --git a/util/compiler-rt.S b/util/compiler-rt.S deleted file mode 100644 index 2a76bd6b..00000000 --- a/util/compiler-rt.S +++ /dev/null @@ -1,517 +0,0 @@ -// This file contains assembly implementations of: -// __udivdi3 -// __umoddi3 -// ... from LLVM's compiler-rt, for use with building -// the ToaruOS kernel with a bare clang, with no need to link -// to libgcc or compiler-rt directly. If more function -// implementations are needed in the future, these should also -// be included here. - -// ============================================================================== -// The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: -// ============================================================================== -// -// 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, whether in Source or -// Object form, 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 any work of authorship, including -// the original version of the Work and any modifications or additions -// to that Work or Derivative Works thereof, that is intentionally -// submitted to 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, "submitted" -// means any form of electronic, verbal, or written communication sent -// to the Licensor or its representatives, including but not limited to -// communication on electronic mailing lists, source code control systems, -// and issue tracking systems that are managed by, or on behalf of, the -// Licensor for the purpose of discussing and improving the Work, but -// excluding communication that is conspicuously marked or otherwise -// designated in writing by the copyright owner as "Not a Contribution." -// -// "Contributor" shall mean Licensor and any individual or Legal Entity -// on behalf of whom a Contribution has been received by Licensor and -// subsequently incorporated 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 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 a Contribution incorporated within the Work constitutes direct -// 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, then any Derivative Works that You distribute must -// include a readable copy of the attribution notices contained -// within such NOTICE file, excluding those notices that do not -// pertain to any part of the Derivative Works, 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 as an addendum 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 copyright statement to Your modifications and -// may provide additional or different license terms and conditions -// for use, reproduction, or distribution of Your modifications, or -// for any such Derivative Works as a whole, provided Your use, -// reproduction, and distribution of the Work otherwise complies with -// the conditions stated in 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 warranties or conditions -// of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -// PARTICULAR PURPOSE. You are solely responsible for determining the -// appropriateness of using or redistributing 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 consequential damages of any character arising as a -// result of this License or out of the use or inability to use the -// Work (including but not limited to damages for loss of goodwill, -// work stoppage, computer failure or malfunction, or any and all -// other commercial damages or losses), 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 act only -// on Your own 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 such warranty or additional liability. -// -// END OF TERMS AND CONDITIONS -// -// APPENDIX: How to apply the Apache License to your work. -// -// To apply the Apache License to your work, attach the following -// boilerplate notice, with the fields enclosed by brackets "[]" -// replaced with your own identifying information. (Don't include -// the brackets!) The text should be enclosed in the appropriate -// comment syntax for the file format. We also recommend that a -// file or class name and description of purpose be included on the -// same "printed page" as the copyright notice for easier -// identification within third-party archives. -// -// Copyright [yyyy] [name of copyright owner] -// -// 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. -// -// -// ---- LLVM Exceptions to the Apache 2.0 License ---- -// -// As an exception, if, as a result of your compiling your source code, portions -// of this Software are embedded into an Object form of such source code, you -// may redistribute such embedded portions in such Object form without complying -// with the conditions of Sections 4(a), 4(b) and 4(d) of the License. -// -// In addition, if you combine or link compiled forms of this Software with -// software that is licensed under the GPLv2 ("Combined Software") and if a -// court of competent jurisdiction determines that the patent provision (Section -// 3), the indemnity provision (Section 9) or other Section of the License -// conflicts with the conditions of the GPLv2, you may retroactively and -// prospectively choose to deem waived or otherwise exclude such Section(s) of -// the License, but only in their entirety and only with respect to the Combined -// Software. -// -// ============================================================================== -// Software from third parties included in the LLVM Project: -// ============================================================================== -// The LLVM Project contains third party software which is under different license -// terms. All such code will be identified clearly using at least one of two -// mechanisms: -// 1) It will be in a separate directory tree with its own `LICENSE.txt` or -// `LICENSE` file at the top containing the specific license and restrictions -// which apply to that software, or -// 2) It will contain specific license and restriction terms at the top of every -// file. -// -// ============================================================================== -// Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): -// ============================================================================== -// -// The compiler_rt library is dual licensed under both the University of Illinois -// "BSD-Like" license and the MIT license. As a user of this code you may choose -// to use it under either license. As a contributor, you agree to allow your code -// to be used under both. -// -// Full text of the relevant licenses is included below. -// -// ============================================================================== -// -// University of Illinois/NCSA -// Open Source License -// -// Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT -// -// All rights reserved. -// -// Developed by: -// -// LLVM Team -// -// University of Illinois at Urbana-Champaign -// -// http://llvm.org -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal with -// 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: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimers. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -// * Neither the names of the LLVM Team, University of Illinois at -// Urbana-Champaign, nor the names of its contributors may be used to -// endorse or promote products derived from this Software without specific -// prior written permission. -// -// 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 -// CONTRIBUTORS 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 WITH THE -// SOFTWARE. -// -// ============================================================================== -// -// Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT -// -// 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. -.text -.balign 4 -.globl __udivdi3 -__udivdi3: - - pushl %ebx - movl 20(%esp), %ebx // Find the index i of the leading bit in b. - bsrl %ebx, %ecx // If the high word of b is zero, jump to - jz 9f // the code to handle that special case [9]. - - // High word of b is known to be non-zero on this branch - - movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b - - shrl %cl, %eax // Practically, this means that bhi is given by: - shrl %eax // - notl %ecx // bhi = (high word of b) << (31 - i) | - shll %cl, %ebx // (low word of b) >> (1 + i) - orl %eax, %ebx // - movl 12(%esp), %edx // Load the high and low words of a, and jump - movl 8(%esp), %eax // to [1] if the high word is larger than bhi - cmpl %ebx, %edx // to avoid overflowing the upcoming divide. - jae 1f - - // High word of a is greater than or equal to (b >> (1 + i)) on this branch - - divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r - - pushl %edi - notl %ecx - shrl %eax - shrl %cl, %eax // q = qs >> (1 + i) - movl %eax, %edi - mull 20(%esp) // q*blo - movl 12(%esp), %ebx - movl 16(%esp), %ecx // ECX:EBX = a - subl %eax, %ebx - sbbl %edx, %ecx // ECX:EBX = a - q*blo - movl 24(%esp), %eax - imull %edi, %eax // q*bhi - subl %eax, %ecx // ECX:EBX = a - q*b - sbbl $0, %edi // decrement q if remainder is negative - xorl %edx, %edx - movl %edi, %eax - popl %edi - popl %ebx - retl - - -1: // High word of a is greater than or equal to (b >> (1 + i)) on this branch - - subl %ebx, %edx // subtract bhi from ahi so that divide will not - divl %ebx // overflow, and find q and r such that - // - // ahi:alo = (1:q)*bhi + r - // - // Note that q is a number in (31-i).(1+i) - // fix point. - - pushl %edi - notl %ecx - shrl %eax - orl $0x80000000, %eax - shrl %cl, %eax // q = (1:qs) >> (1 + i) - movl %eax, %edi - mull 20(%esp) // q*blo - movl 12(%esp), %ebx - movl 16(%esp), %ecx // ECX:EBX = a - subl %eax, %ebx - sbbl %edx, %ecx // ECX:EBX = a - q*blo - movl 24(%esp), %eax - imull %edi, %eax // q*bhi - subl %eax, %ecx // ECX:EBX = a - q*b - sbbl $0, %edi // decrement q if remainder is negative - xorl %edx, %edx - movl %edi, %eax - popl %edi - popl %ebx - retl - - -9: // High word of b is zero on this branch - - movl 12(%esp), %eax // Find qhi and rhi such that - movl 16(%esp), %ecx // - xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b - divl %ecx // - movl %eax, %ebx // - movl 8(%esp), %eax // Find qlo such that - divl %ecx // - movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b - popl %ebx // - retl // and return qhi:qlo - -.text -.balign 4 -.globl __umoddi3 -__umoddi3: - - pushl %ebx - movl 20(%esp), %ebx // Find the index i of the leading bit in b. - bsrl %ebx, %ecx // If the high word of b is zero, jump to - jz 9f // the code to handle that special case [9]. - - // High word of b is known to be non-zero on this branch - - movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b - - shrl %cl, %eax // Practically, this means that bhi is given by: - shrl %eax // - notl %ecx // bhi = (high word of b) << (31 - i) | - shll %cl, %ebx // (low word of b) >> (1 + i) - orl %eax, %ebx // - movl 12(%esp), %edx // Load the high and low words of a, and jump - movl 8(%esp), %eax // to [2] if the high word is larger than bhi - cmpl %ebx, %edx // to avoid overflowing the upcoming divide. - jae 2f - - // High word of a is greater than or equal to (b >> (1 + i)) on this branch - - divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r - - pushl %edi - notl %ecx - shrl %eax - shrl %cl, %eax // q = qs >> (1 + i) - movl %eax, %edi - mull 20(%esp) // q*blo - movl 12(%esp), %ebx - movl 16(%esp), %ecx // ECX:EBX = a - subl %eax, %ebx - sbbl %edx, %ecx // ECX:EBX = a - q*blo - movl 24(%esp), %eax - imull %edi, %eax // q*bhi - subl %eax, %ecx // ECX:EBX = a - q*b - - jnc 1f // if positive, this is the result. - addl 20(%esp), %ebx // otherwise - adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result -1: movl %ebx, %eax - movl %ecx, %edx - - popl %edi - popl %ebx - retl - - -2: // High word of a is greater than or equal to (b >> (1 + i)) on this branch - - subl %ebx, %edx // subtract bhi from ahi so that divide will not - divl %ebx // overflow, and find q and r such that - // - // ahi:alo = (1:q)*bhi + r - // - // Note that q is a number in (31-i).(1+i) - // fix point. - - pushl %edi - notl %ecx - shrl %eax - orl $0x80000000, %eax - shrl %cl, %eax // q = (1:qs) >> (1 + i) - movl %eax, %edi - mull 20(%esp) // q*blo - movl 12(%esp), %ebx - movl 16(%esp), %ecx // ECX:EBX = a - subl %eax, %ebx - sbbl %edx, %ecx // ECX:EBX = a - q*blo - movl 24(%esp), %eax - imull %edi, %eax // q*bhi - subl %eax, %ecx // ECX:EBX = a - q*b - - jnc 3f // if positive, this is the result. - addl 20(%esp), %ebx // otherwise - adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result -3: movl %ebx, %eax - movl %ecx, %edx - - popl %edi - popl %ebx - retl - - - -9: // High word of b is zero on this branch - - movl 12(%esp), %eax // Find qhi and rhi such that - movl 16(%esp), %ecx // - xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b - divl %ecx // - movl %eax, %ebx // - movl 8(%esp), %eax // Find rlo such that - divl %ecx // - movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b - popl %ebx // - xorl %edx, %edx // and return 0:rlo - retl // diff --git a/util/createramdisk.py b/util/createramdisk.py index 525ec083..2b885fc2 100644 --- a/util/createramdisk.py +++ b/util/createramdisk.py @@ -47,7 +47,7 @@ def file_filter(tarinfo): return tarinfo -with tarfile.open('fatbase/ramdisk.img','w') as ramdisk: +with tarfile.open('ramdisk.igz','w:gz') as ramdisk: ramdisk.add('base',arcname='/',filter=file_filter) ramdisk.add('.',arcname='/src',filter=file_filter,recursive=False) # Add a src directory @@ -56,8 +56,8 @@ with tarfile.open('fatbase/ramdisk.img','w') as ramdisk: ramdisk.add('linker',arcname='/src/linker',filter=file_filter) ramdisk.add('lib',arcname='/src/lib',filter=file_filter) ramdisk.add('libc',arcname='/src/libc',filter=file_filter) - ramdisk.add('boot',arcname='/src/boot',filter=file_filter) - ramdisk.add('modules',arcname='/src/modules',filter=file_filter) + #ramdisk.add('boot',arcname='/src/boot',filter=file_filter) + #ramdisk.add('modules',arcname='/src/modules',filter=file_filter) if os.path.exists('tags'): ramdisk.add('tags',arcname='/src/tags',filter=file_filter) ramdisk.add('util/auto-dep.krk',arcname='/usr/bin/auto-dep.krk',filter=file_filter) diff --git a/util/docker/Dockerfile b/util/docker/Dockerfile new file mode 100644 index 00000000..f3771d7a --- /dev/null +++ b/util/docker/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update \ + && apt-get install -y build-essential python3 xorriso genext2fs mtools gnu-efi git automake autoconf wget libgmp-dev libmpfr-dev libmpc-dev flex bison texinfo dosfstools \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/apt-file/* diff --git a/util/docker/README.md b/util/docker/README.md new file mode 100644 index 00000000..83792835 --- /dev/null +++ b/util/docker/README.md @@ -0,0 +1,23 @@ +1. Build the base image from the Dockerfile. + +```bash +docker build . +``` + +2. Run the docker image with `-it bash`. + +3. Clone the repository over `https`: + +```bash +cd +git clone --recurse-submodules https://github.com/toaruos/misaka +cd misaka +util/build-toolchain.sh +cd util/build/binutils +while [[ -e confdir3/confdir3 ]]; do mv confdir3/confdir3 confdir3a; rmdir confdir3; mv confdir3a confdir3; done; rmdir confdir3 +cd ../../.. +mv local /root/gcc_local +cd /root +rm -rf misaka +``` + diff --git a/util/fix-python.sh b/util/fix-python.sh deleted file mode 100755 index 679e2e7c..00000000 --- a/util/fix-python.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# needed for strip -source util/activate.sh - -HDD_PATH=base - -pushd $HDD_PATH/usr/python/lib || exit 1 - - echo "Stripping shared library..." - chmod +w libpython3.6m.so - i686-pc-toaru-strip libpython3.6m.so - chmod -w libpython3.6m.so - - echo "Killing __pycache__ directories..." - find . -name __pycache__ -exec rm -r "{}" \; - - # Let's kill some other shit while we're in here - pushd python3.6 || exit 1 - echo "Cleaning up unused modules..." - rm -r test distutils tkinter multiprocessing ensurepip config-3.6m/libpython3.6m.a - popd - -popd - -pushd $HDD_PATH/usr - if [ ! -d bin ]; then - mkdir bin - fi - - pushd bin - - # Can never be too careful. - ln -s ../python/bin/python3.6 python3.6 - ln -s ../python/bin/python3.6 python3 - ln -s ../python/bin/python3.6 python - - popd - - pushd lib - - ln -s ../python/lib/libpython3.6m.so - - popd - -popd - -echo "Installing readline hook..." -cp util/readline._py $HDD_PATH/usr/python/lib/python3.6/ - diff --git a/util/generate-release-notes.sh b/util/generate-release-notes.sh deleted file mode 100644 index 010600cf..00000000 --- a/util/generate-release-notes.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -VERSION=$(git describe --exact-match --tags) -LAST=$(git describe --abbrev=0 --tags ${VERSION}^) -CHANGELOG=$(git log --pretty=format:%s ${LAST}..HEAD | grep ':' | sed -re 's/(.*)\:/- \`\1\`\:/' | sort) -cat < 2: - f, s, d = field - self.data[s] = d - else: - f, s = field - if f.endswith('s'): - self.data[s] = b"" - else: - self.data[s] = 0 - if self.assert_size != -1: - assert(len(self) == self.assert_size) - - def __len__(self): - return sum([struct.calcsize(f[0]) for f in self.fields]) - - def read(self, data, offset): - - def read_struct(fmt,buf,offset): - out, = struct.unpack_from(fmt,buf,offset) - return out, offset + struct.calcsize(fmt) - - o = offset - for field in self.fields: - if len(field) > 2: - f, s, _ = field - else: - f, s = field - self.data[s], o = read_struct(f, data, o) - return o - - def write(self, data, offset): - - def write_struct(fmt, buf, offset, value): - struct.pack_into(fmt, buf, offset, value) - return offset + struct.calcsize(fmt) - - o = offset - for field in self.fields: - if len(field) > 2: - f, s, _ = field - else: - f, s = field - o = write_struct(f,data,o,self.data[s]) - return o - -def read_struct(fmt,buf,offset): - out, = struct.unpack_from(fmt,buf,offset) - return out, offset + struct.calcsize(fmt) - -class FAT(object): - - def __init__(self, iso, offset): - self.iso = iso - self.offset = offset - - self.bytespersector, _ = read_struct('H', self.iso.data, offset + 11) - self.sectorspercluster, _ = read_struct('B', self.iso.data, offset + 13) - self.reservedsectors, _ = read_struct('H', self.iso.data, offset + 14) - self.numberoffats, _ = read_struct('B', self.iso.data, offset + 16) - self.numberofdirs, _ = read_struct('H', self.iso.data, offset + 17) - self.fatsize, _ = read_struct('H', self.iso.data, offset + 22) - - self.root_dir_sectors = (self.numberofdirs * 32 + (self.bytespersector - 1)) // self.bytespersector - self.first_data_sector = self.reservedsectors + (self.numberoffats * self.fatsize) + self.root_dir_sectors - self.root_sector= self.first_data_sector - self.root_dir_sectors - self.root = FATDirectory(self, self.offset + self.root_sector * self.bytespersector) - - def get_offset(self, cluster): - return self.offset + ((cluster - 2) * self.sectorspercluster + self.first_data_sector) * self.bytespersector - - def get_file(self, path): - units = path.split('/') - units = units[1:] - - me = self.root - out = None - for i in units: - for fatfile in me.list(): - if fatfile.readable_name() == i: - me = fatfile.to_dir() - out = fatfile - break - else: - return None - return out - -class FATDirectory(object): - - def __init__(self, fat, offset): - - self.fat = fat - self.offset = offset - - def list(self): - - o = self.offset - while 1: - out = FATFile(self.fat, o) - if out.name != '\0\0\0\0\0\0\0\0': - yield out - else: - break - o += out.size - - -class FATFile(object): - - def __init__(self, fat, offset): - - self.fat = fat - self.offset = offset - self.magic_long = None - self.size = 0 - self.long_name = '' - - o = self.offset - self.actual_offset = o - - self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) - - while (self.attrib & 0x0F) == 0x0F: - # Long file name entry - tmp = read_struct('10s',self.fat.iso.data,o+1)[0] - tmp += read_struct('12s',self.fat.iso.data,o+14)[0] - tmp += read_struct('4s',self.fat.iso.data,o+28)[0] - tmp = "".join([chr(x) for x in tmp[::2] if x != '\xFF']).strip('\x00') - self.long_name = tmp + self.long_name - self.size += 32 - o = self.offset + self.size - self.actual_offset = o - self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) - - o = self.offset + self.size - - self.name, o = read_struct('8s',self.fat.iso.data,o) - self.ext, o = read_struct('3s',self.fat.iso.data,o) - self.attrib, o = read_struct('B',self.fat.iso.data,o) - self.userattrib, o = read_struct('B',self.fat.iso.data,o) - self.undelete, o = read_struct('b',self.fat.iso.data,o) - self.createtime, o = read_struct('H',self.fat.iso.data,o) - self.createdate, o = read_struct('H',self.fat.iso.data,o) - self.accessdate, o = read_struct('H',self.fat.iso.data,o) - self.clusterhi, o = read_struct('H',self.fat.iso.data,o) - self.modifiedti, o = read_struct('H',self.fat.iso.data,o) - self.modifiedda, o = read_struct('H',self.fat.iso.data,o) - self.clusterlow, o = read_struct('H',self.fat.iso.data,o) - self.filesize, o = read_struct('I',self.fat.iso.data,o) - - self.name = self.name.decode('ascii') - self.ext = self.ext.decode('ascii') - - self.size += 32 - - self.cluster = (self.clusterhi << 16) + self.clusterlow - - def is_dir(self): - return bool(self.attrib & 0x10) - - def is_long(self): - return bool((self.attrib & 0x0F) == 0x0F) - - def to_dir(self): - return FATDirectory(self.fat, self.fat.get_offset(self.cluster)) - - def get_offset(self): - return self.fat.get_offset(self.cluster) - - def readable_name(self): - if self.long_name: - return self.long_name - if self.ext.strip(): - return (self.name.strip() + '.' + self.ext.strip()).lower() - else: - return self.name.strip().lower() - -def make_time(): - data = array.array('b',b'\0'*17) - struct.pack_into( - '4s2s2s2s2s2s2sb', - data, 0, - b'2018', b'11', b'14', # Year, Month, Day - b'12', b'00', b'00', # Hour, Minute, Second - b'00', # Hundreths - 0, # Offset - ) - return bytes(data) - -def make_date(): - data = array.array('b',b'\0'*7) - struct.pack_into( - 'BBBBBBb', - data, 0, - 118, 11, 14, - 12, 0, 0, - 0, - ) - return bytes(data) - -class ISOBootRecord(Structure): - assert_size = 2048 - fields = ( - ('B', 'type_code', 0), - ('5s', 'cd001', b'CD001'), - ('B', 'version', 1), - ('32s', 'boot_system_identifier'), - ('32s', 'boot_identifier'), - ('1977s', 'boot_record_data'), - ) - -class ISOElToritoBootRecord(ISOBootRecord): - assert_size = 2048 - fields = ( - ('B', 'type_code', 0), - ('5s', 'cd001', b'CD001'), - ('B', 'version', 1), - ('32s', 'boot_system_identifier',b'EL TORITO SPECIFICATION'), - ('32s', 'boot_identifier'), - ('I', 'volume_space_msb'), - ('32s', 'unused_2', b'\0'*32), - ('H', 'volume_set_size_msb', 1), - ('H', 'volume_sequence_msb', 1), - ('H', 'logical_block_size_msb', 2048), - ('I', 'path_table_size_msb'), - ('I', 'type_m_table_msb'), - ('>I', 'optional_type_m_table_msb'), - ('34s', 'root_entry_data'), - ('128s', 'volume_set_identifier', b' '*128), - ('128s', 'publisher_identifier', b' '*128), - ('128s', 'data_preparer_identifier', b' '*128), - ('128s', 'application_identifier',b' '*128), - ('38s', 'copyright_file_identifier',b' '*38), - ('36s', 'abstract_file_identifier',b' '*36), - ('37s', 'bibliographic_file_identifier',b' '*37), - ('17s', 'volume_creation_time',make_time()), - ('17s', 'volume_modification_time',make_time()), - ('17s', 'volume_expiration_time',make_time()), - ('17s', 'volume_effective_time',make_time()), - ('B', 'file_structure_version'), - ('B', 'unused_3', 0), - ('512s', 'application_data'), - ('653s', 'reserved', b'\0'*653), - ) - -class ISOVolumeDescriptorSetTerminator(Structure): - assert_size = 2048 - fields = ( - ('B', 'type_code', 0xFF), - ('5s', 'cd001', b'CD001'), - ('B', 'version', 1), - ('2041s', 'unused', b'\0'*2041) - ) - -class ISODirectoryEntry(Structure): - assert_size = 33 - fields = ( - ('B', 'length'), - ('B', 'ext_length'), - ('I', 'extent_start_msb'), - ('I', 'extent_length_msb'), - ('7s', 'record_date', make_date()), - ('B', 'flags'), - ('B', 'interleave_units'), - ('B', 'interleave_gap'), - ('H', 'volume_seq_msb'), - ('B', 'name_len'), - ) - - def set_name(self, name): - self.data['name_len'] = len(name) - self.name = name - self.data['length'] = self.assert_size + len(self.name) - if self.data['length'] % 2: - self.data['length'] += 1 - - def set_extent(self, start, length): - self.data['extent_start_lsb'] = start - self.data['extent_start_msb'] = start - self.data['extent_length_lsb'] = length - self.data['extent_length_msb'] = length - - def write(self, data, offset): - o = super(ISODirectoryEntry,self).write(data,offset) - struct.pack_into(str(len(self.name))+'s', data, o, self.name.encode('utf-8')) - return offset + self.data['length'] - -class ArbitraryData(object): - - def __init__(self, path=None, size=None): - - if path: - with open(path,'rb') as f: - tmp = f.read() - self.data = array.array('b',tmp) - elif size: - self.data = array.array('b',b'\0'*size) - else: - raise ValueError("Expected one of path or size to be set.") - - self.size = len(self.data.tobytes()) - self.actual_size = self.size - while (self.size % 2048): - self.size += 1 - - def write(self, data, offset): - struct.pack_into(str(self.size) + 's', data, offset, self.data.tobytes()) - return offset + self.size - -def make_entry(): - return b'\0'*34 - -class ISO9660(object): - - def __init__(self, from_file=None): - self.primary_volume_descriptor = ISOPrimaryVolumeDescriptor() - self.boot_record = ISOElToritoBootRecord() - self.volume_descriptor_set_terminator = ISOVolumeDescriptorSetTerminator() - self.el_torito_catalog = ElToritoCatalog() - self.allocate = 0x13 - - if from_file: - # Only for a file we produced. - with open(from_file, 'rb') as f: - tmp = f.read() - data = array.array('b', tmp) - self.primary_volume_descriptor.read(data, 0x10 * 2048) - self.boot_record.read(data, 0x11 * 2048) - self.volume_descriptor_set_terminator.read(data, 0x12 * 2048) - self.el_torito_catalog.read(data, self.boot_record.data['catalog_lba'] * 2048) - else: - # Root directory - self.root = ISODirectoryEntry() - self.root.data['flags'] = 0x02 # Directory - self.root.set_name(' ') - self.root_data = ArbitraryData(size=2048) - self.root_data.sector_offset = self.allocate_space(1) - self.root.set_extent(self.root_data.sector_offset,self.root_data.size) - - # Dummy entries - t = ISODirectoryEntry() - t.set_name('') - o = t.write(self.root_data.data, 0) - t = ISODirectoryEntry() - t.set_name('\1') - o = t.write(self.root_data.data, o) - - # Kernel - self.kernel_data = ArbitraryData(path='fatbase/kernel') - self.kernel_data.sector_offset = self.allocate_space(self.kernel_data.size // 2048) - self.kernel_entry = ISODirectoryEntry() - self.kernel_entry.set_name('KERNEL.') - self.kernel_entry.set_extent(self.kernel_data.sector_offset, self.kernel_data.actual_size) - o = self.kernel_entry.write(self.root_data.data, o) - - # Ramdisk - self.ramdisk_data = ArbitraryData(path='fatbase/ramdisk.img') - self.ramdisk_data.sector_offset = self.allocate_space(self.ramdisk_data.size // 2048) - self.ramdisk_entry = ISODirectoryEntry() - self.ramdisk_entry.set_name('RAMDISK.IMG') - self.ramdisk_entry.set_extent(self.ramdisk_data.sector_offset, self.ramdisk_data.actual_size) - o = self.ramdisk_entry.write(self.root_data.data, o) - - # Modules directory - self.mods_data = ArbitraryData(size=(2048*2)) # Just in case - self.mods_data.sector_offset = self.allocate_space(self.mods_data.size // 2048) - self.mods_entry = ISODirectoryEntry() - self.mods_entry.data['flags'] = 0x02 - self.mods_entry.set_name('MOD') - self.mods_entry.set_extent(self.mods_data.sector_offset, self.mods_data.actual_size) - o = self.mods_entry.write(self.root_data.data, o) - - self.payloads = [] - - # Modules themselves - t = ISODirectoryEntry() - t.set_name('') - o = t.write(self.mods_data.data, 0) - t = ISODirectoryEntry() - t.set_name('\1') - o = t.write(self.mods_data.data, o) - for mod_file in [ - 'fatbase/mod/ac97.ko', - 'fatbase/mod/ata.ko', - 'fatbase/mod/ataold.ko', - 'fatbase/mod/debug_sh.ko', - 'fatbase/mod/dospart.ko', - 'fatbase/mod/e1000.ko', - 'fatbase/mod/ext2.ko', - 'fatbase/mod/hda.ko', - 'fatbase/mod/iso9660.ko', - 'fatbase/mod/lfbvideo.ko', - 'fatbase/mod/net.ko', - 'fatbase/mod/packetfs.ko', - 'fatbase/mod/pcnet.ko', - 'fatbase/mod/pcspkr.ko', - 'fatbase/mod/portio.ko', - 'fatbase/mod/procfs.ko', - 'fatbase/mod/ps2kbd.ko', - 'fatbase/mod/ps2mouse.ko', - 'fatbase/mod/random.ko', - 'fatbase/mod/rtl.ko', - 'fatbase/mod/serial.ko', - 'fatbase/mod/snd.ko', - 'fatbase/mod/tmpfs.ko', - 'fatbase/mod/usbuhci.ko', - 'fatbase/mod/vbox.ko', - 'fatbase/mod/vgadbg.ko', - 'fatbase/mod/vgalog.ko', - 'fatbase/mod/vidset.ko', - 'fatbase/mod/vmware.ko', - 'fatbase/mod/xtest.ko', - 'fatbase/mod/zero.ko', - 'fatbase/mod/tarfs.ko', - ]: - payload = ArbitraryData(path=mod_file) - payload.sector_offset = self.allocate_space(payload.size // 2048) - entry = ISODirectoryEntry() - entry.set_name(mod_file.replace('fatbase/mod/','').upper()) - entry.set_extent(payload.sector_offset, payload.actual_size) - o = entry.write(self.mods_data.data, o) - self.payloads.append(payload) - - # Set up the boot catalog and records - self.el_torito_catalog.sector_offset = self.allocate_space(1) - self.boot_record.set_catalog(self.el_torito_catalog.sector_offset) - self.boot_payload = ArbitraryData(path='cdrom/boot.sys') - self.boot_payload.sector_offset = self.allocate_space(self.boot_payload.size // 2048) - self.el_torito_catalog.initial_entry.data['sector_count'] = self.boot_payload.size // 512 - self.el_torito_catalog.initial_entry.data['load_rba'] = self.boot_payload.sector_offset - #self.el_torito_catalog.section.data['sector_count'] = 0 # Expected to be 0 or 1 for "until end of CD" - #self.el_torito_catalog.section.data['load_rba'] = self.fat_payload.sector_offset - self.primary_volume_descriptor.data['root_entry_data'] = make_entry() - - def allocate_space(self, sectors): - out = self.allocate - self.allocate += sectors - return out - - def write(self, file_name): - with open(file_name, 'wb') as f: - data = array.array('b',b'\0'*(2048*self.allocate)) - self.primary_volume_descriptor.write(data,0x10 * 2048) - self.root.write(data,0x10*2048 + 156) - self.boot_record.write(data,0x11 * 2048) - self.mods_data.write(data, self.mods_data.sector_offset * 2048) - self.root_data.write(data,self.root_data.sector_offset * 2048) - self.volume_descriptor_set_terminator.write(data,0x12 * 2048) - self.el_torito_catalog.write(data,self.el_torito_catalog.sector_offset * 2048) - self.boot_payload.write(data,self.boot_payload.sector_offset * 2048) - self.kernel_data.write(data,self.kernel_data.sector_offset * 2048) - self.ramdisk_data.write(data,self.ramdisk_data.sector_offset * 2048) - #self.fat_payload.write(data,self.fat_payload.sector_offset * 2048) - for payload in self.payloads: - payload.write(data,payload.sector_offset * 2048) - data.tofile(f) - -class ElToritoValidationEntry(Structure): - assert_size = 0x20 - fields = ( - ('B','header_id',1), - ('B','platform_id',0), - (' -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_URL "http://10.0.2.1:8080/netboot.img" - -#include -#include -#include "../lib/list.c" -#include "../lib/hashmap.c" -#include "terminal-font.h" - -extern int mount(char* src,char* tgt,char* typ,unsigned long,void*); - -#define SIZE 512 - -struct http_req { - char domain[SIZE]; - char path[SIZE]; - int port; - int ssl; -}; - -struct { - int show_headers; - const char * output_file; - const char * cookie; - FILE * out; -} fetch_options = {0}; - -#define TRACE(msg,...) do { \ - char tmp[512]; \ - sprintf(tmp, msg, ##__VA_ARGS__); \ - fprintf(stderr, "%s", tmp); \ - fflush(stderr); \ - print_string(tmp); \ -} while(0) - -static int has_video = 0; -static int width, height, depth; -static char * framebuffer; -static struct timeval start; -static int framebuffer_fd; - -#define char_height 20 -#define char_width 9 - -#define BG_COLOR 0xFF050505 -#define FG_COLOR 0xFFCCCCCC -#define EX_COLOR 0xFF999999 - -static void set_point(int x, int y, uint32_t value) { - uint32_t * disp = (uint32_t *)framebuffer; - uint32_t * cell = &disp[y * width + x]; - *cell = value; -} - -static void write_char(int x, int y, int val, uint32_t color) { - if (val > 128) { - val = 4; - } -#ifdef number_font - uint8_t * c = number_font[val]; - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - if (c[i] & (1 << (8-j))) { - set_point(x+j,y+i,color); - } else { - set_point(x+j,y+i,BG_COLOR); - } - } - } -#else - uint16_t * c = large_font[val]; - for (uint8_t i = 0; i < char_height; ++i) { - for (uint8_t j = 0; j < char_width; ++j) { - if (c[i] & (1 << (15-j))) { - set_point(x+j,y+i,color); - } else { - set_point(x+j,y+i,BG_COLOR); - } - } - } - -#endif -} - -#define BUF_SIZE 255 -static void read_http_line(char * buf, FILE * f) { - memset(buf, 0x00, BUF_SIZE); - - fgets(buf, BUF_SIZE, f); - char * _r = strchr(buf, '\r'); - if (_r) { - *_r = '\0'; - } - if (!_r) { - _r = strchr(buf, '\n'); /* that's not right, but, whatever */ - if (_r) { - *_r = '\0'; - } - } -} - -static unsigned short * textmemptr = (unsigned short *)0xB8000; -static void placech(unsigned char c, int x, int y, int attr) { - unsigned short *where; - unsigned att = attr << 8; - where = textmemptr + (y * 80 + x); - *where = c | att; -} - - -#define LEFT_PAD 40 -static int x = LEFT_PAD; -static int y = 0; -static int vx = 0; -static int vy = 0; -static void print_string(char * msg) { - if (!has_video) { - while (*msg) { - placech(' ',vx,vy,0); - switch (*msg) { - case '\n': - vx = 0; - vy += 1; - if (vy == 25) { - /* scroll */ - memcpy(textmemptr,textmemptr + 80,sizeof(unsigned short) * 80 * 24); - memset(textmemptr + 80 * 24, 0, sizeof(unsigned short) * 80); - vy = 24; - } - break; - case '\033': - msg++; - if (*msg == '[') { - msg++; - if (*msg == 'G') { - vx = 0; - } - if (*msg == 'K') { - int last_x = vx; - while (vx < 80) { - placech(' ',vx,vy,0); - vx++; - } - vx = last_x; - } - } - break; - default: - placech(*msg,vx,vy,0xF); - vx++; - break; - } - placech('_',vx,vy,0xF); - msg++; - } - } else { - while (*msg) { - write_char(x,y,' ',BG_COLOR); - switch (*msg) { - case '\n': - x = LEFT_PAD; - y += char_height; - if (y > height - 30) { - y = 0; - } - break; - case '\033': - msg++; - if (*msg == '[') { - msg++; - if (*msg == 'G') { - x = LEFT_PAD; - } - if (*msg == 'K') { - int last_x = x; - while (x < width) { - write_char(x,y,' ',FG_COLOR); - x += char_width; - } - x = last_x; - } - } - break; - default: - write_char(x,y,*msg,FG_COLOR); - x += char_width; - break; - } - write_char(x,y,'_',EX_COLOR); - msg++; - } - } -} - -void parse_url(char * d, struct http_req * r) { - if (strstr(d, "http://") == d) { - - d += strlen("http://"); - - char * s = strstr(d, "/"); - if (!s) { - strcpy(r->domain, d); - strcpy(r->path, ""); - } else { - *s = 0; - s++; - strcpy(r->domain, d); - strcpy(r->path, s); - } - if (strstr(r->domain,":")) { - char * port = strstr(r->domain,":"); - *port = '\0'; - port++; - r->port = atoi(port); - } else { - r->port = 80; - } - r->ssl = 0; - } else if (strstr(d, "https://") == d) { - - d += strlen("https://"); - - char * s = strstr(d, "/"); - if (!s) { - strcpy(r->domain, d); - strcpy(r->path, ""); - } else { - *s = 0; - s++; - strcpy(r->domain, d); - strcpy(r->path, s); - } - if (strstr(r->domain,":")) { - char * port = strstr(r->domain,":"); - *port = '\0'; - port++; - r->port = atoi(port); - } else { - r->port = 443; - } - r->ssl = 1; - } else { - TRACE("sorry, can't parse %s\n", d); - exit(1); - } -} - - -static void bad_response(void) { - TRACE("Bad response.\n"); - exit(1); -} - -static char * img = "/tmp/netboot.img"; - -static void update_video(int sig) { - (void)sig; - ioctl(framebuffer_fd, IO_VID_WIDTH, &width); - ioctl(framebuffer_fd, IO_VID_HEIGHT, &height); - ioctl(framebuffer_fd, IO_VID_DEPTH, &depth); - ioctl(framebuffer_fd, IO_VID_ADDR, &framebuffer); - ioctl(framebuffer_fd, IO_VID_SIGNAL, NULL); - /* Clear the screen */ - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - set_point(x,y,BG_COLOR); - } - } - x = LEFT_PAD; - y = 0; - - if (sig) { - TRACE("(video display changed to %d x %d)\n", width, height); - } -} - -static volatile int watchdog_success = 0; - -static void network_error(int is_thread) { - TRACE("\n\n"); - TRACE("ERROR: Network does not seem to be available, or unable to reach host.\n"); - TRACE(" Please check your VM configuration.\n"); - if (is_thread) { - pthread_exit(0); - } else { - exit(1); - } -} - -static void * watchdog_func(void * garbage) { - (void)garbage; - - int i = 0; - - while (i < 5) { - usleep(1000000); - if (watchdog_success) { - pthread_exit(0); - } - i++; - } - - network_error(1); - return NULL; -} - -#define BAR_WIDTH 20 -#define bar_perc "||||||||||||||||||||" -#define bar_spac " " -static void draw_progress(size_t content_length, size_t size) { - struct timeval now; - gettimeofday(&now, NULL); - - TRACE("\033[G%6dkB",(int)size/1024); - if (content_length) { - int percent = (size * BAR_WIDTH) / (content_length); - TRACE(" / %6dkB [%.*s%.*s]", (int)content_length/1024, percent,bar_perc,BAR_WIDTH-percent,bar_spac); - } - double timediff = (double)(now.tv_sec - start.tv_sec) + (double)(now.tv_usec - start.tv_usec)/1000000.0; - if (timediff > 0.0) { - double rate = (double)(size) / timediff; - double s = rate/(1024.0) * 8.0; - if (s > 1024.0) { - TRACE(" %.2f mbps", s/1024.0); - } else { - TRACE(" %.2f kbps", s); - } - - if (content_length) { - if (rate > 0.0) { - double remaining = (double)(content_length - size) / rate; - - TRACE(" (%.2f sec remaining)", remaining); - } - } - } - TRACE("\033[K"); -} - -static unsigned int crctab[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -/* This is taken from the kernel/sys/version.c */ -#if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER)) -# define COMPILER_VERSION "gcc " __VERSION__ -#elif (defined(__clang__)) -# define COMPILER_VERSION "clang " __clang_version__ -#else -# define COMPILER_VERSION "unknown-compiler how-did-you-do-that" -#endif - -int main(int argc, char * argv[]) { - int _stdin = open("/dev/null", O_RDONLY); - int _stdout = open("/dev/ttyS0", O_WRONLY); - int _stderr = open("/dev/ttyS0", O_WRONLY); - - if (_stdout < 0) { - _stdout = open("/dev/null", O_WRONLY); - _stderr = open("/dev/null", O_WRONLY); - } - - (void)_stdin; - (void)_stdout; - (void)_stderr; - - mount("x", "/tmp", "tmpfs", 0, NULL); - - int tmpfd = open("/proc/framebuffer", O_RDONLY); - if (tmpfd < 0) { - has_video = 0; - memset(textmemptr, 0, sizeof(unsigned short) * 80 * 25); - } else { - has_video = 1; - framebuffer_fd = open("/dev/fb0", O_RDONLY); - update_video(0); - signal(SIGWINEVENT, update_video); - } - - TRACE("\n\nToaruOS Netinit Host\n\n"); - - TRACE("ToaruOS is free software under the NCSA / University of Illinois license.\n"); - TRACE(" https://toaruos.org/ https://git.toaruos.org/klange/toaruos\n\n"); - - struct utsname u; - uname(&u); - TRACE("%s %s %s %s\n", u.sysname, u.nodename, u.release, u.version); - - { - char kernel_version[512] = {0}; - int fd = open("/proc/compiler", O_RDONLY); - read(fd, kernel_version, 512); - if (kernel_version[strlen(kernel_version)-1] == '\n') { - kernel_version[strlen(kernel_version)-1] = '\0'; - } - TRACE(" Kernel was built with: %s\n", kernel_version); - } - - TRACE(" Netinit binary was built with: %s\n", COMPILER_VERSION); - - TRACE("\n"); - - if (has_video) { - TRACE("Display is %dx%d (%d bpp), framebuffer at 0x%x\n", width, height, depth, (unsigned int)framebuffer); - } - - TRACE("\n"); - TRACE("Sleeping for a moment to let network initialize...\n"); - sleep(2); - -#define LINE_LEN 100 - char line[LINE_LEN]; - - FILE * f = fopen("/proc/netif", "r"); - - while (fgets(line, LINE_LEN, f) != NULL) { - if (strstr(line, "ip:") == line) { - char * value = strchr(line,'\t')+1; - *strchr(value,'\n') = '\0'; - TRACE(" IP address: %s\n", value); - } else if (strstr(line, "device:") == line) { - char * value = strchr(line,'\t')+1; - *strchr(value,'\n') = '\0'; - TRACE(" Network Driver: %s\n", value); - } else if (strstr(line, "mac:") == line) { - char * value = strchr(line,'\t')+1; - *strchr(value,'\n') = '\0'; - TRACE(" MAC address: %s\n", value); - } else if (strstr(line, "dns:") == line) { - char * value = strchr(line,'\t')+1; - *strchr(value,'\n') = '\0'; - TRACE(" DNS server: %s\n", value); - } else if (strstr(line, "gateway:") == line) { - char * value = strchr(line,'\t')+1; - *strchr(value,'\n') = '\0'; - TRACE(" Gateway: %s\n", value); - } else if (strstr(line,"no network") == line){ - network_error(0); - } - memset(line, 0, LINE_LEN); - } - - fclose(f); - - - struct http_req my_req; - /* TODO: Extract URL from kcmdline */ - if (argc < 2) { - parse_url(DEFAULT_URL, &my_req); - } else { - parse_url(argv[1], &my_req); - } - - char file[100]; - sprintf(file, "/dev/net/%s:%d", my_req.domain, my_req.port); - - TRACE("Fetching from %s... ", my_req.domain); - - fetch_options.out = fopen(img,"w+"); - - pthread_t watchdog; - - pthread_create(&watchdog, NULL, watchdog_func, NULL); - - f = fopen(file,"r+"); - if (!f) { - network_error(0); - } - -#if 0 - char * vbuf = malloc(10240); - setvbuf(f,vbuf,_IOLBF,10240); -#endif - - watchdog_success = 1; - - TRACE("Connection established.\n"); - - fprintf(f, - "GET /%s HTTP/1.0\r\n" - "User-Agent: curl/7.35.0\r\n" - "Host: %s\r\n" - "Accept: */*\r\n" - "\r\n", my_req.path, my_req.domain); - - gettimeofday(&start, NULL); - - hashmap_t * headers = hashmap_create(10); - - /* Parse response */ - { - char buf[BUF_SIZE]; - read_http_line(buf, f); - TRACE("[%s]\n", buf); - - char * elements[3]; - - elements[0] = buf; - elements[1] = strchr(elements[0], ' '); - if (!elements[1]) bad_response(); - *elements[1] = '\0'; - elements[1]++; - - elements[2] = strchr(elements[1], ' '); - if (!elements[2]) bad_response(); - *elements[2] = '\0'; - elements[2]++; - - if (strcmp(elements[1], "200")) { - TRACE("Bad response code: %s\n", elements[1]); - return 1; - } - } - - while (1) { - char buf[BUF_SIZE]; - read_http_line(buf, f); - - if (!*buf) { - TRACE("(done with headers)\n"); - break; - } - - /* Split */ - char * name = buf; - char * value = strstr(buf, ": "); - if (!value) bad_response(); - *value = '\0'; - value += 2; - - hashmap_set(headers, name, strdup(value)); - } - -#if 1 - TRACE("Dumping headers.\n"); - list_t * hash_keys = hashmap_keys(headers); - foreach(_key, hash_keys) { - char * key = (char *)_key->value; - TRACE("[%s] = %s\n", key, (char*)hashmap_get(headers, key)); - } - list_free(hash_keys); - free(hash_keys); -#endif - - /* determine how many bytes we should read now */ - if (!hashmap_has(headers, "Content-Length")) { - TRACE("Don't know how much to read.\n"); - return 1; - } - - int bytes_to_read = atoi(hashmap_get(headers, "Content-Length")); - size_t bytes_total = (size_t)bytes_to_read; - size_t bytes_read = 0; - -#define RBUF_SIZE 10240 - char * buf = malloc(RBUF_SIZE); - uint32_t crc32 = 0xffffffff; - while (bytes_to_read > 0) { - size_t r = fread(buf, 1, bytes_to_read < RBUF_SIZE ? bytes_to_read : RBUF_SIZE, f); - fwrite(buf, 1, r, fetch_options.out); - for (size_t i = 0; i < r; ++i) { - int ind = (crc32 ^ buf[i]) & 0xFF; - crc32 = (crc32 >> 8) ^ (crctab[ind]); - } - bytes_to_read -= r; - bytes_read += r; - draw_progress(bytes_total, bytes_read); - } - crc32 ^= 0xffffffff; - free(buf); - - TRACE("\nDone: 0x%x\n", (unsigned int)crc32); - - fflush(fetch_options.out); - fclose(fetch_options.out); - -#if 0 - FILE * xtmp = fopen(img, "r"); - crc32 = 0xffffffff; - int tab = 0; - size_t bytesread = 0; - while (!feof(xtmp)) { - uint8_t buf[1024]; - size_t r = fread(buf, 1, 1024, xtmp); - for (size_t i = 0; i < r; ++i) { - if (tab & 0x01) { - TRACE("%2x ", (unsigned char)buf[i]); - } else { - TRACE("%2x", (unsigned char)buf[i]); - } - tab++; - if (tab == 32){ - tab = 0; - TRACE("\n"); - } - int ind = (crc32 ^ buf[i]) & 0xFF; - crc32 = (crc32 >> 8) ^ (crctab[ind]); - } - bytesread += r; - } - crc32 ^= 0xffffffff; - TRACE("\nDisk crc32: 0x%x (%d)\n", (unsigned int)crc32, bytesread); -#endif - - TRACE("Mounting filesystem... "); - int err = 0; - if ((err = mount(img, "/", "ext2", 0, NULL))) { - TRACE("Mount error: %d; errno=%d\n", err, errno); - return 0; - } else { - TRACE("Done.\n"); - } - - FILE * tmp = fopen("/bin/init","r"); - if (!tmp) { - TRACE("/bin/init missing?\n"); - } else { - TRACE("/bin/init exists, filesystem successfully mounted\n"); - fclose(tmp); - } - - TRACE("Executing init...\n"); - char * const _argv[] = { - "/bin/init", - NULL, - }; - execve("/bin/init",_argv,NULL); - - TRACE("ERROR: If you are seeing this, there was a problem\n"); - TRACE(" executing the init binary from the downloaded\n"); - TRACE(" filesystem. This may indicate a corrupted\n"); - TRACE(" download. Please try again.\n"); - - return 0; -} diff --git a/util/optimize.py b/util/optimize.py deleted file mode 100644 index acc0800e..00000000 --- a/util/optimize.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -import glob -import os -import subprocess - -bmps = glob.glob("*.bmp") - -for i in bmps: - subprocess.run(["convert",i,"png32:"+i.replace(".bmp",".png")]) - bmp_size = os.stat(i).st_size - png_size = os.stat(i.replace(".bmp",".png")).st_size - - if bmp_size >= png_size: - print(f"{i}: keeping png") - os.remove(i) - else: - print(f"{i}: keeping bmp") - os.remove(i.replace(".bmp",".png")) - - diff --git a/util/patches/binutils.patch b/util/patches/binutils.patch deleted file mode 100644 index f1ea46ad..00000000 --- a/util/patches/binutils.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/bfd/config.bfd b/bfd/config.bfd -index b998830..3d6bdc4 100644 ---- a/bfd/config.bfd -+++ b/bfd/config.bfd -@@ -661,6 +661,10 @@ case "${targ}" in - targ_defvec=i386_elf32_vec - targ_selvecs="iamcu_elf32_vec i386_nlm32_vec i386_coff_vec i386_aout_vec" - ;; -+ i[3-7]86-*-toaru*) -+ targ_defvec=i386_elf32_vec -+ targ_selvecs= -+ ;; - i[3-7]86-*-linux*aout*) - targ_defvec=i386_aout_linux_vec - targ_selvecs="i386_elf32_vec iamcu_elf32_vec" -diff --git a/config.sub b/config.sub -index 2377e13..19fa153 100755 ---- a/config.sub -+++ b/config.sub -@@ -1375,6 +1375,7 @@ case $os in - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ -+ | -toaru* \ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ -diff --git a/gas/configure.tgt b/gas/configure.tgt -index e2df659..72a6bbf 100644 ---- a/gas/configure.tgt -+++ b/gas/configure.tgt -@@ -283,6 +283,7 @@ case ${generic_target} in - i386-*-chaos) fmt=elf ;; - i386-*-rdos*) fmt=elf ;; - i386-*-darwin*) fmt=macho ;; -+ i386-*-toaru*) fmt=elf ;; - - i860-*-*) fmt=elf endian=little ;; - -diff --git a/ld/configure.tgt b/ld/configure.tgt -index a3db909..13c4387 100644 ---- a/ld/configure.tgt -+++ b/ld/configure.tgt -@@ -269,6 +269,7 @@ x86_64-*-linux-*) targ_emul=elf_x86_64 - targ_extra_libpath="elf_i386 elf32_x86_64 elf_l1om elf_k1om" - tdir_i386linux=`echo ${targ_alias}aout | sed -e 's/x86_64/i386/'` - tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'` ;; -+i[3-7]86-*-toaru*) targ_emul=elf_i386 ;; - i[3-7]86-*-sysv[45]*) targ_emul=elf_i386 - targ_extra_emuls=elf_iamcu ;; - i[3-7]86-*-solaris2*) targ_emul=elf_i386_sol2 -diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh -index b08e661..7bd4bd5 100644 ---- a/ld/emulparams/elf_i386.sh -+++ b/ld/emulparams/elf_i386.sh -@@ -33,4 +33,8 @@ case "$target" in - ;; - esac - ;; -+ i[3-7]86*-toaru*) -+ TEXT_START_ADDR=0x40000000 -+ ;; - esac -+ diff --git a/util/patches/gcc.patch b/util/patches/gcc.patch deleted file mode 100644 index 9903e9e9..00000000 --- a/util/patches/gcc.patch +++ /dev/null @@ -1,127 +0,0 @@ -diff --git a/config.sub b/config.sub -index 41146e1..8438e24 100755 ---- a/config.sub -+++ b/config.sub -@@ -1375,6 +1375,7 @@ case $os in - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ -+ | -toaru* \ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ -diff --git a/fixincludes/mkfixinc.sh b/fixincludes/mkfixinc.sh -index 0d96c8c..1ae6bdc 100755 ---- a/fixincludes/mkfixinc.sh -+++ b/fixincludes/mkfixinc.sh -@@ -13,6 +13,7 @@ target=fixinc.sh - case $machine in - i?86-*-cygwin* | \ - i?86-*-mingw32* | \ -+ i?86-*-toaru* | \ - x86_64-*-mingw32* | \ - i?86-*-interix* | \ - powerpc-*-eabisim* | \ -diff --git a/gcc/config.gcc b/gcc/config.gcc -index 1d5b23f..603a22b 100644 ---- a/gcc/config.gcc -+++ b/gcc/config.gcc -@@ -820,6 +820,11 @@ case ${target} in - gnu_ld=yes - default_use_cxa_atexit=yes - ;; -+*-*-toaru*) -+ gas=yes -+ gnu_ld=yes -+ default_use_cxa_atexit=yes -+ ;; - *-*-rtems*) - case ${enable_threads} in - "" | yes | rtems) thread_file='rtems' ;; -@@ -1441,6 +1446,9 @@ x86_64-*-rdos*) - tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rdos.h i386/rdos64.h" - tmake_file="i386/t-i386elf t-svr4" - ;; -+*-*-toaru*) -+ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h glibc-stdint.h i386/i386elf.h toaru.h" -+ ;; - i[34567]86-*-dragonfly*) - tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h dragonfly.h dragonfly-stdint.h i386/dragonfly.h" - tmake_file="${tmake_file} i386/t-crtstuff" -diff --git a/gcc/config/toaru.h b/gcc/config/toaru.h -new file mode 100644 -index 0000000..9157525 ---- /dev/null -+++ b/gcc/config/toaru.h -@@ -0,0 +1,26 @@ -+#undef TARGET_OS_CPP_BUILTINS -+#define TARGET_OS_CPP_BUILTINS() \ -+ do { \ -+ builtin_define_std ("toaru"); \ -+ builtin_define_std ("unix"); \ -+ builtin_assert ("system=toaru"); \ -+ builtin_assert ("system=unix"); \ -+ } while (0); -+ -+#undef STARTFILE_SPEC -+#define STARTFILE_SPEC "%{!shared: %{!pg:crt0.o%s}} crti.o%s %{!shared:crtbegin.o%s}" -+ -+#undef ENDFILE_SPEC -+#define ENDFILE_SPEC "%{!shared:crtend.o%s} crtn.o%s" -+ -+#undef LINK_SPEC -+#define LINK_SPEC "%{shared:-shared} %{static:-static} %{!shared: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld.so}}}" -+ -+#undef LIB_SPEC -+#define LIB_SPEC "%{pthread:-lpthread} -lc" -+ -+#undef OBJECT_FORMAT_ELF -+#define OBJECT_FORMAT_ELF -+ -+#undef NO_IMPLICIT_EXTERN_C -+#define NO_IMPLICIT_EXTERN_C 1 -diff --git a/libgcc/config.host b/libgcc/config.host -index 124f2ce..c865054 100644 ---- a/libgcc/config.host -+++ b/libgcc/config.host -@@ -656,6 +656,10 @@ i[34567]86-*-solaris2* | x86_64-*-solaris2.1[0-9]*) - ;; - i[4567]86-wrs-vxworks|i[4567]86-wrs-vxworksae) - ;; -+i[34567]86-*-toaru*) -+ extra_parts="$extra_parts crtbegin.o crtend.o" -+ tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" -+ ;; - i[34567]86-*-cygwin*) - extra_parts="crtbegin.o crtbeginS.o crtend.o crtfastmath.o" - if test x$enable_vtable_verify = xyes; then -diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4 -index ece1256..97566e6 100644 ---- a/libstdc++-v3/crossconfig.m4 -+++ b/libstdc++-v3/crossconfig.m4 -@@ -248,6 +248,12 @@ case "${host}" in - GLIBCXX_CHECK_MATH_SUPPORT - GLIBCXX_CHECK_STDLIB_SUPPORT - ;; -+ *-toaru*) -+ GLIBCXX_CHECK_COMPILER_FEATURES -+ GLIBCXX_CHECK_LINKER_FEATURES -+ GLIBCXX_CHECK_MATH_SUPPORT -+ GLIBCXX_CHECK_STDLIB_SUPPORT -+ ;; - *-vxworks) - AC_DEFINE(HAVE_ACOSF) - AC_DEFINE(HAVE_ASINF) -diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits -index 03e198a..e0eb9d6 100644 ---- a/libstdc++-v3/include/std/type_traits -+++ b/libstdc++-v3/include/std/type_traits -@@ -38,7 +38,7 @@ - #include - - #ifdef _GLIBCXX_USE_C99_STDINT_TR1 --# if defined (__UINT_LEAST16_TYPE__) && defined(__UINT_LEAST32_TYPE__) -+# if defined (__UINT_LEAST16_TYPE__) && defined(__UINT_LEAST32_TYPE__) && 0 - namespace std - { - typedef __UINT_LEAST16_TYPE__ uint_least16_t; diff --git a/util/process_log.py b/util/process_log.py deleted file mode 100644 index dc47d42f..00000000 --- a/util/process_log.py +++ /dev/null @@ -1,77 +0,0 @@ -import struct -import sys - -addresses = {} -sources = {} -last_touched = {} - -def find_nearby_allocations(addr,size): - results = [] - for key in addresses.keys(): - if abs(addr - key) < size*2 and addresses[key]: - results.append(key) - results = sorted(results) - for key in results: - if key == addr: - print(" self: 0x%x (size %d, allocated by 0x%x)" % (key, addresses[key], sources[key])) - else: - print(" nearby: 0x%x (size %d, allocated by 0x%x)" % (key, addresses[key], sources[key])) - -count = 0 -while 1: - data = sys.stdin.read(17) - t, = struct.unpack_from("c",data,0) - addr, = struct.unpack_from("I",data,1) - size, = struct.unpack_from("I",data,5) - extra, = struct.unpack_from("I",data,9) - fault, = struct.unpack_from("I",data,13) - - count += 1 - if count % 1000 == 0: - print(count) - - if t == 'm': - addresses[addr] = size - sources[addr] = fault - last_touched[addr] = t - elif t == 'v': - addresses[addr] = size - sources[addr] = fault - last_touched[addr] = t - elif t == 'c': - addresses[addr] = 'c' - sources[addr] = 0 - last_touched[addr] = t - elif t == 'r': - if addr not in addresses: - print("Bad realloc: 0x%x" % addr) - else: - addresses[addr] = None - addresses[extra] = size - sources[extra] = fault - last_touched[addr] = t - last_touched[extra] = t - elif t == 'f': - if addr not in addresses: - print("Bad free detected: 0x%x" % addr) - elif addresses[addr] is None: - print("Double free detected: 0x%x (allocated by 0x%x)" % (addr,sources[addr])) - elif addresses[addr] == 'c': - print("freeing something that was calloced...") - addresses[addr] = None - elif extra != 0xDEADBEEF: - print("Large buffer has bad value: 0x%x (0x%x) expected size is %d, supposed is %d" % (addr, extra, addresses[addr], size)) - elif addresses[addr] != size: - print("Size on free is incorrect: 0x%x %d %d 0x%x allocated by 0x%x last touched by %c" % (addr,addresses[addr], size, fault, sources[addr], last_touched[addr])) - find_nearby_allocations(addr,addresses[addr]) - else: - addresses[addr] = None - elif t == 'h': - if addr not in addresses: - print("Spurious halt: 0x%x" % (addr)) - else: - print("Halting on suspected bug: 0x%x size was %d" % (addr, addresses[addr])) - else: - print("Garbage data detected: %c 0x%x %d 0xx" % (t, addr, size, extra)) - break - diff --git a/util/prompt.sh b/util/prompt.sh deleted file mode 100755 index 7cd50aab..00000000 --- a/util/prompt.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if ! $DIR/check-reqs.sh >&2; then - echo "A toolchain is not available and the above issues were found." >&2 - echo "Resolve the problems above and run \`make\` again." >&2 - echo -n "n" && exit 1 -fi - -echo -n "Toolchain has not been built. Would you like to build it now? (y/n) " >&2 -read response -case $response in - [yY]) bash $DIR/build-gcc.sh >&2 ;; - [nN]) echo -n "n" && exit 1 ;; - *) -esac - diff --git a/util/qemu-harness.py b/util/qemu-harness.py deleted file mode 100755 index d6aa5186..00000000 --- a/util/qemu-harness.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -""" -Harness for running QEMU and communicating window sizes through serial. -""" - -import subprocess -import asyncio -import time -import sys - -from Xlib.display import Display -from Xlib.protocol.event import KeyPress, KeyRelease -from Xlib.XK import string_to_keysym -import Xlib - -qemu_bin = 'qemu-system-i386' - -qemu = subprocess.Popen([ - qemu_bin, - '-enable-kvm', - '-cdrom','image.iso', - # 1GB of RAM - '-m','1G', - # Enable audio - '-soundhw','ac97,pcspk', - # The GTK interface does not play well, force SDL - '-display', 'sdl', - # /dev/ttyS0 is stdio multiplexed with monitor - '-serial', 'mon:stdio', - # /dev/ttyS1 is TCP connection to the harness - '-serial','tcp::4444,server,nowait', - # Add a VGA card with 32mb of video RAM - '-device', 'VGA,id=video0,vgamem_mb=32', - # Set the fwcfg flag so our userspace app recognizes us - '-fw_cfg','name=opt/org.toaruos.displayharness,string=1', - # Boot directly to graphical mode - '-fw_cfg','name=opt/org.toaruos.bootmode,string=normal' -]) - -# Give QEMU some time to start up and create a window. -time.sleep(1) - -# Find the QEMU window... -def findQEMU(window): - try: - x = window.get_wm_name() - if 'QEMU' in x: - return window - except: - pass - children = window.query_tree().children - for w in children: - x = findQEMU(w) - if x: return x - return None - -display = Display() -root = display.screen().root -qemu_win = findQEMU(root) - -def send_key(key, state, up=False): - """Send a key press or release to the QEMU window.""" - time.sleep(0.1) - t = KeyPress - if up: - t = KeyRelease - - sym = string_to_keysym(key) - ke = t( - time=int(time.time()), - root=display.screen().root, - window=qemu_win, - same_screen=0, - child=Xlib.X.NONE, - root_x = 0, root_y = 0, event_x = 0, event_y = 0, - state = 0xc, - detail = display.keysym_to_keycode(sym) - ) - qemu_win.send_event(ke) - display.flush() - -class Client(asyncio.Protocol): - - def connection_made(self, transport): - asyncio.ensure_future(heartbeat(transport)) - - def data_received(self, data): - if 'X' in data.decode('utf-8'): - # Send Ctrl-Alt-u - send_key('Control_L',0x00) - send_key('Alt_L',0x04) - send_key('u',0x0c) - send_key('u',0x0c,True) - send_key('Alt_L',0x0c,True) - send_key('Control_L',0x04,True) - -async def heartbeat(transport): - """Heartbeat process checks window size every second and sends update signal.""" - w = 0 - h = 0 - while 1: - await asyncio.sleep(1) - try: - g = qemu_win.get_geometry() - except Xlib.error.BadDrawable: - print("QEMU window is gone, exiting.") - asyncio.get_event_loop().call_soon(sys.exit, 0) - return - if g.width != w or g.height != h: - transport.write(("geometry-changed %d %d\n" % (g.width,g.height)).encode('utf-8')) - w = g.width - h = g.height - -loop = asyncio.get_event_loop() -coro = loop.create_connection(Client,'127.0.0.1',4444) -asyncio.ensure_future(coro) -loop.run_forever() -loop.close() - diff --git a/util/qemu.sh b/util/qemu.sh deleted file mode 100644 index d402a018..00000000 --- a/util/qemu.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -qemu-system-x86_64 \ --kernel fatbase/kernel \ --initrd \ -fatbase/mod/zero.ko,\ -fatbase/mod/random.ko,\ -fatbase/mod/serial.ko,\ -fatbase/mod/debug_sh.ko,\ -fatbase/mod/procfs.ko,\ -fatbase/mod/tmpfs.ko,\ -fatbase/mod/ata.ko,\ -fatbase/mod/ext2.ko,\ -fatbase/mod/ps2kbd.ko,\ -fatbase/mod/ps2mouse.ko,\ -fatbase/mod/lfbvideo.ko,\ -fatbase/mod/vbox.ko,\ -fatbase/mod/vmware.ko,\ -fatbase/mod/vidset.ko,\ -fatbase/mod/packetfs.ko,\ -fatbase/mod/snd.ko,\ -fatbase/mod/ac97.ko,\ -fatbase/mod/net.ko,\ -fatbase/mod/pcnet.ko,\ -fatbase/mod/rtl.ko,\ -fatbase/mod/e1000.ko,\ -fatbase/mod/pcspkr.ko,\ -fatbase/mod/portio.ko,\ -fatbase/mod/tarfs.ko,\ -fatbase/ramdisk.img \ --append "root=/dev/ram0 root_type=tar logtoserial=2 vid=qemu" \ --enable-kvm \ --serial mon:stdio \ --m 1G -soundhw ac97,pcspk - diff --git a/util/readline._py b/util/readline._py deleted file mode 100644 index 5225d32b..00000000 --- a/util/readline._py +++ /dev/null @@ -1,100 +0,0 @@ -import ctypes - -auto_history = True - -py = ctypes.CDLL("libpython3.6m.so") -rline_lib = ctypes.CDLL("libtoaru_rline_exp.so") - -readline_func = ctypes.c_void_p.in_dll(py,"PyOS_ReadlineFunctionPointer") -t = ctypes.c_char_p.in_dll(rline_lib,"rline_exp_for_python") -readline_func.value = ctypes.addressof(t) - -# Change exit string to "exit()" -exit_string_lib = ctypes.c_char_p.in_dll(rline_lib,"rline_exit_string") -exit_string = ctypes.c_char_p(b"") -exit_string_lib.value = exit_string.value - -def parse_and_bind(s): - pass - -def read_init_file(filename=None): - pass - -def get_line_buffer(): - return None - -def insert_text(string): - return None - -def redisplay(): - pass - -def read_history_file(filename): - pass - -def write_history_file(filename): - pass - -def append_history_file(nelements,filename=None): - pass - -def get_history_length(): - return 0 - -def set_history_length(length): - pass - -def clear_history(): - pass - -def get_current_history_length(): - return ctypes.c_int.in_dll(rline_lib,"rline_history_count").value - -def get_history_item(index): - if index < 1 or index > get_current_history_length(): - raise ValueError("bad history index") - index -= 1 - return cast(rline_lib.rline_history_get(index), c_char_p).value.decode('utf-8') - -def remove_history_item(pos): - pass - -def replace_history_item(pos, item): - pass - -def add_history(line): - rline_lib.rline_history_insert(line.encode('utf-8')) - -def set_auto_history(enabled): - auto_history = enabled - -def set_startup_hook(func=None): - pass - -def set_pre_input_hook(func=None): - pass - -def set_completer(func=None): - pass - -def get_completer(): - return None - -def get_completion_type(): - return None - -def get_begidx(): - return 0 - -def get_endidx(): - return 0 - -def set_completer_delims(string): - pass - -def get_completer_delims(): - return "" - -def set_completion_display_matches_hook(func=None): - pass - diff --git a/util/ungz.c b/util/ungz.c deleted file mode 100644 index cce8327b..00000000 --- a/util/ungz.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vim: ts=4 sw=4 noexpandtab - * Really dumb wrapper around gzopen/gzread - * - * build with: - * i686-pc-toaru-gcc -o base/usr/bin/ungz ungz.c -lz - */ -#include -#include -#include -#include - -int main(int argc, char **argv) { - int ret; - - if (argc < 2) { - fprintf(stderr, "Usage: %s file.gz\n", argv[0]); - return 1; - } - - char * dest_name = NULL; - - if (argc < 3) { - if (strstr(argv[1],".gz") != (argv[1] + strlen(argv[1]) - 3)) { - fprintf(stderr, "%s: Not sure if this file is gzipped. Try renaming it to include `.gz' at the end.\n", argv[0]); - return 1; - } - dest_name = strdup(argv[1]); - char * t = strstr(dest_name,".gz"); - *t = '\0'; - } else { - dest_name = argv[2]; - } - - gzFile src = gzopen(argv[1], "r"); - - if (!src) return 1; - - FILE * dest = fopen(dest_name, "w"); - - if (!dest) return 1; - - while (!gzeof(src)) { - char buf[1024]; - int r = gzread(src, buf, 1024); - if (r < 0) return 1; - fwrite(buf, r, 1, dest); - } - - fclose(dest); - - unlink(argv[1]); - - return 0; -} diff --git a/util/update-devtable.py b/util/update-devtable.py deleted file mode 100755 index e47893ab..00000000 --- a/util/update-devtable.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -import os -from pathlib import Path - -def getPaths(base): - out = [] - for root, dirs, files in os.walk(base): - for i in dirs: - out.append(os.path.join(root,i)) - for i in files: - out.append(os.path.join(root,i)) - return out - -with open('util/devtable','w') as devtable: - - # Set sudo apps to setuid, executable, no write - devtable.write('/bin/gsudo f 4555 0 0 - - - - -\n') - devtable.write('/bin/sudo f 4555 0 0 - - - - -\n') - - # Set master.passwd to not be visible except by root - devtable.write('/etc/master.passwd f 600 0 0 - - - - -\n') # /etc/master.passwd should be restricted - devtable.write('/etc/sudoers f 600 0 0 - - - - -\n') - - # Copy permissions and set ownership for user files - for user_details in [('local',1000)]: - user, uid = user_details - devtable.write('/home/{user} d 755 {uid} {uid} - - - - -\n'.format(user=user,uid=uid)) - for path in getPaths('./base/home/{user}'.format(user=user)): - p = Path(path) - path_mod = path.replace('./base','').rstrip('/') - path_type = 's' if p.is_symlink() else ('d' if p.is_dir() else 'f') - st = os.stat(path) - mode = '{:o}'.format(st.st_mode & 0o7777) - devtable.write('{path_mod} {path_type} {mode} {uid} {uid} - - - - -\n'.format(path_mod=path_mod,path_type=path_type,mode=mode,uid=uid)) - - # Special case /tmp to allow all users to write - devtable.write('/tmp d 777 0 0 - - - - -\n') - devtable.write('/var d 755 0 0 - - - - -\n') - diff --git a/util/update-extents.py b/util/update-extents.py deleted file mode 100755 index 337d07b1..00000000 --- a/util/update-extents.py +++ /dev/null @@ -1,303 +0,0 @@ -#!/usr/bin/env python3 -import array -import struct - -def read_struct(fmt,buf,offset): - out, = struct.unpack_from(fmt,buf,offset) - return out, offset + struct.calcsize(fmt) - -class ISO(object): - - def __init__(self, path): - with open(path, 'rb') as f: - tmp = f.read() - self.data = array.array('b', tmp) - self.sector_size = 2048 - o = 0x10 * self.sector_size - self.type, o = read_struct('B',self.data,o) - self.id, o = read_struct('5s',self.data,o) - self.version, o = read_struct('B',self.data,o) - _unused0, o = read_struct('B',self.data,o) - self.system_id, o = read_struct('32s',self.data,o) - self.volume_id, o = read_struct('32s',self.data,o) - _unused1, o = read_struct('8s',self.data,o) - self.volume_space_lsb, o = read_struct('I',self.data,o) - _unused2, o = read_struct('32s',self.data,o) - self.volume_set_lsb, o = read_struct('H',self.data,o) - self.volume_seq_lsb, o = read_struct('H',self.data,o) - self.logical_block_size_lsb, o = read_struct('H',self.data,o) - self.path_table_size_lsb, o = read_struct('I',self.data,o) - self.path_table_lsb, o = read_struct('I',self.data,o) - self.optional_path_table_msb, o = read_struct('>I',self.data,o) - _offset = o - self.root_dir_entry, o = read_struct('34s',self.data,o) - - self.root = ISOFile(self,_offset) - self._cache = {} - - def get_file(self, path): - if path == '/': - return self.root - else: - if path in self._cache: - return self._cache[path] - units = path.split('/') - units = units[1:] # remove root - me = self.root - for i in units: - next_file = me.find(i) - if not next_file: - me = None - break - else: - me = next_file - self._cache[path] = me - return me - -class ISOFile(object): - - def __init__(self, iso, offset): - self.iso = iso - self.offset = offset - - o = offset - self.length, o = read_struct('B', self.iso.data, o) - if not self.length: - return - self.ext_length, o = read_struct('B', self.iso.data, o) - self.extent_start_lsb, o = read_struct('I',self.iso.data, o) - self.extent_length_lsb, o = read_struct('I',self.iso.data, o) - - self.date_data, o = read_struct('7s', self.iso.data, o) - - self.flags, o = read_struct('b', self.iso.data, o) - self.interleave_units, o = read_struct('b', self.iso.data, o) - self.interleave_gap, o = read_struct('b', self.iso.data, o) - - self.volume_seq_lsb, o = read_struct('H',self.iso.data, o) - - self.name_len, o = read_struct('b', self.iso.data, o) - self.name, o = read_struct('{}s'.format(self.name_len), self.iso.data, o) - self.name = self.name.decode('ascii') - - def write_extents(self): - struct.pack_into('I', self.iso.data, self.offset + 6, self.extent_start_lsb) - struct.pack_into('I', self.iso.data, self.offset + 14, self.extent_length_lsb) - - def readable_name(self): - if not ';' in self.name: - return self.name.lower() - else: - tmp, _ = self.name.split(';') - return tmp.lower() - - - def list(self): - sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size] - offset = 0 - - while 1: - f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset) - yield f - offset += f.length - if not f.length: - break - - def find(self, name): - sectors = self.iso.data[self.extent_start_lsb * self.iso.sector_size: self.extent_start_lsb * self.iso.sector_size+ 3 * self.iso.sector_size] - offset = 0 - if '.' in name and len(name.split('.')[0]) > 8: - a, b = name.split('.') - name = a[:8] + '.' + b - if '-' in name: - name = name.replace('-','_') - while 1: - f = ISOFile(self.iso, self.extent_start_lsb * self.iso.sector_size + offset) - if not f.length: - if offset < self.extent_length_lsb: - offset += 1 - continue - else: - break - if ';' in f.name: - tmp, _ = f.name.split(';') - if tmp.endswith('.'): - tmp = tmp[:-1] - if tmp.lower() == name.lower(): - return f - elif f.name.lower() == name.lower(): - return f - offset += f.length - return None - -class FAT(object): - - def __init__(self, iso, offset): - self.iso = iso - self.offset = offset - - self.bytespersector, _ = read_struct('H', self.iso.data, offset + 11) - self.sectorspercluster, _ = read_struct('B', self.iso.data, offset + 13) - self.reservedsectors, _ = read_struct('H', self.iso.data, offset + 14) - self.numberoffats, _ = read_struct('B', self.iso.data, offset + 16) - self.numberofdirs, _ = read_struct('H', self.iso.data, offset + 17) - self.fatsize, _ = read_struct('H', self.iso.data, offset + 22) - - self.root_dir_sectors = (self.numberofdirs * 32 + (self.bytespersector - 1)) // self.bytespersector - self.first_data_sector = self.reservedsectors + (self.numberoffats * self.fatsize) + self.root_dir_sectors - self.root_sector= self.first_data_sector - self.root_dir_sectors - self.root = FATDirectory(self, self.offset + self.root_sector * self.bytespersector) - - def get_offset(self, cluster): - return self.offset + ((cluster - 2) * self.sectorspercluster + self.first_data_sector) * self.bytespersector - - def get_file(self, path): - units = path.split('/') - units = units[1:] - - me = self.root - out = None - for i in units: - for fatfile in me.list(): - if fatfile.readable_name() == i: - me = fatfile.to_dir() - out = fatfile - break - else: - return None - return out - -class FATDirectory(object): - - def __init__(self, fat, offset): - - self.fat = fat - self.offset = offset - - def list(self): - - o = self.offset - while 1: - out = FATFile(self.fat, o) - if out.name != '\0\0\0\0\0\0\0\0': - yield out - else: - break - o += out.size - - -class FATFile(object): - - def __init__(self, fat, offset): - - self.fat = fat - self.offset = offset - self.magic_long = None - self.size = 0 - self.long_name = '' - - o = self.offset - self.actual_offset = o - - self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) - - while (self.attrib & 0x0F) == 0x0F: - # Long file name entry - tmp = read_struct('10s',self.fat.iso.data,o+1)[0] - tmp += read_struct('12s',self.fat.iso.data,o+14)[0] - tmp += read_struct('4s',self.fat.iso.data,o+28)[0] - tmp = "".join([chr(x) for x in tmp[::2] if x != '\xFF']).strip('\x00') - self.long_name = tmp + self.long_name - self.size += 32 - o = self.offset + self.size - self.actual_offset = o - self.attrib, _ = read_struct('B',self.fat.iso.data,o+11) - - o = self.offset + self.size - - self.name, o = read_struct('8s',self.fat.iso.data,o) - self.ext, o = read_struct('3s',self.fat.iso.data,o) - self.attrib, o = read_struct('B',self.fat.iso.data,o) - self.userattrib, o = read_struct('B',self.fat.iso.data,o) - self.undelete, o = read_struct('b',self.fat.iso.data,o) - self.createtime, o = read_struct('H',self.fat.iso.data,o) - self.createdate, o = read_struct('H',self.fat.iso.data,o) - self.accessdate, o = read_struct('H',self.fat.iso.data,o) - self.clusterhi, o = read_struct('H',self.fat.iso.data,o) - self.modifiedti, o = read_struct('H',self.fat.iso.data,o) - self.modifiedda, o = read_struct('H',self.fat.iso.data,o) - self.clusterlow, o = read_struct('H',self.fat.iso.data,o) - self.filesize, o = read_struct('I',self.fat.iso.data,o) - - self.name = self.name.decode('ascii') - self.ext = self.ext.decode('ascii') - - self.size += 32 - - self.cluster = (self.clusterhi << 16) + self.clusterlow - - def is_dir(self): - return bool(self.attrib & 0x10) - - def is_long(self): - return bool((self.attrib & 0x0F) == 0x0F) - - def to_dir(self): - return FATDirectory(self.fat, self.fat.get_offset(self.cluster)) - - def get_offset(self): - return self.fat.get_offset(self.cluster) - - def readable_name(self): - if self.long_name: - return self.long_name - if self.ext.strip(): - return (self.name.strip() + '.' + self.ext.strip()).lower() - else: - return self.name.strip().lower() - - -image = ISO('image.iso') -fat = image.root.find('FAT.IMG') - -fatfs = FAT(image, fat.extent_start_lsb * image.sector_size) - -def process(fatfile, path): - if fatfile.is_long(): - return - if fatfile.readable_name() == '.': - return - if fatfile.readable_name() == '..': - return - if fatfile.is_dir(): - for i in fatfile.to_dir().list(): - process(i, path + fatfile.readable_name() + '/') - else: - cdfile = image.get_file(path + fatfile.readable_name()) - if not cdfile: - if fatfile.readable_name() != 'bootia32.efi' and fatfile.readable_name() != 'bootx64.efi': - print("Warning:", fatfile.readable_name(), "not found in ISO") - else: - cdfile.extent_start_lsb = fatfile.get_offset() // 2048 - cdfile.extent_length_lsb = fatfile.filesize - cdfile.write_extents() - - -for i in fatfs.root.list(): - process(i,'/') - -with open('image.iso','wb') as f: - f.write(image.data) -