openblt

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit bd15c8cdcface9cbd7ddc13b78c501445a53d769
Author: Brian Swetland <swetland@frotz.net>
Date:   Thu, 11 Jul 2013 18:09:44 -0700

OpenBLT snapshot from early 2000

Diffstat:
ALICENSE | 27+++++++++++++++++++++++++++
AMakefile | 41+++++++++++++++++++++++++++++++++++++++++
Abin/Makefile | 7+++++++
Abin/bltsh/Makefile | 9+++++++++
Abin/bltsh/bltsh.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/cat/Makefile | 8++++++++
Abin/cat/cat.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/fdisk/Makefile | 9+++++++++
Abin/fdisk/fdisk.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/ls/Makefile | 9+++++++++
Abin/ls/ls.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/mkdir/Makefile | 8++++++++
Abin/mkdir/mkdir.c | 42++++++++++++++++++++++++++++++++++++++++++
Abin/pci/Makefile | 9+++++++++
Abin/pci/pci.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/pci/pci.h | 31+++++++++++++++++++++++++++++++
Abin/sysinfo/Makefile | 11+++++++++++
Abin/sysinfo/sysinfo.cpp | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/tell/Makefile | 8++++++++
Abin/tell/tell.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/tests/Makefile | 10++++++++++
Abin/tests/tests.cpp | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/uname/Makefile | 8++++++++
Abin/uname/uname.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/validate/Makefile | 8++++++++
Abin/validate/validate.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/vfs_test/Makefile | 14++++++++++++++
Abin/vfs_test/foo.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/vfs_test/vfs_test.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/winapp/Connection.o | 0
Abin/winapp/Makefile | 10++++++++++
Abin/winapp/Window.o | 0
Abin/winapp/main.cpp | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aboot/Makefile | 12++++++++++++
Aboot/boot.c | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aboot/bootstub.S | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aboot/fs.ini | 33+++++++++++++++++++++++++++++++++
Aboot/grub | 0
Aboot/grub_e2fs | 0
Aboot/grub_fat | 0
Aboot/grub_ffs | 0
Aboot/grubxx | 0
Aboot/misc.ini | 43+++++++++++++++++++++++++++++++++++++++++++
Aboot/net2.ini | 30++++++++++++++++++++++++++++++
Aboot/openblt.ini | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aboot/window.ini | 13+++++++++++++
Abuild/GENERIC/Makefile | 19+++++++++++++++++++
Abuild/GENERIC/openblt.ini | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/VULCAN/Makefile | 22++++++++++++++++++++++
Abuild/VULCAN/openblt.ini | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/VULCAN/rc | 17+++++++++++++++++
Adoc/TODO | 42++++++++++++++++++++++++++++++++++++++++++
Adoc/add-syscall | 44++++++++++++++++++++++++++++++++++++++++++++
Adoc/boot.html | 190+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/ipcdocs | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/notes | 9+++++++++
Adoc/openblt.html | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/vfs.txt | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aetc/rc | 24++++++++++++++++++++++++
Aetc/rc.boot | 15+++++++++++++++
Ainclude/ansi.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/Connection.h | 35+++++++++++++++++++++++++++++++++++
Ainclude/blt/Message.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/atomic.h | 44++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/blkdev.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/conio.h | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/disk.h | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/error.h | 44++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/fdl.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/hash.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/libsyms.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/namer.h | 27+++++++++++++++++++++++++++
Ainclude/blt/network/eth.h | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/network/ipv4.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/network/mbuf.h | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/network/module.h | 44++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/os.h | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/qsem.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/syscall.h | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/syscall_id.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/tell.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/types.h | 43+++++++++++++++++++++++++++++++++++++++++++
Ainclude/blt/vfs.h | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/boot.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/ctype.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Ainclude/dirent.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/dlfcn.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/elf.h | 236+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/errno.h | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/fcntl.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/i386/asm.h | 40++++++++++++++++++++++++++++++++++++++++
Ainclude/i386/io.h | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/i386/io.h.new | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/multiboot.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/stdarg.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/stddef.h | 35+++++++++++++++++++++++++++++++++++
Ainclude/stdio.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/stdlib.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/string.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/sys/ioctl.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Ainclude/sys/stat.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/sys/types.h | 44++++++++++++++++++++++++++++++++++++++++++++
Ainclude/unistd.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/win/Button.h | 21+++++++++++++++++++++
Ainclude/win/Canvas.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/win/Event.h | 20++++++++++++++++++++
Ainclude/win/Window.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Akernel/Makefile | 18++++++++++++++++++
Akernel/aspace.c | 453+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/aspace.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/cpuid.S | 43+++++++++++++++++++++++++++++++++++++++++++
Akernel/debug.c | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/fault.c | 329+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/i386.c | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/i386.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/init.h | 33+++++++++++++++++++++++++++++++++
Akernel/jump.S | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/kernel.c | 448+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/kernel.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/ktrace.c | 332+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/list.c | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/list.h | 44++++++++++++++++++++++++++++++++++++++++++++
Akernel/memory.c | 302++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/memory.h | 37+++++++++++++++++++++++++++++++++++++
Akernel/pager.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/pager.h | 27+++++++++++++++++++++++++++
Akernel/port.c | 244+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/port.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/resource.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/resource.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/rights.c | 29+++++++++++++++++++++++++++++
Akernel/rights.h | 38++++++++++++++++++++++++++++++++++++++
Akernel/sem.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/sem.h | 22++++++++++++++++++++++
Akernel/smp.c | 583+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/smp.h | 200+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/stub.c | 30++++++++++++++++++++++++++++++
Akernel/syscall.c | 279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/task.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/task.h | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/team.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/team.h | 25+++++++++++++++++++++++++
Akernel/trampoline.S | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akernel/types.h | 24++++++++++++++++++++++++
Alib/Makefile | 28++++++++++++++++++++++++++++
Alib/c++rt0.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/crt0.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/crtb.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/Connection.cpp | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/Makefile | 11+++++++++++
Alib/libblt/Message.cpp | 312+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/blkdev.c | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/disk.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/hash.c | 234+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/namer.cpp | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libblt/tell.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/Makefile | 19+++++++++++++++++++
Alib/libc/atomic.S | 45+++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/cppglue.cpp | 33+++++++++++++++++++++++++++++++++
Alib/libc/ctype.c | 38++++++++++++++++++++++++++++++++++++++
Alib/libc/errno.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/malloc.c | 2878+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/malloc.h | 46++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/memory.c | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/qsem.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/qsort.c | 174+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/snprintf.c | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/stdlib.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/strcmp.S | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/strcpy.S | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/string.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/strlcat.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/strlcpy.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libc/strlen.S | 23+++++++++++++++++++++++
Alib/libc/syscalls.S | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libconsole/Makefile | 8++++++++
Alib/libconsole/conio.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libdl/Makefile | 16++++++++++++++++
Alib/libdl/dl-int.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libdl/elf.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libdl/load.c | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libdl/rtld.c | 14++++++++++++++
Alib/libdl/sym.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/Makefile | 10++++++++++
Alib/libposix/console.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/exec.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/fdl.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/getopt.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/printf.c | 44++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/stdio.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libposix/vfs.c | 353+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libwin/Button.cpp | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libwin/Canvas.cpp | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libwin/Connection.cpp | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libwin/Connection.h | 35+++++++++++++++++++++++++++++++++++
Alib/libwin/Makefile | 9+++++++++
Alib/libwin/Window.cpp | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/version.c | 3+++
Amake.actions | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amake.conf | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/Makefile | 37+++++++++++++++++++++++++++++++++++++
Anetboot/crt0.c | 33+++++++++++++++++++++++++++++++++
Anetboot/err.h | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/go | 5+++++
Anetboot/io.h | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/makerom.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/ne2000.c | 627+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/ne2000.h | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/ne2k.h | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/net.h | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/netboot.c | 701+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/netboot.h | 43+++++++++++++++++++++++++++++++++++++++++++
Anetboot/netrom.asm | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anetboot/netrom.bin | 0
Anetboot/pci.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/Makefile | 6++++++
Asrv/console2/Makefile | 9+++++++++
Asrv/console2/console.c | 368+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/console2/vt100.c | 464+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/console2/vt100.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrv/fb/Makefile | 9+++++++++
Asrv/fb/fb.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fb/fb.h | 21+++++++++++++++++++++
Asrv/fb/mga1x64.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fb/mga1x64.h | 30++++++++++++++++++++++++++++++
Asrv/fb/pci.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fb/pci.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fish/Makefile | 9+++++++++
Asrv/fish/dfp.h | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fish/fish.c | 1020+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fish/font.h | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fish/vga.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/fish/vga.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ide/Makefile | 9+++++++++
Asrv/ide/TODO | 16++++++++++++++++
Asrv/ide/blkdev.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ide/disk.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ide/ide-int.h | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ide/identify.c | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ide/main.c | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/init/Makefile | 9+++++++++
Asrv/init/init.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/namer/Makefile | 9+++++++++
Asrv/namer/namer.cpp | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/Makefile | 10++++++++++
Asrv/ne2000/err.h | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/ne2000.c | 858+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/ne2000.h | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/ne2k.c | 609+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/ne2k.h | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/net.h | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/ne2000/pciglue.cpp | 35+++++++++++++++++++++++++++++++++++
Asrv/network/Makefile | 10++++++++++
Asrv/network/device/Makefile | 6++++++
Asrv/network/device/ne/Makefile | 9+++++++++
Asrv/network/device/ne/defs.h | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/device/ne/err.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/device/ne/ne2000.c | 860+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/device/ne/ne2000.h | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/device/ne/support.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/device/ne/wrap.c | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/device/ne/wrap.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrv/network/mbuf.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/network.c | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/protocol/Makefile | 6++++++
Asrv/network/protocol/arp/Makefile | 8++++++++
Asrv/network/protocol/arp/arp.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/protocol/eth/Makefile | 8++++++++
Asrv/network/protocol/eth/eth.c | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/network/protocol/ipv4/Makefile | 8++++++++
Asrv/network/protocol/ipv4/iface.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/pci/Makefile | 9+++++++++
Asrv/pci/pci.c | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/pci/pci.h | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/pci/server.cpp | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/Makefile | 14++++++++++++++
Asrv/vfs/bootfs.c | 317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/bootfs.h | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/Makefile | 6++++++
Asrv/vfs/drivers/ffs/Makefile | 9+++++++++
Asrv/vfs/drivers/ffs/dinode.h | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/dir.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/dir.h | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/ffs-blt.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/ffs.h | 520+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/file.c | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/inode.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/drivers/ffs/super.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/fs.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/path.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/path.h | 36++++++++++++++++++++++++++++++++++++
Asrv/vfs/rootfs.c | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/rootfs.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/sandbox/Makefile | 14++++++++++++++
Asrv/vfs/sandbox/README | 17+++++++++++++++++
Asrv/vfs/sandbox/blkdev.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/sandbox/blkdev.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/sandbox/hash.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/sandbox/types.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/sandbox/vfs.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/shm.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/shm.h | 40++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/super.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/vfs-int.h | 211+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/vfs.c | 671+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/vfs/vnode.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/GraphicsContext.cpp | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/GraphicsContext.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Makefile | 13+++++++++++++
Asrv/window/Rect.h | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Region.cpp | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Region.h | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Renderer.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Renderer_8bpp.cpp | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Renderer_8bpp.h | 20++++++++++++++++++++
Asrv/window/Renderer_vga.cpp | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Renderer_vga.h | 30++++++++++++++++++++++++++++++
Asrv/window/SerialMouse.cpp | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/SerialMouse.h | 24++++++++++++++++++++++++
Asrv/window/Window.cpp | 303+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/Window.h | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/WindowManager.cpp | 524+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/WindowManager.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/assert.h | 7+++++++
Asrv/window/font.h | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/main.cpp | 290+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/protocol.h | 20++++++++++++++++++++
Asrv/window/util.h | 7+++++++
Asrv/window/vga.cpp | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrv/window/vga.h | 34++++++++++++++++++++++++++++++++++
Autil/Makefile | 26++++++++++++++++++++++++++
Autil/blt-link | 13+++++++++++++
Autil/blt_i386.x | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/bootblock.h | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/bootmaker.c | 414+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/dfp.h | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/dumph.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/dumphex.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/fishfinder.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/ic.c | 368+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil/namer.ifc | 15+++++++++++++++
Autil/netboot.c | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
342 files changed, 40442 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,27 @@ +/* $Id: //depot/blt/LICENSE#6 $ +** +** Copyright 1999 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/Makefile b/Makefile @@ -0,0 +1,41 @@ +BLTHOME := . +include make.conf + +ifeq ($(BUILDLOG),) +BUILDLOG := `pwd`/build.log +endif + +SUBDIRS := lib kernel srv boot bin util + +image: log subdirs + ./util/bootmaker $(INIFILES) $(LOCALINIFILES) -o boot/openblt.boot + +floppy: subdirs + ./util/bootmaker $(INIFILES) $(LOCALINIFILES) -o boot/openblt.boot --floppy + +fimage: floppy + dd if=/dev/zero of=fd.img bs=1024 count=1440 + dd if=boot/openblt.boot of=fd.img conv=notrunc + +bfloppy: floppy + dd if=boot/openblt.boot of=/dev/disk/floppy/raw bs=18k + +lfloppy: floppy + dd if=boot/openblt.boot of=/dev/fd0 bs=18k + +run: image + ./util/netboot boot/openblt.boot $(IP) + +go: + ./util/bootmaker $(INIFILES) $(LOCALINIFILES) -o boot/openblt.boot + ./util/netboot boot/openblt.boot $(IP) + +all:: log + +log:: + @echo "### `date`" > $(BUILDLOG) + +clean:: + @rm -f boot/openblt.boot + +include make.actions diff --git a/bin/Makefile b/bin/Makefile @@ -0,0 +1,7 @@ +BLTHOME := ../ +include $(BLTHOME)make.conf + +SUBDIRS := vfs_test bltsh ls cat tell validate \ + fdisk mkdir uname winapp tests sysinfo + +include $(BLTHOME)make.actions diff --git a/bin/bltsh/Makefile b/bin/bltsh/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := bltsh.c +BINARY := bltsh.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions + diff --git a/bin/bltsh/bltsh.c b/bin/bltsh/bltsh.c @@ -0,0 +1,132 @@ +/* $Id: //depot/blt/bin/bltsh/bltsh.c#12 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> +#include <blt/syscall.h> + +void grab_console(void); +char **params; +void __libc_init_console_input (void); + +void do_command(int argc, char **argv) +{ + struct stat s; + int thid; + + if(!strcmp(argv[0], "exit")) os_terminate (1); + + if(!stat(argv[0],&s)){ + if((thid = execve(argv[0],argv,NULL)) > 0){ + thr_wait(thid); + grab_console(); + } else { + printf("bltsh: failed to execve(): %s\n", argv[0]); + } + } else { + /* try our "path" */ + char *x = (char *) malloc(7 + strlen(argv[0])); + + strcpy(x,"/boot/"); + strcpy(x+6,argv[0]); + free(argv[0]); + argv[0] = x; + + if(!stat(x,&s)){ + if((thid = execve(argv[0],argv,NULL)) > 0){ + thr_wait(thid); + grab_console(); + } else { + printf("bltsh: failed to execve(): %s\n", argv[0]); + } + } else { + printf("bltsh: no such file or directory: %s\n", argv[0]); + } + } +} + +int main (void) +{ + char line[256], *c; + int len, space, i, p_argc; + + __libc_init_console_input (); + printf ("\n"); + + for (;;) + { + printf ("$ "); + + *line = len = 0; + while (read (0, line + len++, 1) > 0) + { + if ((line[len - 1] == 8) && (len > 1)) /* BS */ + len -= 2; + else if (line[len - 1] == '\n') + { + line[len-- - 1] = 0; + for (i = space = 0, p_argc = 2; i < len; i++) + if ((line[i] == ' ') && !space) + space = 1; + else if ((line[i] != ' ') && space) + { + p_argc++; + space = 0; + } + if ((*line != '#') && *line) + { + params = malloc (sizeof (char *) * p_argc); + c = line; + for (i = 0; i < p_argc - 1; i++) + { + for (len = 0; c[len] && (c[len] != ' '); len++) ; + params[i] = malloc (len + 1); + strlcpy (params[i], c, len + 1); + c += len + 1; + } + params[p_argc - 1] = NULL; + + do_command(p_argc, params); + + for(i=0;i<p_argc;i++) + free(params[i]); + free(params); + } + len = 0; + break; + } + } + } + + return 0; +} + diff --git a/bin/cat/Makefile b/bin/cat/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := cat.c +BINARY := cat.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/bin/cat/cat.c b/bin/cat/cat.c @@ -0,0 +1,60 @@ +/* $Id: //depot/blt/bin/cat/cat.c#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> + +int main (int argc, char **argv) +{ + char *buf; + int fd, res; + + if (argc == 1) + { + printf ("cat: must specify a file\n"); + return -1; + } + buf = malloc (256); + fd = open (argv[1], O_RDONLY, 0); + if (fd < 0) + { + printf ("cat: no such file or directory: %s\n", argv[1]); + return 0; + } + while ((res = read (fd, buf, 255))) + { + buf[res] = 0; + printf (buf); + } + close (fd); + + return 0; +} + diff --git a/bin/fdisk/Makefile b/bin/fdisk/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := fdisk.c +BINARY := fdisk.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions + diff --git a/bin/fdisk/fdisk.c b/bin/fdisk/fdisk.c @@ -0,0 +1,78 @@ +/* $Id: //depot/blt/bin/fdisk/fdisk.c#6 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <blt/blkdev.h> +#include <blt/disk.h> + +const static char *def_device = "ide/0/0/raw"; + +int main (int argc, char **argv) +{ + const char *devname; + unsigned char *buf; + int i; + blkdev_t *dev; + disk_t *disk; + + if (argc == 1) + { + printf ("fdisk: no device specified; using default of %s\n", + def_device); + devname = def_device; + } + else + devname = argv[1]; + + blk_open (devname, 0, &dev); + if (dev == NULL) + { + printf ("fdisk: error opening %s\n", devname); + return 1; + } + buf = malloc (dev->blksize * 2); + blk_read (dev, buf, 0, 2); + + disk = disk_alloc (dev); + for (i = 0; i < disk->numparts; i++) + printf ("partition %s%s, type %X%X, start = %d, size = %d\n", + disk_partition_name (disk, i), + disk_partition_name (disk, i)[1] ? "" : " ", + ((int) disk_partition_type (disk, i) & 0xff00) >> 8, + (int) disk_partition_type (disk, i) & 0xff, + (int) disk_partition_start (disk, i), + (int) disk_partition_size (disk, i)); + disk_free (disk); + + blk_close (dev); + free (buf); + + return 0; +} + diff --git a/bin/ls/Makefile b/bin/ls/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := ls.c +BINARY := ls.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions + diff --git a/bin/ls/ls.c b/bin/ls/ls.c @@ -0,0 +1,79 @@ +/* $Id: //depot/blt/bin/ls/ls.c#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> + +static int dirent_compare (const void *a, const void *b) +{ + const struct dirent *c, *d; + + c = a, d = b; + return strcmp (c->d_name, d->d_name); +} + +int main (int argc, char **argv) +{ + char *path; + int i, j, k, l, maxlen, maxnum; + struct dirent *ent[128]; + DIR *dir; + + path = (argc == 1) ? "/" : argv[1]; + i = maxlen = 0; + dir = opendir (path); + if (dir == NULL) + { + printf ("ls: %s: no such file or directory\n", path); + return 0; + } + while ((ent[i] = readdir (dir)) != NULL) + { + maxlen = (strlen (ent[i]->d_name) > maxlen) ? strlen (ent[i]->d_name) : + maxlen; + i++; + } + closedir (dir); + maxnum = 80 / (maxlen + 2); + qsort (*ent, i, sizeof (struct dirent), dirent_compare); + for (k = 0; k < i; k+= j) + { + for (j = 0; ((j + k) < i) && (j < maxnum); j++) + { + printf ("%s", ent[j + k]->d_name); + for (l = strlen (ent[j + k]->d_name); l < (maxlen + 2); l++) + printf (" "); + } + printf ("\n"); + } + + return 0; +} + diff --git a/bin/mkdir/Makefile b/bin/mkdir/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := mkdir.c +BINARY := mkdir.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/bin/mkdir/mkdir.c b/bin/mkdir/mkdir.c @@ -0,0 +1,42 @@ +/* $Id: //depot/blt/bin/mkdir/mkdir.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <sys/stat.h> + +int main (int argc, char **argv) +{ + if (argc != 2) + { + printf ("usage: mkdir dirname\n"); + return 1; + } + mkdir (argv[1], 755); + return 0; +} + diff --git a/bin/pci/Makefile b/bin/pci/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +BINARY := pci.bin +SRCS := pci.c +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions + diff --git a/bin/pci/pci.c b/bin/pci/pci.c @@ -0,0 +1,160 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> + +#include <i386/io.h> + +#include "pci.h" + +uint32 read_pci(int bus, int dev, int func, int reg, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + outl(u.n,0xCF8); + + base = 0xCFC + (reg & 0x03); + + switch(bytes){ + case 1: return inb(base); + case 2: return inw(base); + case 4: return inl(base); + default: return 0; + } +} + +void write_pci(int bus, int dev, int func, int reg, uint32 v, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + base = 0xCFC + (reg & 0x03); + outl(u.n,0xCF8); + switch(bytes){ + case 1: outb(v,base); break; + case 2: outw(v,base); break; + case 4: outl(v,base); break; + } + +} + +void probe(int bus, int dev, int func) +{ + union { + pci_cfg cfg; + uint32 word[4]; + } x; + pci_cfg *cfg = &x.cfg; + uint32 v; + int i; + for(i=0;i<4;i++){ + x.word[i] = read_pci(bus,dev,func,4*i,4); + } + if(cfg->vendor_id == 0xffff) return; + + printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func); + printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n", + cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface); + printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n", + cfg->status, cfg->command, cfg->bist, cfg->header_type, + cfg->latency_timer, cfg->cache_line_size); + + switch(cfg->header_type & 0x7F){ + case 0: /* normal device */ + for(i=0;i<6;i++){ + v = read_pci(bus,dev,func,i*4 + 0x10, 4); + if(v) { + int v2; + write_pci(bus,dev,func,i*4 + 0x10, 0xffffffff, 4); + v2 = read_pci(bus,dev,func,i*4+0x10, 4) & 0xfffffff0; + v2 = 1 + ~v2; + if(v & 1) { + printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff); + } else { + printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2); + } + } + } + v = read_pci(bus,dev,func,0x3c,1); + if((v != 0xff) && (v != 0)) printf(" * Interrupt Line: %X\n",v); + break; + case 1: + printf(" * PCI <-> PCI Bridge\n"); + break; + default: + printf(" * Unknown Header Type\n"); + } + + if(cfg->header_type & 0x80){ + for(i=1;i<8;i++){ + probe(bus,dev,i); + } + } + +// v = read_pci(bus,dev,func,0x3C); +// printf(" * Lat/Gnt/IntPin/IntLine: %x\n",v); +} + +int main (int argc, char **argv) +{ + int bus,dev; + + for(bus=0;bus<255;bus++){ + for(dev=0;dev<32;dev++) { + probe(bus,dev,0); + } + } + + return 0; +} + diff --git a/bin/pci/pci.h b/bin/pci/pci.h @@ -0,0 +1,31 @@ + +typedef struct +{ + uchar reg:8; + uchar func:3; + uchar dev:5; + uchar bus:8; + uchar rsvd:7; + uchar enable:1; +} confadd; + +typedef struct +{ + uint16 vendor_id; + uint16 device_id; + + uint16 command; + uint16 status; + + uint8 revision_id; + uint8 interface; + uint8 sub_class; + uint8 base_class; + + uint8 cache_line_size; + uint8 latency_timer; + uint8 header_type; + uint8 bist; +} pci_cfg; + + diff --git a/bin/sysinfo/Makefile b/bin/sysinfo/Makefile @@ -0,0 +1,11 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +BINARY := sysinfo.bin +SRCS := sysinfo.cpp +LIBS := -lposix -lblt -lc +CXXFLAGS += -I ../../srv/pci +CFLAGS += -I ../../srv/pci + +include $(BLTHOME)make.actions + diff --git a/bin/sysinfo/sysinfo.cpp b/bin/sysinfo/sysinfo.cpp @@ -0,0 +1,90 @@ +#include <blt/Message.h> +#include <blt/Connection.h> + +#include <blt/syscall.h> + +#include <stdio.h> + +#define PCI_STUB + +#include <pci.h> +#include <string.h> +#include <stdlib.h> + +using namespace BLT; + +int pci_dump(PCI *pci) +{ + Message msg; + pci_cfg cfg; + int n; + + printf("bus dev func vndr devc cls sub ifc irq base[0] size[0] base[1] size[1] \n"); + printf("---- ---- ---- ---- ---- ---- ---- ---- ---- -------- -------- -------- --------\n"); + + for(n=0;pci->get_nth_cfg(n,&cfg) == 0;n++){ + printf("%U %U %U %S %S %U %U %U ", + cfg.bus, cfg.dev, cfg.func, + cfg.vendor_id, cfg.device_id, + cfg.base_class, cfg.sub_class, cfg.interface); + switch(cfg.header_type & 0x7f){ + case 0: + printf("%U %x %x %x %x\n", cfg.irq, + cfg.base[0], cfg.size[0], + cfg.base[1], cfg.size[1]); + break; + + case 1: + printf(" (pci <-> pci bridge)\n"); + break; + + default: + printf(" (unknown header type)\n"); + } + } +} + +void dump_rom(PCI *pci, int bus, int dev, int func) +{ + int i; + uchar *rom = (uchar *) 0xf0000000; + + area_create(4096, 0, (void**) &rom, AREA_PHYSMAP); + printf("device: %d / %d / %d\n",bus,dev,func); + + pci->write(bus,dev,func,0x30,0xf0000001,4); + + for(i=0;i<256;i+=16){ + printf("%S: %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X\n", + i, rom[i+0], rom[i+1], rom[i+2], rom[i+3], + rom[i+4], rom[i+5], rom[i+6], rom[i+7], + rom[i+8], rom[i+9], rom[i+10], rom[i+11], + rom[i+12], rom[i+13], rom[i+14], rom[i+15]); + } +} + +int main(int argc, char *argv[]) +{ + PCI *pci = PCI::FindService(); + + if(argc == 5){ + char *cmd = argv[1]; + int bus = atoi(argv[2]); + int dev = atoi(argv[3]); + int func = atoi(argv[4]); + + if(!strcmp(cmd,"rom")){ + dump_rom(pci,bus,dev,func); + } + + return 0; + } + + if(!pci) { + printf("sysinfo: cannot find pci service\n"); + } else { + pci_dump(pci); + } + + return 0; +} diff --git a/bin/tell/Makefile b/bin/tell/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := tell.c +BINARY := tell.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/bin/tell/tell.c b/bin/tell/tell.c @@ -0,0 +1,50 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <blt/syscall.h> +#include <blt/namer.h> + +int main (int argc, char **argv) +{ + char *text; + int i, loc_port, rem_port; + msg_hdr_t mh; + + if (argc < 3) + { + printf ("tell: syntax: tell [server] [message]\n"); + return 0; + } + text = malloc (256); + strlcpy (text, argv[1], 256); + strlcat (text, ":tell", 256); + + rem_port = namer_find (text, 0); + if (rem_port < 1) + { + printf ("tell: no such server or server not using tell\n"); + return 0; + } + loc_port = port_create (rem_port,"port"); + strlcpy (text, argv[2], 256); + for (i = 3; i < argc; i++) + { + strlcat (text, " ", 256); + strlcat (text, argv[i], 256); + } + + mh.src = loc_port; + mh.dst = rem_port; + mh.data = text; + mh.size = strlen (text) + 1; + old_port_send (&mh); + mh.src = rem_port; + mh.dst = loc_port; + old_port_recv (&mh); + return 0; +} + diff --git a/bin/tests/Makefile b/bin/tests/Makefile @@ -0,0 +1,10 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := tests.cpp +CFLAGS += -fno-rtti -fno-exceptions -fno-rtti +LIBS := -lposix -lblt -lc +BINARY := tests.bin + +include $(BLTHOME)make.actions + diff --git a/bin/tests/tests.cpp b/bin/tests/tests.cpp @@ -0,0 +1,125 @@ +#include <stdio.h> +#include <stdlib.h> +#include <blt/syscall.h> +#include <blt/os.h> + +#define LOOK_ITS_A_RACE 1 + +#if LOOK_ITS_A_RACE + int malloc_sem = -1; +#endif + +// +// Test malloc() +// +int malloc_thread(void*) +{ + for (int i = 0; i < 50000; i++){ +#if LOOK_ITS_A_RACE + sem_acquire(malloc_sem); +#endif + free(malloc(10000)); + +#if LOOK_ITS_A_RACE + sem_release(malloc_sem); +#endif + } + + printf("malloc thread finished\n"); + os_terminate(0); + return 0; +} + +void malloc_test(void) +{ + printf("starting malloc tests\n"); +#if LOOK_ITS_A_RACE + malloc_sem = sem_create(1,"malloc lock"); +#endif + + for (int i = 0; i < 5; i++) + thr_create(malloc_thread, 0, "malloc_thread"); +} + + +// +// producer/consumer +// +struct cl_info { + char name[32]; + int port; +}; + +int consumer(void *_p) +{ + int port = ((cl_info*) _p)->port; + char buffer[10]; + + for (;;) { + msg_hdr_t header; + header.src = 0; + header.dst = port; + header.data = buffer; + header.size = 10; + old_port_recv(&header); + printf("%s receive\n", ((cl_info*) _p)->name); + } +} + +int producer(void *_p) +{ + int port = ((cl_info*) _p)->port; + char buffer[10]; + + for (;;) { + msg_hdr_t header; + header.src = port; + header.dst = port; + header.data = buffer; + header.size = 10; + old_port_send(&header); + printf("%s send\n", ((cl_info*) _p)->name); + } +} + +void prodcons(int num_producers, int num_consumers) +{ + int port = port_create(0, "prodcons"); + printf("%d producers, %d consumers\n", num_producers, num_consumers); + for (int i = 0; i < num_producers; i++) { + cl_info *scinfo = new cl_info; + snprintf(scinfo->name, 32, "producer %d", i + 1); + scinfo->port = port; + thr_create(producer, scinfo, scinfo->name); + } + + for (int i = 0; i < num_consumers; i++) { + cl_info *scinfo = new cl_info; + snprintf(scinfo->name, 32, "consumer %d", i + 1); + scinfo->port = port; + thr_create(consumer, scinfo, scinfo->name); + } +} + + +int main() +{ + // Case 1: malloc tests. + // This crashes the kernel when more than 1 thread is doing malloc/ + // free operations. Using only one thread, or using my own locks, + // reduces the problem, although I still see a reboot once in a while. + malloc_test(); + + // Case 2: single producer, single consumer + // The system quickly wedges when I do this. +// prodcons(1, 1); + + // case 3: multi-producer, single consumer + // The kernel code looks like it might not handle this case properly. +// prodcons(2, 1); + + // Case 4: multi-consumer, single producer +// prodcons(1, 2); + + return 0; +} diff --git a/bin/uname/Makefile b/bin/uname/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +BINARY := uname.bin +OBJS := uname.o ../../lib/version.o +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/bin/uname/uname.c b/bin/uname/uname.c @@ -0,0 +1,96 @@ +/* $Id: //depot/blt/bin/uname/uname.c#3 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <unistd.h> + +#define ATTR(attr, value) \ + if (attr) \ + { \ + if (start) \ + printf (" "); \ + else \ + start = 1; \ + printf (value); \ + } + +extern char *ostype, *osrelease, *osversion; + +int main (int argc, char **argv) +{ + int opt, any, start, machine, nodename, processor, system, release, version; + + any = machine = nodename = processor = system = release = version = 0; + while ((opt = getopt (argc, argv, "amnpsrv")) != -1) + switch (opt) + { + case 'a': + any = machine = nodename = processor = system = release = + version = 1; + break; + + case 'm': + any = machine = 1; + break; + + case 'n': + any = nodename = 1; + break; + + case 'p': + any = processor = 1; + break; + + case 's': + any = system = 1; + break; + + case 'r': + any = release = 1; + break; + + case 'v': + any = version = 1; + break; + + default: + return 1; + } + + if (!any) + system = 1; + start = 0; + ATTR (system, ostype) + ATTR (nodename, "(noname)") + ATTR (release, osrelease) + ATTR (version, osversion) + ATTR (machine, "Intel") + printf ("\n"); + return 0; +} + diff --git a/bin/validate/Makefile b/bin/validate/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := validate.c +BINARY := validate.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/bin/validate/validate.c b/bin/validate/validate.c @@ -0,0 +1,125 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <blt/syscall.h> +#include <blt/namer.h> + +int send_port, recv_port; + + +void sender(void) +{ + char buffer[32]; + msg_hdr_t mh; + + os_sleep(20); + + for(;;){ + mh.src = send_port; + mh.dst = recv_port; + mh.size = 32; + mh.flags = 0; + mh.data = buffer; + + old_port_send(&mh); + } +} + +void receiver(void) +{ + char buffer[32]; + msg_hdr_t mh; + + recv_port = port_create(0,"recv port"); + os_sleep(20); + + for(;;){ + mh.src = 0; + mh.dst = recv_port; + mh.size = 32; + mh.flags = 0; + mh.data = buffer; + + old_port_recv(&mh); + } +} + +int port_test(void) +{ + int s,c; + printf("port_test: starting\n"); + for(c=0;c<1000000;c++){ + if(!(c % 100000)) printf("port_test: %dth port\n",c); + if((s = port_create(0,"port test")) < 1) { + printf("port_test: failed (in create) - iteration %d\n",c); + return 1; + } + if(port_destroy(s)){ + printf("port_test: failed (in destroy) - iteration %d\n",c); + return 1; + } + } + printf("port_test: passed\n"); + return 0; +} + +int semid; + +void tt_thread(void *data) +{ + sem_release(semid); + os_terminate(0); +} + +int thread_test(void) +{ + int n; + semid = sem_create(0, "thread_test_step"); + + for(n=0;n<100000;n++){ + if(!(n % 1000)) printf("thread_test: %dth thread\n",n); + thr_create(tt_thread, NULL, "thread test"); + sem_acquire(semid); + } + +} + +int sem_test(void) +{ + int s,c; + printf("sem_test: starting\n"); + for(c=0;c<1000000;c++){ + if(!(c % 100000)) printf("sem_test: %dth semaphore\n",c); + if((s = sem_create(1,"sem test")) < 1) { + printf("sem_test: failed (in create) - iteration %d\n",c); + return 1; + } + if(sem_destroy(s)){ + printf("sem_test: failed (in destroy) - iteration %d\n",c); + return 1; + } + } + printf("sem_test: passed\n"); + return 0; +} + +int main (int argc, char **argv) +{ + int s,c; + +#if 0 + send_port = port_create(0,"xmit port"); + os_thread(sender); + receiver(); +#endif + +#if 0 + if(sem_test()) return 0; + if(port_test()) return 0; +#endif + + if(thread_test()) return 0; + + return 0; +} + diff --git a/bin/vfs_test/Makefile b/bin/vfs_test/Makefile @@ -0,0 +1,14 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := vfs_test.c +BINARY := vfs_test.bin +LIBS := -lposix -lblt -ldl -lc + +TARGETS := foo.so + +foo.so: foo.o + $(LD) -Bshareable -o foo.so foo.o + +include $(BLTHOME)make.actions + diff --git a/bin/vfs_test/foo.c b/bin/vfs_test/foo.c @@ -0,0 +1,50 @@ +/* $Id: //depot/blt/bin/vfs_test/foo.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> + +extern void jim (void); + +static void _init (void) +{ + printf ("foo: hello\n"); +#ifdef MAKE_DLOPEN_ERROR + jim (); +#endif +} + +static void _fini (void) +{ + printf ("foo: goodbye\n"); +} + +void bar (void) +{ + printf ("foo: bar\n"); +} + diff --git a/bin/vfs_test/vfs_test.c b/bin/vfs_test/vfs_test.c @@ -0,0 +1,107 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <dirent.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <dlfcn.h> +#include <sys/stat.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <blt/qsem.h> +#include <blt/fdl.h> + + +int main (void) +{ +#if 0 + int i, j, k; + msg_hdr_t mh; + qsem_t *sem; + DIR *dir1, *dir2; + struct dirent *dirent; + struct stat buf; + char c; + void *ptr; + int (*fn1)(char *), (*fn2)(void); + +/* + dir1 = opendir ("/"); + while ((dirent = readdir (dir1)) != NULL) + printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name); + closedir (dir1); + dir2 = opendir ("/"); + while ((dirent = readdir (dir2)) != NULL) + printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name); + closedir (dir2); + dir1 = opendir ("/boot"); + while ((dirent = readdir (dir1)) != NULL) + printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name); + closedir (dir1); +*/ + i = open ("/boot/rc.boot", O_RDONLY, 0); + printf ("got fd %d\n", i); +/* + if (i >= 0) + while (read (i, &c, 1)) + printf ("%c", c); +*/ + close (i); + i = open ("/boot/rc.boot", O_RDONLY, 0); + printf ("got fd %d\n", i); +/* + if (i >= 0) + while (read (i, &c, 1)) + printf ("%c", c); +*/ + close (i); +/* + dir1 = opendir ("/portal"); + if (dir1 != NULL) + while ((dirent = readdir (dir1)) != NULL) + printf ("readdir says %d %s\n", dirent->d_fileno, dirent->d_name); + closedir (dir1); +*/ + //i = stat ("/boot/rc.boot", &buf); +/* + if (i) + printf ("stat failed\n"); + else + { + printf ("stat is good\n"); + printf ("size is %d\n", buf.st_size); + } +*/ +/* + printf ("going for input...\n"); + for (;;) + { + c = getchar (); + printf ("we got %d\n", c); + } +*/ +/* + printf ("opening /boot/foo.so\n"); + ptr = dlopen ("/boot/foo.so", 0); + if (ptr != NULL) + { + fn2 = dlsym (ptr, "bar"); + (*fn2) (); + printf ("closing\n"); + dlclose (ptr); + } + else + printf ("error: %s\n", dlerror ()); +*/ +#endif + + int *ptr; + + ptr = 1; + printf ("hello %d\n", *ptr); + + return 0; +} + diff --git a/bin/winapp/Connection.o b/bin/winapp/Connection.o Binary files differ. diff --git a/bin/winapp/Makefile b/bin/winapp/Makefile @@ -0,0 +1,10 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := main.cpp +CFLAGS += -fno-rtti -fno-exceptions +LIBS := -lwin -lblt -lposix -lc +BINARY := winapp.bin + +include $(BLTHOME)make.actions + diff --git a/bin/winapp/Window.o b/bin/winapp/Window.o Binary files differ. diff --git a/bin/winapp/main.cpp b/bin/winapp/main.cpp @@ -0,0 +1,123 @@ +#include <blt/os.h> +#include <blt/syscall.h> +#include <blt/qsem.h> +#include <win/Window.h> +#include <win/Canvas.h> +#include <win/Event.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +const int kCellWidth = 10; + +class DrawingArea : public Canvas { +public: + DrawingArea(); + virtual void EventReceived(const Event*); +private: + int fLastX; + int fLastY; + bool fButtonDown; +}; + +class PaletteArea : public Canvas { +public: + PaletteArea(DrawingArea *draw); + virtual void EventReceived(const Event*); + virtual void Repaint(long left, long top, long right, long bottom); +private: + DrawingArea *fDrawingArea; + int fCurrentColor; +}; + +DrawingArea::DrawingArea() + : fButtonDown(false) +{ +} + +void DrawingArea::EventReceived(const Event *event) +{ + switch (event->what) { + case EVT_MOUSE_DOWN: + LockMouseFocus(); + fButtonDown = true; + fLastX = event->x; + fLastY = event->y; + break; + + case EVT_MOUSE_UP: + fButtonDown = false; + break; + + case EVT_MOUSE_MOVED: + if (fButtonDown) { + printf("DrawLine(%d, %d, %d, %d)\n", fLastX, fLastY, event->x, event->y); + DrawLine(fLastX, fLastY, event->x, event->y); + fLastX = event->x; + fLastY = event->y; + GetWindow()->Flush(); + } + + break; + + default: + Canvas::EventReceived(event); + + } +} + +PaletteArea::PaletteArea(DrawingArea *draw) + : fDrawingArea(draw) +{ +} + +void PaletteArea::EventReceived(const Event *event) +{ + switch (event->what) { + case EVT_MOUSE_DOWN: + printf("PaletteArea: EventReceived\n"); + fDrawingArea->SetPenColor(event->x / kCellWidth * 2); + Invalidate(fCurrentColor * kCellWidth, 0, fCurrentColor * kCellWidth + kCellWidth, 10); + fCurrentColor = event->x / kCellWidth; + Invalidate(fCurrentColor * kCellWidth, 0, fCurrentColor * kCellWidth + kCellWidth, 10); + break; + + default: + Canvas::EventReceived(event); + } +} + +void PaletteArea::Repaint(long left, long top, long right, long bottom) +{ + int x = (left / kCellWidth) * kCellWidth; + while (x < right) { + SetPenColor(x / kCellWidth * 2); + FillRect(x, top, x + kCellWidth, bottom); + if (x / kCellWidth == fCurrentColor) { + SetPenColor(0); + DrawLine(x, top, x + kCellWidth, top); + DrawLine(x, bottom, x + kCellWidth, bottom); + DrawLine(x, top, x, bottom); + DrawLine(x + kCellWidth, top, x + kCellWidth, bottom); + } + + x += kCellWidth; + } +} + +int main() +{ + Window *win = new Window(50, 30, 270, 180); + win->Lock(); + win->Show(); + Canvas *border = new Canvas; + win->AddChild(border, 0, 0, 250, 150); + border->SetBackgroundColor(10); + DrawingArea *draw = new DrawingArea; + PaletteArea *palette = new PaletteArea(draw); + border->AddChild(draw, 2, 2, 218, 139); + border->AddChild(palette, 2, 140, 218, 148); + draw->SetBackgroundColor(250); + win->Unlock(); + return 0; +} diff --git a/boot/Makefile b/boot/Makefile @@ -0,0 +1,12 @@ +BLTHOME := ../ + +include $(BLTHOME)make.conf + +CFLAGS += -I../kernel +BINARY := boot.bin +OBJS := bootstub.o boot.o +LIBS := -lconsole +ENTRY := $(ENTRY_BOOTSTRAP) +CRT0 := + +include $(BLTHOME)make.actions diff --git a/boot/boot.c b/boot/boot.c @@ -0,0 +1,156 @@ +/* $Id: //depot/blt/boot/boot.c#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Stage Two Bootloader -- init paged memory, map the kernel, and + * relocate to k_start() + */ +#define noDIAG + +#include "types.h" +#include "boot.h" +#include <multiboot.h> + +#ifdef DIAG +#include "../include/blt/conio.h" +#endif + +void (*k_start)(void); + +struct _kinfo +{ + uint32 memsize; + uint32 entry_ebp; + boot_dir *bd; + unsigned char *param; +} *kinfo = (struct _kinfo *) 0x00102000; + +static unsigned int multiboot[] __attribute__ ((__section__ (".text"))) = +{ + 0x1badb002, + 0x00010002, + (unsigned int) 0 - 0x1badb002 - 0x00010002, + (unsigned int) multiboot, + 0x100000, + 0x14a000, + 0x14a000, + 0x101074 +}; + +static void enable_paging (void) +{ + __asm__ ("movl $0x80000001, %eax ; mov %eax, %cr0"); +} + +void bootstrap(boot_dir *bd, uint32 memsize, uint32 entry_ebp, char *p) +{ + uint32 *flat; + uint32 _cr3; + int i; + + kinfo->memsize = memsize; + kinfo->entry_ebp = entry_ebp; + kinfo->bd = bd; + kinfo->param = p; + +#ifdef DIAG + con_init(); + cprintf("memsize = %x, bdir @ %x, ebp = %x\n",memsize,(int)bd,entry_ebp); + cprintf("name[0] = %s\n",bd->bd_entry[0].be_name); + cprintf("name[1] = %s\n",bd->bd_entry[1].be_name); + cprintf("name[2] = %s\n",bd->bd_entry[2].be_name); +#endif + + flat = (void*) ((4096*(memsize/4096)) - 4096*3); + + for(i=0;i<1024;i++){ + flat[i] = 0; + flat[1024+i] = 4096*i | 3; + flat[2048+i] = i > bd->bd_entry[2].be_size ? 0 : /* XXX! EEK! */ + ( (bd->bd_entry[2].be_offset*4096+0x100000) + 4096*i) | 3; + +#ifdef DIAG + if(flat[2048+i]){ + cprintf("%x -> %x\n", + bd->bd_entry[2].be_offset*4096+0x100000 + 4096*i, + 0x8000000+4096*i); + } +#endif + } + + k_start = (void (*)(void)) 0x80000000 + (bd->bd_entry[2].be_code_ventr); + + /* point the pdir at ptab1 and ptab2 */ + flat[0] = (uint32) &flat[1024] | 3; + flat[512] = (uint32) &flat[2048] | 3; + + /* map the pdir, ptab1, ptab2 starting at 0x803FD000 */ + flat[2048+1023] = ((uint32) flat + 2*4096) | 3; + flat[2048+1022] = ((uint32) flat + 1*4096) | 3; + flat[2048+1021] = ((uint32) flat) | 3; + + _cr3 = (uint32) flat; + __asm__ ("mov %0, %%cr3"::"r" (_cr3)); + enable_paging (); + +#ifdef DIAG + flat = 0x803fd000; + + for(i=0;i<3000000;i++); + for(i=0;i<3000000;i++); + if(flat[0] & 0xffffff00 != 0x007fe000) cprintf("danger will robinson! (a)\n"); + if(flat[512] & 0xffffff00 != 0x007ff000) cprintf("danger will robinson! (b)\n"); + cprintf("a = %x b = %x\n",flat[0],flat[512]); + for(i=0;i<3000000;i++); + cprintf("go! go! go!\n\n"); + for(i=0;i<3000000;i++); + + +/* for(i=0;i<80*4;i++){ + cprintf("."); + *((char *) 0x100000+i) = 'X'; + } + asm("hlt"); */ +#endif + + k_start(); +} + +void grub_bootstrap (multiboot_info *minfo) +{ + const static unsigned int temp_gdt[] = { 0x00000000, 0x00000000, + 0x0000ffff, 0x00cf9a00, 0x0000ffff, 0x00cf9200 }; + unsigned int i[2]; + + i[0] = 24 << 16; + i[1] = (unsigned int) temp_gdt; + asm ("lgdt (%0)" : : "p" (((char *) i) + 2)); + adjust_seg_regs (); + bootstrap ((boot_dir *) 0x100000, (minfo->mem_lower + minfo->mem_upper + + 384) * 1024, 0, minfo->cmdline); +} + diff --git a/boot/bootstub.S b/boot/bootstub.S @@ -0,0 +1,72 @@ +/* $Id: //depot/blt/boot/bootstub.S#1 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +.globl _start +.globl adjust_seg_regs + +_start: + cmpl $0x2badb002, %eax + je grub + jmp netboot + +netboot: + pushl %ebp + movl %esp, %ebp + subl $0x18, %esp + movl %ebp, -4(%ebp) + movl 0xc(%ebp), %eax + pushl %eax + movl -4(%ebp), %eax + pushl %eax + movl 0x8(%ebp), %eax + pushl %eax + movl 0x10(%ebp), %eax + pushl %eax + call bootstrap + hlt + +grub: + movl $0x90ffc, %esp + pushl %ebx + call grub_bootstrap + hlt + +adjust_seg_regs: + ljmp $0x8, $new_cs +new_cs: + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + ret + diff --git a/boot/fs.ini b/boot/fs.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------- +# Stuff that works with vfs +# + +[vfs_test] +type=data +file=bin/vfs_test/vfs_test.bin +ventry=116 + +[foo.so] +type=data +file=bin/vfs_test/foo.so +ventry=0 + +#[ide] +#type=data +#file=srv/ide/ide.bin +#ventry=0 + +#[fdisk] +#type=data +#file=bin/fdisk/fdisk.bin +#ventry=0 + +#[ffs.so] +#type=data +#file=srv/vfs/drivers/ffs/ffs.so +#ventry=0 + +#[mkdir] +#type=data +#file=bin/mkdir/mkdir.bin +#ventry=0 diff --git a/boot/grub b/boot/grub Binary files differ. diff --git a/boot/grub_e2fs b/boot/grub_e2fs Binary files differ. diff --git a/boot/grub_fat b/boot/grub_fat Binary files differ. diff --git a/boot/grub_ffs b/boot/grub_ffs Binary files differ. diff --git a/boot/grubxx b/boot/grubxx Binary files differ. diff --git a/boot/misc.ini b/boot/misc.ini @@ -0,0 +1,43 @@ + +# --------------------------------------------------------------- +# The PCI server provides access to PCI enumeration info, +# read/write access to PCI configuration space, etc. +# +[pci] +type=data +file=srv/pci/pci.bin +ventry=0 + +[sysinfo] +type=data +file=bin/sysinfo/sysinfo.bin +ventry=0 + + +# --------------------------------------------------------------- +# The "old" klunky network stuff. Due for replacement +# +[ne2000] +type=data +file=srv/ne2000/ne2000.bin +ventry=116 + +# The fish client demo. Works with or without networking +# +[fish] +type=data +file=srv/fish/fish.bin +ventry=116 + +# --------------------------------------------------------------- +# Programs to exercise BLT and find or reproduce bugs +# +[tests] +type=data +file=bin/tests/tests.bin +ventry=0 + +[validate] +type=data +file=bin/validate/validate.bin +ventry=0 diff --git a/boot/net2.ini b/boot/net2.ini @@ -0,0 +1,30 @@ +# --------------------------------------------------------------- +# The "new" modular network stack +# A work in progress (but on hold) +# + +[network] +type=data +file=srv/network/network.bin +ventry=0 + +[eth.so] +type=data +file=srv/network/protocol/eth/eth.so +ventry=0 + +[arp.so] +type=data +file=srv/network/protocol/arp/arp.so +ventry=0 + +[ne.so] +type=data +file=srv/network/device/ne/ne.so +ventry=0 + +[ipv4.so] +type=data +file=srv/network/protocol/ipv4/ipv4.so +ventry=0 + diff --git a/boot/openblt.ini b/boot/openblt.ini @@ -0,0 +1,84 @@ +# --------------------------------------------------------------- +# The bootstrap code is where control starts once netboot, boot.com, +# etc loads the image. It creates a page table to map the kernel in +# at 0x80000000 and then jumps to the kernel entrypoint where things +# really start happening. This MUST be the first entry in the .ini +# +[bootstrap] +type=boot +file=boot/boot.bin +ventry=116 + +# --------------------------------------------------------------- +# The OpenBLT kernel must be the second entry here +# (the bootstrap isn't very bright). +# +[kernel] +type=boot +file=kernel/kernel.bin +ventry=116 + +# --------------------------------------------------------------- +# The kernel will start any entries of type "code" +# immediately on boot. Right now only the naming service +# and init do this. init brings up the rest of the system +# +[init] +type=code +file=srv/init/init.bin +ventry=116 + +[namer] +type=code +file=srv/namer/namer.bin +ventry=116 + +# --------------------------------------------------------------- +# These rc files are read by init to determine what to start +# (thus init needs the vfs) +# +[rc.boot] +type=data +file=etc/rc.boot +ventry=0 + +[rc] +type=data +file=etc/rc +ventry=0 + +# --------------------------------------------------------------- +# The vfs and console servers provide core services +# +[vfs] +type=data +file=srv/vfs/vfs.bin +ventry=116 + +[console] +type=data +file=srv/console2/console.bin +ventry=116 + +# --------------------------------------------------------------- +# The shell and some shell tools +# +[bltsh] +type=data +file=bin/bltsh/bltsh.bin +ventry=0 + +[ls] +type=data +file=bin/ls/ls.bin +ventry=0 + +[cat] +type=data +file=bin/cat/cat.bin +ventry=0 + +[tell] +type=data +file=bin/tell/tell.bin +ventry=0 diff --git a/boot/window.ini b/boot/window.ini @@ -0,0 +1,13 @@ +# --------------------------------------------------------------- +# The Window Server and related apps +# + +[window_server] +type=data +file=srv/window/window_server.bin +ventry=0 + +[winapp] +type=data +file=bin/winapp/winapp.bin +ventry=0 diff --git a/build/GENERIC/Makefile b/build/GENERIC/Makefile @@ -0,0 +1,19 @@ +BLTHOME := ../../ + +all: version build image + +version: + echo "0" > version + +build: + $(BLTHOME)/lib/newvers + mv -f version.c $(BLTHOME)lib + @cd $(BLTHOME) ; make subdirs + +image: + @( DIR=`pwd` ; cd $(BLTHOME) ; util/bootmaker $$DIR/openblt.ini $$DIR/openblt ) + +clean: + rm -f openblt + @cd $(BLTHOME) ; make clean + diff --git a/build/GENERIC/openblt.ini b/build/GENERIC/openblt.ini @@ -0,0 +1,135 @@ +[bootstrap] +type=boot +file=boot/boot.bin +ventry=116 + +[kernel] +type=boot +file=kernel/kernel.bin +ventry=116 + +[init] +type=code +file=srv/init/init.bin +ventry=116 + +[namer] +type=code +file=srv/namer/namer.bin +ventry=116 + +[console] +type=data +file=srv/console2/console.bin +ventry=116 + +#[ne2000] +#type=data +#file=srv/ne2000/ne2000.bin +#ventry=116 + +[vfs] +type=data +file=srv/vfs/vfs.bin +ventry=116 + +#[fish] +#type=data +#file=srv/fish/fish.bin +#ventry=116 + +#[vfs_test] +#type=data +#file=bin/vfs_test/vfs_test.bin +#ventry=116 + +#[foo.so] +#type=data +#file=bin/vfs_test/foo.so +#ventry=0 + +[rc.boot] +type=data +file=etc/rc.boot +ventry=0 + +[rc] +type=data +file=etc/rc +ventry=0 + +[bltsh] +type=data +file=bin/bltsh/bltsh.bin +ventry=0 + +[ls] +type=data +file=bin/ls/ls.bin +ventry=0 + +[cat] +type=data +file=bin/cat/cat.bin +ventry=0 + +[tell] +type=data +file=bin/tell/tell.bin +ventry=0 + +#[network] +#type=data +#file=srv/network/network.bin +#ventry=0 + +#[eth.so] +#type=data +#file=srv/network/protocol/eth/eth.so +#ventry=0 + +#[arp.so] +#type=data +#file=srv/network/protocol/arp/arp.so +#ventry=0 + +#[ne.so] +#type=data +#file=srv/network/device/ne/ne.so +#ventry=0 + +#[ipv4.so] +#type=data +#file=srv/network/protocol/ipv4/ipv4.so +#ventry=0 + +#[validate] +#type=data +#file=bin/validate/validate.bin +#ventry=0 + +[ide] +type=data +file=srv/ide/ide.bin +ventry=0 + +#[fdisk] +#type=data +#file=bin/fdisk/fdisk.bin +#ventry=0 + +[ffs.so] +type=data +file=srv/vfs/drivers/ffs/ffs.so +ventry=0 + +[mkdir] +type=data +file=bin/mkdir/mkdir.bin +ventry=0 + +[uname] +type=data +file=bin/uname/uname.bin +ventry=0 + diff --git a/build/VULCAN/Makefile b/build/VULCAN/Makefile @@ -0,0 +1,22 @@ +BLTHOME := ../../ + +all: version build image + +version: + echo "0" > version + +build: + $(BLTHOME)lib/newvers + mv -f version.c $(BLTHOME)lib + @cd $(BLTHOME) ; make subdirs + +image: + @( DIR=`pwd` ; cd $(BLTHOME) ; util/bootmaker $$DIR/openblt.ini $$DIR/openblt ) + +floppy: + @( DIR=`pwd` ; cd ../.. ; util/bootmaker $$DIR/openblt.ini $$DIR/openblt -floppy ) + +clean: + rm -f openblt + @cd $(BLTHOME) ; make clean + diff --git a/build/VULCAN/openblt.ini b/build/VULCAN/openblt.ini @@ -0,0 +1,135 @@ +[bootstrap] +type=boot +file=boot/boot.bin +ventry=116 + +[kernel] +type=boot +file=kernel/kernel.bin +ventry=116 + +[init] +type=code +file=srv/init/init.bin +ventry=116 + +[namer] +type=code +file=srv/namer/namer.bin +ventry=116 + +[console] +type=data +file=srv/console2/console.bin +ventry=116 + +#[ne2000] +#type=data +#file=srv/ne2000/ne2000.bin +#ventry=116 + +[vfs] +type=data +file=srv/vfs/vfs.bin +ventry=116 + +#[fish] +#type=data +#file=srv/fish/fish.bin +#ventry=116 + +#[vfs_test] +#type=data +#file=bin/vfs_test/vfs_test.bin +#ventry=116 + +#[foo.so] +#type=data +#file=bin/vfs_test/foo.so +#ventry=0 + +[rc.boot] +type=data +file=etc/rc.boot +ventry=0 + +[rc] +type=data +file=build/VULCAN/rc +ventry=0 + +[bltsh] +type=data +file=bin/bltsh/bltsh.bin +ventry=0 + +[ls] +type=data +file=bin/ls/ls.bin +ventry=0 + +[cat] +type=data +file=bin/cat/cat.bin +ventry=0 + +[tell] +type=data +file=bin/tell/tell.bin +ventry=0 + +#[network] +#type=data +#file=srv/network/network.bin +#ventry=0 + +#[eth.so] +#type=data +#file=srv/network/protocol/eth/eth.so +#ventry=0 + +#[arp.so] +#type=data +#file=srv/network/protocol/arp/arp.so +#ventry=0 + +#[ne.so] +#type=data +#file=srv/network/device/ne/ne.so +#ventry=0 + +#[ipv4.so] +#type=data +#file=srv/network/protocol/ipv4/ipv4.so +#ventry=0 + +#[validate] +#type=data +#file=bin/validate/validate.bin +#ventry=0 + +[ide] +type=data +file=srv/ide/ide.bin +ventry=0 + +#[fdisk] +#type=data +#file=bin/fdisk/fdisk.bin +#ventry=0 + +[ffs.so] +type=data +file=srv/vfs/drivers/ffs/ffs.so +ventry=0 + +[mkdir] +type=data +file=bin/mkdir/mkdir.bin +ventry=0 + +[uname] +type=data +file=bin/uname/uname.bin +ventry=0 + diff --git a/build/VULCAN/rc b/build/VULCAN/rc @@ -0,0 +1,17 @@ +# $Id: //depot/blt/build/VULCAN/rc#1 $ +# +# System initialisation script. This is run by init after running +# rc.boot to get enough services going to proceed normally. We can +# run any program here, so we must use full pathnames. + +# /boot/network +# /boot/tell network load eth ipv4 arp ne +# /boot/tell network probe ne +# /boot/tell network config ne0 ipv4 up 10.0.1.5 255.255.255.0 + +/boot/ide +/boot/tell vfs load ffs +/boot/mkdir /freebsd +/boot/tell vfs mount ffs /freebsd ide/0/0/1a +/boot/bltsh + diff --git a/doc/TODO b/doc/TODO @@ -0,0 +1,42 @@ + +* area_destroy() +* perm checking (area, sem, etc) +* right_*() +* stacks should be area_create()'d +* thread_kill() / teardown +* paging? copy-on-write? +* console +* if a non-owner sleeps on a readport it won't be awakened +* ports; multiple readers? + +os_sleep() syscall -- timed sleep? or maybe have a sleeper driver? +port_option() -- allow for OPT_NOWAIT +resource reclaimation when a thread dies +kernel memory pooling for getpages and kgetpages should actually exist +overhaul aspaces to use spans and pspans +modify system timer for faster preemption +perms handoff by namer to other threads/tasks +port groups + +standard support objects: +namer.bin +keyboard.bin +console.bin +idler.bin + + +libc todos: +malloc/free, using os_brk() + + +struct msg_hdr { + int from; + int to; + int size; + char *buf; +} + +port_create(int restrict); +port_delete(int port); +port_send(struct msg_hdr *m); +port_recv(struct msg_hdr *m); diff --git a/doc/add-syscall b/doc/add-syscall @@ -0,0 +1,44 @@ +$Id: //depot/blt/doc/add-syscall#1 $ + +Copyright 1999 Sidney Cammeresi. All rights reserved. + + +How to add a system call to the kernel +-------------------------------------- + +Suppose we want to add a new system call named `port_fry' that will find +all threads listening on a given port and cause the DRAM cells in which +their code is stored to explode in a given number of microseconds. + +1. Reserve a number for the system call in include/blt/syscall_id.h. At + the end of the list add a line like + + #define BLT_SYS_port_fry 666 + + This name must begin with BLT_SYS_ because all of the actual system + call functions are generated by preprocessor macros. + +2. Add a function prototype to include/blt/syscall.h. + + int port_fry (int port, int when); + +3. Add an entry for port_fry in lib/libblt/syscalls.S. At the bottom + of the file and add a line like + + SYSCALL(port_fry) + + This will generate code that traps into the kernel when you call the + C symbol port_fry(). + +4. Implement the system call in the kernel. In the function syscall() + in kernel/syscall.c, add a clause to the case statement: + + case BLT_SYS_port_fry : + kprintf ("kernel: will fry on %d in %d usecs", p_uint32 (1), + p_uint32 (2)); + /* ... */ + break; + + Note that to retrieve the arguments to your system call, you need to + use the macros p_uint32() and friends. Argument numbers start at 1. + diff --git a/doc/boot.html b/doc/boot.html @@ -0,0 +1,190 @@ +<HTML> +<HEAD> +<TITLE>Booting 'n Stuff</TITLE> +</HEAD> +<BODY BGCOLOR="#ffffff"> + +<CENTER> +<TABLE WIDTH=600> + + +<TR BGCOLOR="#a0a0a0"><TD><B>About uBoot</B></TD></TR> +<TR><TD><BR> +The uBoot system is intended to provide a simple mechanism for booting +microkernel OS's from one self-contained file in various environments. +<UL> +<LI>From a remote network host +<LI>From the boot sector of a floppy disk +<LI>From a file on a DOS partition +</UL> +The boot image is not simply an executable file, but a 'filesystem' of sorts, +containing a 2nd stage bootstrap, and whatever other images are needed by +the target system. A utility (bootmaker) is used to create this boot +image from a description file and various components. +<BR><BR><BR></TD></TR> + +<TR BGCOLOR="#a0a0a0"><TD><B>Boot Environment</B></TD></TR> +<TR><TD><BR> + +<TABLE BORDER=1> +<TR><TH>member</TH><TH>type</TH><TH>description</TH></TR> +<TR><TD>be_name</TD><TD>char[32]</TD><TD> +Name of the object. Zero terminated ASCII. Entry 0 is always named +"SBBB/Directory". +</TD></TR> +<TR><TD>be_offset</TD><TD>uint32</TD><TD> +Offset (in 4K pages) from the start of the image to the start of this +entry. +</TD></TR> +<TR><TD>be_type</TD><TD>uint32</TD><TD> +The object type of the entry. One of the defined types listed below, +or a system-specific type. Entry 0 must be BE_TYPE_DIRECTORY and entry 1 +must be BE_TYPE_BOOTSTRAP. +</TD></TR> +<TR><TD>be_size</TD><TD>uint32</TD><TD> +The size (in 4K pages) of this entry in the image. +</TD></TR> +<TR><TD>be_vsize</TD><TD>uint32</TD><TD> +The size (in 4K pages) that this entry would like when mapped into memory. +</TD></TR> +<TR><TD>be_extra0</TD><TD>uint32</TD><TD> +extra field +</TD></TR> +<TR><TD>be_extra1</TD><TD>uint32</TD><TD> +extra field +</TD></TR> +<TR><TD>be_extra2</TD><TD>uint32</TD><TD> +extra field +</TD></TR> +<TR><TD>be_extra3</TD><TD>uint32</TD><TD> +extra field +</TD></TR> +</TABLE> + +<UL> +<LI>The boot image will be located starting at 0x100000. +<LI>The boot directory (64 entries) will be located at offset 0 of the +boot image (also 0x100000. +<LI>Entry 0 in the directory must be the directory itself (be_offset = 0, +be_type = BE_TYPE_DIRECTORY, be_size = 1, be_vsize = 1) +<LI>Entry 1 in the directory must be the 2nd stage loader (or kernel if +the kernel is sufficiently simple). be_offset = 1, be_type = BE_TYPE_BOOTSTRAP +<LI>Once the Image is loaded, control is transferred to +boot_dir->bd_entry[1].be_extra1 + 0x101000; +<LI>The bootstrap entry point looks like:<BR> +<TT>void _start(uint32 mem, char *params, boot_dir *bd);</TT><BR> +mem = system memory size (in bytes), params = zero terminate parameter +string, bd = 0x100000 +<LI>The last entry will be of type BE_TYPE_NONE to indicate the end of +the directory +</UL> +<PRE> + +typedef struct { + char be_name[32]; /* asciiZ */ + unsigned int be_offset; /* 4K pages */ + unsigned int be_type; /* BE_* */ + unsigned int be_size; /* 4K pages */ + unsigned int be_vsize; /* 4K pages */ + unsigned int be_extra0; + unsigned int be_extra1; + unsigned int be_extra2; + unsigned int be_extra3; +} boot_entry; + +typedef struct { + boot_entry bd_entry[64]; +} boot_dir; + +#define BE_TYPE_NONE 0 /* empty entry */ +#define BE_TYPE_DIRECTORY 1 /* directory (entry 0) */ +#define BE_TYPE_BOOTSTRAP 2 /* bootstrap code object */ +#define BE_TYPE_CODE 3 /* executable code object */ +#define BE_TYPE_DATA 4 /* raw data object */ +#define BE_TYPE_ELF32 5 /* 32bit ELF object */ + +/* for BE_TYPE_CODE / BE_TYPE_BOOTSTRAP */ +#define be_code_vaddr be_extra0 /* virtual address (rel offset 0) */ +#define be_code_ventr be_extra1 /* virtual entry point (rel offset 0) */ +</PRE> +<BR></TD></TR> + +<TR BGCOLOR="#a0a0a0"><TD><B>BootMaker (building the image)</B></TD></TR> +<TR><TD><BR> + +The bootmaker util reads description file that looks like: + +<PRE> +# Boot Image for stock OpenBLT +# + +[bootstrap] +type=boot +file=boot/boot.bin +ventry=128 + +[kernel] +type=code +file=kernel/kernel.bin + +[namer] +type=code +file=srv/namer/namer.bin + +[console] +type=code +file=srv/console/console.bin +</PRE> + +Each section (headed by a name in []'s) is an entry in the boot directory, +starting with entry 1 (entry 0 being the directory itself). Each entry +must have a valid type and a valid file to load. Some entry types will +allow extra params (eg ventry in a type=boot entry). Valid types are +boot -> BE_TYPE_BOOTSTRAP, code -> BE_TYPE_CODE, elf32 -> BE_TYPE_ELF32, +data -> BE_TYPE_DATA. +<P> A mechanism for defining your own types and meanings +for the extra[0123] fields will be available soon. The name in the []'s +starting the section will be placed in be_name. The first entry should +be a bootstrap entry (as the bootloader will transfer control into it +whether it is or no. +<P> +<P> +<TT>bootmaker &lt;descr_file&gt; &lt;bootimage_file&gt; [ -floppy ]</TT><P> +The bootmaker util reads the descr_file, writes the bootimage_file, and +if the optional -floppy flag is specified, the bootimage_file will be +a disk image suitable for rawriting or copying with dd. + +<BR><BR><BR></TD></TR> + +<TR BGCOLOR="#a0a0a0"><TD><B>boot.com (loading the image)</B></TD></TR> +<TR><TD><BR> +The DOS bootloader (boot.com) can be invoked in two ways: +<P> +<TT>boot.com bootfile</TT><BR> +Will load the boot image in bootfile to 0x100000 and transfer control +to it as described above. +<P> +<TT>boot.com net=ip=x.y.z.w</TT><BR> +Will load the netboot bootstrap out of netboot.bin (this will be bundled +in boot.com in the next revision) and start a netboot server, waiting for +a unix netboot client to send it a boot image file (see below). + +<BR><BR><BR></TD></TR> + +<TR BGCOLOR="#a0a0a0"><TD><B>NetBoot Client</B></TD></TR> +<TR><TD><BR> +<TT>netboot &lt;bootfile&gt; &lt;ip_address&gt;</TT><BR> +netboot will send the specified bootfile to the netboot server at the +specified ip address. + +<BR><BR><BR></TD></TR> + +<TR BGCOLOR="#a0a0a0"><TD><B>BootMaker (building the image)</B></TD></TR> +<TR><TD><BR> +<BR></TD></TR> + + +</TABLE> +</CENTER> +</BODY> +</HTML> diff --git a/doc/ipcdocs b/doc/ipcdocs @@ -0,0 +1,57 @@ + +typedef struct { + int flags; + uint32 src; + uint32 dst; + uint32 size; + void *data; +} msg_hdr_t; + +int port_create(int restrict); +/* Create a new port owned by the running thread. Only allow messages from + * port 'restrict' to be received. If 'restrict' is 0, messages from any + * source will be received. Will return ERR_MEMORY if the system lacks the + * resources to create the port, otherwise the port number will be returned. +*/ + +int port_destroy(uint32 port); +/* Destroy an existing port. + * Returns ERR_RESOURCE if port is not a valid port or if there are other + * ports slaved to this port. Returns ERR_PERMISSION if the running thread + * is not the owner of this port. Returns ERR_NONE upon success/ +*/ + +int port_send(msg_hdr_t *mh); +/* Send the message in mh->data, of length mh->size from port mh->src to port + * mh->dst. Returns mh->size upon success, ERR_MEMORY if there is a bounds + * error, ERR_RESOURCE if either the source or destination ports do not exist, + * ERR_PERMISSION if the source is not owned by the running thread or the + * destination is not sendable from the source port. +*/ + +int port_recv(msg_hdr_t *mh); +/* Receive a message (in buffer mh->data, maxlen mh->size) from port mh->dst. + * Upon success, mh->src will be set to the sender, mh->dst will be set to + * the destination if it was a slaved port, and the number of received bytes + * will be returned. If the data or header are out of bounds, ERR_MEMORY is + * returned. If the destination port does not exist ERR_RESOURCE is returned. + * If the running thread does not own the destination port, ERR_PERMISSION is + * returned. This call will block if no messages are available, unless the + * port is set to NOWAIT, in which case ERR_WOULDBLOCK is returned. +*/ + +int port_slave(uint32 master, uint32 slave); +/* Cause the master port to receive all messages sent to the slave port. + * If master is 0, the slave is released from bondage. Returns ERR_NONE + * upon success, ERR_PERMISSION if the master and slave are not both owned + * by the running thread, or ERR_RESOURCE if the master or slave are not + * valid ports. +*/ + +int port_set_restrict(uint32 port, uint32 restrict); +/* Change the restriction on a port. Returns ERR_NONE on success, ERR_RESOURCE + * if the port does not exits, or ERR_PERMISSION if the running thread does not + * own the port. A restriction of 0 allows any port to send to this port. +*/ + +#endif diff --git a/doc/notes b/doc/notes @@ -0,0 +1,9 @@ + + +803e1ffc: 00000000 tss->esp0 contains this address (top of kernel stack) +803e1ff8: 0000002b SS ? +803e1ff4: 003fff6c ESP +803e1ff0: 00014293 EFLAGS +803e1fec: 00000023 CS +803e1fe8: 0000052a EIP +803e1fe3: 00010004 error (ESP points here on entry to trap) diff --git a/doc/openblt.html b/doc/openblt.html @@ -0,0 +1,206 @@ +<HTML> +<HEAD> +<TITLE>OpenBLT Overview</TITLE> +</HEAD> +<BODY BGCOLOR="#ffffff"> + +<CENTER> +<TABLE WIDTH=600> +<TR><TD> + +<H1>OpenBLT: An Overview</H1> +<I>by Brian J. Swetland</I> + +<P> +OpenBLT is a microkernel operating system for PC's based on the Intel +80386 or later CPUs. Some aspects of OpenBLT were inspired by Andy +Valencia's VSTa OS, Mach, assorted UNIX variants, and the author's +deranged imagination. The acronym BLT expands to "Brian's Lightweight +Tasker" or "Bacon, Lettuce, and Threads". The word Open was tacked on +for no particular reason. +<P> +The OpenBLT kernel is responsible for managing system memory, providing +IPC facilities, and creation, destruction, and scheduling threads of control. +<P> +Below, we'll examine Tasks, Aspaces, and Ports (the basic objects managed +by the OpenBLT kernel) in terms of their use in and appearance to userland +programs. + +<P><B>Tasks</B><BR> +Tasks in OpenBLT are single threads of control. Each task is associated +with an address space, within which it runs. Tasks may terminate themselves +using the +<PRE>void os_terminate(int status);</PRE> +system call. A task may start another task (sharing the same address space) +using the + +<PRE>int os_thread(void *addr);</PRE> +system call. The new task begins execution at the specified address and +a 4K stack is created for it. <I>[ os_thread() will probably take a stack +pointer address in the next revision ]</I> + +<P><B>Address Spaces</B><BR> +Address spaces are currently not readily manipulated from userland. +In the near future, shared memory system calls should allow the creation +of new address spaces and sharing memory between address spaces. A +thread may request that its address space be expanded using the <TT>os_brk()</TT> system call: +<PRE> +int os_brk(int addr); +</PRE> + +<P><B>Ports</B><BR> +IPC (interprocess communication) in OpenBLT occurs when one task sends a +message to another task via a port. Ports are 'owned' by one task (the +task that created them). Messages are send from one port to another port +(thus a port must exist for the sending task to send from). A port may +be restricted so that it can only receive messages from one specified +other port <I>[ future versions will likely allow a list of allowed senders ]</I>. + + +<P> +All messages sent or received via an OpenBLT port are described with +a message header. The header indicates the source port, destination port, +size of message, pointer to message data (or receive data buffer), and +flags (to allow for future expansion -- non-blocking IO, scatter/gather +IO, etc) +<PRE> +typedef struct { + int flags; + int src; + int dst; + int size; + void *data; +} msg_hdr_t; +</PRE> + + +<P><TT>int <B>port_create</B>(uint32 restrict);</TT><BR> +Create a new port owned by the running thread. Only allow messages +from port 'restrict' to be received. If <TT>restrict</TT> is 0, messages +from any source will be received. Will return <TT>ERR_MEMORY</TT> if +the system lacks the resources to create the port, otherwise the port +number will be returned. + +<P><TT>int <B>port_destroy</B>(uint32 port);</TT><BR> +Destroy an existing port. Returns <TT>ERR_RESOURCE</TT> if <TT>port</TT> is +not a valid port or if there are other ports slaved to this port. +Returns <TT>ERR_PERMISSION</TT> if the running thread is not the owner +of this port. Returns <TT>ERR_NONE</TT> upon success/ + +<P><TT>int <B>port_send</B>(msg_hdr_t *mh);</TT></BR> +Send the message in <TT>mh->data</TT>, of length <TT>mh->size</TT> +from port <T>mh->src</TT> to port <TT>mh->dst</TT>. Returns +<TT>mh->size</TT> upon success, <TT>ERR_MEMORY</TT> if there is a +bounds error, <TT>ERR_RESOURCE</TT> if either the source or +destination ports do not exist, <TT>ERR_PERMISSION</TT> if the source +is not owned by the running thread or the destination is not sendable +from the source port. + +<P><TT>int <B>port_recv</B>(msg_hdr_t *mh);</TT></BR> +Receive a message (in buffer <TT>mh->data</TT>, max length +<TT>mh->size</TT>) from port <TT>mh->dst</TT>. Upon success, +<TT>mh->src</TT> will be set to the sender, <TT>mh->dst</TT> will be +set to the destination if it was a slaved port, and the number of +received bytes will be returned. If the data or header are out of +bounds, <TT>ERR_MEMORY</TT> is returned. If the destination port does +not exist <TT>ERR_RESOURCE</TT> is returned. If the running thread +does not own the destination port, <TT>ERR_PERMISSION</TT> is +returned. This call will block if no messages are available, unless +the port is set to NOWAIT, in which case <TT>ERR_WOULDBLOCK</TT> is +returned. + +<P><TT>int <B>port_option</B>(uint32 port, int opt, int arg);</TT></BR> +Modify port options. The two functions below are wrappers around +<TT>port_option()</TT> + +<P><TT>int <B>port_slave</B>(uint32 master, uint32 slave);</TT><BR> +Cause the master port to receive all messages sent to the slave port. +If master is 0, the slave is released from bondage. Returns ERR_NONE +upon success, <TT>ERR_PERMISSION</TT> if the master and slave are not +both owned by the running thread, or <TT>ERR_RESOURCE</TT> if the +master or slave are not valid ports. + +<P><TT>int <B>port_set_restrict</B>(uint32 port, uint32 restrict);</TT><BR> +Change the restriction on a port. Returns <TT>ERR_NONE</TT> on +success, <TT>ERR_RESOURCE</TT> if the port does not exits, or +<TT>ERR_PERMISSION</TT> if the running thread does not own the port. +A restriction of 0 allows any port to send to this port. + +<P><B>Finding other tasks to talk to</B><BR> +Since port numbers are generated dynamically by the kernel and tend to +be different depending on the order tasks are started, etc, there needs +to be a mechanism for locating device drivers or just other tasks to +talk to. The kernel automatically creates port 1 (the uberport) and gives +ownership of this port to the first task created. This task is the namer, +a service that allows drivers to register ports under specific names and +allows tasks that wish to find these drivers to look up the port that is +associated with a specific name. +<P> +The utility functions listed below are part of the OpenBLT libc and provide +convenient ways to access the namer. +<PRE> +int namer_newhandle(void); +int namer_delhandle(int nh); +int namer_register(int nh, int port, char *name); +int namer_find(int nh, char *name); +</PRE> + +<P><B>Connections between Connectionless ports</B><BR> +Ports in OpenBLT are connectionless. Each <TT>port_send()</TT> specifies +a source and destination port. Tasks may send from any port they own to +any port they are allowed to write to. Ports may be writable to be any +other port or restricted to just one other port. <I>[ multiple port restrict +lists will be in a later version ]</I> +<P> +The general procedure for providing a service in OpenBLT is +<UL> +<LI>Create an unrestricted port +<LI>Register this port with the namer under a descriptive name (eg ne2000, console, etc) +</UL> +When one task (a client) wishes to connect to a service (the server), +the following occurs: +<UL> +<LI>The client looks up the servers unrestricted port using the namer +<LI>The client creates a port that is restricted to the server's +unrestricted port +<LI>The client sends a message to the servers unrestricted port +requesting a connection +<LI>If the server accepts the connection, it will send a response back +to the client's port notifying it that the connection is accepted and + possibly providing a different port than the unrestricted port that the +client should send future messages too. +</UL> +<I>[ a toolkit in libc will streamline this process ]</I> + +<P><B>Handling Devices</B><BR> +The security model in OpenBLT is still being designed. Most likely +there will be a task that is a "security manager" which will be able +to give permissions (for accession IO devices, etc) to tasks that need them. +The two syscalls described below are sufficient for simple device drivers +in the initial (overly trusting) version of OpenBLT: + +<P><TT>void <B>os_handle_irq</B>(int irq);</TT><BR> +Ask the kernel to make this task eligible to process the specified IRQ. +The kernel will also allow the task IO access. + + +<P><TT>void <B>os_sleep_irq</B>(void);</TT><BR> +Suspend this task until the IRQ it is registered to handle is triggered. +When that IRQ is triggered, the task will be scheduled (preempting the +currently running task). The IRQ will be ignored by the kernel when the +task is no sleeping in <TT>os_sleep_irq()</TT>. + +<P><B>Startup</B><BR> +On startup, OpenBLT creates initializes its internal memory and resource +management, sets up kernel space at the 2gb line (0x8000000), creates +an address space and task for each userland program that it can find. +An idle task is created (to give the scheduler something to schedule, +should all other tasks be sleeping on something). The kernel schedules +the first task in the run queue to execute and the fun starts. + + +</TD></TR> +</TABLE> +</CENTER> + +</BODY> diff --git a/doc/vfs.txt b/doc/vfs.txt @@ -0,0 +1,98 @@ +$Id: //depot/blt/doc/vfs.txt#4 $ + +Documentation for the OpenBLT Virtual Filesystem +------------------------------------------------ + +This documentation is Copyright 1999 Sidney Cammeresi. All rights reserved. + + + +Contents +-------- + 1. Overview + 2. File descriptor layer + 3. Vnode layer + 4. Filesystem layer + + 5. VFS server message protocol + + +1. Overview +----------- + + + +2. File descriptor layer +------------------------ + +This layer is not written yet. + + + +3. Vnode layer +-------------- + + + +4. Filesystem layer +------------------- + + + +5. VFS server message protocol +------------------------------ + +vfs command and return parameters (a.k.a. data[] contents) + + +static symbols are for use by libc only! + + +static void __vfs_openconn (int src_port, int dest_port, int filename_area); +============================================================================ +0 filename area + +0 private port for talking to vfs + +static void __vfs_scroll_area (int fd, int offset) +================================================== +0 vfs file descriptor +1 new offset (in bytes for file, dirents for directory) + +0 number of bytes copied +1 more? + +DIR *opendir (const char *dir) +============================== +0 filename offset +1 payload area id +2 payload offset +3 payload length + +0 vfs file descriptor +1 number of dirents in shmem +2 more? + +int closedir (DIR *dirp) +======================== +0 vfs file descriptor + +no output data + +int open (const char *path, int flags, mode_t mode) +=================================================== +0 filename offset +1 payload area id +2 payload offset +3 payload length + +0 vfs file descriptor +1 length of data in shmem +2 more? + +int stat (const char *path, struct stat *buf) +============================================= +0 filename offset + +no output data, but a (struct stat) follows the vfs_res_t + diff --git a/etc/rc b/etc/rc @@ -0,0 +1,24 @@ +# $Id: //depot/blt/etc/rc#5 $ +# +# System initialisation script. This is run by init after running +# rc.boot to get enough services going to proceed normally. We can +# run any program here, so we must use full pathnames. + +# /boot/network +# /boot/tell network load eth ipv4 arp ne +# /boot/tell network probe ne +# /boot/tell network config ne0 ipv4 up 10.0.1.5 255.255.255.0 + +# /boot/ide +# /boot/tell vfs load ffs +# /boot/mkdir /freebsd +# /boot/tell vfs mount ffs /freebsd ide/0/0/1aZ + +# PCI device services +# +/boot/pci + +# Start the shell +# +/boot/bltsh + diff --git a/etc/rc.boot b/etc/rc.boot @@ -0,0 +1,15 @@ +# $Id: //depot/blt/etc/rc.boot#2 $ +# +# List of servers to run in order to bootstrap the system. Each +# server must be in the boot filesystem and statically linked since +# the VFS isn't running yet. +# +# Order is important! These programs don't get run concurrently like +# they do when you run them from the kernel. If you get the order +# wrong, or if a bug causes one of these servers to crash or not detach +# correctly, your system is probably wedged. + +# namer +console +vfs + diff --git a/include/ansi.h b/include/ansi.h @@ -0,0 +1,78 @@ +/* $OpenBSD: ansi.h,v 1.6 1997/07/07 05:56:37 millert Exp $ */ +/* $NetBSD: ansi.h,v 1.7 1996/11/15 22:38:50 jtc Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ansi.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _ANSI_H_ +#define _ANSI_H_ + +/* + * Types which are fundamental to the implementation and may appear in + * more than one standard header are defined here. Standard headers + * then use: + * #ifdef _BSD_SIZE_T_ + * typedef _BSD_SIZE_T_ size_t; + * #undef _BSD_SIZE_T_ + * #endif + */ +#define _BSD_CLOCK_T_ unsigned long /* clock() */ +#define _BSD_PTRDIFF_T_ int /* ptr1 - ptr2 */ +#define _BSD_SIZE_T_ unsigned int /* sizeof() */ +#define _BSD_SSIZE_T_ int /* byte count or error */ +#define _BSD_TIME_T_ int /* time() */ +#define _BSD_VA_LIST_ char * /* va_list */ +#define _BSD_CLOCKID_T_ int +#define _BSD_TIMER_T_ int + +/* + * Runes (wchar_t) is declared to be an ``int'' instead of the more natural + * ``unsigned long'' or ``long''. Two things are happening here. It is not + * unsigned so that EOF (-1) can be naturally assigned to it and used. Also, + * it looks like 10646 will be a 31 bit standard. This means that if your + * ints cannot hold 32 bits, you will be in trouble. The reason an int was + * chosen over a long is that the is*() and to*() routines take ints (says + * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you + * lose a bit of ANSI conformance, but your programs will still work. + * + * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t + * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains + * defined for ctype.h. + */ +#define _BSD_WCHAR_T_ int /* wchar_t */ +#define _BSD_WINT_T_ int /* wint_t */ +#define _BSD_RUNE_T_ int /* rune_t */ + +#endif /* _ANSI_H_ */ diff --git a/include/blt/Connection.h b/include/blt/Connection.h @@ -0,0 +1,35 @@ +// Copyright 1999, Brian J. Swetland. All Rights Reserved. +// This file is provided under the terms of the OpenBLT License + +#ifndef __BLT_CONNECTION_H +#define __BLT_CONNECTION_H + +#include <blt/types.h> + +namespace BLT { + +class Message; + +class Connection +{ +public: + ~Connection(); + + int Send(const Message *msg); + int Recv(Message *msg); + + int Call(const Message *send, Message *recv); + + static Connection *FindService(const char *name); + static Connection *CreateService(const char *name); + +private: + Connection(); + + int _local_port; + int _remote_port; +}; + +} + +#endif diff --git a/include/blt/Message.h b/include/blt/Message.h @@ -0,0 +1,60 @@ +// Copyright 1999, Brian J. Swetland. All Rights Reserved. +// This file is provided under the terms of the OpenBLT License + +#ifndef __BLT_MESSAGE_H +#define __BLT_MESSAGE_H + +#include <blt/types.h> + +#define BLT_TYPE_INT32 'bI32' +#define BLT_TYPE_STRING 'bSTR' +#define BLT_TYPE_POINTER 'bPTR' +#define BLT_TYPE_MESSAGE 'bMSG' + +namespace BLT { + +class Message +{ +public: + Message(); + ~Message(); + + /* -------------------------------------------------------- */ + int PutData(uint32 type, uint32 id, const void *data, uint32 len); + int GetData(uint32 type, uint32 id, void *data, uint32 len) const; + int GetData(uint32 type, uint32 id, const void **data, uint32 *len) const; + int GetEntry(uint32 n, uint32 *type, uint32 *id, const void **data, uint32 *len) const; + + /* -------------------------------------------------------- */ + int PutInt32(uint32 id, int32 data); + int PutString(uint32 id, const char *data); + int PutPointer(uint32 id, void *data); + int PutMessage(uint32 id, Message *msg); + + /* -------------------------------------------------------- */ + int GetInt32(uint32 id, int32 *data) const; + int GetString(uint32 id, const char **data) const; + int GetPointer(uint32 id, void **ptr) const; + int GetMessage(uint32 id, Message *msg) const; + + /* -------------------------------------------------------- */ + int GetPackedData(const void **data, uint32 *length) const; + int PutPackedData(const void *data, uint32 length, int reply_port = -1); + + int Reply(const Message *msg) const; + + void Empty(); + + void dump(); + +private: + void *_data; + uint32 _length; + uint32 _available; + + int _reply_port; +}; + +} +#endif + diff --git a/include/blt/atomic.h b/include/blt/atomic.h @@ -0,0 +1,44 @@ +/* $Id: //depot/blt/include/blt/atomic.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BLT_ATOMIC_H__ +#define __BLT_ATOMIC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + long atomic_add (long *var, long amount); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/blt/blkdev.h b/include/blt/blkdev.h @@ -0,0 +1,78 @@ +/* $Id: //depot/blt/include/blt/blkdev.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_BLKDEV_H_ +#define _BLT_BLKDEV_H_ + +#include <blt/types.h> + +#define BLK_CMD_OPEN 1 +#define BLK_CMD_READ 2 +#define BLK_CMD_WRITE 3 + +typedef struct +{ + int blksize; + int local_port, remote_port; + dev_t devno; +} blkdev_t; + +typedef struct +{ + dev_t device; + unsigned int cmd, block, count; +} blktxn_t; + +typedef struct +{ + dev_t device; + int status; + int data[2]; +} blkres_t; + +#ifdef __cplusplus +extern "C" { +#endif + + int _blk_open (const char *name, int flags, blkdev_t **dev); + int blk_open (const char *name, int flags, blkdev_t **dev); + int _blk_close (blkdev_t *dev); + int blk_close (blkdev_t *dev); + + int _blk_read (blkdev_t *dev, void *buf, int block, int count); + int blk_read (blkdev_t *dev, void *buf, int block, int count); + int _blk_write (blkdev_t *dev, const void *buf, int block, int count); + int blk_write (blkdev_t *dev, const void *buf, int block, int count); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/blt/conio.h b/include/blt/conio.h @@ -0,0 +1,74 @@ +/* $Id: //depot/blt/include/blt/conio.h#6 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _CONIO_H +#define _CONIO_H + +#include <stdarg.h> + +#ifdef MONO +#define CON_SCREEN 0x000B0000 +#else +#define CON_SCREEN 0x000B8000 +#endif + +#define CON_BLACK 0 +#define CON_BLUE 1 +#define CON_GREEN 2 +#define CON_CYAN 3 +#define CON_RED 4 +#define CON_MAGENTA 5 +#define CON_YELLOW 6 +#define CON_WHITE 7 + +#ifdef __cplusplus +extern "C" { +#endif + + void con_attr(int a); + void con_clear(void); + void con_putc(char ch); + void con_puts(char *s); + void con_putp(unsigned int p); + void con_putx(unsigned char x); + void con_goto(int x, int y); + + #define con_fgbg(fg,bg) con_attr((bg) << 4 | (fg)); + + #define con_init() { con_attr(CON_WHITE); con_clear(); } + + void con_start(unsigned int video); + + void cprintf(char *fmt, ...); + +#ifdef __cplusplus +} +#endif + + +#endif /* _CONIO_H */ diff --git a/include/blt/disk.h b/include/blt/disk.h @@ -0,0 +1,252 @@ +/* $Id: //depot/blt/include/blt/disk.h#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_DISK_H_ +#define _BLT_DISK_H_ + +#include <blt/blkdev.h> + +#define FDISK_TYPE_EMPTY 0x00 +#define FDISK_TYPE_FAT12 0x01 +#define FDISK_TYPE_FAT16_SMALL 0x04 +#define FDISK_TYPE_EXTENDED 0x05 +#define FDISK_TYPE_FAT16_BIG 0x06 +#define FDISK_TYPE_NTFS 0x07 +#define FDISK_TYPE_LINUX_SWAP 0x82 +#define FDISK_TYPE_EXT2 0x83 +#define FDISK_TYPE_FREEBSD 0xa5 +#define FDISK_TYPE_OPENBSD 0xa6 +#define FDISK_TYPE_BFS 0xeb + +#define FREEBSD_FFS 0x100 +#define FREEBSD_SWAP 0x101 +#define OPENBSD_FFS 0x102 +#define OPENBSD_SWAP 0x103 + +typedef struct +{ + unsigned char bootflag; + unsigned char start0; + unsigned char start1; + unsigned char start2; + unsigned char type; + unsigned char end0; + unsigned char end1; + unsigned char end2; + unsigned int start_sect_num; + unsigned int num_sects; +} fdisk_partition; + +typedef struct +{ + char name[3]; /* 0, 0a, etc. */ + int type; + unsigned long long start, size; +} partition_t; + +typedef struct +{ + blkdev_t *dev; + int numparts; + partition_t *partition; +} disk_t; + +#ifdef __cplusplus +extern "C" { +#endif + + disk_t *disk_alloc (blkdev_t *dev); + void disk_free (disk_t *disk); + const char *disk_partition_name (disk_t *disk, int partition); + unsigned long long disk_partition_start (disk_t *disk, int partition); + unsigned long long disk_partition_size (disk_t *disk, int partition); + unsigned int disk_partition_type (disk_t *disk, int partition); + +#ifdef __cplusplus +} +#endif + + +/* + * Copyright (c) 1987, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)disklabel.h 8.2 (Berkeley) 7/10/94 + */ + +#define NDDATA 5 +#define NSPARE 5 +#define BSD_MAXSLICES 16 +#define BSD_DISKLABEL_MAGIC 0x82564557 + +typedef struct +{ + unsigned int d_magic; /* the magic number */ + unsigned short d_type; /* drive type */ + unsigned short d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + + /* + * d_packname contains the pack identifier and is returned when + * the disklabel is read off the disk or in-core copy. + * d_boot0 and d_boot1 are the (optional) names of the + * primary (block 0) and secondary (block 1-15) bootstraps + * as found in /usr/mdec. These are returned when using + * getdiskbyname(3) to retrieve the values from /etc/disktab. + */ + union + { + char un_d_packname[16]; /* pack identifier */ + struct + { + char *un_d_boot0; /* primary bootstrap name */ + char *un_d_boot1; /* secondary bootstrap name */ + } un_b; + } d_un; + + /* disk geometry: */ + unsigned int d_secsize; /* # of bytes per sector */ + unsigned int d_nsectors; /* # of data sectors per track */ + unsigned int d_ntracks; /* # of tracks per cylinder */ + unsigned int d_ncylinders; /* # of data cylinders per unit */ + unsigned int d_secpercyl; /* # of data sectors per cylinder */ + unsigned int d_secperunit; /* # of data sectors per unit */ + + /* + * Spares (bad sector replacements) below are not counted in + * d_nsectors or d_secpercyl. Spare sectors are assumed to + * be physical sectors which occupy space at the end of each + * track and/or cylinder. + */ + unsigned short d_sparespertrack; /* # of spare sectors per track */ + unsigned short d_sparespercyl; /* # of spare sectors per cylinder */ + + /* + * Alternate cylinders include maintenance, replacement, configuration + * description areas, etc. + */ + unsigned int d_acylinders; /* # of alt. cylinders per unit */ + + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the + * formatter or controller when formatting. When interleaving is + * in use, logically adjacent sectors are not physically + * contiguous, but instead are separated by some number of + * sectors. It is specified as the ratio of physical sectors + * traversed per logical sector. Thus an interleave of 1:1 + * implies contiguous layout, while 2:1 implies that logical + * sector 0 is separated by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N relative to + * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew + * is the offset of sector 0 on cylinder N relative to sector 0 + * on cylinder N-1. + */ + unsigned short d_rpm; /* rotational speed */ + unsigned short d_interleave; /* hardware sector interleave */ + unsigned short d_trackskew; /* sector 0 skew, per track */ + unsigned short d_cylskew; /* sector 0 skew, per cylinder */ + unsigned int d_headswitch; /* head switch time, usec */ + unsigned int d_trkseek; /* track-to-track seek, usec */ + unsigned int d_flags; /* generic flags */ + unsigned int d_drivedata[NDDATA]; /* drive-type specific information */ + unsigned int d_spare[NSPARE]; /* reserved for future use */ + unsigned int d_magic2; /* the magic number (again) */ + unsigned short d_checksum; /* xor of data incl. partitions */ + + /* filesystem and partition information: */ + unsigned short d_npartitions; /* number of partitions in following */ + unsigned int d_bbsize; /* size of boot area at sn0, bytes */ + unsigned int d_sbsize; /* max size of fs superblock, bytes */ + + struct partition /* the partition table */ + { + unsigned int p_size; /* number of sectors in partition */ + unsigned int p_offset; /* starting sector */ + unsigned int p_fsize; /* filesystem basic fragment size */ + unsigned char p_fstype; /* filesystem type, see below */ + unsigned char p_frag; /* filesystem fragments per block */ + union + { + unsigned short cpg; /* UFS: FS cylinders per group */ + unsigned short sgs; /* LFS: FS segment shift */ + } p_u1; + } d_partitions[BSD_MAXSLICES]; /* actually may be more */ +} bsd_disklabel; + +#define BSD_FS_UNUSED 0 /* unused */ +#define BSD_FS_SWAP 1 /* swap */ +#define BSD_FS_V6 2 /* Sixth Edition */ +#define BSD_FS_V7 3 /* Seventh Edition */ +#define BSD_FS_SYSV 4 /* System V */ +#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ +#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define BSD_FS_MSDOS 8 /* MSDOS file system */ +#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ +#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ +#define BSD_FS_ISO9660 12 /* ISO 9660, normally CD-ROM */ +#define BSD_FS_BOOT 13 /* partition contains bootstrap */ +#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ +#define BSD_FS_HFS 15 /* Macintosh HFS */ +#define BSD_FS_ADFS 16 /* Acorn Disk Filing System */ +#define BSD_FS_EXT2FS 17 /* ext2fs */ +#define BSD_FS_CCD 18 /* ccd component */ + +#endif + diff --git a/include/blt/error.h b/include/blt/error.h @@ -0,0 +1,44 @@ +/* $Id: //depot/blt/include/blt/error.h#4 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_ERROR_H +#define _BLT_ERROR_H + +/* these match the E_ constants in kernel.h */ + +#define ERR_NONE 0 +#define ERR_PERMISSION -1 +#define ERR_RESOURCE -2 +#define ERR_MEMORY -3 + +#define ERR_SENDPORT -4 +#define ERR_RECVPORT -5 +#define ERR_WOULD_BLOCK -6 + +#define ERR_SEGV -7 +#endif diff --git a/include/blt/fdl.h b/include/blt/fdl.h @@ -0,0 +1,66 @@ +/* $Id: //depot/blt/include/blt/fdl.h#3 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_FDL_H_ +#define _BLT_FDL_H_ + +#include <blt/types.h> + +#define MAX_FD_HANDLERS 64 +#define MAX_FDS 256 + +typedef struct +{ + const char *name; + + int (*read) (void *cookie, void *buf, size_t count); + int (*write) (void *cookie, const void *buf, size_t count); + int (*ioctl) (void *cookie, unsigned long request, char *argp); + int (*close) (void *cookie); +} fdl_type; + +typedef struct +{ + fdl_type *imp; + void *cookie; +} __filedesc; + + +#ifdef __cplusplus +extern "C" { +#endif + void __libc_init_fdl (void); + void __libc_fini_fdl (void); + int _fdl_alloc_descriptor (fdl_type *handler, void *cookie); + void _fdl_free_descriptor (int desc); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/blt/hash.h b/include/blt/hash.h @@ -0,0 +1,65 @@ +/* $Id: //depot/blt/include/blt/hash.h#3 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_HASH_H_ +#define _BLT_HASH_H_ + +typedef struct +{ + int valid, dirty, key, dsize; + void *data; +} hashnode_t; + +typedef struct +{ + hashnode_t *table; + int size_index, used, dirty; + float max_load; +} hashtable_t; + +#ifdef __cplusplus +extern "C" { +#endif + + hashtable_t *hashtable_new (float max_load); + void hashtable_del (hashtable_t *t); + void hashtable_insert (hashtable_t *t, int key, void *data, int dsize); + void *hashtable_lookup (hashtable_t *t, int key, int *dsize); + void *hashtable_remove (hashtable_t *t, int key, int *dsize); + void hashtable_print (hashtable_t *t); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/blt/libsyms.h b/include/blt/libsyms.h @@ -0,0 +1,60 @@ +/* $Id: //depot/blt/include/blt/libsyms.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BLT_LIBSYMS_H__ +#define __BLT_LIBSYMS_H__ + +/* + * this creates a weak alias from the symbol original to the symbol alias. + * functions like printf should actually be defined as _printf in libc, + * with weak aliases linking printf to _printf. by doing this, a user can + * put a wrapper around the actual libc functions without rebuilding + * libc (for profiling, say). i.e., + * + * weak_alias (_printf, printf) + * int _printf (char *fmt, ...); + * + * printf ("foo"); + * + * results in a call to _printf. + */ +#define weak_alias(original, alias) \ + asm (".weak " #alias " ; " #alias " = " #original); + +/* + * this causes the GNU linker to emit a warning when this symbol is + * referenced during a linking stage. + * + * only the name of the section matters. this must be char[], not char * + */ +#define link_warning(symbol, text) \ + static const char ___link_warning_##symbol[] \ + __attribute__ ((section (".gnu.warning." #symbol))) = text; + +#endif + diff --git a/include/blt/namer.h b/include/blt/namer.h @@ -0,0 +1,27 @@ +/* Copyright 1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _NAMER_H_ +#define _NAMER_H_ + +#include <blt/types.h> + +#define NAMER_PORT 1 + +#define NAMER_FIND 1 +#define NAMER_REGISTER 2 + +#ifdef __cplusplus +extern "C" { +#endif + +int namer_register(int port, const char *name); +int namer_find(const char *name, int blocking); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/blt/network/eth.h b/include/blt/network/eth.h @@ -0,0 +1,116 @@ +/* $Id: //depot/blt/include/blt/network/eth.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * XXX all multibyte quanities are in network byte order + */ + +#ifndef _BLT_NETWORK_ETH_H_ +#define _BLT_NETWORK_ETH_H_ + +#include <blt/types.h> + +#pragma pack(2) + +#define ETH_PROT_IP 0x0800 +#define ETH_PROT_ARP 0x0806 +#define ETH_PROT_RARP 0x8035 + +#define ETH_ARP_OP_REQUEST 1 +#define ETH_ARP_OP_REPLY 2 +#define ETH_RARP_OP_REQUEST 3 +#define ETH_RARP_OP_REPLY 4 + +struct mbuf; + +typedef struct __eth_drv_t +{ + const char *name; + void (*output) (int num, struct mbuf *); + struct __eth_drv_t *next; +} eth_drv_t; + +typedef struct __eth_dev_t +{ + eth_drv_t *dev_driver; + int dev_num; + char dev_addr[6]; + void *dev_data; + struct __eth_dev_t *next; +} eth_dev_t; + +typedef struct +{ + uint8 dst[6]; + uint8 src[6]; + uint16 frame_type; +} ether_header; + +typedef struct +{ + ether_header header; + uint16 hard_type; + uint16 prot_type; + uint8 hard_size; + uint8 prot_size; + uint16 op; + uint8 send_eth_addr[6]; + uint8 send_ip_addr[4]; + uint8 targ_eth_addr[6]; + uint8 targ_ip_addr[4]; + uint8 __pad__[18]; +} arp_packet; + +typedef struct __eth_prot_t +{ + const char *name; + int num; + void (*input) (struct mbuf *); + struct __eth_prot_t *next; +} eth_prot_t; + +char eth_broadcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +#ifdef _NETWORK + +extern eth_drv_t *drvlist; +extern eth_dev_t *devlist; +extern eth_prot_t *protlist; + +void register_eth_driver (eth_drv_t *drv); +void unregister_eth_driver (eth_drv_t *drv); +void register_eth_device (eth_dev_t *dev); +void unregister_eth_device (eth_dev_t *dev); +void register_eth_protocol (eth_prot_t *prot); +void unregister_eth_protocol (eth_prot_t *prot); +void eth_input (struct mbuf *mbuf); + +#endif + +#endif + diff --git a/include/blt/network/ipv4.h b/include/blt/network/ipv4.h @@ -0,0 +1,50 @@ +/* $Id: //depot/blt/include/blt/network/ipv4.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_NETWORK_IPV4_H_ +#define _BLT_NETWORK_IPV4_H_ + +#include <blt/types.h> + +struct mbuf; + +typedef struct __ipv4_iface_t +{ + const char *name; + uint8 addr[4]; + uint8 netmask[4]; + void (*output) (struct mbuf *); + struct __ipv4_iface_t *next; +} ipv4_iface_t; + +#ifdef _NETWORK +extern ipv4_iface_t *iflist; +#endif + +#endif + diff --git a/include/blt/network/mbuf.h b/include/blt/network/mbuf.h @@ -0,0 +1,140 @@ +/* $Id: //depot/blt/include/blt/network/mbuf.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mbuf.h 8.5 (Berkeley) 2/19/95 + */ + +#ifndef _BLT_NETWORK_MBUF_H_ +#define _BLT_NETWORK_MBUF_H_ + +#define MSIZE 128 +#define MCLBYTES 2048 + +#define MLEN (MSIZE - sizeof(struct m_hdr)) /* normal data len */ +#define MHLEN (MLEN - sizeof(struct m_pkthdr)) /* data len w/pkthdr */ +#define MINCLSIZE (MHLEN+MLEN+1) /* smallest amount to put in cluster */ +#define M_MAXCOMPRESS (MHLEN / 2) /* max amount to copy for compression */ + +struct m_hdr +{ + struct mbuf *mh_next, *mh_nextpkt; + int mh_len; + char *mh_data; + short mh_type, mh_flags; +}; + +struct m_pkthdr +{ + void *rcvif; + int len; +}; + +struct m_ext +{ + char *ext_buf; + void (*ext_free) (char *, int); + int ext_size; + volatile int ext_refcnt; +}; + +struct mbuf +{ + struct m_hdr m_hdr; + union + { + struct + { + struct m_pkthdr mh_pkthdr; + union + { + struct m_ext *mh_ext; + char mh_ext_databuf[MHLEN]; + } mh_dat; + } mh; + char mh_databuf[MLEN]; + } m_dat; +}; + +#define m_next m_hdr.mh_next +#define m_nextpkt m_hdr.mh_nextpkt +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_type m_hdr.mh_type +#define m_flags m_hdr.mh_flags +#define m_databuf m_dat.mh_databuf +#define m_ext_databuf m_dat.mh.mh_dat.mh_ext_databuf + +#define MT_FREE 1 +#define MT_DATA 2 +#define MT_HEADER 3 +#define MT_IFADDR 4 + +#ifdef _NETWORK + +void mbinit (void); +struct mbuf *mget (void); +char *mgetcl (struct mbuf *mbuf); +void mput (struct mbuf *mbuf); +void mputcl (struct mbuf *mbuf); + +#endif + +#endif + diff --git a/include/blt/network/module.h b/include/blt/network/module.h @@ -0,0 +1,44 @@ +/* $Id: //depot/blt/include/blt/network/module.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_NETWORK_MODULE_H_ +#define _BLT_NETWORK_MODULE_H_ + +typedef struct __module_t +{ + char *name; + void *handle; + struct __module_t *next; +} module_t; + +#ifdef _NETWORK +extern module_t *modlist; +#endif + +#endif + diff --git a/include/blt/os.h b/include/blt/os.h @@ -0,0 +1,107 @@ +/* Copyright 1999 Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +#ifndef __BLT_OS_H__ +#define __BLT_OS_H__ + +/* + * this is generic stuff that is used both in userspace and in the kernel + * that doesn't really fit elsewhere. + * + * this file is included in both apps and the kernel, so don't include + * silly userland files here! + */ + +#define BLT_MAX_NAME_LENGTH 32 +#define BLT_MAX_CPUS 8 + +#define PORT_OPT_NOWAIT 1 +#define PORT_OPT_SETRESTRICT 2 +#define PORT_OPT_SETDEFAULT 3 +#define PORT_OPT_SLAVE 4 + +#define RIGHT_PERM_READ 0x0001 /* allow 'read' access to something */ +#define RIGHT_PERM_WRITE 0x0002 /* allow 'write' access to something */ +#define RIGHT_PERM_DESTROY 0x0004 /* allow the something to be destroyed */ +#define RIGHT_PERM_ATTACH 0x0008 /* allows other rights to be attached */ +#define RIGHT_PERM_GRANT 0x0010 /* this right may be granted to another */ + /* thread by a thread that is not the */ + /* owner */ +#define RIGHT_MODE_INHERIT 0x0020 /* automatically granted to child */ +#define RIGHT_MODE_DISSOLVE 0x0040 /* When the owner thread terminates, */ + /* the right is destroyed */ + +#define AREA_PHYSMAP 0x00000001 +#define AREA_UNMAPPED 0x00000002 +#define AREA_COPY_ON_WRITE 0x00000004 +#define PAGE_PRESENT 0x00000001 +#define PAGE_WRITABLE 0x00000002 +#define PAGE_USER 0x00000004 +#define PAGE_NORMAL_KERNEL 0x00000003 +#define PAGE_NORMAL_USER 0x00000007 + +#define JOIN_NO_HANG 0x00000001 + +#ifndef __ASM__ + +typedef enum +{ + CPU_INTEL_386, + CPU_INTEL_486, + CPU_INTEL_PENTIUM, + CPU_INTEL_PENTIUM_PRO, + CPU_INTEL_PENTIUM_II, + CPU_INTEL_PENTIUM_III, + CPU_MOT_PPC_601, + CPU_MOT_PPC_603, + CPU_MOT_PPC_603e, + CPU_MOT_PPC_604, + CPU_MOT_PPC_604e +} cpu_type; + +typedef struct +{ + cpu_type c_type; + char c_revision, c_active; +} cpu_info; + +typedef struct +{ + char *name; +} thread_info; + +typedef struct +{ + int num_cpus; + cpu_info c_info[BLT_MAX_CPUS]; + char kernel_name[BLT_MAX_NAME_LENGTH]; + char kernel_version[BLT_MAX_NAME_LENGTH]; + char kernel_build_date[BLT_MAX_NAME_LENGTH]; + char kernel_build_time[BLT_MAX_NAME_LENGTH]; +} sys_info; + +typedef struct +{ + int rid; + union + { + thread_info t_info; + sys_info s_info; + } r_un; +} rsrc_info; + +typedef struct +{ + void (*func)(void); + int priority; +} init_info; + +#define META_NULL_REQUEST 0 +#define META_MIN_RESERVED 0xf0000000 +#define META_MAX_RESERVED 0xffffffff + +#endif + +#endif + diff --git a/include/blt/qsem.h b/include/blt/qsem.h @@ -0,0 +1,56 @@ +/* $Id: //depot/blt/include/blt/qsem.h#3 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BLT_QSEM_H__ +#define __BLT_QSEM_H__ + +typedef struct +{ + volatile int count; + volatile int mutex; +} qsem_t; + +#ifdef __cplusplus +extern "C" { +#endif + + qsem_t *qsem_create (int count); + void qsem_destroy (qsem_t *s); + void qsem_acquire (qsem_t *s); + void qsem_release (qsem_t *s); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/blt/syscall.h b/include/blt/syscall.h @@ -0,0 +1,104 @@ +/* Copyright 1998-2000 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +#ifndef _SYSCALL_H_ +#define _SYSCALL_H_ + +#include <blt/types.h> +#include <blt/os.h> + +#ifdef __cplusplus +extern "C" { +#endif + + void os_terminate(int status); + void os_console(char *string); + int os_brk(int addr); + void os_handle_irq(int irq); + void os_sleep_irq(void); + void os_debug(void); + void os_sleep(int ticks); + int os_identify(int rsrc); /* returns the team_id of the owner of a resource */ + + sem_id sem_create(int value, const char *name); + int sem_destroy(sem_id sem); + int sem_acquire(sem_id sem); + int sem_release(sem_id sem); + + port_id port_create(int restrict, const char *name); + int port_destroy(port_id port); + int port_option(port_id port, uint32 opt, uint32 arg); + ssize_t port_send(port_id src, port_id dst, const void *data, size_t len, uint32 code); + ssize_t port_recv(port_id dst, port_id *src, void *data, size_t max, uint32 *code); + ssize_t port_peek(port_id *src, port_id *dst, int *code); + + #define port_set_restrict(port, restrict) port_option(port,PORT_OPT_SETRESTRICT,restrict); + #define port_slave(master, slave) port_option(slave,PORT_OPT_SLAVE,master) + #define port_set_nonblocking(port) port_option(port, PORT_OPT_NOWAIT, 1); + #define port_set_blocking(port) port_option(port, PORT_OPT_NOWAIT, 0); + #define port_set_timeout(port, useconds) + + thread_id thr_create(void *addr, void *data, const char *name); + int thr_resume(thread_id thr_id); + int thr_suspend(thread_id thr_id); + int thr_kill(thread_id thr_id); + int thr_detach(thread_id (*addr)(void)); + int thr_wait(thread_id thr_id); + + thread_id thr_spawn(uint32 eip, uint32 esp, + area_id area0, uint32 vaddr0, + area_id area1, uint32 vaddr1, + const char *name); + + area_id area_create(off_t size, off_t virt, void **addr, uint32 flags); + area_id area_clone(area_id aid, off_t virt, void **addr, uint32 flags); + int area_destroy(area_id aid); + int area_resize(area_id aid, off_t size); + + int right_create(int rsrc_id, uint32 flags); + int right_destroy(int right_id); + int right_revoke(int right_id, int thread_id); + int right_grant(int right_id, int thread_id); + + /* look up a resource by name or id number and fill in information about it */ + int rsrc_find_id (rsrc_info *info, int rsrc_id, int rsrc_type); + int rsrc_find_name (rsrc_info *info, const char *name, int rsrc_type); + + /* + * the metacall is for random things that are not compiled into the kernel + * by default, but might be useful for debugging, etc. if you think you + * need to add a syscall temporarily in order to debug something, using + * this will save you some time, since you only have to edit two files + * instead of four. + * + * the request parameter is used to multiplex the call among many different + * purposes. the range META_MIN_RESERVED to META_MAX_RESERVED is for + * temporary purposes that are not submitted to the repository. request + * defines are in include/blt/os.h. + */ + + int os_meta(unsigned int request, ...); + +#ifdef __cplusplus +} +#endif + +/* compatability defines */ +#define os_thread(addr) thr_create(addr,NULL,NULL); +#define thr_join(thr_id,opt) thr_wait(thr_id); +#define thr_detach(addr) (0) + +/* deprecated messaging system */ +typedef struct { + int flags; + int src; + int dst; + int size; + void *data; +} msg_hdr_t; + +#define old_port_send(mh) port_send((mh)->src, (mh)->dst, (mh)->data, (mh)->size, 0) +#define old_port_recv(mh) port_recv((mh)->dst, &((mh)->src), (mh)->data, (mh)->size, 0) + +#endif diff --git a/include/blt/syscall_id.h b/include/blt/syscall_id.h @@ -0,0 +1,72 @@ +/* $Id: //depot/blt/include/blt/syscall_id.h#11 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _SYSCALL_ID_H +#define _SYSCALL_ID_H + +/* syscall id #'s */ +#define BLT_SYS_os_meta 0 +#define BLT_SYS_os_terminate 1 +#define BLT_SYS_os_console 2 +#define BLT_SYS_os_brk 3 +#define BLT_SYS_os_handle_irq 4 +#define BLT_SYS_os_sleep_irq 5 +#define BLT_SYS_os_debug 6 +#define BLT_SYS_os_sleep 7 + +#define BLT_SYS_sem_create 8 +#define BLT_SYS_sem_destroy 9 +#define BLT_SYS_sem_acquire 10 +#define BLT_SYS_sem_release 11 + +#define BLT_SYS_port_create 12 +#define BLT_SYS_port_destroy 13 +#define BLT_SYS_port_option 14 +#define BLT_SYS_port_send 15 +#define BLT_SYS_port_recv 16 + +#define BLT_SYS_os_identify 17 + +#define BLT_SYS_right_create 18 +#define BLT_SYS_right_destroy 19 +#define BLT_SYS_right_revoke 20 +#define BLT_SYS_right_attach 21 +#define BLT_SYS_right_grant 22 + +#define BLT_SYS_thr_create 24 +#define BLT_SYS_thr_spawn 25 +#define BLT_SYS_thr_resume 26 +#define BLT_SYS_thr_suspend 27 +#define BLT_SYS_thr_kill 28 +#define BLT_SYS_thr_wait 29 + +#define BLT_SYS_area_create 30 +#define BLT_SYS_area_clone 31 +#define BLT_SYS_area_destroy 32 +#define BLT_SYS_area_resize 33 + +#endif diff --git a/include/blt/tell.h b/include/blt/tell.h @@ -0,0 +1,47 @@ +/* $Id: //depot/blt/include/blt/tell.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_TELL_H_ +#define _BLT_TELL_H_ + +#define TELL_MAX_LEN 256 + +#ifdef __cplusplus +extern "C" { +#endif + + int _tell_init (char *name, void (*func)(const char *)); + int tell_init (char *name, void (*func)(const char *)); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/blt/types.h b/include/blt/types.h @@ -0,0 +1,43 @@ +/* Copyright 1998-2000 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +#ifndef _BLT_TYPES_H +#define _BLT_TYPES_H + +#define CHAR_BIT 8 +#define NULL ((void *) 0) + +#define ntohs(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) ) +#define htons(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) ) + +typedef unsigned long long uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; +typedef long long int64; +typedef int int32; +typedef short int16; +typedef char int8; +typedef unsigned char uchar; + +typedef int ssize_t; +typedef unsigned long int size_t; + +typedef unsigned int time_t; + +typedef unsigned int off_t; +typedef unsigned int mode_t; +typedef unsigned int dev_t; +typedef unsigned int ino_t; +typedef unsigned int nlink_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; + +/* system resources */ +typedef int port_id; +typedef int area_id; +typedef int sem_id; +typedef int thread_id; + +#endif diff --git a/include/blt/vfs.h b/include/blt/vfs.h @@ -0,0 +1,118 @@ +/* $Id: //depot/blt/include/blt/vfs.h#7 $ +** +** Copyright 1998-1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BLT_VFS_H_ +#define _BLT_VFS_H_ + +#include <blt/types.h> +#include <blt/fdl.h> + +/* operations */ +#define VFS_OPENCONN 1 +#define VFS_CLOSECONN 2 +#define VFS_SCROLL_AREA 19 + +#define VFS_MOUNT 3 +#define VFS_UNMOUNT 4 +#define VFS_INITIALISE 5 +#define VFS_SYNC 6 +#define VFS_RFSTAT 7 +#define VFS_WFSTAT 8 + +#define VFS_CREATE 9 +#define VFS_MKDIR 10 +#define VFS_SYMLINK 11 +#define VFS_LINK 12 +#define VFS_RENAME 13 +#define VFS_UNLINK 14 +#define VFS_RMDIR 15 +#define VFS_READLINK 16 + +#define VFS_OPENDIR 17 +#define VFS_CLOSEDIR 18 + +#define VFS_OPEN 21 +#define VFS_CLOSE 22 +#define VFS_READ 23 +#define VFS_WRITE 24 +#define VFS_IOCTL 25 +#define VFS_SETFLAGS 26 +#define VFS_RSTAT 27 +#define VFS_WSTAT 28 +#define VFS_FSYNC 29 + +#define VFS_OPEN_ATTRDIR 30 +#define VFS_CLOSE_ATTRDIR 31 +#define VFS_REWIND_ATTRDIR 32 +#define VFS_READ_ATTRDIR 33 +#define VFS_READ_ATTR 34 +#define VFS_WRITE_ATTR 35 +#define VFS_REMOVE_ATTR 36 +#define VFS_RENAME_ATTR 37 +#define VFS_STAT_ATTR 38 + +#define VFS_OPEN_INDEXDIR 39 +#define VFS_CLOSE_INDEXDIR 40 +#define VFS_REWIND_INDEXDIR 41 +#define VFS_READ_INDEXDIR 42 +#define VFS_READ_INDEX 43 +#define VFS_WRITE_INDEX 44 +#define VFS_REMOVE_INDEX 45 +#define VFS_RENAME_INDEX 46 +#define VFS_STAT_INDEX 47 + +#define VFS_OPEN_QUERY 48 +#define VFS_CLOSE_QUERY 49 +#define VFS_READ_QUERY 50 + +/* vfs result codes */ +#define VFS_OK 1 +#define VFS_ERROR 2 +#define VFS_MORE_DATA 4 + +typedef struct +{ + unsigned int cmd; + unsigned int data[6]; +} vfs_cmd_t; + +typedef struct +{ + unsigned int status, errno; + unsigned int data[6]; +} vfs_res_t; + +typedef struct +{ + char *buf; + int srv_fd, area_offset; + int offset, length, more; +} vfs_fd; + +#endif + diff --git a/include/boot.h b/include/boot.h @@ -0,0 +1,66 @@ +/* $Id: //depot/blt/include/boot.h#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BOOT_H_ +#define _BOOT_H_ + +#define BOOTDIR_NAMELEN 32 +#define BOOTDIR_MAX_ENTRIES 64 +#define BOOTDIR_DIRECTORY "SBBB/Directory" + +typedef struct { + char be_name[BOOTDIR_NAMELEN]; /* name of loaded object, zero terminated */ + int be_offset; /* offset of object relative to the start of boot_dir */ + int be_type; /* object type designator */ + int be_size; /* size of loaded object (pages) */ + int be_vsize; /* size loaded object should occupy when mapped in */ + int be_extra0; + int be_extra1; + int be_extra2; + int be_extra3; +} boot_entry; + +typedef struct { + boot_entry bd_entry[BOOTDIR_MAX_ENTRIES]; +} boot_dir; + +/* void _start(uint32 mem, char *params, boot_dir *bd); */ + +#define BE_TYPE_NONE 0 /* empty entry */ +#define BE_TYPE_DIRECTORY 1 /* directory (entry 0) */ +#define BE_TYPE_BOOTSTRAP 2 /* bootstrap code object (entry 1) */ +#define BE_TYPE_CODE 3 /* executable code object */ +#define BE_TYPE_DATA 4 /* raw data object */ +#define BE_TYPE_ELF32 5 /* 32bit ELF object */ + +/* for BE_TYPE_CODE */ +#define be_code_vaddr be_extra0 /* virtual address (rel offset 0) */ +#define be_code_ventr be_extra1 /* virtual entry point (rel offset 0) */ + +#endif + diff --git a/include/ctype.h b/include/ctype.h @@ -0,0 +1,45 @@ +/* $Id: //depot/blt/include/ctype.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _CTYPE_H_ +#define _CTYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + int _isdigit (int c); + int isdigit (int c); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/dirent.h b/include/dirent.h @@ -0,0 +1,66 @@ +/* $Id: //depot/blt/include/dirent.h#3 $ +** +** Copyright 1999 Sidney Cammersi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DIRENT_H__ +#define __DIRENT_H__ + +#include <blt/types.h> +#include <blt/os.h> + +typedef struct +{ + int fd, hoffset, more, len, left; + struct dirent *head, *current; +} DIR; + +struct dirent +{ + uint32 d_fileno; + uint16 d_reclen; + char d_name[BLT_MAX_NAME_LENGTH + 1]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + + DIR *_opendir (const char *path); + DIR *opendir (const char *path); + int _closedir (DIR *dirp); + int closedir (DIR *dirp); + struct dirent *_readdir (DIR *dirp); + struct dirent *readdir (DIR *dirp); + void _rewinddir (DIR *dirp); + void rewinddir (DIR *dirp); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/dlfcn.h b/include/dlfcn.h @@ -0,0 +1,55 @@ +/* $Id: //depot/blt/include/dlfcn.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _DLFCN_H_ +#define _DLFCN_H_ + +#define RTLD_GLOBAL 1 +#define RTLD_LAZY 2 +#define RTLD_NOW 4 + +#ifdef __cplusplus +extern "C" { +#endif + + void *_dlopen (const char *filename, int flag); + void *dlopen (const char *filename, int flag); + const char *_dlerror (void); + const char *dlerror (void); + void *_dlsym (void *handle, const char *symbol); + void *dlsym (void *handle, const char *symbol); + int _dlclose (void *handle); + int dlclose (void *handle); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/elf.h b/include/elf.h @@ -0,0 +1,236 @@ +/* $Id: //depot/blt/include/elf.h#4 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __ELF_H__ +#define __ELF_H__ + +#define EI_NIDENT 16 + +/* ELF header */ +typedef struct +{ + unsigned char e_ident [EI_NIDENT]; + unsigned short e_type, e_machine; + unsigned int e_version, e_entry, e_phoff, e_shoff, e_flags; + unsigned short e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, + e_shstrndx; +} elf32_hdr_t; + +#define ELF_MAGIC 0x464c457f + +/* e_ident indices */ +#define EI_MAG0 0 /* 0x7F */ +#define EI_MAG1 1 /* 'E' */ +#define EI_MAG2 2 /* 'L' */ +#define EI_MAG3 3 /* 'F' */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* file version */ +#define EI_PAD 7 /* start of padding bytes */ + +/* e_ident data */ +#define ELFCLASSNONE 0 /* invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFDATANONE 0 /* invalid data encoding */ +#define ELFDATA2LSB 1 /* little-endian */ +#define ELFDATA2MSB 2 /* big-endian */ + +/* e_type */ +#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 0xFF00 /* beginning processor specific range */ +#define ET_HIPROC 0xFFFF /* end of processor specific range */ + +/* e_machine */ +#define EM_NONE 0 /* no machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 486 - unused */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ +#define EM_SPARC64 11 /* SPARC V9 64-bit */ +#define EM_HPPA 15 /* HP PA-RISC */ +#define EM_PPC 20 /* PowerPC */ + +/* e_version */ +#define EV_NONE 0 /* invalid version */ +#define EV_CURRENT 1 /* current version */ + +/* section header */ +typedef struct +{ + unsigned int sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size, + sh_link, sh_info, sh_addralign, sh_entsize; +} elf32_sec_hdr_t; + +/* sh_type */ +#define SHT_NULL 0 /* section header is inactive */ +#define SHT_PROGBITS 1 /* program specific information */ +#define SHT_SYMTAB 2 /* symbol table, only one of these */ +#define SHT_STRTAB 3 /* string table */ +#define SHT_RELA 4 /* relocation entries with addends - ? */ +#define SHT_HASH 5 /* symbol hash table, only one of these */ +#define SHT_DYNAMIC 6 /* dynamic linking information, only one of these */ +#define SHT_NOTE 7 /* file marking information */ +#define SHT_NOBITS 8 /* occupies no space, but similar to SHT_PROGBITS */ +#define SHT_REL 9 /* relocation entries without addends - ? */ +#define SHT_SHLIB 10 /* reserved and unspecified */ +#define SHT_DYNSYM 11 /* symbol table for dynamic linking, only one */ + +#define SHF_WRITE 1 /* section should be writable */ +#define SHF_ALLOC 2 /* section occupies memory during execution */ +#define SHF_EXECINSTR 4 /* section contains executable text */ +#define SHF_MASKPROC 0xF0000000 /* reserved for machine specific data */ + +/* program header */ +typedef struct +{ + unsigned int p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags, + p_align; +} elf32_pgm_hdr_t; + +/* p_type */ +#define PT_NULL 0 /* array element unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* contains dynamic linking information */ +#define PT_INTERP 3 /* location and size of path to interpreter */ +#define PT_NOTE 4 /* location and size of auxillary information */ +#define PT_SHLIB 5 /* reserved and unspecified */ +#define PT_PHDR 6 /* location and size of program header table */ +#define PT_LOPROC 0x70000000 /* reserved for processor specific use */ +#define PT_HIPROC 0x7FFFFFFF /* end of range */ + +typedef struct +{ + int d_tag; + union + { + unsigned int d_val, d_ptr; + } d_un; +} elf32_dyn_t; + +/* d_tag */ +#define DT_NULL 0 /* ignored, but mandatory */ +#define DT_NEEDED 1 /* name of needed library */ +#define DT_PLTRELSZ 2 /* size of plt */ +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 /* string table with symbol and library names */ +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_REL 17 /* reloc entries for data */ +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_JMPREL 23 /* reloc entries associated with plt */ + +/* relocation entry without addend */ +typedef struct +{ + unsigned int r_offset, r_info; +} elf32_rel_t; + +/* relocation entry with addend */ +typedef struct +{ + unsigned int r_offset, r_info, r_addend; +} elf32_rela_t; + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char) (i)) +#define ELF32_R_INFO(i,j) (((i) << 8) + (unsigned char) (j)) + +#define R_386_NONE 0 /* none */ +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 /* location of procedure linkage table entry */ +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +typedef struct +{ + unsigned int st_name, st_value, st_size; + unsigned char st_info, st_other; + unsigned short st_shndx; +} elf32_sym_t; + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xF) +#define ELF32_ST_INFO(i,j) (((i) << 4) + ((j) & 0xF)) + +#define STT_NOTYPE 0 /* type not specified */ +#define STT_OBJECT 1 /* symbol references data */ +#define STT_FUNC 2 /* symbol represents text */ +#define STT_SECTION 3 /* symbol is a section */ +#define STT_FILE 4 /* object file */ +#define STT_LOPROC 13 /* reserved for processor */ +#define STT_MEDPROC 14 /* reserved for processor */ +#define STT_HIPROC 15 /* reserved for processor */ + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +#ifdef __cplusplus +extern "C" { +#endif + + elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name); + elf32_sec_hdr_t *elf_find_section_hdr (elf32_hdr_t *hdr, char *name); + void *_elf_lookup_sym (int filenum, const char *name); + void *elf_lookup_sym (int filenum, const char *name); + void *_elf_find_section_data (elf32_hdr_t *hdr, char *name); + void *elf_find_section_data (elf32_hdr_t *hdr, char *name); + int _elf_section_size (elf32_hdr_t *hdr, char *name); + int elf_section_size (elf32_hdr_t *hdr, char *name); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/errno.h b/include/errno.h @@ -0,0 +1,156 @@ +/* $Id: //depot/blt/include/errno.h#1 $ */ +/* $OpenBSD: errno.h,v 1.8 1999/01/07 05:34:29 deraadt Exp $ */ +/* $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)errno.h 8.5 (Berkeley) 1/21/94 + */ + +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +extern int errno; /* global error number */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ + +/* math software */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define EAGAIN 35 /* Resource temporarily unavailable */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Operation timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + +#define ELOOP 62 /* Too many levels of symbolic links */ +#define ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EAUTH 80 /* Authentication error */ +#define ENEEDAUTH 81 /* Need authenticator */ +#define EIPSEC 82 /* IPsec processing failure */ +#define ELAST 82 /* Must be equal largest errno */ + +#endif + diff --git a/include/fcntl.h b/include/fcntl.h @@ -0,0 +1,61 @@ +/* $Id: //depot/blt/include/fcntl.h#4 $ +** +** Copyright 1998 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _FCNTL_H_ +#define _FCNTL_H_ + +#include <blt/types.h> + +#define O_RDONLY 0x00000001 +#define O_WRONLY 0x00000002 +#define O_RDWR 0x00000003 +#define O_NONBLOCK 0x00000004 +#define O_APPEND 0x00000008 +#define O_CREAT 0x00000010 +#define O_TRUNC 0x00000020 +#define O_EXCL 0x00000040 +#define O_SHLOCK 0x00000080 +#define O_EXLOCK 0x00000100 + +#ifdef __cplusplus +extern "C" { +#endif + + int _open (const char *path, int flags, mode_t mode); + int open (const char *path, int flags, mode_t mode); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/i386/asm.h b/include/i386/asm.h @@ -0,0 +1,40 @@ +/* $Id: //depot/blt/include/i386/asm.h#1 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __I386_ASM_H__ +#define __I386_ASM_H__ + +#define FUNCTION(name) \ + .text; \ + .globl name; \ + .type name, @function; \ + .align 4; \ + name: + +#endif + diff --git a/include/i386/io.h b/include/i386/io.h @@ -0,0 +1,165 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +#define SLOW_IO_BY_JUMPING + +/* + * This file contains the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl and the "string versions" of the same + * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" + * versions of the single-IO instructions (inb_p/inw_p/..). + * + * This file is not meant to be obfuscating: it's just complicated + * to (a) handle it all in a way that makes gcc able to optimize it + * as well as possible and (b) trying to avoid writing the same thing + * over and over again with slight variations and possibly making a + * mistake somewhere. + */ + +/* + * Thanks to James van Artsdalen for a better timing-fix than + * the two short jumps: using outb's to a nonexistent port seems + * to guarantee better timings even on fast machines. + * + * On the other hand, I'd like to be sure of a non-existent port: + * I feel a bit unsafe about using 0x80 (should be safe, though) + * + * Linus + */ + +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") +#else +#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") +#endif + +#define SLOW_DOWN_IO __SLOW_DOWN_IO + +/* + * Talk about misusing macros.. + */ + +#define __OUT1(s,x) \ +extern inline void __out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ +__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ +__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; } + +#define __IN1(s) \ +extern inline RETURN_TYPE __in##s(unsigned short port) { RETURN_TYPE _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ +__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ +__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; } + +#define __INS(s) \ +extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define __OUTS(s) \ +extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define RETURN_TYPE unsigned char +/* __IN(b,"b","0" (0)) */ +__IN(b,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned short +/* __IN(w,"w","0" (0)) */ +__IN(w,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned int +__IN(l,"") +#undef RETURN_TYPE + +__OUT(b,"b",char) +__OUT(w,"w",short) +__OUT(l,,int) + +__INS(b) +__INS(w) +__INS(l) + +__OUTS(b) +__OUTS(w) +__OUTS(l) + +/* + * Note that due to the way __builtin_constant_p() works, you + * - can't use it inside a inline function (it will never be true) + * - you don't have to worry about side effects within the __builtin.. + */ +#define outb(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc((val),(port)) : \ + __outb((val),(port))) + +#define inb(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc(port) : \ + __inb(port)) + +#define outb_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc_p((val),(port)) : \ + __outb_p((val),(port))) + +#define inb_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc_p(port) : \ + __inb_p(port)) + +#define outw(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc((val),(port)) : \ + __outw((val),(port))) + +#define inw(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc(port) : \ + __inw(port)) + +#define outw_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc_p((val),(port)) : \ + __outw_p((val),(port))) + +#define inw_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc_p(port) : \ + __inw_p(port)) + +#define outl(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outlc((val),(port)) : \ + __outl((val),(port))) + +#define inl(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inlc(port) : \ + __inl(port)) + +#define outl_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outlc_p((val),(port)) : \ + __outl_p((val),(port))) + +#define inl_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inlc_p(port) : \ + __inl_p(port)) + +#endif diff --git a/include/i386/io.h.new b/include/i386/io.h.new @@ -0,0 +1,222 @@ +/* $OpenBSD: pio.h,v 1.5 1997/11/10 23:40:45 niklas Exp $ */ +/* $NetBSD: pio.h,v 1.13 1996/03/08 20:15:23 cgd Exp $ */ + +/* + * Copyright (c) 1993, 1995 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _I386_PIO_H_ +#define _I386_PIO_H_ + +/* + * Functions to provide access to i386 programmed I/O instructions. + * + * The in[bwl]() and out[bwl]() functions are split into two varieties: one to + * use a small, constant, 8-bit port number, and another to use a large or + * variable port number. The former can be compiled as a smaller instruction. + */ + +#include "blt/types.h" + +#define __SLOW_DOWN_IO asm volatile ("jmp 1f \n 1: jmp 1f \n 1:") +#define SLOW_DOWN_IO __SLOW_DOWN_IO + +#define outb_p(a,b) { outb(a,b) ; SLOW_DOWN_IO; } +#define inb_p(a,b) { inb(a,b) ; SLOW_DOWN_IO; } +#define outw_p(a,b) { outw(a,b) ; SLOW_DOWN_IO; } +#define inw_p(a,b) { inw(a,b) ; SLOW_DOWN_IO; } + +#ifdef __OPTIMIZE__ + +#define __use_immediate_port(port) \ + (__builtin_constant_p((port)) && (port) < 0x100) + +#else + +#define __use_immediate_port(port) 0 + +#endif + + +#define inb(port) \ + (__use_immediate_port(port) ? __inbc(port) : __inb(port)) + +static inline uint8 +__inbc(int port) +{ + uint8 data; + __asm __volatile("inb %1,%0" : "=a" (data) : "id" (port)); + return data; +} + +static inline uint8 +__inb(int port) +{ + uint8 data; + __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static inline void +insb(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsb" : + : + "d" (port), "D" (addr), "c" (cnt) : + "%edi", "%ecx", "memory"); +} + +#define inw(port) \ + (__use_immediate_port(port) ? __inwc(port) : __inw(port)) + +static inline uint16 +__inwc(int port) +{ + uint16 data; + __asm __volatile("inw %1,%0" : "=a" (data) : "id" (port)); + return data; +} + +static inline uint16 +__inw(int port) +{ + uint16 data; + __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static inline void +insw(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsw" : + : + "d" (port), "D" (addr), "c" (cnt) : + "%edi", "%ecx", "memory"); +} + +#define inl(port) \ + (__use_immediate_port(port) ? __inlc(port) : __inl(port)) + +static inline uint32 +__inlc(int port) +{ + uint32 data; + __asm __volatile("inl %1,%0" : "=a" (data) : "id" (port)); + return data; +} + +static inline uint32 +__inl(int port) +{ + uint32 data; + __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static inline void +insl(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsl" : + : + "d" (port), "D" (addr), "c" (cnt) : + "%edi", "%ecx", "memory"); +} + +#define outb(port, data) \ + (__use_immediate_port(port) ? __outbc(port, data) : __outb(port, data)) + +static inline void +__outbc(int port, uint8 data) +{ + __asm __volatile("outb %0,%1" : : "a" (data), "id" (port)); +} + +static inline void +__outb(int port, uint8 data) +{ + __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); +} + +static inline void +outsb(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsb" : + : + "d" (port), "S" (addr), "c" (cnt) : + "%esi", "%ecx"); +} + +#define outw(port, data) \ + (__use_immediate_port(port) ? __outwc(port, data) : __outw(port, data)) + +static inline void +__outwc(int port, uint16 data) +{ + __asm __volatile("outw %0,%1" : : "a" (data), "id" (port)); +} + +static inline void +__outw(int port, uint16 data) +{ + __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); +} + +static inline void +outsw(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsw" : + : + "d" (port), "S" (addr), "c" (cnt) : + "%esi", "%ecx"); +} + +#define outl(port, data) \ + (__use_immediate_port(port) ? __outlc(port, data) : __outl(port, data)) + +static inline void +__outlc(int port, uint32 data) +{ + __asm __volatile("outl %0,%1" : : "a" (data), "id" (port)); +} + +static inline void +__outl(int port, uint32 data) +{ + __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); +} + +static inline void +outsl(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsl" : + : + "d" (port), "S" (addr), "c" (cnt) : + "%esi", "%ecx"); +} + +#endif /* _I386_PIO_H_ */ diff --git a/include/multiboot.h b/include/multiboot.h @@ -0,0 +1,64 @@ +/* $Id$ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _MULTIBOOT_H_ +#define _MULTIBOOT_H_ + +#define MBI_MEM 0x00000001 +#define MBI_BOOTDEV 0x00000002 +#define MBI_CMDLINE 0x00000004 +#define MBI_MODS 0x00000008 +#define MBI_SYMS_AOUT 0x00000010 +#define MBI_SYMS_ELF 0x00000020 +#define MBI_MMAP 0x00000040 + +typedef struct +{ + unsigned int flags, mem_lower, mem_upper, boot_device; + char *cmdline; + unsigned int mods_count, mods_addr; + union + { + struct + { + unsigned int tabsize, strsize, addr, _pad_; + } sym_aout; + struct + { + unsigned int num, size, addr, shndx; + } sym_elf; + } mb_sym_un; + unsigned int mmap_length, mmap_addr; +} multiboot_info; + + +#endif + diff --git a/include/stdarg.h b/include/stdarg.h @@ -0,0 +1,56 @@ +/* $NetBSD: stdarg.h,v 1.12 1995/12/25 23:15:31 mycroft Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stdarg.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _I386_STDARG_H_ +#define _I386_STDARG_H_ + +#include <ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define __va_size(type) \ + (((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long)) + +#define va_start(ap, last) \ + ((ap) = (va_list)&(last) + __va_size(last)) + +#define va_arg(ap, type) \ + (*(type *)((ap) += __va_size(type), (ap) - __va_size(type))) + +#define va_end(ap) ((void)0) + +#endif /* !_I386_STDARG_H_ */ diff --git a/include/stddef.h b/include/stddef.h @@ -0,0 +1,35 @@ +/* $Id: //depot/blt/include/stddef.h#2 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#define NULL ((void *) 0) + +#endif + diff --git a/include/stdio.h b/include/stdio.h @@ -0,0 +1,64 @@ +/* $Id: //depot/blt/include/stdio.h#7 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _STDIO_H_ +#define _STDIO_H_ + +#include <blt/types.h> + +typedef struct +{ + int fd; +} FILE; + +extern FILE *stdin, *stdout, *stderr; + +#ifdef __cplusplus +extern "C" { +#endif + + int _console_read (void *cookie, void *buf, size_t count); + + int _getc (FILE *stream); + int getc (FILE *stream); + int _getchar (void); + int getchar (void); + + int _printf (const char *format, ...); + int printf (const char *format, ...); + + int _snprintf (char *str, size_t size, const char *format, ...); + int snprintf (char *str, size_t size, const char *format, ...); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/stdlib.h b/include/stdlib.h @@ -0,0 +1,61 @@ +/* $Id: //depot/blt/include/stdlib.h#7 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _stdlib_h +#define _stdlib_h + +#include <blt/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + + void *_malloc(size_t size); + void *malloc(size_t size); + void _free(void *ptr); + void free(void *ptr); + void *_realloc(void *ptr, size_t size); + void *realloc(void *ptr, size_t size); + + void _exit (int status); + void exit (int status); + + void _qsort (void *base, size_t nmembers, size_t membsize, + int (*compar)(const void *, const void *)); + void qsort (void *base, size_t nmembers, size_t membsize, + int (*compar)(const void *, const void *)); + + int _atoi (const char *a); + int atoi (const char *a); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/string.h b/include/string.h @@ -0,0 +1,64 @@ +/* $Id: //depot/blt/include/string.h#9 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _STRING_H_ +#define _STRING_H_ + +#include <blt/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + + char *strcpy(char *dst, const char *src); + char *strcat(char *dst, const char *src); + char *strncpy(char *dst, const char *src, size_t size); + int strncmp(const char *s1, const char *s2, size_t n); + int strcmp(const char *s1, const char *s2); + size_t strlen(const char *str); + char *strchr (const char *cs, int c); + size_t strlcpy (char *dst, const char *src, size_t size); + size_t strlcat (char *dst, const char *src, size_t size); + + void *memset(void *s, int c, size_t n); + int memcmp(const void *dst, const void *src, size_t size); + void *memcpy(void *dst, const void *src, size_t size); + void *memmove(void *dest, const void *src, size_t n); + + int bcmp (const void *s, const void *t, size_t len); + void bzero (void *b, size_t len); + + char *_strerror (int errnum); + char *strerror (int errnum); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h @@ -0,0 +1,45 @@ +/* $Id: //depot/blt/include/sys/ioctl.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _SYS_IOCTL_H_ +#define _SYS_IOCTL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + int _ioctl (int fd, unsigned long request, char *argp); + int ioctl (int fd, unsigned long request, char *argp); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/sys/stat.h b/include/sys/stat.h @@ -0,0 +1,69 @@ +/* $Id: //depot/blt/include/sys/stat.h#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _SYS_STAT_H_ +#define _SYS_STAT_H_ + +#include <sys/types.h> + +struct stat +{ + dev_t st_dev; /* device on which filesystem resides */ + ino_t st_ino; /* inode number */ + mode_t st_mode; /* inode protection mode */ + nlink_t st_nlink; /* number of hard links to file */ + uid_t st_uid; /* user id of owner */ + gid_t st_gid; /* group id of owner */ + dev_t st_rdev; /* device type for device inodes */ + off_t st_size; /* file size in bytes */ + uint32 st_blocks; /* file size in blocks */ + uint32 st_blksize; /* size of block */ + struct timespec st_atimespec; /* time of last access */ + struct timespec st_mtimespec; /* time of last modification */ + struct timespec st_ctimespec; /* time of last status change */ + uint32 st_flags; /* user-defined flags */ + uint32 st_gen; /* file generation number */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int _stat (const char *path, struct stat *buf); +int stat (const char *path, struct stat *buf); + +int _mkdir (const char *path, mode_t mode); +int mkdir (const char *path, mode_t mode); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/sys/types.h b/include/sys/types.h @@ -0,0 +1,44 @@ +/* $Id: //depot/blt/include/sys/types.h#1 $ +** +** Copyright 1998 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _SYS_TYPES_H_ +#define _SYS_TYPES_H_ + +#include <blt/types.h> + +struct timespec +{ + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +#endif + diff --git a/include/unistd.h b/include/unistd.h @@ -0,0 +1,62 @@ +/* $Id: //depot/blt/include/unistd.h#11 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _UNISTD_H_ +#define _UNISTD_H_ + +#include <blt/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + + ssize_t _read (int fd, void *buf, size_t count); + ssize_t read (int fd, void *buf, size_t count); + ssize_t _write (int fd, const void *buf, size_t count); + ssize_t write (int fd, const void *buf, size_t count); + int _close (int fd); + int close (int fd); + + int _execve (const char *path, char * const *argv, char * const *envp); + int execve (const char *path, char * const *argv, char * const *envp); + + void *_sbrk (int diff); + void *sbrk (int diff); + + extern char *optarg; + extern int optind, optopt, opterr, optreset; + int _getopt (int argc, char * const *argv, const char *optstring); + int getopt (int argc, char * const *argv, const char *optstring); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/win/Button.h b/include/win/Button.h @@ -0,0 +1,21 @@ +#ifndef _BUTTON_H +#define _BUTTON_H + +#include "Canvas.h" + +class Button : public Canvas { +public: + Button(const char *text); + virtual ~Button(); + virtual void Invoke(); + +private: + virtual void Repaint(long, long, long, long); + virtual void EventReceived(const Event*); + + char *fText; + bool fMouseDown; + bool fOverButton; +}; + +#endif diff --git a/include/win/Canvas.h b/include/win/Canvas.h @@ -0,0 +1,51 @@ +#ifndef _CANVAS_H +#define _CANVAS_H + +class Window; +class Event; + +class Canvas { +public: + + Canvas(); + virtual ~Canvas(); + + void AddChild(Canvas *child, long left, long top, long right, long bottom); + void RemoveChild(Canvas *child); + void DrawLine(long, long, long, long); + void FillRect(long, long, long, long); + void SetBackgroundColor(char); + void SetPenColor(char); + void DrawString(long, long, const char*); + void Hide(); + void Show(); + void CopyRect(long left, long top, long right, long bottom, long newLeft, + long newTop); + Window* GetWindow() const; + void GetBounds(long *left, long *top, long *right, long *bottom); + void Invalidate(long left = 0, long top = 0, long right = 100000, long bottom + = 100000); + void LockMouseFocus(); + + virtual void Repaint(long left, long top, long right, long bottom); + virtual void EventReceived(const Event*); + + +private: + + void HandleEvent(Event*); + void BeginPaint(long *out_left, long *out_top, long *out_right, long *out_bottom); + void EndPaint(); + + int fID; + Window *fWindow; + bool fInPaint; + int fShowLevel; + Canvas *fWinListNext, **fWinListPrev; + long fLeft, fTop, fRight, fBottom; + + friend class Window; +}; + + +#endif diff --git a/include/win/Event.h b/include/win/Event.h @@ -0,0 +1,20 @@ +#ifndef _EVENT_H +#define _EVENT_H + +const int EVT_PAINT = 1; +const int EVT_QUIT = 2; +const int EVT_MOUSE_DOWN = 3; +const int EVT_MOUSE_UP = 4; +const int EVT_MOUSE_MOVED = 5; +const int EVT_MOUSE_ENTER = 6; +const int EVT_MOUSE_LEAVE = 7; + +struct Event { + int what; + int target; + + int x, y; +}; + +#endif + diff --git a/include/win/Window.h b/include/win/Window.h @@ -0,0 +1,44 @@ +#ifndef _WINDOW_H +#define _WINDOW_H + +#include <blt/qsem.h> + +class Canvas; +class Connection; +struct Event; + +class Window { +public: + + Window(long, long, long, long); + void Quit(); + void AddChild(Canvas *child, long left, long top, long right, long bottom); + void RemoveChild(Canvas *child); + void Flush(); + void MakeFocus(); + void Lock(); + void Unlock(); + void Show(); + void Hide(); + +private: + + ~Window(); + static int EventLoop(void*); + Canvas* FindChild(int id); + void DispatchEvent(Event*); + void WaitEvent(Event*); + + Connection *fConnection; + int fID; + int fShowLevel; + int fEventPort; + qsem_t *fLock; + + Canvas *fCanvasList; + + friend class Canvas; +}; + + +#endif +\ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile @@ -0,0 +1,18 @@ +BLTHOME := ../ +include $(BLTHOME)make.conf + +CFLAGS += -DASSERT $(SMP) $(SERIAL) $(SERIALDEBUG) +BINARY := kernel.bin +LIBS := -lkern -lconsole +ENTRY := $(ENTRY_KERNEL) +CRT0 := + +OBJS := stub.o kernel.o i386.o jump.o ktrace.o \ + memory.o resource.o port.o sem.o aspace.o task.o rights.o \ + list.o team.o fault.o syscall.o debug.o pager.o + +ifeq ($(SMP),-D__SMP__) +OBJS += smp.o cpuid.o trampoline.o +endif + +include $(BLTHOME)make.actions diff --git a/kernel/aspace.c b/kernel/aspace.c @@ -0,0 +1,453 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <blt/os.h> +#include "kernel.h" +#include "memory.h" +#include "aspace.h" + +extern uint32 _cr3; +extern aspace_t *flat; + +int snprintf (char *s, int len, const char *fmt, ...); + +void aspace_pprint(uint32 *page, uint32 vbase) +{ + int i,j; + + char buf[80]; + + for(i=0;i<1024;i++){ + if(page[i]){ + j = page[i]; + snprintf(buf,80,"%s %s %s ", + (j & 4) ? "USR" : "SYS", + (j & 2) ? "RW" : "RO", + (j & 1) ? "P" : "X"); + + snprintf(buf+9,80-9,"%xv %xp", i*4096+vbase, j&0xFFFFFF00); + + for(j=1;(i+j < 1024) && + ( (0xFFFFFF00 & page[i+j]) == + (0xFFFFFF00 & page[i+j-1])+0x1000 );j++); + + if(j>1) { + i += j-1; + snprintf(buf+29,80-29," - %xp (%x)", + 0x0FFF + (page[i]&0xFFFFFF00), j); + } + kprintf(buf); + } + } +} + +void aspace_kprint(aspace_t *a) +{ + aspace_pprint(a->high,0x80000000); +} + +void aspace_print(aspace_t *a) +{ + aspace_pprint(a->ptab,0); +} + +aspace_t *aspace_create(void) +{ + int i; + uint32 phys0,phys1; + uint32 *raw0,*raw1; + + aspace_t *a = kmalloc(aspace_t); + raw0 = kgetpage(&phys0); + raw1 = kgetpage(&phys1); + a->pdir = raw0; + a->ptab = raw1; + a->high = flat->high; + a->pdirphys = phys0; + list_init(&a->areas); + + for(i=0;i<1024;i++){ + a->pdir[i] = 0; + a->ptab[i] = 0; + } + a->pdir[0] = phys1 | 7; + a->pdir[512] = (_cr3 + 2*4096) | 3; + rsrc_bind(&a->rsrc, RSRC_ASPACE, kernel_team); + return a; +} + +void aspace_protect(aspace_t *a, uint32 virt, uint32 flags) +{ + a->ptab[virt] = ((a->ptab[virt] & 0xFFFFF000) | (flags & 0x00000FFF)); +} + +void aspace_map(aspace_t *a, uint32 phys, uint32 virt, uint32 len, uint32 flags) +{ + int i; + for(i=0;i<len;i++){ + a->ptab[virt+i] = (((phys+i)*4096) & 0xFFFFF000) | + (flags & 0x00000FFF); + local_flush_pte(0x1000*((virt)+i)); + } +} + +void aspace_maphi(aspace_t *a, uint32 phys, uint32 virt, uint32 len, uint32 flags) +{ + int i; + for(i=0;i<len;i++){ + a->high[(virt&0x3FF)+i] = (phys+i)*4096 | flags; + local_flush_pte(0x1000*((virt)+i)); + } + +} + +void aspace_clr(aspace_t *a, uint32 virt, uint32 len) +{ + int i; + for(i=0;i<len;i++){ + a->ptab[virt+i] = 0; + } +} + +void aspace_destroy(aspace_t *a) +{ + area_t *area; + + /* tear down all attached areas */ + while((area = (area_t*) list_peek_head(&a->areas))){ + area_destroy(a, area->rsrc.id); + } + + rsrc_release(&a->rsrc); + /* release page directory and table(s) */ + kfreepage(a->pdir); + kfreepage(a->ptab); + kfree(aspace_t, a); +} + +/* find a span of contig virtual pages */ +static int locate_span(aspace_t *a, uint32 start, uint32 len) +{ + uint32 *map = a->ptab; + uint32 found = 0; + uint32 foundat = 0; + + /* default to 2mb line if unspec or invalid */ + if((start < 1) || (start > 1023)) start = 512; + + while((found < len) && (start < 1024)){ + if(map[start]){ + found = 0; + foundat = 0; + } else { + if(found == 0) foundat = start; + found++; + } + start++; + } + return foundat; +} + +/* userland calls */ +int area_create(aspace_t *aspace, off_t size, off_t virt, void **addr, uint32 flags) +{ + int ppo,i,p=0,at; + area_t *area; + pagegroup_t *pg; + phys_page_t *pp; + size = (size & 0x0FFF) ? (size / 0x1000 + 1) : (size / 0x1000); + + if(size < 1) size = 1; + + if(flags & AREA_PHYSMAP) { + p = ((uint32) *addr) / 0x1000; + } + + /* find a virtaddr */ + if(!(at = locate_span(aspace, virt/0x1000, size))){ + return ERR_MEMORY; + } + + /* create a fresh pagegroup and enough phys_page_t's */ + pg = (pagegroup_t *) kmalloc(pagegroup_t); + pg->flags = flags; + pg->refcount = 1; + pg->size = size; + pg->pages = NULL; + list_init(&pg->areas); + for(i=0;i<size;i+=6){ + pp = (phys_page_t *) kmalloc(phys_page_t); + pp->refcount = 0; + pp->next = pg->pages; + pg->pages = pp; + }; + + /* create an area to ref the pagegroup */ + area = (area_t *) kmalloc(area_t); + area->pgroup = pg; + area->virt_addr = at; + area->length = size; + area->maxlength = size; + + /* link this area into the new pagegroup */ + list_add_tail(&pg->areas, area); + + /* link this area into the aspace's arealist */ + list_add_tail(&aspace->areas, area); + + /* check for valid ptr */ + *addr = (void *) (at * 0x1000); + + /* allocate pages, fill phys_page_t's, and map 'em */ + for(ppo=0,pp=pg->pages,i=0;i<size;i++){ + if(!(flags & AREA_PHYSMAP)) { + p = getpage(); + } + aspace_map(aspace, p, at, 1, 7); + pp->addr[ppo] = p; + ppo++; + if(ppo == 6) { + ppo = 0; + pp = pp->next; + } + if(flags & AREA_PHYSMAP) p++; + at++; + } + + /* + * zero extra space in last phys_page_t. + * careful, ppo == 0 and pp == NULL if size == 6. + */ + while((ppo < 6) && (pp != NULL)){ + pp->addr[ppo] = 0; + ppo++; + } + + /* bind the resource and return the id */ + rsrc_bind(&(area->rsrc), RSRC_AREA, current->rsrc.owner); + return area->rsrc.id; +} + +int area_create_uber(off_t size, void *addr) +{ + int ppo,i,p,at=0; + area_t *area; + pagegroup_t *pg; + phys_page_t *pp; + + size = (size & 0x0FFF) ? (size / 0x1000 + 1) : (size / 0x1000); + if(size < 1) size = 1; + + p = ((uint32) addr) / 0x1000; + + /* create a fresh pagegroup and enough phys_page_t's */ + pg = (pagegroup_t *) kmalloc(pagegroup_t); + pg->flags = AREA_PHYSMAP; + pg->refcount = 1; + pg->size = size; + pg->pages = NULL; + list_init(&pg->areas); + for(i=0;i<size;i+=6){ + pp = (phys_page_t *) kmalloc(phys_page_t); + pp->refcount = 0; + pp->next = pg->pages; + pg->pages = pp; + }; + + /* create an area to ref the pagegroup */ + area = (area_t *) kmalloc(area_t); + area->pgroup = pg; + area->virt_addr = at; + area->length = size; + area->maxlength = size; + + /* link this area into the new pagegroup */ + list_add_tail(&pg->areas, area); + + /* allocate pages, fill phys_page_t's, and map 'em */ + for(ppo=0,pp=pg->pages,i=0;i<size;i++){ + pp->addr[ppo] = p; + ppo++; + if(ppo == 6) { + ppo = 0; + pp = pp->next; + } + p++; + at++; + } + + /* + * zero extra space in last phys_page_t. + * careful, ppo == 0 and pp == NULL if size == 6. + */ + while((ppo < 6) && (pp != NULL)){ + pp->addr[ppo] = 0; + ppo++; + } + + /* bind the resource and return the id */ + rsrc_bind(&(area->rsrc), RSRC_AREA, kernel_team); + return area->rsrc.id; +} + +int area_clone(aspace_t *aspace, int area_id, off_t virt, void **addr, uint32 flags) +{ + area_t *area0, *area1; + uint32 at, size; + phys_page_t *pp; + int i,ppo; + + /* make sure the area exists */ + /* xxx : check perm */ + if(!(area0 = rsrc_find_area(area_id))) return ERR_RESOURCE; + + /* find virt space for it */ + if(!(at = locate_span(aspace, virt/0x1000, area0->length))){ + return ERR_MEMORY; + } + + +/* xxx lock area1 and area1->pgroup */ + + /* allocate the clone area and init it from the orig */ + area1 = (area_t *) kmalloc(area_t); + area0->pgroup->refcount++; + area1->pgroup = area0->pgroup; + size = area1->length = area0->length; + area1->maxlength = area0->maxlength; + area1->virt_addr = at; + + /* link this area into the new pagegroup */ + list_add_tail(&area0->pgroup->areas, area1); + + /* link this area into the aspace's arealist */ + list_add_tail(&aspace->areas, area1); + + /* check for valid ptr */ + *addr = (void *) (at * 0x1000); + + /* map the phys_page_t's into the clone area */ + for(ppo=0,i=0,pp=area1->pgroup->pages;i<size;i++){ + aspace_map(aspace, pp->addr[ppo], at, 1, 7); + at++; + ppo++; + if(ppo == 6){ + ppo = 0; + pp = pp->next; + } + } + /* + kprintf("area0 pgroup %x",area1->pgroup); + kprintf("area1 pgroup %x",area1->pgroup); + */ + /* bind and return an id */ + rsrc_bind(&(area1->rsrc), RSRC_AREA, current->rsrc.owner); +// kprintf("area_clone(%d) -> %d",area_id,area1->rsrc.id); + return area1->rsrc.id; +} + +int area_destroy(aspace_t *aspace, int area_id) +{ + area_t *area; + pagegroup_t *pg; + + if(!(area = rsrc_find_area(area_id))) return ERR_RESOURCE; + + /* find and unchain the area from its aspace -- complain if it is foreign */ + if(list_remove(&aspace->areas, area)) return ERR_RESOURCE; + + /* unmap the memory */ + aspace_clr(aspace, area->virt_addr, area->length); + + pg = area->pgroup; + + /* remove this area from the pgroup's area list */ + list_remove(&pg->areas, area); + + /* decr the pagegroup refcount and tear it down if zero */ + pg->refcount--; + + if(pg->refcount == 0){ + int release = !(pg->flags & AREA_PHYSMAP); + int count = 0; + phys_page_t *pp; + + while((pp = pg->pages)){ + pg->pages = pp->next; + if(release){ + for(count=0;pg->size && (count < 6);count++){ + putpage(pp->addr[count]); + pg->size--; + } + } + kfree(phys_page_t, pp); + } + kfree(pagegroup_t, pg); + } + + rsrc_release(&area->rsrc); + + kfree(area_t, area); + return ERR_NONE; +} + +int area_resize(aspace_t *aspace, int area_id, off_t size) +{ + area_t *area; + pagegroup_t *pg; + int ppo; + phys_page_t *pp,*pp0; + uint32 at,p; + + if(!(area = rsrc_find_area(area_id))) return ERR_RESOURCE; + + pg = area->pgroup; + pp = area->pgroup->pages; + +// kprintf("area_resize(%x,%d,%d)",aspace,area_id,size); + + if(size <= pg->size*0x1000) return 0; + + size = size/0x1000 - pg->size; /* pages to add */ + +// kprintf("area_resize: %x %x %x + %x",area,pg,pp,size); + + at = locate_span(aspace, area->virt_addr + pg->size, size); + if(at != (area->virt_addr + pg->size)) { + kprintf("oops: cannot grow area (%x != %x)",at,area->virt_addr+pg->size); + return ERR_MEMORY; + } + + while(pp->next) pp = pp->next; + ppo = pg->size % 6; + + pg->size += size; + area->length += size; + area->maxlength += size; + + while(size){ + if(!ppo){ + pp0 = (phys_page_t *) kmalloc(phys_page_t); + pp0->next = NULL; + pp->next = pp0; + pp0->refcount = 0; + pp = pp0; + } + p = getpage(); + aspace_map(aspace, p, at, 1, 7); + pp->addr[ppo] = p; + at++; + ppo++; + if(ppo == 6) ppo = 0; + size--; + } + + return 0; +} + + + + + + diff --git a/kernel/aspace.h b/kernel/aspace.h @@ -0,0 +1,72 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _ASPACE_H_ +#define _ASPACE_H_ + +#include "resource.h" +#include "list.h" + +#define SEL_KCODE (1*8) +#define SEL_KDATA (2*8) +#define SEL_KDATA2 (3*8) +#define SEL_UCODE (4*8) +#define SEL_UDATA (5*8) +#define SEL_KTSS (6*8) +#define SEL_UTSS (7*8) + +typedef struct __phys_page_t { + struct __phys_page_t *next; + uint32 refcount; + uint32 addr[6]; +} phys_page_t; /* 32 bytes */ + +typedef struct __pagegroup_t { + uint32 size; /* number of pages */ + uint32 refcount; /* number of areamaps */ + uint32 flags; /* page info */ + list_t areas; /* areas sharing this pagegroup */ + phys_page_t *pages; /* physical pages that compose this pagegroup */ +} pagegroup_t; + +struct __area_t { + resource_t rsrc; + pagegroup_t *pgroup; + uint32 virt_addr; /* virtual PAGE address */ + uint32 length; /* length in pages */ + uint32 maxlength; /* maxlength in pages */ +}; + +struct __aspace_t { + resource_t rsrc; + list_t areas; /* list of mapped areas */ + uint32 maxvirt; /* highest virt addr pagetabs maps */ + /* platform specific */ + uint32 *pdir; /* page directory -- 4k */ + uint32 *ptab; /* page table -- 4k */ + uint32 *high; /* high page table -- 4k (0x8000000 -> ) */ + uint32 pdirphys; /* physical address of page directory */ +}; + + +aspace_t *aspace_create(void); +void aspace_destroy(aspace_t *a); +void aspace_map(aspace_t *a, uint32 phys, uint32 virt, + uint32 len, uint32 flags); +void aspace_maphi(aspace_t *a, uint32 phys, uint32 virt, + uint32 len, uint32 flags); +void aspace_clr(aspace_t *a, uint32 virt, uint32 len); +void aspace_print(aspace_t *a); +void aspace_protect(aspace_t *a, uint32 virt, uint32 flags); + +/* userland stuff */ +int area_create(aspace_t *aspace, off_t size, off_t virt, void **addr, uint32 flags); +int area_create_uber(off_t size, void *addr); +int area_destroy(aspace_t *aspace, int area_id); +int area_clone(aspace_t *aspace, int area_id, off_t virt, void **addr, uint32 flags); +int area_destroy(aspace_t *aspace, int area_id); +int area_resize(aspace_t *aspace, int area_id, off_t size); + + +#endif diff --git a/kernel/cpuid.S b/kernel/cpuid.S @@ -0,0 +1,43 @@ +/* $Id: //depot/blt/kernel/cpuid.S#3 $ +** +** Copyright 1998 Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +#include "smp.h" + +.section ".text.init" + +.globl smp_check_cpu + +smp_check_cpu: + #.byte 0x66 + pushfl + #.byte 0x66 + popl %eax + movl %eax, %ebx + andl $0x00200000, %eax + jz not_pentium_or_newer + + xor %eax, %eax + cpuid + mov %eax, cpuid_max_level + + cmp %ebx, CPUID_GEN_EBX + jne not_genuine_intel + cmp %ecx, CPUID_GEN_ECX + jne not_genuine_intel + cmp %edx, CPUID_GEN_EDX + jne not_genuine_intel + + mov %eax, cpuid_eax + mov %edx, cpuid_edx + mov $1, %eax + ret + +not_pentium_or_newer: +not_genuine_intel: + xor %eax, %eax + mov %ebx, %eax + ret + diff --git a/kernel/debug.c b/kernel/debug.c @@ -0,0 +1,440 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef KDEBUG + +#include <i386/io.h> +#include <blt/conio.h> + +#include <string.h> +#include "kernel.h" +#include "port.h" +#include "rights.h" +#include "resource.h" +#include "list.h" +#include "i386.h" + +extern list_t resource_list; + +#define RMAX 1024 + +static char *tstate[] = +{ "KERNL", "RUNNG", "READY", "DEAD ", "WAIT ", "S/IRQ", "S/TMR", "S/PAG" }; + +uint32 readnum(const char *s); + +char *taskstate(task_t *task) +{ + static char ts[60]; + if(task->waiting_on){ + snprintf(ts,60,"Waiting on %s #%d \"%s\"", + rsrc_typename(task->waiting_on), task->waiting_on->id, + task->waiting_on->name); + return ts; + } else { + return "Running"; + } +} + +void printres(resource_t *r) +{ + switch(r->type){ + case RSRC_PORT: + kprintf(" PORT %U: (slave=%d) (size=%d) \"%s\"",r->id, + ((port_t*)r)->slaved, ((port_t*)r)->msgcount,r->name); + break; + case RSRC_TASK: + kprintf(" TASK %U: \"%s\"",r->id,r->name); + kprintf(" : %s",taskstate((task_t*)r)); + break; + case RSRC_ASPACE: + kprintf(" ASPACE %U: @ %x",r->id,((aspace_t*)r)->pdir[0]&0xFFFFF000); + break; + case RSRC_RIGHT: + kprintf(" RIGHT %U: %x",r->id,((right_t*)r)->flags); + break; + case RSRC_SEM: + kprintf(" SEM %U: (count=%d) \"%s\"", + r->id,((sem_t*)r)->count,r->name); + break; + case RSRC_AREA: + kprintf(" AREA %U: virt %x size %x pgroup %x (refcnt=%d)",r->id, + ((area_t*)r)->virt_addr * 0x1000, ((area_t*)r)->length * 0x1000, + ((area_t*)r)->pgroup, ((area_t*)r)->pgroup->refcount); + break; + case RSRC_QUEUE: + kprintf(" QUEUE %U: (count=%d) \"%s\"",r->id,r->queue.count,r->name); + break; + case RSRC_TEAM: + kprintf(" TEAM %U: \"%s\"",r->id,r->name); + break; + } +} + +void dumprsrc(list_t *rl) +{ + node_t *rn = rl->next; + while(rn != (node_t*) rl) { + printres((resource_t*)rn->data); + rn = rn->next; + } +} + +void dumponersrc(const char *num) +{ + int n; + node_t *rn; + + n = readnum (num); + rn = resource_list.next; + while(rn != (node_t*) &resource_list) { + if (((resource_t*)rn->data)->id == n) { + printres((resource_t*) rn->data); + break; + } else { + rn = rn->next; + } + } +} + +void dumptasks(void) +{ + int i,j,n; + task_t *t; + aspace_t *a; + team_t *team; + + kprintf("Task Team Aspc State Wait esp scount Name"); + kprintf("---- ---- ---- ----- ---- -------- -------- --------------------------------"); + + for(i=1;i<RMAX;i++){ + if((t = rsrc_find_task(i))){ + team = t->rsrc.owner; + a = team->aspace; + { + area_t *area = rsrc_find_area(t->rsrc.owner->heap_id); + if(area) j = area->virt_addr + area->length; + else j =0; + } + + kprintf("%U %U %U %s %U %x %x %s", + i,team->rsrc.id,a->rsrc.id,tstate[t->flags], + (t->waiting_on ? t->waiting_on->id : 0),t->esp /*j*4096*/,t->scount, + t->rsrc.name); + + } + } +} + + +void dumpports() +{ + int i; + port_t *p; + + kprintf("Port Task Rstr Slav Size Owner Name"); + kprintf("---- ---- ---- ---- ---- --------------------------------"); + + for(i=1;i<RMAX;i++){ + if((p = rsrc_find_port(i))){ + kprintf("%U %U %U %U %U %s", + i, p->rsrc.owner->rsrc.id, p->restrict, p->slaved, + p->msgcount, p->rsrc.owner->rsrc.name); + } + } + +} + + +static void trace(uint32 ebp,uint32 eip) +{ + int f = 1; + + kprintf("f# EBP EIP"); + kprintf("00 xxxxxxxx %x",eip); + do { +/* kprintf("%X %x %x",f,ebp, *((uint32*)ebp));*/ + kprintf("%X %x %x",f,ebp+4, *((uint32*)(ebp+4))); + ebp = *((uint32*)ebp); + f++; + } while(ebp < 0x00400000 && ebp > 0x00200000); +} + + +static void dump(uint32 addr, int sections) +{ + int i; + unsigned char *x; + + for(i=0;i<sections;i++){ + x = (unsigned char *) (addr + 16*i); + kprintf("%x: %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X", + addr+16*i,x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7], + x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15]); + } +} + +static char *hex = "0123456789abcdef"; + +#define atoi readhex +uint32 readhex(const char *s) +{ + uint32 n=0; + char *x; + while(*s) { + x = hex; + while(*x) { + if(*x == *s){ + n = n*16 + (x - hex); + break; + } + x++; + } + s++; + } + return n; +} + +uint32 readnum(const char *s) +{ + uint32 n=0; + if((*s == '0') && (*(s+1) == 'x')) return readhex(s+2); + //while(isdigit(*s)) { + while(*s) { + n = n*10 + (*s - '0'); + s++; + } + return n; +} + +void reboot(void) +{ + i386lidt(0,0); + asm("int $0"); +} + +extern aspace_t *flat; + +void dumpaddr(int id) +{ + node_t *an; + area_t *area; + aspace_t *a = rsrc_find_aspace(id); + + if(id == 0){ + aspace_kprint(flat); + return; + } + + if(!a) { + kprintf("no such aspace %d",id); + return; + } + + aspace_print(a); + for(an = a->areas.next; an != (node_t *) &a->areas; an = an->next){ + area = (area_t*) an->data; + + kprintf("area %U virtaddr %x size %x pgroup %x (refcnt=%d)", + area->rsrc.id, + area->virt_addr * 0x1000, + area->length * 0x1000, + area->pgroup, area->pgroup->refcount); + } + +} + +void memory_status(void); +void print_regs(regs *r, uint32 eip, uint32 cs, uint32 eflags); + +void dumpteams(void) +{ + node_t *rn = resource_list.next; + resource_t *rsrc; + + while(rn != (node_t*) &resource_list) { + rsrc = (resource_t*)rn->data; + if(rsrc->type == RSRC_TEAM){ + kprintf("Team %d (%s)",rsrc->id,rsrc->name); + } + rn = rn->next; + } +} + +void dumpteam(int id) +{ + node_t *rn; + + team_t *team = rsrc_find_team(id); + if(team){ + kprintf("team %d (%s)...",team->rsrc.id,team->rsrc.name); + rn = team->resources.next; + while(rn != (node_t*) &team->resources) { + printres((resource_t*) rn->data); + rn = rn->next; + } + } else { + kprintf("no such team %d",id); + } + +} + +void dumpqueue(int num) +{ + resource_t *rsrc; + node_t *n; + + int i; + + for(i=1;i<RSRC_MAX;i++){ + if(rsrc = rsrc_find(i,num)){ + task_t *task; + kprintf("resource: %d \"%s\"",rsrc->id,rsrc->name); + kprintf("type : %s",rsrc_typename(rsrc)); + if(rsrc->owner){ + kprintf("owner : %d \"%s\"", + rsrc->owner->rsrc.id,rsrc->owner->rsrc.name); + } + kprintf("count : %d",rsrc->queue.count); + + for(n = rsrc->queue.next; n != (node_t*) &rsrc->queue; n = n->next){ + kprintf("queue : task %d \"%s\"",((task_t*)n->data)->rsrc.id, + ((task_t*)n->data)->rsrc.name); + } + return; + } + } + kprintf("no such resource %d",n); +} + +static int ipchksum(unsigned short *ip, int len) +{ + unsigned long sum = 0; + + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return((~sum) & 0x0000FFFF); +} + +void checksum (char *range) +{ + char *s; + unsigned int i, good, begin, end; + + if (!*range) + return; + for (i = good = 0; (i < strlen (range)) && !good; i++) + { + if (range[i] == ' ') + { + *(s = range + i) = 0; + s++; + good = 1; + } + } + if ((!good) || !*s) + return; + begin = atoi (range); + end = atoi (s); + kprintf ("%x", ipchksum ((unsigned short *) begin, end - begin)); +} + +static void dumppgroup(uint32 addr) +{ + pagegroup_t *pg = (pagegroup_t*) addr; + phys_page_t *pp = pg->pages; + node_t *an = pg->areas.next; + int size = pg->size; + + kprintf("pgroup @ 0x%x rc=%d sz=%d",addr,pg->refcount,pg->size); + while(an != (node_t*) &pg->areas){ + kprintf(" area @ 0x%x (id %d) (owner #%d \"%s\")", + an->data,((area_t*)an->data)->rsrc.id, + ((area_t*)an->data)->rsrc.owner->rsrc.id, + ((area_t*)an->data)->rsrc.owner->rsrc.name); + an = an->next; + } + while(size > 0){ + kprintf(" pages %U %U %U %U %U %U", + pp->addr[0],pp->addr[1],pp->addr[2], + pp->addr[3],pp->addr[4],pp->addr[5]); + size -= 6; + pp = pp->next; + } +} + +int findpage(uint32 n) +{ + node_t *rn = resource_list.next; + resource_t *rsrc; + int count = 0; + int size,i; + + while(rn != (node_t*) &resource_list) { + rsrc = (resource_t*)rn->data; + if(rsrc->type == RSRC_AREA){ + area_t *area = (area_t*) rsrc; + phys_page_t *pp = area->pgroup->pages; + size = area->pgroup->size; + while(size > 0){ + for(i=0;i<6;i++,size--){ + if(pp->addr[i] == n){ + kprintf("area %U pgroup %x slot %d",rsrc->id,area->pgroup,i); + count ++; + } + } + pp = pp->next; + } + } + rn = rn->next; + } + return count; +} + +static char linebuf[80]; +void k_debugger(regs *r,uint32 eip, uint32 cs, uint32 eflags) +{ + char *line; + uint32 n; + + kprintf("OpenBLT Kernel Debugger"); + + for(;;){ + krefresh(); + line = kgetline(linebuf,80); + + if(!strncmp(line,"pgroup ",7)) { dumppgroup(readnum(line+7)); continue; } + if(!strncmp(line,"resource ", 9)) { dumponersrc(line+9); continue; } + if(!strcmp(line,"resources")) { dumprsrc(&resource_list); continue; } + if(!strncmp(line,"queue ",6)) { dumpqueue(readnum(line+6)); continue; } + if(!strcmp(line,"tasks")) { dumptasks(); continue; } + if(!strcmp(line,"ports")) { dumpports(); continue; } + if(!strcmp(line,"memory")) { memory_status(); continue; } + if(!strcmp(line,"trace")) { trace(r->ebp,eip); continue; } + if(!strcmp(line,"regs")) { print_regs(r,eip,cs,eflags); continue; } + if(!strncmp(line,"dump ",5)) { dump(readnum(line+5),16); continue; } + if(!strncmp(line,"aspace ",7)) { dumpaddr(readnum(line+7)); continue; } + if(!strcmp(line,"reboot")) { reboot(); } + if(!strncmp(line,"checksum ",9)) { checksum(line+9); continue; } + if(!strncmp(line,"team ",5)) { dumpteam(readnum(line+5)); continue; } + if(!strncmp(line,"find ",5)) { findpage(readnum(line+5)); continue; } + if(!strcmp(line,"teams")) { dumpteams(); continue; } + + if(!strcmp(line,"exit")) break; + if(!strcmp(line,"x")) break; + if(!strcmp(line,"c")) break; + } +} + +void DEBUGGER(void) +{ + regs r; + k_debugger(&r, 0, 0, 0); +} + +#endif diff --git a/kernel/fault.c b/kernel/fault.c @@ -0,0 +1,329 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <i386/io.h> +#include "kernel.h" +#include "memory.h" +#include "smp.h" +#include "init.h" +#include "port.h" +#include "task.h" +#include "aspace.h" +#include "resource.h" +#include "pager.h" +#include "i386.h" + +#define noHALT_ON_FAULT +#define DEBUG_ON_FAULT +#define noCRASH_ON_FAULT + +static char *etable[] = { + "Divide-by-zero", + "Debug Exception", + "NMI", + "Breakpoint", + "INTO", + "BOUNDS", + "Invalid Opcode", + "Device Not Available", + "Double-fault", + "Coprocessor segment overrun", + "Invalid TSS fault", + "Segment Not Present", + "Stack Exception", + "General Protection", + "Page Fault", + "*reserved*", + "Floating-point error", + "Alignment Check", + "Machine Check" +}; + +typedef void (*ehfunc)(); + +static void __fault(uint32 number, regs r, uint32 eip, uint32 cs, + uint32 eflags); +static void __faultE(uint32 number, regs r, uint32 error, uint32 eip, uint32 cs, + uint32 eflags); + +ehfunc ehfunctab[] = + { __fault, __fault, __fault, __fault, + __fault, __fault, __fault, __fault, + __faultE, __fault, __faultE, __faultE, + __faultE, __faultE, __faultE /*page_fault*/, __fault, + __fault, __fault, __fault }; + +extern unsigned char *screen; + +task_t *irq_task_map[16]; + +void k_debugger(regs *r, uint32 eip, uint32 cs, uint32 eflags); +void terminate(void); + +void print_regs(regs *r, uint32 eip, uint32 cs, uint32 eflags) +{ + kprintf(" EAX = %x EBX = %x ECX = %x EDX = %x", + r->eax, r->ebx, r->ecx, r->edx); + kprintf(" EBP = %x ESP = %x ESI = %x EDI = %x", + r->ebp, r->esp, r->esi, r->edi); + kprintf("EFLAGS = %x CS = %x EIP = %x", + eflags, cs, eip); +} + +void user_debug(regs *r, uint32 *eip, uint32 *eflags) +{ +#if 1 + return; +#else + int src,p,sz; + task_t *t0; + uchar buf[16]; + uint32 code; + + p = port_create(0, "debug control"); + + /* wake all blocking objects */ + while((t0 = list_detach_head(&current->rsrc.queue))) task_wake(t0,ERR_RESOURCE); + + kprintf("Waiting on debug control port (%d)... ",p); + current->team = kernel_team; // XXX hack + + while((sz = port_recv(p, &src, buf, 16, &code)) >= 0){ + } + kprintf("debug control error %d\n",sz); + +#endif +} + + +static void __faultE(uint32 number, + regs r, uint32 error, + uint32 eip, uint32 cs, uint32 eflags) +{ + uint32 _cr2, _cr3; + + kprintf(""); + kprintf("*** Exception 0x%X* (%s)",number,etable[number]); +#ifdef __SMP__ + if (smp_configured) + kprintf (" on cpu#%d", smp_my_cpu ()); +#endif + print_regs(&r, eip, cs, eflags); + + asm("mov %%cr2, %0":"=r" (_cr2)); + asm("mov %%cr3, %0":"=r" (_cr3)); + kprintf(" cr2 = %x cr3 = %x error = %x",_cr2,_cr3,error); + kprintf(""); + kprintf("Task %d (%s) crashed.",current->rsrc.id,current->rsrc.name); + + if((cs & 0xFFF8) == SEL_UCODE) user_debug(&r, &eip, &eflags); + +#ifdef DEBUG_ON_FAULT + current->flags = tDEAD; + k_debugger(&r, eip, cs, eflags); +#endif + +#ifdef HALT_ON_FAULT + asm("hlt"); +#endif + + terminate(); +} + +static void __fault(uint32 number, + regs r, + uint32 eip, uint32 cs, uint32 eflags) +{ + + kprintf(""); + kprintf("*** Exception 0x%X (%s)",number,etable[number]); + print_regs(&r, eip, cs, eflags); + + kprintf(""); + kprintf("Task %d (%s) crashed.",current->rsrc.id,current->rsrc.name); + + if((cs & 0xFFF8) == SEL_UCODE) user_debug(&r, &eip, &eflags); + +#ifdef DEBUG_ON_FAULT + if(number != 2){ + current->flags = tDEAD; + } + k_debugger(&r, eip, cs, eflags); +#endif +#ifdef HALT_ON_FAULT + asm("hlt"); +#endif + if(number != 2){ + terminate(); + } +} + +void irq_dispatch(regs r, uint32 number) +{ + mask_irq(number); + if(irq_task_map[number]){ + if(irq_task_map[number]->flags == tSLEEP_IRQ){ + preempt(irq_task_map[number],ERR_NONE); + } + } +} + +int kernel_timer = 0; + +unsigned char x[] = { '-', '-', '\\', '\\', '|', '|', '/', '/' }; + +void pulse (void) +{ +#ifndef __SMP__ + screen[0] = x[kernel_timer%8]; + screen[1] = 7; +#else + screen[smp_my_cpu () * 2] = x[kernel_timer%8]; + screen[smp_my_cpu () * 2 + 1] = 7; +#endif +} + +void timer_irq(regs r, uint32 eip, uint32 cs, uint32 eflags) +{ + task_t *task; + kernel_timer++; + + while((task = rsrc_queue_peek(timer_queue))){ + if(task->wait_time <= kernel_timer){ + task = rsrc_dequeue(timer_queue); + rsrc_enqueue(run_queue, task); + } else { + break; + } + } +#ifdef PULSE + pulse (); +#endif + swtch(); +} + +extern void __null_irq(void); +extern void __timer_irq(void); +extern void __kbd_irq(void); +extern void __syscall(void); + +#define EX(n) extern void __ex##n(void); +EX(0); EX(1); EX(2); EX(3); EX(4); EX(5); EX(6); EX(7); EX(8); EX(9); +EX(10); EX(11); EX(12); EX(13); EX(14); EX(15); EX(16); EX(17); EX(18); + +#define IQ(n) extern void __irq##n(void); +IQ(1); IQ(2); IQ(3); IQ(4); IQ(5); IQ(6); IQ(7); IQ(8); IQ(9); +IQ(10); IQ(11); IQ(12); IQ(13); IQ(14); IQ(15); + +extern void __ipi_cf (void), __ipi_tlb (void), __ipi_pte (void), + __ipi_resched (void), __ipi_stop (void); + +static void set_irq(uint32 *IDT, int n, void *func) +{ + IDT[2*n+1] = (((uint32) func) & 0xFFFF0000) | 0x00008E00; + IDT[2*n] = (((uint32) func) & 0x0000FFFF) | (SEL_KCODE << 16); +} + +static void set_irqU(uint32 *IDT, int n, void *func) +{ + IDT[2*n+1] = (((uint32) func) & 0xFFFF0000) | 0x00008E00 | 0x00006000; + IDT[2*n] = (((uint32) func) & 0x0000FFFF) | (SEL_KCODE << 16); +} + +void __init__ init_idt(uint32 *IDT) +{ + int i; + for(i=0;i<16;i++) irq_task_map[i] = NULL; + + set_irq(IDT,0x00,__ex0); + set_irq(IDT,0x01,__ex1); + set_irq(IDT,0x02,__ex2); + set_irq(IDT,0x03,__ex3); + set_irq(IDT,0x04,__ex4); + set_irq(IDT,0x05,__ex5); + set_irq(IDT,0x06,__ex6); + set_irq(IDT,0x07,__ex7); + set_irq(IDT,0x08,__ex8); + set_irq(IDT,0x09,__ex9); + set_irq(IDT,0x0A,__ex10); + set_irq(IDT,0x0B,__ex11); + set_irq(IDT,0x0C,__ex12); + set_irq(IDT,0x0D,__ex13); + set_irq(IDT,0x0E,__ex14); + set_irq(IDT,0x0F,__ex15); + set_irq(IDT,0x10,__ex16); + set_irq(IDT,0x11,__ex17); + set_irq(IDT,0x12,__ex18); + + set_irqU(IDT,0x20,__syscall); + + set_irq(IDT,0x30,__timer_irq); + set_irq(IDT,0x31,__irq1); + set_irq(IDT,0x32,__irq2); + set_irq(IDT,0x33,__irq3); + set_irq(IDT,0x34,__irq4); + set_irq(IDT,0x35,__irq5); + set_irq(IDT,0x36,__irq6); + set_irq(IDT,0x37,__irq7); + set_irq(IDT,0x38,__irq8); + set_irq(IDT,0x39,__irq9); + set_irq(IDT,0x3A,__irq10); + set_irq(IDT,0x3B,__irq11); + set_irq(IDT,0x3C,__irq12); + set_irq(IDT,0x3D,__irq13); + set_irq(IDT,0x3E,__irq14); + set_irq(IDT,0x3F,__irq15); + +#ifdef __SMP__ + set_irq(IDT,0x40,__ipi_cf); + set_irq(IDT,0x41,__ipi_tlb); + set_irq(IDT,0x42,__ipi_pte); + set_irq(IDT,0x43,__ipi_resched); + set_irq(IDT,0x44,__ipi_stop); +#endif + + i386lidt((uint32) IDT, 0x3FF); + + remap_irqs(); + unmask_irq(0); + unmask_irq(2); +} + +void restore_idt(void) +{ + unmap_irqs(); + i386lidt(0,0x3FF); +} + + +#ifdef __SMP__ +void ipi_dispatch (regs r, uint32 number) +{ + unsigned int config; + + kprintf ("cpu#%d got ipi %x", smp_my_cpu (), number); + apic_write (APIC_EOI, 0); + switch (number) + { + case IPI_CACHE_FLUSH: + asm ("wbinvd"); + break; + case IPI_INV_TLB: + local_flush_tlb (); + break; + case IPI_INV_PTE: + local_flush_tlb (); /* FIXME */ + break; + case IPI_INV_RESCHED: + break; + case IPI_STOP: + config = apic_read (APIC_LVTT); + apic_write (APIC_LVTT, config | 0x10000); + while (!smp_begun) ; + apic_write (APIC_LVTT, config); + break; + } +} +#endif + diff --git a/kernel/i386.c b/kernel/i386.c @@ -0,0 +1,205 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Copyright 1998-1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "types.h" +#include "i386.h" +#include <i386/io.h> + +void i386SetSegment(void *entry, + uint32 base, uint32 limit, + uint8 rights, uint8 gran) +{ + *((uint32 *) entry) = (limit & 0xFFFF) | ((base & 0xFFFF) << 16); + + *((uint32 *) ( ((char *) entry) + 4 ) ) = + ((base & 0x00FF0000) >> 16) | (base & 0xFF000000) | + (rights << 8) | ((gran & 0xF0) << 16) | + ((limit & 0x000F000) << 4); +} + +void i386SetTaskGate(void *entry, uint16 selector, uint8 rights) +{ + *((uint32 *) entry) = selector << 16; + *((uint32 *) ( ((char *) entry) + 4 ) ) = (0x05 | (rights & 0xF0)) << 8; +} + +/* thanks to paul swanson for these... */ + +void i386ltr(uint32 selector) +{ + __asm__ __volatile__ ("ltr %%ax": :"eax" (selector)); +} + +void i386lidt(uint32 base, uint32 limit) +{ + uint32 i[2]; + + i[0] = limit << 16; + i[1] = (uint32) base; + __asm__ __volatile__ ("lidt (%0)": :"p" (((char *) i)+2)); +} + +void i386lgdt(uint32 base, uint32 limit) +{ + uint32 i[2]; + + i[0] = limit << 16; + i[1] = base; + __asm__ __volatile__ ("lgdt (%0)": :"p" (((char *) i)+2)); +} + +uint32 *i386sgdt(uint32 *limit) +{ + uint32 gdtptr[2]; + __asm__ __volatile__ ("sgdt (%0)": :"p" (((char *) gdtptr)+2)); + *limit = gdtptr[0] >> 16; + return (uint32 *) gdtptr[1]; +} + +#if 0 +//#ifdef __SMP__ + +void remap_irqs (void) +{ + unsigned int i, config; + + for (i = 0; i < 16; i++) + { + config = + ioapic_write (IOAPIC_REDIR_TABLE + 2 * i, config); + config = 0xff << 24; /* logical destination address */ + ioapic_write (IOAPIC_REDIR_TABLE + 2 * i + 1, config); + } +} + +void unmap_irqs (void) +{ +} + +void unmask_irq (int irq) +{ +} + +void mask_irq (int irq) +{ +} + +#else /* __SMP__ */ + +#define PORTA0 0x20 +#define PORTB0 0x21 +#define PORTA1 0xA0 +#define PORTB1 0xA1 + +void remap_irqs(void) +{ + outb_p(0x11, PORTA0); + outb_p(0x30, PORTB0); + outb_p(0x04, PORTB0); + outb_p(0x01, PORTB0); + outb_p(0xff, PORTB0); + + outb_p(0x11, PORTA1); + outb_p(0x38, PORTB1); + outb_p(0x02, PORTB1); + outb_p(0x01, PORTB1); + outb_p(0xff, PORTB1); +} + +void unmap_irqs(void) +{ + outb_p(0x11, PORTA0); + outb_p(0x08, PORTB0); + outb_p(0x04, PORTB0); + outb_p(0x01, PORTB0); + outb_p(0x00, PORTB0); + + outb_p(0x11, PORTA1); + outb_p(0x70, PORTB1); + outb_p(0x02, PORTB1); + outb_p(0x01, PORTB1); + outb_p(0x00, PORTB1); +} + +void unmask_irq(int irq) +{ + if(irq < 8) + outb((inb(PORTB0) & ~(1 << irq)), PORTB0); + else + outb((inb(PORTB1) & ~(1 << (irq-8))), PORTB1); +} + +void mask_irq(int irq) +{ + if(irq < 8) + outb((inb(PORTB0) | (1 << irq)), PORTB0); + else + outb((inb(PORTB1) | (1 << (irq-8))), PORTB1); +} + +#endif /* __SMP__ */ + +static int PIT_COUNTER[2][3]={ { 0x40, 0x41, 0x42 }, + { 0x48, 0x49, 0x4a } }; +static int PIT_CONTROL[2] = { 0x43, 0x4b }; + +#define PIT_DOSRESET 1 // resert PIT to DOS condition +#define PIT_IKU 2 // start preemptivlly multitasking + +void init_timer(void) +{ + outb(0x24,PIT_CONTROL[0]); + /* write to counter 0, binary, high byte, mode 2 */ +#if 0 + outb(0x2f,PIT_COUNTER[0][0]); + /*0x2f00=12032 * .8380965us ~= 10.083ms*/ +#else + outb(0x0e,PIT_COUNTER[0][0]); + /*0x0e00=3584 * .8380965us ~= 3.004ms*/ +#endif +} + +void cli (void) +{ + asm ("cli"); +} + +void sti (void) +{ + asm ("sti"); +} + +void local_flush_tlb (void) +{ + int junk; + + asm ("mov %%cr3, %0 ; mov %0, %%cr3" : : "r" (junk)); +} + +void local_flush_pte (unsigned int addr) +{ +#ifdef I386 + local_flush_tlb (); +#else + asm ("invlpg (%0)" : : "r" (addr)); +#endif +} + +void p (unsigned char *lock) +{ + int res; + + res = 1; + asm ("lock ; xchgb %1, %0" : "=m" (*lock), "=r" (res) : "1" (res) : "memory"); + while (res) + asm ("lock ; xchgb %1, %0" : "=m" (*lock), "=r" (res) : "1" (res) : + "memory"); +} + +void v (unsigned char *lock) +{ + asm ("lock ; btrl $0, %0" : "=m" (*lock)); +} + diff --git a/kernel/i386.h b/kernel/i386.h @@ -0,0 +1,76 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _I386_H +#define _I386_H + +typedef struct +{ + uint16 link, __unused0; + uint32 esp0; + uint16 ss0, __unused1; + uint32 esp1; + uint16 ss1, __unused2; + uint32 esp2; + uint16 ss2, __unused3; + uint32 cr3,eip,eflags,eax,ecx,edx,ebx,esp,ebp,esi,edi; + uint16 es, __unused4; + uint16 cs, __unused5; + uint16 ss, __unused6; + uint16 ds, __unused7; + uint16 fs, __unused8; + uint16 gs, __unused9; + uint16 ldts, __unused10; + uint16 debugtrap, iomapbase; +} TSS; + +typedef struct { uint32 edi, esi, ebp, esp, ebx, edx, ecx, eax; } regs; + +/* rights bits options */ +#define i386rPRESENT 0x80 /* segment is present */ + +#define i386rDPL0 0x00 +#define i386rDPL1 0x20 +#define i386rDPL2 0x40 +#define i386rDPL3 0x60 + +/* for Data/Code/TSS segments */ +#define i386rDATA 0x12 /* segment is data, read/write */ +#define i386rDATAro 0x10 /* segment is data, read only */ +#define i386rCODE 0x1A /* segment is code, read/exec */ +#define i386rCODExo 0x18 /* segment is code, read only */ + +#define i386rTSS 0x09 /* segment is an i386 TSS */ + +/* gran bits options */ +#define i386g4K 0x80 /* segment gran is 4K (else 1B) */ +#define i386g32BIT 0x40 /* segment default is 32bit (else 16bit) */ +#define i386gAVL 0x10 /* segment AVL is set */ + +void i386SetSegment(void *entry, + uint32 base, uint32 limit, + uint8 rights, uint8 gran); +void i386SetTaskGate(void *entry, uint16 selector, uint8 rights); + +void i386ltr(uint32 selector); +void i386lidt(uint32 base, uint32 limit); +void i386lgdt(uint32 base, uint32 limit); +uint32 *i386sgdt(uint32 *limit); + +#define I386_PAGING_ON() asm("push %eax; mov %cr0, %eax; orl $0x80000000,%eax ; mov %eax, %cr0 ; pop %eax"); +#define I386_PAGING_OFF() asm("push %eax; mov %cr0, %eax; andl $0x7FFFFFFF,%eax ; mov %eax, %cr0 ; pop %eax"); + +void unmap_irqs(void); +void remap_irqs(void); +void unmask_irq(int irq); +void mask_irq(int irq); +void init_timer(void); + +void cli (void); +void sti (void); +void local_flush_tlb (void); +void local_flush_pte (unsigned int addr); + +#endif /* _I386_H */ + diff --git a/kernel/init.h b/kernel/init.h @@ -0,0 +1,33 @@ +/* Copyright 1998-1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _INIT_H_ +#define _INIT_H_ + +/* + * Behold macros to place functions or variables in special elf sections. To + * use these jewels, write your functions like this + * + * void __init__ foo_init (int a, int b) + * { + * } + * + * and your function prototypes like this + * + * extern void foo_init (int a, int b) __init__; + * + * and your data like this + * + * static char *foo_stuff __initdata__ = "Foo rules the world."; + * + * At some point in the future, the .text.init and .data.init sections of the + * kernel may be discarded at the end of the kernel's initialisation to free + * up a bit of memory. + */ + +#define __init__ __attribute__ ((__section__ (".text.init"))) +#define __initdata__ __attribute__ ((__section__ (".data.init"))) + +#endif + diff --git a/kernel/jump.S b/kernel/jump.S @@ -0,0 +1,208 @@ +/* $Id: //depot/blt/kernel/jump.S#8 $ +** +** Copyright 1998 Brian Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +#include "smp.h" + +.text +.globl __syscall +.globl __null_irq +.globl __timer_irq +.globl __kbd_irq +.globl __ipi_cf +.globl __ipi_tlb +.globl __ipi_pte +.globl __ipi_resched +.globl __ipi_stop +.globl ehfunctab + +__null_irq: + movb $32, %al + outb %al, $32 + iret + +__syscall: + pusha + call syscall + popa + iret + +__timer_irq: + pusha +#ifdef __SMP__ + movb smp_configured, %al + cmpb $1, %al + je 1f +#endif + movb $32, %al + outb %al, $32 +#ifdef __SMP__ + jmp 2f +1: + call apic_eoi +#endif +2: + call timer_irq + popa + iret + +#define FAULT(n) \ +.globl __ex##n ;\ +__ex##n: ;\ + pusha ;\ + push $n ;\ + mov $(n * 4 + ehfunctab), %ebx ;\ + mov (%ebx), %ebx ;\ + call *%ebx ;\ + add $4,%esp ;\ + popa ;\ + iret + +#define FAULTE(n) \ +.globl __ex##n ;\ +__ex##n: ;\ + pusha ;\ + push $n ;\ + mov $(n * 4 + ehfunctab), %ebx ;\ + mov (%ebx), %ebx ;\ + call *%ebx ;\ + add $4,%esp ;\ + popa ;\ + add $4,%esp ;\ + iret + +FAULT(0) +FAULT(1) +FAULT(2) +FAULT(3) +FAULT(4) +FAULT(5) +FAULT(6) +FAULT(7) +FAULTE(8) +FAULT(9) +FAULTE(10) +FAULTE(11) +FAULTE(12) +FAULTE(13) +FAULTE(14) +FAULT(15) +FAULT(16) +FAULT(17) +FAULT(18) + +#define IRQ(n) \ +.globl __irq##n ;\ +__irq##n: ;\ + push $n ;\ + pusha ;\ + call irq_dispatch ;\ + movb $0x20, %al ;\ + outb %al, $0x20 ;\ + popa ;\ + add $4,%esp ;\ + iret + +#define IRQHI(n) \ +.globl __irq##n ;\ +__irq##n: ;\ + push $n ;\ + pusha ;\ + call irq_dispatch ;\ + movb $0x20, %al ;\ + outb %al, $0xA0 ;\ + movb $0x20, %al ;\ + outb %al, $0x20 ;\ + popa ;\ + add $4,%esp ;\ + iret + +IRQ(1) +IRQ(2) +IRQ(3) +IRQ(4) +IRQ(5) +IRQ(6) +IRQ(7) +IRQHI(8) +IRQHI(9) +IRQHI(10) +IRQHI(11) +IRQHI(12) +IRQHI(13) +IRQHI(14) +IRQHI(15) + +# From: Jeff Bush <jeff@be.com> + +;# 1. Stores necessary registers on old stack +;# 2. Changes old stack pointer to reflect new offset +;# 3. Change address space if necessary +;# 4. Pops state off old stack +;# 5. returns to address on old stack, resuming thread + + +.globl _context_switch +.globl thread_bootstrap +.globl kthread_bootstrap + +_context_switch: + pushf + pushl %ebp + pushl %esi + pushl %edi + pushl %ebx + movl 24(%esp), %eax # Where to save stack pointer + movl %esp, (%eax) # Save old stack + movl 32(%esp), %eax # Get new PDBR + movl 28(%esp), %ebx # Get new stack loc + + cmpl $0, %eax # Need to change addr. space? + je changed_pdbr # If parameter was zero, no + movl %eax, %cr3 # Change address space + +changed_pdbr: movl %ebx, %esp # switch to new stack + popl %ebx + popl %edi + popl %esi + popl %ebp + popf + ret + +thread_bootstrap: + iret + +kthread_bootstrap: + lret + + +#ifdef __SMP__ + +__ipi_cf: + pushl $0x40 + jmp __ipi +__ipi_tlb: + pushl $0x41 + jmp __ipi +__ipi_pte: + pushl $0x42 + jmp __ipi +__ipi_resched: + pushl $0x43 + jmp __ipi +__ipi_stop: + pushl $0x44 + jmp __ipi + +__ipi: + pusha + call ipi_dispatch + call apic_eoi + popa + add $4, %esp + iret + +#endif + diff --git a/kernel/kernel.c b/kernel/kernel.c @@ -0,0 +1,448 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <blt/os.h> +#include "kernel.h" +#include "memory.h" +#include "boot.h" +#include "port.h" + +#include <i386/io.h> +#include <string.h> +#include "resource.h" +#include "aspace.h" +#include "task.h" +#include "smp.h" +#include "team.h" +#include "pager.h" + +void DEBUGGER(void); + +void restore_idt(void); +void init_idt(char *idt); + +void _context_switch(uint32 *old_stack, uint32 new_stack, uint32 pdbr); + +aspace_t *flat = NULL; +boot_dir *bdir = NULL; + +char *idt; +char *gdt; +char *gdt2; +char *toppage; +task_t *current; +task_t *kernel; +uint32 gdt2len; +uint32 entry_ebp; +uint32 _cr3; +task_t *idle_task; +int live_tasks = 0; + +resource_t *run_queue, *timer_queue, *reaper_queue; +team_t *kernel_team = NULL; +int reaper_sem; + +uint32 memsize; /* pages */ +uint32 memtotal; + +static int uberportnum = 0, uberareanum = 0; + +void destroy_kspace(void) +{ +/* memory_status();*/ + + asm("mov %0, %%cr3"::"r" (_cr3)); /* insure we're in kernel map */ + restore_idt(); + + i386lgdt((uint32)gdt2,gdt2len); + asm ("mov %0, %%esp; ret": :"r" (entry_ebp + 4)); +} + +void panic(char *reason) +{ + kprintf(""); + kprintf("PANIC: %s",reason); + DEBUGGER(); + asm("hlt"); +} + +void idler(void) +{ + for(;;){ + asm("hlt"); + } +} + +void reaper(void) +{ + task_t *task; + + asm("cli"); /* XXX race condition? */ + for(;;){ + sem_acquire(reaper_sem); + task = rsrc_dequeue(reaper_queue); +// kprintf("reaper reclaiming thread #%d (%s)",task->rsrc.id,task->rsrc.name); + task_destroy(task); + } + +} + +static aspace_t _flat; +static TSS *ktss; + +void init_kspace(int membottom) +{ + uint32 *raw; + + /* there's an existing aspace at vaddr 0x803FD000 that was initialized + by the 2nd stage loader */ + raw = (uint32 *) 0x803FD000; + flat = &_flat; + flat->pdir = raw; + flat->ptab = &raw[1024]; + flat->high = &raw[2048]; + memtotal = memsize; + + memsize -= 3; /* three pages already in use */ + + memory_init(membottom, memsize); + + + toppage = (char *) kgetpages(3); /* kernel startup stack */ + gdt = (char *) kgetpages(1); + rsrc_init(kgetpages(6),4096*6); + + + kernel = (task_t *) kmalloc(task_t); + ktss = (TSS *) kgetpages(1); + kernel->flags = tKERNEL; + kernel->rsrc.id = 0; + kernel->rsrc.owner = NULL; + list_init(&kernel->rsrc.rights); + list_init(&kernel->rsrc.queue); + current = kernel; + + init_idt(idt = kgetpages(1)); /* init the new idt, save the old */ + gdt2 = (void *) i386sgdt(&gdt2len); /* save the old gdt */ + + i386SetSegment(gdt + SEL_KCODE, /* #01 - 32bit DPL0 CODE */ + 0, 0xFFFFF, + i386rPRESENT | i386rDPL0 | i386rCODE, + i386g4K | i386g32BIT); + + i386SetSegment(gdt + SEL_KDATA, /* #02 - 32bit DPL0 DATA */ + 0, 0xFFFFF, + i386rPRESENT | i386rDPL0 | i386rDATA, + i386g4K | i386g32BIT); + + i386SetSegment(gdt + SEL_KDATA2, /* #02 - 32bit DPL0 DATA */ + 0, 0xFFFFF, + i386rPRESENT | i386rDPL0 | i386rDATA, + i386g4K | i386g32BIT); + + i386SetSegment(gdt + SEL_UCODE, /* #03 - 32bit DPL3 CODE */ + 0, 0xFFFFF, + i386rPRESENT | i386rDPL3 | i386rCODE, + i386g4K | i386g32BIT); + + i386SetSegment(gdt + SEL_UDATA, /* #04 - 32bit DPL3 DATA */ + 0, 0xFFFFF, + i386rPRESENT | i386rDPL3 | i386rDATA, + i386g4K | i386g32BIT); + + i386SetSegment(gdt + SEL_KTSS, /* #05 - DPL0 TSS (Kernel) */ + (uint32) ktss, 104, + i386rPRESENT | i386rDPL0 | i386rTSS, + 0); + + i386lgdt((uint32) gdt, 1024/8); + + asm("mov %%cr3, %0":"=r" (_cr3)); + + /* setup the kernel TSS to insure that it's happy */ + ktss->cs = SEL_KCODE; + ktss->ds = ktss->es = ktss->ss = ktss->fs = ktss->gs = SEL_KDATA; + ktss->ldts = ktss->debugtrap = ktss->iomapbase = 0; + ktss->cr3 = _cr3; + ktss->ss0 = SEL_KDATA; + ktss->esp1 = ktss->esp2 = ktss->ss1 = ktss->ss2 = 0; + i386ltr(SEL_KTSS); +} + +/* current is running -- we want to throw it on the run queue and + transfer control to the preemptee */ +void preempt(task_t *task, int status) +{ + uint32 *savestack = &(current->esp); + + /* current thread MUST be running, requeue it */ + if(current != idle_task) rsrc_enqueue(run_queue, current); + + TCHKMAGIC(task); + if(task == (task_t *)tDEAD) panic("The dead have returned!"); + + /* transfer control to the preemtee -- it had better not be on any queues */ + current = task; + current->status = status; + current->flags = tRUNNING; + current->scount++; + ktss->esp0 = current->esp0; + if(*savestack != current->esp){ + _context_switch(savestack, current->esp, current->cr3); + } +} + +void swtch(void) +{ + /* current == running thread */ + uint32 *savestack = &(current->esp); + + /* fast path for the case of only one running thread */ + if(!run_queue->queue.count && (current->flags == tRUNNING)) return; + + if(current->flags == tRUNNING) { + if(current != idle_task) rsrc_enqueue(run_queue, current); + } + + /* get the next candidate */ + current = rsrc_dequeue(run_queue); + + if(!current) { + if(live_tasks){ + current = idle_task; + } else { + kprintf(""); + kprintf("No runnable tasks. Exiting."); + destroy_kspace(); + } + } + + if(current->flags == tDEAD) panic("The dead have returned!"); + TCHKMAGIC(current); + + current->flags = tRUNNING; + current->scount++; + ktss->esp0 = current->esp0; + if(*savestack != current->esp){ + _context_switch(savestack, current->esp, current->cr3); + } +} + +task_t *new_thread(team_t *team, uint32 ip, int kernelspace) +{ + task_t *t; + int stack; + void *addr; + int i; + + /* xxx this should be cleaner -- have a flag to area_create perhaps */ + for(i=1023;i>0;i--){ + if(!team->aspace->ptab[i]) break; + } + stack = area_create(team->aspace, 4096, i*4096, &addr, 0); + if(!stack) panic("cannot create a stack area. eek"); + + t = task_create(team, ip, i*4096+4092, kernelspace); + t->ustack = (void *) (i << 12); + t->stack_area = rsrc_find(RSRC_AREA,stack); + rsrc_bind(&t->rsrc, RSRC_TASK, team); + t->flags = tREADY; + if(!kernelspace) { + rsrc_enqueue(run_queue, t); + live_tasks++; + } + + return t; +} + +int brk(uint32 addr) +{ + aspace_t *a = current->rsrc.owner->aspace; + area_t *area = rsrc_find_area(current->rsrc.owner->heap_id); + + if(area){ +// kprintf("brk addr %x thid %d",addr,current->rsrc.id); + return area_resize(a,current->rsrc.owner->heap_id, + 0x1000 + ((addr - area->virt_addr) & 0xFFFFF000)); + } + return ERR_MEMORY; +} + +/* + 0 = directory + 1 = bootstrap + 2 = kernel +*/ + + +void go_kernel(void) +{ + task_t *t; + int i,len; + void *ptr,*phys; + port_t *uberport; + area_t *uberarea; + team_t *team; + + for (i = 0, len = 1; (bdir->bd_entry[i].be_type != BE_TYPE_NONE); i++){ + len += bdir->bd_entry[i].be_size; + } + len *= 0x1000; + + uberport = rsrc_find_port(uberportnum = port_create(0,"uberport")); + uberarea = rsrc_find_area(uberareanum = area_create_uber(len, + (void *) 0x100000)); + kprintf("uberport allocated with rid = %d",uberportnum); + kprintf("uberarea allocated with rid = %d",uberareanum); + + kernel_team = team_create(); + rsrc_set_name(&kernel_team->rsrc, "kernel team"); + + run_queue = rsrc_find_queue(queue_create("run queue",kernel_team)); + reaper_queue = rsrc_find_queue(queue_create("reaper queue",kernel_team)); + timer_queue = rsrc_find_queue(queue_create("timer queue",kernel_team)); + rsrc_set_owner(&uberarea->rsrc,kernel_team); + rsrc_set_owner(&uberport->rsrc,kernel_team); + + for(i=3;bdir->bd_entry[i].be_type;i++){ + if(bdir->bd_entry[i].be_type != BE_TYPE_CODE) continue; + + team = team_create(); + t = new_thread(team, 0x1074 /*bdir->bd_entry[i].be_code_ventr*/, 0); + current = t; + + phys = (void *) (bdir->bd_entry[i].be_offset*0x1000 + 0x100000); + team->text_area = area_create(team->aspace,bdir->bd_entry[i].be_size*0x1000, + 0x1000, &phys, AREA_PHYSMAP); + team->heap_id = area_create(team->aspace,0x2000,0x1000 + bdir->bd_entry[i].be_size* + 0x1000, &ptr, 0); + + /* make the thread own it's address space */ + /* rsrc_set_owner(&a->rsrc, t); */ + + if (!strcmp (bdir->bd_entry[i].be_name, "namer")) { + rsrc_set_owner(&uberport->rsrc, team); + } + + rsrc_set_name(&t->rsrc,bdir->bd_entry[i].be_name); + rsrc_set_name(&team->rsrc,bdir->bd_entry[i].be_name); + + kprintf("task %X @ 0x%x, size = 0x%x (%s)",t->rsrc.id, + bdir->bd_entry[i].be_offset*4096+0x100000, + bdir->bd_entry[i].be_size*4096, + t->rsrc.name); + } + + kprintf("creating idler..."); + idle_task = new_thread(kernel_team, (int) idler, 1); + rsrc_set_name((resource_t*)idle_task,"idler"); + + kprintf("creating grim reaper..."); + current = new_thread(kernel_team, (int) reaper, 1); + rsrc_set_name((resource_t*)current,"grim reaper"); + reaper_sem = sem_create(0,"death toll"); + rsrc_enqueue(run_queue, current); + live_tasks++; + + kprintf("creating pager..."); + current = pager_task = new_thread(kernel_team, (int) pager, 1); + rsrc_set_name((resource_t*)current,"pager"); + pager_port_no = port_create(0,"pager port"); + pager_sem_no = sem_create(0, "pager sem"); + rsrc_enqueue(run_queue, current); + live_tasks++; + + rsrc_set_name((resource_t*)kernel,"kernel"); + +#ifdef __SMP__ + smp_init (); +#endif + +// DEBUGGER(); + kprintf("starting scheduler..."); + +#ifdef __SMP__ + if (smp_configured) + { + smp_final_setup (); + kprintf ("smp: signaling other processors"); + smp_begin (); + } +#endif + + /* + * when the new vm stuffas are done, we can at this point discard any + * complete pages in the .text.init and .data.init sections of the kernel + * by zeroing them and adding them to the free physical page pool. + */ + + current = kernel; + current->flags = tDEAD; + current->waiting_on = NULL; + swtch(); + + kprintf("panic: returned from scheduler?"); + asm("hlt"); +} + +struct _kinfo +{ + uint32 memsize; + uint32 entry_ebp; + boot_dir *bd; + unsigned char *params; +} *kinfo = (struct _kinfo *) 0x80000000; + +const static char *copyright1 = + "OpenBLT Release I (built "__DATE__ ", " __TIME__ ")"; +const static char *copyright2 = + " Copyright (c) 1998-2000 The OpenBLT Dev. Team. All rights reserved."; + +void kmain(void) +{ + int n,len; + memsize = ((kinfo->memsize) / 4096) & ~0xff; + entry_ebp = kinfo->entry_ebp; + bdir = kinfo->bd; + + for (n = 0, len = 1; (bdir->bd_entry[n].be_type != BE_TYPE_NONE); n++) + len += bdir->bd_entry[n].be_size; + + init_timer(); + init_kspace(256 + len + 16); /* bottom of kernel memory */ + + kprintf_init(); +#ifdef SERIAL + dprintf_init(); +#endif + + kprintf(""); + kprintf (copyright1); + kprintf (copyright2); + kprintf(""); +#ifdef DPRINTF + dprintf (""); + dprintf (copyright1); + dprintf (copyright2); + dprintf (""); + kprintf ("serial port is in dprintf mode"); + dprintf ("serial port is in dprintf mode"); + dprintf (""); +#endif + + kprintf("system memory 0x%x",memsize*4096); + + n = ((uint32) toppage) + 4080; + asm("mov %0, %%esp"::"r" (n) ); + + n = SEL_UDATA | 3; + asm("pushl %0; popl %%ds"::"r" (n)); + asm("pushl %0; popl %%es"::"r" (n)); + asm("pushl %0; popl %%fs"::"r" (n)); + asm("pushl %0; popl %%gs"::"r" (n)); + + kprintf("kernel space initialized"); + go_kernel(); +} + diff --git a/kernel/kernel.h b/kernel/kernel.h @@ -0,0 +1,53 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _KERNEL_H_ +#define _KERNEL_H_ + +#include "types.h" +#include "i386.h" +#include "aspace.h" +#include "task.h" +#include "port.h" +#include "sem.h" +#include "team.h" + +#include <blt/types.h> +#include <blt/error.h> + +void panic(char *reason); + +task_t *new_thread(team_t *team, uint32 ip, int kernel); + +int brk(uint32 addr); + +void destroy_kspace(void); + +/* debugger functions */ +void kprintf_init(void); +void kprintf(const char *fmt, ...); +char *kgetline(char *line, int maxlen); +void krefresh(void); + +#ifdef SERIAL +void dprintf_init(void); +void dprintf(const char *fmt, ...); +#endif + +void preempt(task_t *t, int status); +void swtch(void); +extern char *idt, *gdt; +extern uint32 _cr3; + +extern int kernel_timer; + +extern task_t *current; +extern resource_t *run_queue; +extern resource_t *reaper_queue; +extern resource_t *timer_queue; +extern team_t *kernel_team; + +void user_debug(regs *r, uint32 *eip, uint32 *eflags); + +#endif diff --git a/kernel/ktrace.c b/kernel/ktrace.c @@ -0,0 +1,332 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +/* serial tracing */ + +#include <stdarg.h> +#include "memory.h" +#include <i386/io.h> +#include <blt/conio.h> +#include "kernel.h" + +#define NULL ((void *) 0) + +#define com1 0x3f8 +#define com2 0x2f8 + +#define combase com1 + +char *kprintf_lock = 0; + +void va_snprintf(char *b, int l, const char *fmt, va_list pvar); + +/* catch bad configurations */ +#if defined (SERIAL_DEBUG) && defined (DPRINTF) +#error cannot use both serial debugging and dprintf +#endif + +#if (defined (SERIAL_DEBUG) || defined (DPRINTF)) && !defined (SERIAL) && !defined (PORT_E9) +#error cannot use serial debugging or dprintf without serial port code +#endif + +#ifdef PORT_E9 +/* Bochs has this special direct to console thing */ + +void dprintf_init(void) +{ +} + +static int ser_getc(void) +{ + for(;;) ; +} + +static void ser_putc(int ch) +{ + while (!(inb(combase + 5) & 0x20)); + outb((unsigned char) ch, 0xe9); +} + +static void ser_puts(char *s) +{ + int t; + while(*s){ + ser_putc(*s); + s++; + } +} + +#endif + +#ifdef SERIAL + +void dprintf_init(void) +{ + outb(0, combase + 4); + outb(0, combase + 0); + outb(0x83, combase + 3); + outb(6, combase); /* 9600 bps, 8-N-1 */ + outb(0, combase+1); + outb(0x03, combase + 3); +} + +static int ser_getc(void) +{ + while (!(inb(combase + 5) & 0x01)); + return inb(combase); +} + +static void ser_putc(int ch) +{ + while (!(inb(combase + 5) & 0x20)); + outb((unsigned char) ch, combase); +} + +static void ser_puts(char *s) +{ + int t; + while(*s){ + ser_putc(*s); + s++; + } +} + +#endif + +#ifdef SERIAL_DEBUG +void krefresh(void) +{ +} + +unsigned char *screen = NULL; + +void kprintf_init(void) +{ + screen = (unsigned char *) kmappages( +#ifdef MONO + 0xB0, +#else + 0xB8, +#endif + 2, 3); +} + +char *kgetline(char *line, int len) +{ + char c; + int pos = 0; + + ser_puts(": "); + + for(;;){ + switch(c = ser_getc()){ + case 10: + case 13: + line[pos]=0; + ser_puts("\r\n"); + return line; + + case 8: + if(pos) { + pos--; + ser_puts("\b \b"); + } + break; + + case 27: + while(pos) { + pos--; + ser_puts("\b \b"); + } + break; + + default: + if((c >= ' ') && (c < 0x7f) && (pos < len-1)){ + line[pos] = c; + pos++; + ser_putc(c); + } + } + } +} + +static char Line[128]; +void kprintf(const char *fmt, ...) +{ + va_list pvar; + va_start(pvar,fmt); +#ifdef __SMP__ + p (&kprintf_lock); +#endif + va_snprintf(Line,128,fmt,pvar); + Line[127]=0; + va_end(pvar); + ser_puts(Line); + ser_puts("\r\n"); +#ifdef __SMP__ + v (&kprintf_lock); +#endif +} + +#else + +#define ESC 27 +#define BS 8 +#define TAB 9 +#define CR 13 +char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r', + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR, ' ', + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n', + 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '}; +char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*', + '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR, ' ', + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N', + 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '}; +#define LSHIFT 42 +#define RSHIFT 54 + +unsigned char *screen = NULL; +static unsigned char vscreen[80*25*2]; + +void *kmappages(int phys, int count, int flags); + +void kprintf_init() +{ + screen = (unsigned char *) kmappages( +#ifdef MONO + 0xB0, +#else + 0xB8, +#endif + 2, 3); + + con_start((uint32) vscreen); + con_attr(CON_YELLOW|0x08); + con_clear(); +} + +void krefresh(void) +{ + memcpy(screen,vscreen,80*25*2); +} + +static char line[80]; +void kprintf(const char *fmt, ...) +{ + va_list pvar; + va_start(pvar,fmt); +#ifdef __SMP__ + p (&kprintf_lock); +#endif + va_snprintf(line,80,fmt,pvar); + line[79] = 0; + va_end(pvar); + con_goto(0,24); + con_puts(line); + con_puts("\n"); + memcpy(screen,vscreen,80*25*2); +#ifdef __SMP__ + v (&kprintf_lock); +#endif +} + +#ifdef DPRINTF + +void dprintf(const char *fmt, ...) +{ + va_list pvar; + va_start(pvar,fmt); +#ifdef __SMP__ + p (&kprintf_lock); +#endif + va_snprintf(line,80,fmt,pvar); + line[79]=0; + va_end(pvar); + ser_puts(line); + ser_puts("\r\n"); +#ifdef __SMP__ + v (&kprintf_lock); +#endif +} + +#endif + +void movecursor (int x, int y) +{ + int offset; + + offset = 80 * y + x; + outb (0xe, 0x3d4); + outb (offset / 256, 0x3d5); + outb (0xf, 0x3d4); + outb (offset % 256, 0x3d5); +} + +char *kgetline(char *line, int len) +{ + int i,lp,key; + int shift = 0; + if(len > 80) len = 80; + + restart: + for(i=1;i<len-1;i++) line[i] = ' '; + line[0] = ':'; + line[1] = ' '; + line[len-1] = 0; + lp = 2; + + for(;;){ + con_goto(0,24); + con_puts(line); + movecursor(lp,24); + + memcpy(screen + (80*24*2), vscreen + (80*24*2), 160); + while(!(inb(0x64) & 0x01)); + key = inb(0x60); + switch(key){ + case LSHIFT: + case RSHIFT: + shift = 1; + break; + case LSHIFT | 0x80: + case RSHIFT | 0x80: + shift = 0; + break; + default: + if(key & 0x80){ + /* break */ + } else { + if(key < 59){ + key = shift ? ShiftTable[key] : ScanTable[key]; + + switch(key){ + case CR: + line[lp] = 0; + kprintf(line); + return line + 2; + case ESC: + goto restart; + case BS: + if(lp > 2){ + lp--; + line[lp]=' '; + } + break; + default: + if(lp < len-1); + line[lp] = key; + lp++; + } + + } + } + } + } +} + +#endif diff --git a/kernel/list.c b/kernel/list.c @@ -0,0 +1,165 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "list.h" +#include "memory.h" + +#include <blt/error.h> + +void list_init(list_t *list) +{ + list->next = (node_t *) list; + list->prev = (node_t *) list; + list->count = 0; +} + +void list_add_head(list_t *list, void *data) +{ + node_t *node = kmalloc(node_t); + node->data = data; + node->next = list->next; + node->next->prev = node; + node->prev = (node_t*) list; + list->next = node; + list->count++; +} + +void list_add_tail(list_t *list, void *data) +{ + node_t *node = kmalloc(node_t); + node->data = data; + node->prev = list->prev; + node->prev->next = node; + node->next = (node_t*) list; + list->prev = node; + list->count++; +} + +void *list_peek_head(list_t *list) +{ + if(list->next == (node_t*) list) { + return NULL; + } else { + return list->next->data; + } +} + +void *list_peek_tail(list_t *list) +{ + if(list->prev == (node_t*) list) { + return NULL; + } else { + return list->prev->data; + } +} + +void *list_remove_head(list_t *list) +{ + node_t *node = list->next; + void *data; + + if(node == (node_t*) list){ + return NULL; + } else { + data = node->data; + node->prev->next = node->next; + node->next->prev = node->prev; + kfree(node_t, node); + list->count--; + return data; + } +} + +void *list_remove_tail(list_t *list) +{ + node_t *node = list->prev; + void *data; + + if(node == (node_t*) list){ + return NULL; + } else { + data = node->data; + node->prev->next = node->next; + node->next->prev = node->prev; + kfree(node_t, node); + list->count--; + return data; + } +} + +int list_remove(list_t *list, void *data) +{ + node_t *node = list->next; + while(node != (node_t *) list){ + if(node->data == data){ + node->next->prev = node->prev; + node->prev->next = node->next; + kfree(node_t, node); + list->count--; + return ERR_NONE; + } + node = node->next; + } + return -1; +} + + +void list_attach_head(list_t *list, node_t *node) +{ + node->next = list->next; + node->next->prev = node; + node->prev = (node_t*) list; + list->next = node; + list->count++; +} + +void list_attach_tail(list_t *list, node_t *node) +{ + node->prev = list->prev; + node->prev->next = node; + node->next = (node_t*) list; + list->prev = node; + list->count++; +} + +void *list_detach_head(list_t *list) +{ + node_t *node = list->next; + if(node == (node_t*) list){ + return NULL; + } else { + node->prev->next = node->next; + node->next->prev = node->prev; + list->count--; + return node->data; + } +} + +void *list_detach_tail(list_t *list) +{ + node_t *node = list->prev; + if(node == (node_t*) list){ + return NULL; + } else { + node->prev->next = node->next; + node->next->prev = node->prev; + list->count--; + return node->data; + } +} + +int list_detach(list_t *list, void *data) +{ + node_t *node = list->next; + while(node != (node_t *) list){ + if(node->data == data){ + node->next->prev = node->prev; + node->prev->next = node->next; + list->count--; + return ERR_NONE; + } + node = node->next; + } + return -1; +} diff --git a/kernel/list.h b/kernel/list.h @@ -0,0 +1,43 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _LIST_H +#define _LIST_H + +#include "types.h" + +struct __list_t +{ + node_t *next; /* aka head */ + node_t *prev; /* aka tail */ + uint32 count; +}; + +/* generic or template dlinklist node */ +struct __node_t +{ + node_t *next; + node_t *prev; + void *data; +}; + +void list_init(list_t *list); + +/* these functions allocate and destroy node_t's to store the items */ +void list_add_head(list_t *list, void *data); +void list_add_tail(list_t *list, void *data); +void *list_peek_head(list_t *list); +void *list_peek_tail(list_t *list); +void *list_remove_head(list_t *list); +void *list_remove_tail(list_t *list); +int list_remove(list_t *list, void *data); + +/* these functions are for items that "own" the node_t */ +void list_attach_head(list_t *list, node_t *node); +void list_attach_tail(list_t *list, node_t *node); +void *list_detach_head(list_t *list); +void *list_detach_tail(list_t *list); +int list_detach(list_t *list, void *data); + +#endif +\ No newline at end of file diff --git a/kernel/memory.c b/kernel/memory.c @@ -0,0 +1,302 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "memory.h" + +static unsigned char size_map[513] = { + KM16, + + KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16, + KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16, + + KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32, + KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32, + + KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, + KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, + KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, + KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, + + KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, + KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, + KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, + KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, + + KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, + KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, + KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, + KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, + + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, + + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, + KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, +}; + + +void *kmallocB(int size) +{ + if(size < 256) return kmallocP(size_map[size]); + panic("invalid kmallocB"); +} + +void kfreeB(int size, void *block) +{ + if(size < 256) return kfreeP(size_map[size],block); + panic("invalid kmallocB"); +} + + + +struct km_mnode +{ + struct km_mnode *next; +}; + +static struct _km_map +{ + int size; + int used_count; + int fresh_count; + int free_count; + struct km_mnode *free_chain; + void *fresh_chain; +} km_map[KMMAX] = { + { 16, 0, 256, 0, NULL, NULL }, + { 32, 0, 128, 0, NULL, NULL }, + { 64, 0, 64, 0, NULL, NULL }, + { 96, 0, 42, 0, NULL, NULL }, + { 128, 0, 32, 0, NULL, NULL }, + { 192, 0, 21, 0, NULL, NULL }, + { 256, 0, 16, 0, NULL, NULL } +}; + +extern uint32 memsize; +extern uint32 memtotal; + +static uint32 total_pages; +static uint32 used_pages; + +void memory_status(void) +{ + int i; + int inuse = 0, allocated = 0; + + kprintf(""); + kprintf("size used free fresh"); + for(i=0;i<KMMAX;i++){ + kprintf("%U %U %U %U", km_map[i].size, km_map[i].used_count, + km_map[i].free_count, km_map[i].fresh_count); + inuse += km_map[i].size * km_map[i].used_count; + allocated += km_map[i].size * + (km_map[i].free_count+km_map[i].used_count+km_map[i].fresh_count); + + } + inuse /= 1024; + allocated /= 1024; + kprintf(""); + kprintf("%dkb allocated, %dkb in use",allocated,inuse); + kprintf("%d (of %d) pages in use",used_pages, total_pages); + +} + + +/* kernel 'heap' is allocated top down ... top three pages used by the bootstrap */ +static uint32 nextmem = 0x80400000 - 4*4096; +static node_t *freevpagelist = NULL; + +static uint32 *pagelist = NULL; +static uint32 freepage = 0; + +extern aspace_t *flat; + +void putpage(uint32 number) +{ +// kprintf("- %d",number); + + pagelist[number] = freepage; + freepage = number; + used_pages--; +} + +uint32 getpage(void) +{ + uint32 n = freepage; + +// kprintf("+ %d",n); + + if(n){ + freepage = pagelist[n]; + } else { + panic("Out of physical memory"); + } + used_pages++; + return n; +} + +void kfreepage(void *vaddr) +{ + node_t *n; + int pageno; + int vpage = (((uint32)vaddr)/0x1000) & 0x3ff; + + if(!flat->high[vpage]){ + kprintf("vpage %d / %x unmapped already?!",vpage,vaddr); + DEBUGGER(); + } + + /* release the underlying page */ + pageno = flat->high[vpage] / 0x1000; +// kprintf("kfreepage(%x) high[%d] = %d",vaddr,vpage,pageno); + putpage( pageno ); + + flat->high[vpage] = 0; + local_flush_pte(vaddr); + + /* stick it on the virtual page freelist */ + n = kmalloc(node_t); + n->next = freevpagelist; + n->data = vaddr; + freevpagelist = n; +} + +void *kgetpage(uint32 *phys) +{ + uint32 pg = getpage(); + *phys = pg * 0x1000; + + if(nextmem < 0x80050000) panic("kernel vspace exhausted"); + + if(freevpagelist){ + node_t *n = freevpagelist; + void *page = n->data; + freevpagelist = n->next; + kfree(node_t, n); + if(flat->high[(((uint32)page)/0x1000) & 0x3ff]){ + kprintf("page collision @ %x",page); + DEBUGGER(); + } + aspace_maphi(flat, pg, (((uint32)page)/0x1000) , 1, 3); + return page; + } else { + nextmem -= 4096; + aspace_maphi(flat, pg, nextmem/0x1000, 1, 3); + return (void *) nextmem; + } +} + +void *kgetpages(int count) +{ + if(count == 1){ + uint32 phys; + return kgetpage(&phys); + } else { + int i,n; + nextmem -= 4096*count; + for(n=nextmem/0x1000,i=0;i<count;n++,i++){ + aspace_maphi(flat, getpage(), n, 1, 3); + } + return (void *) nextmem; + } +} + +/* map specific physical pages into kernel space, return virtaddr */ +void *kmappages(int phys, int count, int flags) +{ + nextmem -= 4096*count; + aspace_maphi(flat, phys, nextmem/0x1000, count, flags); + return (void *) nextmem; +} + +void memory_init(uint32 bottom_page, uint32 top_page) +{ + int i,count; + + /* we can track 1024 pages for every 4K of pagelist */ + count = ((top_page - bottom_page) / 1024) + 1; + + /* allocate the pagelist */ + top_page -= count; + total_pages = 0; + used_pages = 0; + + nextmem -= 4096*count; + pagelist = (uint32 *) nextmem; + aspace_maphi(flat, top_page, nextmem/0x1000, count, 3); + + /* setup the pagelist */ + freepage = 0; + for(i=top_page;i>=bottom_page;i--){ + total_pages++; + pagelist[i] = freepage; + freepage = i; + } + + /* setup the memory pools */ + for(i=0;i<KMMAX;i++){ + km_map[i].fresh_chain = kgetpages(1); + } +} + + +void *kmallocP(int size) +{ + struct _km_map *km; + void *block; + if(size >= KMMAX) panic("illegal size in kmalloc()"); + km = &km_map[size]; + + km->used_count++; + + if(km->free_chain) { + /* recycle free'd blocks if available */ + km->free_count--; + block = (void *) km->free_chain; + km->free_chain = km->free_chain->next; + } else { + /* shave a new block off of the fresh page if + we can't recycle */ + km->fresh_count--; + block = km->fresh_chain; + + if(km->fresh_count){ + /* still some left, just bump us to the next chunk */ + km->fresh_chain = (void *) + (((char *) km->fresh_chain) + km->size); + } else { + /* gotta grab a new page */ + km->fresh_count = 4096 / km->size; + km->fresh_chain = kgetpages(1); + } + } + + return block; +} + +void kfreeP(int size, void *block) +{ + struct _km_map *km; + if(size > KMMAX) panic("illegal size in kmalloc()"); + km = &km_map[size]; + + km->free_count++; + km->used_count--; + ((struct km_mnode *) block)->next = km->free_chain; + km->free_chain = (struct km_mnode *) block; +} + diff --git a/kernel/memory.h b/kernel/memory.h @@ -0,0 +1,37 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _MEMORY_H_ +#define _MEMORY_H_ + +#include "types.h" + +#define KM16 0 +#define KM32 1 +#define KM64 2 +#define KM96 3 +#define KM128 4 +#define KM192 5 +#define KM256 6 +#define KMMAX 7 + +uint32 getpage(void); /* allocate a single physical page */ +void putpage(uint32); /* release a single physical page */ + +void *kgetpage(uint32 *phys); /* allocate one page (and return phys addr) */ +void *kgetpages(int count); /* allocate count pages */ +void kfreepage(void *vaddr); +void *kmallocP(int pool); /* allocate from pool (eg KM16, KM128, ...)*/ +void kfreeP(int pool, void *block); /* release back to pool */ + +void *kmallocB(int size); /* allocate from appropriate pool for size */ +void kfreeB(int size, void *block); /* release back to appropriate pool */ +#define kmalloc(type) kmallocB(sizeof(type)) +#define kfree(type,ptr) kfreeB(sizeof(type),ptr) + +void memory_init(uint32 bottom, uint32 top); /* only call once - on kernel launch */ +void memory_status(void); /* dump memory usage information */ + +#endif + diff --git a/kernel/pager.c b/kernel/pager.c @@ -0,0 +1,93 @@ +/* $Id: //depot/blt/kernel/pager.c#3 $ +** +** Copyright 2000, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "memory.h" +#include "types.h" +#include "sem.h" +#include "list.h" +#include "pager.h" + +int pager_port_no, pager_sem_no; +task_t *pager_task; +sem_t *pager_sem; +list_t pager_queue; + +void terminate (void); +void k_debugger (regs *r, uint32 eip, uint32 cs, uint32 eflags); + +void pager (void) +{ + pager_fault_t *fault; + list_t *list; + node_t *node; + area_t *area; + + pager_sem = rsrc_find_sem (pager_sem_no); + list_init (&pager_queue); + + for (;;) + { + sem_acquire (pager_sem_no); + fault = list_remove_head (&pager_queue); + + kprintf ("pager: got paging request %d for vaddr %x", fault->op, + fault->vaddr); + list = &fault->task->team->aspace->areas; + node = list->next; + while (node->next != (node_t *) list) + { + area = node->data; + kprintf ("pager: checking %x+%x", area->virt_addr, area->length); + if (((fault->vaddr >> 12) >= area->virt_addr) && + (fault->vaddr >> 12) < (area->virt_addr + area->length)) + { + /* shouldn't happen yet */ + kprintf ("pager: found it"); + continue; + } + node = node->next; + } + kprintf ("pager: task %d (%s) SEGV: eip = %x, addr = %x", + fault->task->rsrc.id, fault->task->rsrc.name, fault->eip, + fault->vaddr); + task_wake (fault->task, ERR_SEGV); + } +} + +void page_fault (uint32 number, regs r, uint32 error, uint32 eip, uint32 cs, + uint32 eflags) +{ + pager_fault_t *fault; + + /* queue the paging request */ + fault = kmalloc (pager_fault_t); + fault->op = 666; + asm ("mov %%cr2, %0" : "=r" (fault->vaddr)); + fault->eip = eip; + fault->task = current; + list_add_tail (&pager_queue, fault); + + /* wake up the kernel pager */ + current->flags = tSLEEP_PAGING; + pager_sem->count++; + task_wake (pager_task, ERR_NONE); /* XXX: sem_release requeues us */ + swtch (); + + /* paging is done; check result */ + if (current->status == ERR_SEGV) { + if((cs & 0xFFF8) == SEL_UCODE) { + user_debug(&r, &eip, &eflags); + } else { + kprintf("pf: cs = %x\n",cs& 0xfff8); + } + + current->flags = tDEAD; + k_debugger (&r, eip, cs, eflags); + terminate (); + } +} + diff --git a/kernel/pager.h b/kernel/pager.h @@ -0,0 +1,27 @@ +/* $Id: //depot/blt/kernel/pager.h#2 $ +** +** Copyright 1998-2000, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _PAGER_H_ +#define _PAGER_H_ + +#include "i386.h" + +struct __pager_fault_t +{ + unsigned int op, vaddr, eip; + task_t *task; +}; + +extern int pager_port_no, pager_sem_no; +extern task_t *pager_task; +extern sem_t *pager_sem; + +void pager (void); +void page_fault (uint32 number, regs r, uint32 error, uint32 eip, uint32 cs, + uint32 eflags); + +#endif + diff --git a/kernel/port.c b/kernel/port.c @@ -0,0 +1,244 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "memory.h" +#include "port.h" +#include "resource.h" + +#define MAX_MSGCOUNT 16 + +int snprintf (char *s, int len, char *fmt, ...); + +int port_create(int restrict, const char *name) +{ + port_t *p; + char qname[16]; + + /* create new port */ + p = kmalloc(port_t); + p->sendqueue = kmalloc(resource_t); + + p->msgcount = 0; + p->first = p->last = NULL; + p->slaved = 0; + p->refcount = 1; + p->nowait = 0; + p->restrict = restrict; + + rsrc_bind(&p->rsrc, RSRC_PORT, current->rsrc.owner); + rsrc_bind(p->sendqueue, RSRC_QUEUE, current->rsrc.owner); + rsrc_set_name(&p->rsrc, name); + snprintf(qname,16,"port:%d",p->rsrc.id); + rsrc_set_name(p->sendqueue, name); + return p->rsrc.id; +} + +int port_destroy(int port) +{ + port_t *p; + if(!(p = rsrc_find_port(port))) return ERR_RESOURCE; +// if(p->rsrc.owner != current) return ERR_PERMISSION; + + if(p->refcount == 1) { + /* destroy port */ + rsrc_release(&p->rsrc); + rsrc_release(p->sendqueue); + kfree(resource_t,p->sendqueue); + kfree(port_t,p); + return ERR_NONE; + } + + /* port is the master of one or more slaves */ + return ERR_RESOURCE; +} + +uint32 port_option(uint32 port, uint32 opt, uint32 arg) +{ + port_t *p; + + if(!(p = rsrc_find_port(port))) return ERR_RESOURCE; + if(p->rsrc.owner != current->rsrc.owner) return ERR_PERMISSION; + + if(opt == PORT_OPT_SETRESTRICT){ + p->restrict = arg; + return ERR_NONE; + } + + if(opt == PORT_OPT_SLAVE){ + port_t *master; + + if(arg){ + /* arg == 0 will simply release the old master */ + + if(!(master = rsrc_find_port(arg))) return ERR_RESOURCE; + if(master->rsrc.owner != current->rsrc.owner) return ERR_PERMISSION; + + /* indicate that our master has one more slave */ + master->refcount++; + } + + if(p->slaved){ + /* change in slave status, deref our old master */ + if(!(master = rsrc_find_port(p->slaved))) + panic("port_option(): master port not found?"); + + master->refcount--; + } + p->slaved = arg; + return ERR_NONE; + } + + if (opt == PORT_OPT_NOWAIT) { + p->nowait = arg; + return ERR_NONE; + } + + return ERR_PERMISSION; +} + +static chain_t *msg_pool = NULL; + + +int port_send(int src, int dst, void *msg, size_t size, uint32 code) +{ + int i; + message_t *m; + port_t *f,*p; + + if(!(f = rsrc_find_port(src))) return ERR_SENDPORT; +#if 0 + if(f->rsrc.owner != current) { + task_t *t = current->rsrc.owner; /* XXX */ + while(t){ + if(t == f->rsrc.owner) break; + t = t->rsrc.owner; + + } + if(!t) return ERR_PERMISSION; + } +#endif + /* insure the port exists and we may send to it */ + if(!(p = rsrc_find_port(dst))) return ERR_RECVPORT; +/* if((p->restrict) && + (p->restrict != src)) return ERR_PERMISSION; XXX */ + + /* are we slaved to a different port? */ + if(p->slaved){ + if(!(p = rsrc_find_port(p->slaved))) return ERR_RESOURCE; + if(p->slaved) return ERR_RESOURCE; +/* if((p->restrict) && + (p->restrict != src)) return ERR_PERMISSION; XXX */ + } + + while(p->msgcount >= MAX_MSGCOUNT){ + int status; + if(p->nowait) return ERR_WOULD_BLOCK; + if((status = wait_on(p->sendqueue))) return status; + } + + /* ignore invalid sizes/locations */ + if( (((uint32) msg) > 0x400000) || + (size > 4096)) return ERR_MEMORY; + + m = kmalloc(message_t); + + /* allocate a 4k page to carry the message. klunky... */ + if(size < 256){ + m->data = size ? kmallocB(size) : NULL; + } else { + if(msg_pool){ + m->data = (void *) msg_pool; + msg_pool = (chain_t *) msg_pool->next; + } else { + m->data = kgetpages(1); + } + } + + for(i=0;i<size;i++){ + ((unsigned char *) m->data)[i] = *((unsigned char *) msg++); + } + + m->from_port = src; + m->to_port = dst; + m->code = code; + m->size = size; + m->next = NULL; + if(p->last){ + p->last->next = m; + } else { + p->first = m; + } + p->last = m; + p->msgcount++; + + + /* If a thread is sleeping on the destination, wake it up + */ + if(p->slaved){ + port_t *p0 = rsrc_find_port(p->slaved); + if(p0){ + task_t *task = rsrc_dequeue(&p0->rsrc); + if(task) task_wake(task,ERR_NONE); + } + } else { + task_t *task = rsrc_dequeue(&p->rsrc); + if(task) task_wake(task,ERR_NONE); + } + + return size; +} + +/*int old_port_recv(int port, void *msg, int size, int *from)*/ +int port_recv(int dst, int *src, void *msg, size_t size, uint32 *code) +{ + int i; + message_t *m; + port_t *p; + + /* insure the port exists and we may receive on it */ + if(!(p = rsrc_find_port(dst))) return ERR_RECVPORT; +#if 0 + if(p->rsrc.owner != current) return ERR_PERMISSION; +#endif + + /* bounds check the message... should be more careful */ + if((current->team != kernel_team) && (((uint32) msg) > 0x400000)) + return ERR_MEMORY; + + /* no messages -- sleep */ + while(!p->msgcount) { + int status; + if (p->nowait) return ERR_WOULD_BLOCK; + if((status = wait_on(&p->rsrc))) return status; + } + + m = p->first; + for(i=0;i<m->size && (i <size);i++){ + *((unsigned char *) msg++) = ((unsigned char *) m->data)[i]; + } + if(src) *src = m->from_port; + if(code) *code = m->code; + dst = m->to_port; // XXX + + /* unchain from the head of the queue */ + if(!(p->first = p->first->next)) p->last = NULL; + + if(p->sendqueue->queue.count && (p->msgcount <= MAX_MSGCOUNT)) { + task_t *task = rsrc_dequeue (p->sendqueue); + if(task) task_wake(task, ERR_NONE); + } + p->msgcount--; + + /* add to the freepool */ + if(m->size < 256){ + if(m->size) kfreeB(m->size,m->data); + } else { + ((chain_t *) m->data)->next = msg_pool; + msg_pool = ((chain_t *) m->data); + } + kfree(message_t,m); + return size < m->size ? size : m->size; +} + diff --git a/kernel/port.h b/kernel/port.h @@ -0,0 +1,50 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _PORT_H_ +#define _PORT_H_ + +#include "resource.h" +#include "types.h" + +#define PORT_OPT_NOWAIT 1 +#define PORT_OPT_SETRESTRICT 2 +#define PORT_OPT_SETDEFAULT 3 +#define PORT_OPT_SLAVE 4 + +typedef struct __chain_t +{ + struct __chain_t *next; +} chain_t; + +typedef struct __message_t { + struct __message_t *next; + uint32 size; + uint32 code; + int from_port; + int to_port; + void *data; +} message_t; + +struct __port_t +{ + resource_t rsrc; + + int msgcount; /* number of messages waiting in the queue */ + int slaved; /* deliver my messages to a master port */ + message_t *first; /* head of the queue */ + message_t *last; /* tail of the queue */ + int refcount; /* counts owner and any slaved ports */ + int nowait; /* do we block on an empty queue? */ + int restrict; /* is port public or private? */ + resource_t *sendqueue; +}; + +int port_create(int restrict, const char *name); +int port_destroy(int port); +uint32 port_option(uint32 port, uint32 opt, uint32 arg); +ssize_t port_send(int src, int dst, void *data, size_t len, uint32 code); +ssize_t port_recv(int dst, int *src, void *data, size_t max, uint32 *code); + +#endif diff --git a/kernel/resource.c b/kernel/resource.c @@ -0,0 +1,183 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "memory.h" +#include "resource.h" +#include "team.h" + +typedef struct _rtab { + resource_t *resource; + int next; +} rtab; + +static resource_t null_resource; + +static rtab *rmap; +static uint32 rmax = 0; +static uint32 rfree = 0; + +list_t resource_list; + +void rsrc_init(void *map, int size) +{ + int i; + + list_init(&resource_list); + + null_resource.id = 0; + null_resource.type = RSRC_NONE; + null_resource.owner = NULL; + list_init(&null_resource.rights); + + rfree = 1; + rmax = size / sizeof(rtab); + rmap = (rtab *) map; + for(i = 0; i < rmax; i++) { + rmap[i].resource = &null_resource; + rmap[i].next = i+1; + } + rmap[rmax-1].next = 0; +} + +void *rsrc_find(int type, int id) +{ + if((id < rmax) && (rmap[id].resource->type == type)) { + return rmap[id].resource; + } else { + return NULL; + } +} + +void rsrc_set_owner(resource_t *r, team_t *owner) +{ + if(r->owner) list_remove(&r->owner->resources, r); + if(r->owner = owner) list_add_tail(&owner->resources, r); +} + +int rsrc_identify(uint32 id) +{ + if((id >= rmax) || (rmap[id].resource->type == RSRC_NONE)) return 0; + return rmap[id].resource->owner->rsrc.id; +} + +int queue_create(const char *name, team_t *team) +{ + resource_t *rsrc = (resource_t*) kmalloc(resource_t); + rsrc_bind(rsrc,RSRC_QUEUE,team); + rsrc_set_name(rsrc,name); + return rsrc->id; +} + +void rsrc_bind(resource_t *rsrc, rsrc_type type, team_t *owner) +{ + uint32 id; + + if(rfree){ + id = rfree; + rfree = rmap[rfree].next; + } else { + panic("resource exhaustion"); + } + + rmap[id].resource = rsrc; + rsrc->id = id; + rsrc->type = type; + rsrc->owner = owner; + rsrc->name[0] = 0; + + list_init(&rsrc->queue); + list_init(&rsrc->rights); + + if(owner) list_add_tail(&owner->resources, rsrc); + + list_add_tail(&resource_list, rsrc); +} + +void rsrc_release(resource_t *r) +{ + uint32 id = r->id; + task_t *t; + + /* unchain it from the owner */ + if(r->owner) list_remove(&r->owner->resources, r); + + /* unchain it from the global pool */ + list_remove(&resource_list, r); + + /* wake all blocking objects */ + while((t = list_detach_head(&r->queue))) { + task_wake(t,ERR_RESOURCE); + } + + r->type = RSRC_NONE; + r->id = 0; + rmap[id].resource = &null_resource; + rmap[id].next = rfree; + rfree = id; +} + +void rsrc_set_name(resource_t *r, const char *name) +{ + if(name){ + int i; + for(i=0;*name && (i<31);i++){ + r->name[i] = *name; + name++; + } + r->name[i] = 0; + } else { + r->name[0] = 0; + } +} + +void rsrc_enqueue_ordered(resource_t *rsrc, task_t *task, uint32 wake_time) +{ +/* XXX fixme*/ + list_attach_tail(&rsrc->queue, &task->node); + task->wait_time = wake_time; + task->flags = tWAITING; + task->waiting_on = rsrc; +} + +void rsrc_enqueue(resource_t *rsrc, task_t *task) +{ + task->wait_time = 0; + task->flags = tWAITING; + task->waiting_on = rsrc; + list_attach_tail(&rsrc->queue,&task->node); +} + +task_t *rsrc_dequeue(resource_t *rsrc) +{ + task_t *task = (task_t *) list_detach_head(&rsrc->queue); + if(task){ + task->waiting_on = NULL; + task->flags = tREADY; + } + return task; +} + +task_t *rsrc_queue_peek(resource_t *rsrc) +{ + if(rsrc->queue.next != (node_t*) &rsrc->queue) { + return (task_t*) rsrc->queue.next->data; + } +} + +const char *rsrc_typename(resource_t *rsrc) +{ + switch(rsrc->type){ + case RSRC_NONE: return "none"; + case RSRC_TASK: return "task"; + case RSRC_ASPACE: return "aspace"; + case RSRC_PORT: return "port"; + case RSRC_SEM: return "sem"; + case RSRC_RIGHT: return "right"; + case RSRC_AREA: return "area"; + case RSRC_QUEUE: return "queue"; + case RSRC_TEAM: return "team"; + default: return "????"; + } +} +\ No newline at end of file diff --git a/kernel/resource.h b/kernel/resource.h @@ -0,0 +1,66 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _RESOURCE_H_ +#define _RESOURCE_H_ + +#include "types.h" +#include "list.h" + +typedef enum +{ + RSRC_NONE, RSRC_TASK, RSRC_ASPACE, RSRC_PORT, RSRC_SEM, RSRC_RIGHT, + RSRC_AREA, RSRC_QUEUE, RSRC_TEAM, RSRC_MAX +} rsrc_type; + +struct __resource_t +{ + uint32 id; + rsrc_type type; + team_t *owner; + + list_t rights; + list_t queue; + + char name[32]; +}; + + +/* initialize the resource map */ +void rsrc_init(void *map, int size); + +/* locate a specifically typed resource */ +void *rsrc_find(int type, int id); + +/* remove the resource from the table */ +void rsrc_release(resource_t *r); + +/* assign a portnumber and put it in the resource table */ +void rsrc_bind(resource_t *r, rsrc_type type, team_t *owner); + +void rsrc_set_owner(resource_t *r, team_t *owner); +void rsrc_set_name(resource_t *r, const char *name); + +/* usercall - return the rsrc_id of the owner of the resource */ +int rsrc_identify(uint32 id); + +void rsrc_enqueue(resource_t *rsrc, task_t *task); +void rsrc_enqueue_ordered(resource_t *rsrc, task_t *task, uint32 wake_time); +task_t *rsrc_dequeue(resource_t *rsrc); +const char *rsrc_typename(resource_t *rsrc); + +task_t *rsrc_queue_peek(resource_t *rsrc); + +#define rsrc_find_task(id) ((task_t *) rsrc_find(RSRC_TASK, id)) +#define rsrc_find_port(id) ((port_t *) rsrc_find(RSRC_PORT, id)) +#define rsrc_find_aspace(id) ((aspace_t *) rsrc_find(RSRC_ASPACE, id)) +#define rsrc_find_sem(id) ((sem_t *) rsrc_find(RSRC_SEM, id)) +#define rsrc_find_area(id) ((area_t *) rsrc_find(RSRC_AREA, id)) +#define rsrc_find_right(id) ((right_t *) rsrc_find(RSRC_RIGHT, id)) +#define rsrc_find_queue(id) ((resource_t *) rsrc_find(RSRC_QUEUE, id)) +#define rsrc_find_team(id) ((team_t *) rsrc_find(RSRC_TEAM, id)) + +int queue_create(const char *name, team_t *team); + +#endif diff --git a/kernel/rights.c b/kernel/rights.c @@ -0,0 +1,29 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "blt/error.h" +#include "kernel.h" +#include "resource.h" +#include "rights.h" + +int right_create(uint32 rsrc_id, uint32 flags) +{ + return ERR_NONE; +} + +int right_destroy(uint32 right_id) +{ + return ERR_NONE; +} + +int right_revoke(uint32 right_id, uint32 thread_id) +{ + return ERR_NONE; +} + +int right_grant(uint32 right_id, uint32 thread_id) +{ + return ERR_NONE; +} + diff --git a/kernel/rights.h b/kernel/rights.h @@ -0,0 +1,37 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _RIGHTS_H_ +#define _RIGHTS_H_ + +#include "resource.h" + +#define RIGHT_PERM_READ 0x0001 /* allow 'read' access to something */ +#define RIGHT_PERM_WRITE 0x0002 /* allow 'write' access to something */ +#define RIGHT_PERM_DESTROY 0x0004 /* allow the something to be destroyed */ +#define RIGHT_PERM_ATTACH 0x0008 /* allows other rights to be attached */ +#define RIGHT_PERM_GRANT 0x0010 /* this right may be granted to another */ + /* thread by a thread that is not the owner */ +#define RIGHT_MODE_INHERIT 0x0020 /* automatically granted to child */ +#define RIGHT_MODE_DISSOLVE 0x0040 /* When the owner thread terminates, */ + /* the right is destroyed */ + +int right_create(uint32 rsrc_id, uint32 flags); +int right_destroy(uint32 right_id); +int right_revoke(uint32 right_id, uint32 thread_id); +int right_grant(uint32 right_id, uint32 thread_id); + +struct __right_t +{ + resource_t rsrc; + + resource_t *attached; + uint32 flags; + uint32 refcount; + struct __tnode_t *holders; +}; + + + +#endif +\ No newline at end of file diff --git a/kernel/sem.c b/kernel/sem.c @@ -0,0 +1,64 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "resource.h" +#include "memory.h" + +int sem_create(int count, const char *name) +{ + sem_t *s = (sem_t *) kmalloc(sem_t); + s->count = count; + rsrc_bind(&s->rsrc, RSRC_SEM, current->rsrc.owner); + rsrc_set_name(&s->rsrc, name); + return s->rsrc.id; +} + +int sem_destroy(int id) +{ + sem_t *s; + if(!(s = rsrc_find_sem(id))) { + return ERR_RESOURCE; + } + rsrc_release(&s->rsrc); + kfree(sem_t,s); + return ERR_NONE; +} + +int sem_acquire(int id) +{ + int status; + sem_t *s; + + if(!(s = rsrc_find_sem(id))) { + return ERR_RESOURCE; + } + + if(s->count > 0 ){ + s->count--; + } else { + s->count--; + if(status = wait_on(&s->rsrc)) return status; + } + return ERR_NONE; +} + +int sem_release(int id) +{ + int x; + sem_t *s; + task_t *t; + + if(!(s = rsrc_find_sem(id))) { + return ERR_RESOURCE; + } + + s->count++; + + if(t = rsrc_dequeue(&s->rsrc)){ + preempt(t,ERR_NONE); + } + + return ERR_NONE; +} diff --git a/kernel/sem.h b/kernel/sem.h @@ -0,0 +1,22 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _SEM_H +#define _SEM_H + +#include "resource.h" + +struct __sem_t +{ + resource_t rsrc; + + int count; +}; + +int sem_create(int count, const char *name); +int sem_destroy(int sem); +int sem_acquire(int id); +int sem_release(int id); + +#endif diff --git a/kernel/smp.c b/kernel/smp.c @@ -0,0 +1,583 @@ +/* $Id: //depot/blt/kernel/smp.c#6 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** Copyright (c) 1996, by Steve Passe +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "kernel.h" +#include "i386/io.h" +#include "init.h" +#include "smp.h" + +#undef SMP_DEBUG + +#ifdef SMP_DEBUG +#define SMP_PRINTF(f,a...) kprintf (f, ## a) +#else +#define SMP_PRINTF(f,a...) +#endif + +const char *cpu_family[] __initdata__ = { "", "", "", "", "Intel 486", + "Intel Pentium", "Intel Pentium Pro", "Intel Pentium II" }; +const unsigned int temp_gdt[] = {0x00000000, 0x00000000, /* null descriptor */ + 0x0000ffff, 0x00cf9a00, /* kernel text */ + 0x0000ffff, 0x00cf9200 };/* kernel data */ + +char mp_num_def_config, smp_num_cpus = 1, smp_num_running_cpus; +volatile char smp_cpus_ready[BLT_MAX_CPUS], smp_configured = 0, smp_begun = 0; +unsigned int cpuid_max_level, cpuid_eax, cpuid_edx, apic_addr, + cpu_apic_id[BLT_MAX_CPUS], cpu_os_id[BLT_MAX_CPUS], + cpu_apic_version[BLT_MAX_CPUS], *apic, *apic_virt, *ioapic; + +mp_flt_ptr *mp_config; + +extern aspace_t *flat; +extern void (*flush) (void); + +volatile char ipi_lock = 0; + +volatile unsigned int apic_read (unsigned int *addr) +{ + return *addr; +} + +void apic_write (unsigned int *addr, unsigned int data) +{ + *addr = data; +} + +/* XXX - hack until we can figure this out */ +int bus_clock (void) +{ + return 66000000; +} + +/********** adapted from FreeBSD's i386/i386/mpapic.c **********/ + +void __init__ apic_set_timer (int value) +{ + unsigned long lvtt; + long ticks_per_us; + + /* calculate divisor and count from value */ + apic_write (APIC_TDCR, APIC_TDCR_1); + ticks_per_us = bus_clock () / 1000000; + + /* configure timer as one-shot */ + lvtt = apic_read (APIC_LVTT) & ~(APIC_LVTT_VECTOR | APIC_LVTT_DS | + APIC_LVTT_M | APIC_LVTT_TM) | APIC_LVTT_M | 0xff; + apic_write (APIC_LVTT, lvtt); + apic_write (APIC_ICRT, value * ticks_per_us); +} + +/************************* end FreeBSD *************************/ + +int apic_read_timer (void) +{ + return apic_read (APIC_CCRT); +} + +void __init__ u_sleep (int count) +{ + int i; + + apic_set_timer (count); + while (i = apic_read (APIC_CCRT)) ; +} + +void __init__ mp_probe (int base, int limit) +{ + unsigned int i, *ptr; + + for (ptr = (unsigned int *) base; (unsigned int) ptr < limit; ptr++) + if (*ptr == MP_FLT_SIGNATURE) + { + SMP_PRINTF ("smp: found floating pointer structure at %x", ptr); + mp_config = (mp_flt_ptr *) ptr; + return; + } +} + +int __init__ mp_verify_data (void) +{ + char *ptr, total; + int i; + + /* check signature */ + if (mp_config->signature != MP_FLT_SIGNATURE) + return 0; + + /* compute floating pointer structure checksum */ + ptr = (unsigned char *) mp_config; + for (i = total = 0; i < (mp_config->mpc_len * 16); i++) + total += ptr[i]; + if (total) + return 0; + kprintf ("smp: CHECKSUMMED"); + + /* compute mp configuration table checksum if we have one*/ + if ((ptr = (unsigned char *) mp_config->mpc) != NULL) + { + for (i = total = 0; i < sizeof (mp_config_table); i++) + total += ptr[i]; + if (total) + return 0; + } + else + kprintf ("smp: no configuration table\n"); + + return 1; +} + +void __init__ mp_do_config (void) +{ + char *ptr; + int i; + mp_ext_pe *pe; + mp_ext_ioapic *io; + + /* + * we are not running in standard configuration, so we have to look through + * all of the mp configuration table crap to figure out how many processors + * we have, where our apics are, etc. + */ + smp_num_cpus = 0; + + /* print out our new found configuration. */ + ptr = (char *) &(mp_config->mpc->oem[0]); + kprintf ("smp: oem id: %c%c%c%c%c%c%c%c product id: " + "%c%c%c%c%c%c%c%c%c%c%c%c", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], + ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], + ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19], + ptr[20]); + SMP_PRINTF ("smp: base table has %d entries, extended section %d bytes", + mp_config->mpc->num_entries, mp_config->mpc->ext_len); + apic = (unsigned int *) mp_config->mpc->apic; + + ptr = (char *) ((unsigned int) mp_config->mpc + sizeof (mp_config_table)); + for (i = 0; i < mp_config->mpc->num_entries; i++) + switch (*ptr) + { + case MP_EXT_PE: + pe = (mp_ext_pe *) ptr; + cpu_apic_id[smp_num_cpus] = pe->apic_id; + cpu_os_id[pe->apic_id] = smp_num_cpus; + cpu_apic_version [smp_num_cpus] = pe->apic_version; + kprintf ("smp: cpu#%d: %s, apic id %d, version %d%s", + smp_num_cpus++, cpu_family[(pe->signature & 0xf00) >> 8], + pe->apic_id, pe->apic_version, (pe->cpu_flags & 0x2) ? + ", BSP" : ""); + ptr += 20; + break; + case MP_EXT_BUS: + ptr += 8; + break; + case MP_EXT_IO_APIC: + io = (mp_ext_ioapic *) ptr; + ioapic = io->addr; + SMP_PRINTF ("smp: found io apic with apic id %d, version %d", + io->ioapic_id, io->ioapic_version); + ptr += 8; + break; + case MP_EXT_IO_INT: + ptr += 8; + break; + case MP_EXT_LOCAL_INT: + ptr += 8; + break; + } + + kprintf ("smp: apic @ 0x%x, i/o apic @ 0x%x, total %d processors detected", + (unsigned int) apic, (unsigned int) ioapic, smp_num_cpus); +} + +/* FIXME - this is a very long stretch that needs to be broken up. */ +void __init__ smp_init (void) +{ + unsigned char *ptr, init_val; + unsigned int i, j, config, num_startups, *new_stack, *dir, *table, *page, + *common; + + SMP_PRINTF ("smp: initialising"); + /* + * first let's check the kind of processor this is since only intel chips + * support the MP specification. + */ +#if 0 + /* FIXME - this check doesn't work */ + if (!smp_check_cpu ()) + SMP_ERROR ("smp: processor is not Genuine Intel or is a 386 or 486\n"); +#else + j = smp_check_cpu (); + SMP_PRINTF ("smp: cpu is %x", j); +#endif + + /* + * scan the three spec-defined regions for the floating pointer + * structure. if we find one, copy its address into mp_config, + * otherwise, abort smp initialisation. after that, check the + * integrity of the structures. + */ + mp_config = (mp_flt_ptr *) 0x1000; /* small hack */ + /* mp_probe (0, 0x400); */ + mp_probe (0x9fc00, 0xa0000); + mp_probe (0xf0000, 0x100000); + if (mp_config == (mp_flt_ptr *) 0x1000) /* if unchanged */ + SMP_ERROR ("smp: no floating pointer structure detected\n"); + +#if 0 + /* FIXME - this check doesn't work */ + if (!smp_verify_data ()) + SMP_ERROR ("smp: bad configuration information\n"); + kprintf ("smp: it's all good\n"); +#endif + + /* + * whee, we're running on an smp machine with valid configuration + * information. print out some of this new intelligence. + */ + kprintf ("smp: intel mp version %s, %s", (mp_config->mp_rev == 1) ? "1.1" : + "1.4", (mp_config->mp_feature_2 & 0x80) ? + "imcr and pic compatibility mode." : "virtual wire compatibility mode."); + + if (!mp_config->mpc) + { + /* this system conforms to one of the default configurations */ + mp_num_def_config = mp_config->mp_feature_1; + kprintf ("smp: standard configuration %d", mp_num_def_config); + smp_num_cpus = 2; + cpu_apic_id[0] = 0; + cpu_apic_id[1] = 1; + apic = (unsigned int *) 0xfee00000; + ioapic = (unsigned int *) 0xfec00000; + kprintf ("smp: WARNING: standard configuration code is untested"); + else + { + /* + * we don't have a default configuration, so now we have to locate all + * of our hardware. boy, do we have a lot of work to do. + */ + SMP_PRINTF ("smp: not a standard configuration"); + mp_num_def_config = 0; + mp_do_config (); + } + smp_configured = 1; + + /* set up the apic */ + aspace_maphi (flat, 0xfee00, 0x3fc, 1, 0x13); + apic_virt = (unsigned int *) 0x803fc000; + asm ("mov %0, %%cr3" : : "r" (_cr3)); + + config = apic_read ((unsigned int *) APIC_SIVR) & APIC_FOCUS | APIC_ENABLE | + 0xff; /* set spurious interrupt vector to 0xff */ + apic_write (APIC_SIVR, config); + config = apic_read (APIC_TPRI) & 0xffffff00; /* accept all interrupts */ + apic_write (APIC_TPRI, config); + + apic_read (APIC_SIVR); + apic_write (APIC_EOI, 0); + + config = apic_read (APIC_LVT3) & 0xffffff00 | 0xfe; /* XXX - set vector */ + apic_write (APIC_LVT3, config); + + /* grab a page at 0x9000 for communicating with the aps */ + aspace_map (flat, 0x9, 0x9, 1, 3); + common = (unsigned int *) 0x9000; + for (i = 0; i < 6; i++) + common [i + 1] = temp_gdt [i]; + *((unsigned int *) 0x9024) = _cr3; + aspace_map (flat, 0xa, 0xa, 1, 3); + ptr = (unsigned char *) 0xa000; + for (j = 0; j < ((unsigned int) &trampoline_end - (unsigned int) + &trampoline + 1); j++) + ptr[j] = ((unsigned char *) &trampoline)[j]; + + /* + * okay, we're ready to go. boot all of the ap's now. we loop through + * using the kernel pe id numbers which were set up in smp_do_config () + * + * XXX - we assume the bsp is the first detected. trying to boot it here + * would be, ahem, bad. + */ + for (i = 1; i < smp_num_cpus; i++) + { + kprintf ("smp: booting cpu#%d with stack 0x%x", i, i * 0x1000); + + /* map stacks and copy bootstrap code onto them */ + aspace_map (flat, i, i, 1, 3); + ptr = (unsigned char *) (0x1000 * i); + for (j = 0; j < ((unsigned int) &trampoline_end - (unsigned int) + &trampoline + 1); j++) + ptr[j] = ((unsigned char *) &trampoline)[j]; + + /* + * modify the bootstrap code, specifically, the third highest order + * byte of the ljmp. we need to do this if we have more than two + * processors, i.e. more than one ap. + */ + ptr = (char *) flush; + *(ptr - 5) = i << 4; + + /* write the location of the stack into a fixed spot in memory */ + *common = 0x1000 * i; + + /* set shutdown code and warm reset vector */ + ptr = (unsigned char *) 0xf; + *ptr = 0xa; + ptr = (unsigned char *) 0x467; + *ptr = 0x1000 * i; + ptr = (unsigned char *) 0x469; + *ptr = 0; + + /* reset cpu ready bit */ + smp_cpus_ready[i] = 0; + + /* clear apic errors */ + if (cpu_apic_version[i] & 0xf0) + { + apic_write (APIC_ESR, 0); + apic_read (APIC_ESR); + } + + /* send (aka assert) INIT IPI */ + SMP_PRINTF ("smp: asserting INIT"); + config = apic_read (APIC_ICR2) & 0xf0ffffff | (cpu_apic_id[i] << 24); + apic_write (APIC_ICR2, config); /* set target pe */ + config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DM_INIT | + APIC_LEVEL_TRIG | APIC_ASSERT; + apic_write (APIC_ICR1, config); + + /* deassert INIT */ + SMP_PRINTF ("smp: deasserting INIT"); + config = apic_read (APIC_ICR2) & 0xffffff | (cpu_apic_id[i] << 24); + apic_write (APIC_ICR2, config); + config = apic_read (APIC_ICR1) & ~0xcdfff | APIC_LEVEL_TRIG | + APIC_DM_INIT; + + /* wait 10ms */ + u_sleep (10000); + + /* is this a local apic or an 82489dx ? */ + num_startups = (cpu_apic_version[i] & 0xf0) ? 2 : 0; + for (j = 0; j < num_startups; j++) + { + /* it's a local apic, so send STARTUP IPIs */ + SMP_PRINTF ("smp: sending STARTUP"); + apic_write (APIC_ESR, 0); + + /* set target pe */ + config = apic_read (APIC_ICR2) & 0xf0ffffff | (cpu_apic_id[i] << + 24); + apic_write (APIC_ICR2, config); + + /* send the IPI */ + config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DM_STARTUP | + ((0x1000 * i) >> 12); + apic_write (APIC_ICR1, config); + + /* wait */ + u_sleep (200); + while (apic_read (APIC_ICR1) & 0x1000) ; + } + + /* wait for processor to boot */ + SMP_PRINTF ("smp: waiting for cpu#%d to come online", i); + apic_set_timer (5000000); /* 5 seconds */ + while (apic_read_timer ()) + if (smp_cpus_ready[i]) + break; + if (!smp_cpus_ready[i]) + kprintf ("smp: initialisation of cpu#%d failed", i); + } + + /* this processor is already booted */ + smp_cpus_ready[smp_my_cpu ()] = 1; + + //ioapic_init (); + //apic_write (APIC_LVTT, 0x100fe); + //ipi_all_but_self (0x40); +} + +void __init__ smp_cpu_setup (void) +{ + unsigned int config; + + /* load the correct values into the idtr and gdtr */ + i386lidt ((uint32) idt, 0x3ff); + i386lgdt ((uint32) gdt, 0x400 / 8); + + /* set up the local apic */ + config = apic_read ((unsigned int *) APIC_SIVR) & APIC_FOCUS | APIC_ENABLE | + 0xff; /* set spurious interrupt vector to 0xff */ + apic_write (APIC_SIVR, config); + config = apic_read (APIC_TPRI) & 0xffffff00; /* accept all interrupts */ + apic_write (APIC_TPRI, config); + + apic_read (APIC_SIVR); + apic_write (APIC_EOI, 0); + + config = apic_read (APIC_LVT3) & 0xffffff00; /* XXX - set vector */ + apic_write (APIC_LVT3, config); +} + +void __init__ smp_final_setup (void) +{ + unsigned int config, ticks_per_us; + + ticks_per_us = bus_clock () / 1000000; + apic_write (APIC_ICRT, ticks_per_us * 10000); /* 10 ms */ + config = 0x20030; + apic_write (APIC_LVTT, config); + + if (smp_my_cpu ()) + sti (); + else + mask_irq (0); +} + +void __init__ smp_cpu_ready (void) +{ + /* + * C code entry point for aps. we finish initialisation and wait for the + * signal from the bsp before heading off into the wild blue yonder. + */ + + /* finish processor initialisation. */ + smp_cpu_setup (); + + /* inform the world of our presence. */ + kprintf ("smp: cpu#%d is online", smp_my_cpu ()); + smp_cpus_ready[smp_my_cpu ()] = 1; + + /* wait for signal from bsp. */ + while (!smp_begun) ; + kprintf ("smp: cpu#%d running", smp_my_cpu ()); + + /* set up local apic to generate timer interrupts. */ + smp_final_setup (); + + /* bon voyage. */ + //swtch (); + while (1) ; +} + +void __init__ smp_begin (void) +{ + /* + * begin smp. we set the begun bit to release the application processors + * out of their cages. they storm out, fly into the scheduler, and off + * we go. + */ + smp_begun = 1; +} + +int smp_my_cpu (void) +{ + if (!smp_configured) + return 0; + else + return cpu_os_id [(apic_read (APIC_ID) & 0xffffffff) >> 24]; +} + +void ipi_dest (int num, int pe) +{ + int config; + + p (&ipi_lock); + cli (); + config = apic_read (APIC_ICR2) & 0xffffff | (pe << 24); + apic_write (APIC_ICR2, config); + config = apic_read (APIC_ICR1) & 0xfff0f800 | APIC_DEST_FIELD | num | + 0x4000; + apic_write (APIC_ICR1, config); + sti (); + v (&ipi_lock); +} + +void ipi_self (int num) +{ + int config; + + p (&ipi_lock); + cli (); + config = apic_read (APIC_ICR2) & 0xffffff; + apic_write (APIC_ICR2, config); + config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_SELF | num; + apic_write (APIC_ICR1, config); + sti (); + v (&ipi_lock); +} + +void ipi_all (int num) +{ + int config; + + p (&ipi_lock); + cli (); + config = apic_read (APIC_ICR2) & 0xffffff; + apic_write (APIC_ICR2, config); + config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_ALL | num; + apic_write (APIC_ICR1, config); + sti (); + v (&ipi_lock); +} + +void ipi_all_but_self (int num) +{ + int config; + + p (&ipi_lock); + cli (); + config = apic_read (APIC_ICR2) & 0xffffff; + apic_write (APIC_ICR2, config); + config = apic_read (APIC_ICR1) & ~0xfdfff | APIC_DEST_ALL_BUT_SELF | num; + apic_write (APIC_ICR1, config); + sti (); + v (&ipi_lock); +} + +volatile unsigned int ioapic_read (unsigned int offset) +{ + *ioapic = offset; + return *(ioapic + 4); /* ioapic + 16 bytes */ +} + +void ioapic_write (unsigned int offset, unsigned int data) +{ + *ioapic = offset; + *(ioapic + 4) = data; /* ioapic + 16 bytes */ +} + +void ioapic_init (void) +{ +} + +void apic_eoi (void) +{ + apic_write (APIC_EOI, 0); +} + diff --git a/kernel/smp.h b/kernel/smp.h @@ -0,0 +1,200 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _SMP_H_ +#define _SMP_H_ + +#include <blt/os.h> + +#ifndef __SMP__ +# ifndef __SMP_ONLY__ +# define UP_OR_SMP(u,s) { u; } +# else +# error defined __SMP_ONLY__ without __SMP__ +# endif +#else +# if !defined (__SMP_ONLY__) +# define UP_OR_SMP(u,s) if (!smp_configured) { u; } else { s; } +# else +# define UP_OR_SMP(u,s) { s; } +# endif +#endif + +#define CPUID_GEN_EBX 0x756e6547 /* Genu */ +#define CPUID_GEN_ECX 0x49656369 /* ineI */ +#define CPUID_GEN_EDX 0x6c65746e /* ntel */ + +#define MP_FLT_SIGNATURE (('_' << 24) | ('P' << 16) | ('M' << 8) | ('_')) +#define MP_CTH_SIGNATURE (('P' << 24) | ('C' << 16) | ('M' << 8) | ('P')) + +#define MP_DEF_LOCAL_APIC 0xfee00000 /* default local apic address */ +#define MP_DEF_IO_APIC 0xfec00000 /* default i/o apic address */ + +#define APIC_DM_INIT (5 << 8) +#define APIC_DM_STARTUP (6 << 8) +#define APIC_LEVEL_TRIG (1 << 14) +#define APIC_ASSERT (1 << 13) + +#define APIC_ENABLE 0x100 +#define APIC_FOCUS (~(1 << 9)) +#define APIC_SIV (0xff) + +#define MP_EXT_PE 0 +#define MP_EXT_BUS 1 +#define MP_EXT_IO_APIC 2 +#define MP_EXT_IO_INT 3 +#define MP_EXT_LOCAL_INT 4 + +#define MP_EXT_PE_LEN 20 +#define MP_EXT_BUS_LEN 8 +#define MP_EXT_IO_APIC_LEN 8 +#define MP_EXT_IO_INT_LEN 8 +#define MP_EXT_LOCAL_INT_LEN 8 + +#define SET_APIC_DEST(x) (x << 24) + +#ifndef __ASM__ + +#include "kernel.h" + +extern unsigned int *apic, *apic_virt; + +#define SMP_ERROR(x) { kprintf (x); return; } + +#define APIC_ID ((unsigned int *) ((unsigned int) apic_virt + 0x020)) +#define APIC_VERSION ((unsigned int *) ((unsigned int) apic_virt + 0x030)) +#define APIC_TPRI ((unsigned int *) ((unsigned int) apic_virt + 0x080)) +#define APIC_EOI ((unsigned int *) ((unsigned int) apic_virt + 0x0b0)) +#define APIC_SIVR ((unsigned int *) ((unsigned int) apic_virt + 0x0f0)) +#define APIC_ESR ((unsigned int *) ((unsigned int) apic_virt + 0x280)) +#define APIC_ICR1 ((unsigned int *) ((unsigned int) apic_virt + 0x300)) +#define APIC_ICR2 ((unsigned int *) ((unsigned int) apic_virt + 0x310)) +#define APIC_LVTT ((unsigned int *) ((unsigned int) apic_virt + 0x320)) +#define APIC_LINT0 ((unsigned int *) ((unsigned int) apic_virt + 0x350)) +#define APIC_LVT3 ((unsigned int *) ((unsigned int) apic_virt + 0x370)) +#define APIC_ICRT ((unsigned int *) ((unsigned int) apic_virt + 0x380)) +#define APIC_CCRT ((unsigned int *) ((unsigned int) apic_virt + 0x390)) +#define APIC_TDCR ((unsigned int *) ((unsigned int) apic_virt + 0x3e0)) + +#define APIC_TDCR_2 0x00 +#define APIC_TDCR_4 0x01 +#define APIC_TDCR_8 0x02 +#define APIC_TDCR_16 0x03 +#define APIC_TDCR_32 0x08 +#define APIC_TDCR_64 0x09 +#define APIC_TDCR_128 0x0a +#define APIC_TDCR_1 0x0b + +#define APIC_LVTT_VECTOR 0x000000ff +#define APIC_LVTT_DS 0x00001000 +#define APIC_LVTT_M 0x00010000 +#define APIC_LVTT_TM 0x00020000 + +#define APIC_LVT_DM 0x00000700 +#define APIC_LVT_IIPP 0x00002000 +#define APIC_LVT_TM 0x00008000 +#define APIC_LVT_M 0x00010000 +#define APIC_LVT_OS 0x00020000 + +#define APIC_TPR_PRIO 0x000000ff +#define APIC_TPR_INT 0x000000f0 +#define APIC_TPR_SUB 0x0000000f + +#define APIC_SVR_SWEN 0x00000100 +#define APIC_SVR_FOCUS 0x00000200 + +#define APIC_DEST_STARTUP 0x00600 + +#define LOPRIO_LEVEL 0x00000010 + +#define APIC_DEST_FIELD (0) +#define APIC_DEST_SELF (1 << 18) +#define APIC_DEST_ALL (2 << 18) +#define APIC_DEST_ALL_BUT_SELF (3 << 18) + +#define IOAPIC_ID 0x0 +#define IOAPIC_VERSION 0x1 +#define IOAPIC_ARB 0x2 +#define IOAPIC_REDIR_TABLE 0x10 + +#define IPI_CACHE_FLUSH 0x40 +#define IPI_INV_TLB 0x41 +#define IPI_INV_PTE 0x42 +#define IPI_INV_RESCHED 0x43 +#define IPI_STOP 0x44 + +typedef struct +{ + unsigned int signature; /* "PCMP" */ + unsigned short table_len; /* length of this structure */ + unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */ + unsigned char checksum; /* checksum, all bytes add up to zero */ + char oem[8]; /* oem identification, not null-terminated */ + char product[12]; /* product name, not null-terminated */ + void *oem_table_ptr; /* addr of oem-defined table, zero if none */ + unsigned short oem_len; /* length of oem table */ + unsigned short num_entries; /* number of entries in base table */ + unsigned int apic; /* address of apic */ + unsigned short ext_len; /* length of extended section */ + unsigned char ext_checksum; /* checksum of extended table entries */ +} mp_config_table; + +typedef struct +{ + unsigned int signature; /* "_MP_" */ + mp_config_table *mpc; /* address of mp configuration table */ + unsigned char mpc_len; /* length of this structure in 16-byte units */ + unsigned char mp_rev; /* spec supported, 1 for 1.1 or 4 for 1.4 */ + unsigned char checksum; /* checksum, all bytes add up to zero */ + unsigned char mp_feature_1; /* mp system configuration type if no mpc */ + unsigned char mp_feature_2; /* imcrp */ + unsigned char mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */ +} mp_flt_ptr; + +typedef struct +{ + unsigned char type; + unsigned char apic_id; + unsigned char apic_version; + unsigned char cpu_flags; + unsigned int signature; /* stepping, model, family, each four bits */ + unsigned int feature_flags; + unsigned int res1, res2; +} mp_ext_pe; + +typedef struct +{ + unsigned char type; + unsigned char ioapic_id; + unsigned char ioapic_version; + unsigned char ioapic_flags; + unsigned int *addr; +} mp_ext_ioapic; + +extern char smp_num_cpus, *trampoline, *trampoline_end; +extern volatile char smp_configured, smp_begun; + +int smp_check_cpu (void); +void smp_init (void); +void smp_cpu_setup (void); +void smp_cpu_ready (void); +void smp_begin (void); +void ioapic_init (void); + +/* these are more interesting functions for use by the rest of the kernel */ + +int smp_my_cpu (void); + +void ipi_dest (int num, int pe); +void ipi_self (int num); +void ipi_all (int num); +void ipi_all_but_self (int num); + +volatile unsigned int ioapic_read (unsigned int offset); +void ioapic_write (unsigned int offset, unsigned int data); + +#endif /* __ASM__ */ + +#endif /* __SMP__ */ + diff --git a/kernel/stub.c b/kernel/stub.c @@ -0,0 +1,30 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifdef __SMP__ +#include "smp.h" +#endif + +void kmain(void); + +/* + * Our state here depends on how we got here. If we are called from the + * first stage bootstrap, we go into the kernel setup code. We can also + * arrive here executing on an application processor that has just completed + * its move into the wonderful world of protected mode. If this is the case, + * we jump into smp code to finish our setup and wait for word from the + * bootstrap processor. + */ +void _start(void) +{ +#ifdef __SMP__ + /* have we detected more processors yet? */ + if (smp_num_cpus > 1) + smp_cpu_ready (); + else +#endif + kmain(); + /* not reached */ +} + diff --git a/kernel/syscall.c b/kernel/syscall.c @@ -0,0 +1,279 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <i386/io.h> +#include "kernel.h" +#include "memory.h" +#include "resource.h" +#include "boot.h" +#include "aspace.h" +#include "task.h" +#include "smp.h" +#include "rights.h" + +#include <blt/syscall_id.h> + +extern task_t *irq_task_map[16]; + +void k_debugger(regs *r, uint32 eip, uint32 cs, uint32 eflags); + +extern int live_tasks; +extern int reaper_sem; + +extern boot_dir *bdir; + +/* HACK: sem_release will cause a reschedule which would not be good */ +void wake_the_reaper(void) +{ + task_t *task; + sem_t *sem = rsrc_find_sem(reaper_sem); + sem->count++; + if((task = rsrc_dequeue(&sem->rsrc)) != NULL) task_wake(task,ERR_NONE); +} + +void terminate(void) +{ + task_t *t = current, *t0; + + //kprintf("Task %X terminated.",current->rsrc.id); + live_tasks--; + rsrc_enqueue(reaper_queue,current); + current->flags = tDEAD; + + /* wake all blocking objects */ + while((t0 = list_detach_head(&t->rsrc.queue)) != NULL) + task_wake(t0,ERR_RESOURCE); + + wake_the_reaper(); + + swtch(); + kprintf("panic: HUH? Back from the dead? %x / %x",t,current); + asm("hlt"); +} + +void sleep(int ticks) +{ + /* convert from microseconds to 3ms ticks - round up slightly */ + ticks = ((ticks + 2000) / 3000); + + if(ticks) { + rsrc_enqueue_ordered(timer_queue, current, kernel_timer + ticks); + } + swtch(); +} + +#define p_uint32(n) (esp[n]) +#define p_int(n) ((int) esp[n]) +#define p_voidptr(n) ((void *) esp[n]) +#define p_charptr(n) ((char *) esp[n]) +#define p_sizet(n) ((size_t) esp[n]) +#define p_pint(n) ((int*) esp[n]) +#define p_puint32(n) ((uint32*) esp[n]) + +#define res r.eax +int metacall (volatile uint32 *esp); + +void syscall(regs r, volatile uint32 eip, uint32 cs, uint32 eflags, + volatile uint32 *esp) +{ +#if 0 + kprintf("* %d %x #%d@%x",current->rsrc.id,eip,r.eax,(uint32)esp); +#endif + + switch(r.eax){ + case BLT_SYS_os_terminate : + terminate(); + break; + + case BLT_SYS_os_console : + kprintf("task %X> %s",current->rsrc.id,p_charptr(1)); + break; + + case BLT_SYS_os_brk : + res = brk(p_uint32(1)); + break; + + case BLT_SYS_os_handle_irq : + /* thread wants to listen to irq in eax */ + if(p_uint32(1) > 0 && p_uint32(1) < 16) { + current->irq = p_uint32(1); + irq_task_map[p_uint32(1)] = current; + }; + + eflags |= 2<<12 | 2<<13; + break; + + case BLT_SYS_os_sleep_irq : + if(current->irq){ + /* sleep */ + current->flags = tSLEEP_IRQ; + unmask_irq(current->irq); + } + swtch(); + break; + + case BLT_SYS_os_debug : +#ifdef __SMP__ + if (smp_configured) + { + config = apic_read (APIC_LVTT); + apic_write (APIC_LVTT, config | 0x10000); + smp_begun = 0; + ipi_all_but_self (IPI_STOP); + } +#endif + k_debugger(&r, eip, cs, eflags); + kprintf("bye bye debugger"); + +#ifdef __SMP__ + if (smp_configured) + { + smp_begin (); + apic_write (APIC_LVTT, config); + } +#endif + break; + + case BLT_SYS_os_sleep : + sleep(p_uint32(1)); + break; + + case BLT_SYS_os_identify : + res = rsrc_identify(p_uint32(1)); + break; + + case BLT_SYS_os_meta : + res = metacall(esp); + break; + + case BLT_SYS_sem_create : + res = sem_create(p_uint32(1),p_charptr(2)); + break; + + case BLT_SYS_sem_destroy : + res = sem_destroy(p_uint32(1)); + break; + + case BLT_SYS_sem_acquire : + res = sem_acquire(p_uint32(1)); + break; + + case BLT_SYS_sem_release : + res = sem_release(p_uint32(1)); + break; + + case BLT_SYS_port_create : + res = port_create(p_uint32(1),p_charptr(2)); + break; + + case BLT_SYS_port_destroy : + res = port_destroy(p_uint32(1)); + break; + + case BLT_SYS_port_option : + res = port_option(p_uint32(1), p_uint32(2), p_uint32(3)); + break; + + case BLT_SYS_port_send : + res = port_send(p_int(1), p_int(2), p_voidptr(3), p_sizet(4), p_uint32(5)); + break; + + case BLT_SYS_port_recv : + res = port_recv(p_int(1), p_pint(2), p_voidptr(3), p_sizet(4), p_puint32(5)); + break; + + case BLT_SYS_right_create : + res = right_create(p_uint32(1), p_uint32(1)); + break; + + case BLT_SYS_right_destroy : + res = right_destroy(p_uint32(1)); + break; + + case BLT_SYS_right_revoke : + res = right_revoke(p_uint32(1), p_uint32(2)); + break; + + case BLT_SYS_right_grant : + res = right_grant(p_uint32(1), p_uint32(2)); + break; + + case BLT_SYS_area_create : + res = area_create(current->rsrc.owner->aspace, p_uint32(1), p_uint32(2), (void **)p_voidptr(3), p_uint32(4)); + break; + + case BLT_SYS_area_clone : + res = area_clone(current->rsrc.owner->aspace, p_uint32(1), p_uint32(2), (void **)p_voidptr(3), p_uint32(4)); + break; + + case BLT_SYS_area_destroy : + res = area_destroy(current->rsrc.owner->aspace, p_uint32(1)); + break; + + case BLT_SYS_area_resize : + res = area_resize(current->rsrc.owner->aspace, p_uint32(1), p_uint32(2)); + break; + + case BLT_SYS_thr_create : { + char *name; + int i; + task_t *t; + t = new_thread(current->rsrc.owner, p_uint32(1), 0); + if(t) { + *((unsigned int *) (t->ustack + 0xfec)) = p_uint32(2); + name = p_charptr(3); + if (name == NULL) + { + for(i=0;current->rsrc.name[i] && i<31;i++) { + t->rsrc.name[i] = current->rsrc.name[i]; + } + if(i<30) t->rsrc.name[i++] = '+'; + t->rsrc.name[i] = 0; + } else { + rsrc_set_name((resource_t *)t, name); + } + res = t->rsrc.id; + } else { + res = -1; + } + } + break; + + case BLT_SYS_thr_resume : + break; + + case BLT_SYS_thr_suspend : + break; + + case BLT_SYS_thr_spawn : + res = thr_spawn(p_uint32(1), p_uint32(2), + p_uint32(3), p_uint32(4), + p_uint32(5), p_uint32(6), + p_charptr(7)); + break; + + case BLT_SYS_thr_kill : + break; + + case BLT_SYS_thr_wait : + res = thr_wait(p_uint32(1)); + break; + + default: + res = -1; + } +} + +int metacall (volatile uint32 *esp) +{ + switch (p_uint32 (0)) + { + case META_NULL_REQUEST : + return 0; + + default: + return -1; + } +} + diff --git a/kernel/task.c b/kernel/task.c @@ -0,0 +1,167 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "memory.h" +#include "task.h" + +extern char *gdt; +extern int live_tasks; + +void thread_bootstrap(void); +void kthread_bootstrap(void); + +void task_wake(task_t *task, int status) +{ + task->status = status; + rsrc_enqueue(run_queue, task); +} + +int wait_on(resource_t *rsrc) +{ + task_t *task = current; + task->status = 0; + rsrc_enqueue(rsrc, task); + swtch(); + return current->status; +} + +void task_destroy(task_t *task) +{ + team_t *team = task->rsrc.owner; + + if(task == current) panic("cannot destroy the running task"); + + TCLRMAGIC(task); + + if(task->stack_area) { + area_destroy(team->aspace, task->stack_area->rsrc.id); + } + + kfreepage(task->kstack); + rsrc_release(&task->rsrc); + kfree(task_t, task); + + team->refcount--; + if(team->refcount == 0) team_destroy(team); +} + +/* create a new task, complete with int stack */ +task_t *task_create(team_t *team, uint32 ip, uint32 sp, int kernel) +{ + task_t *t = kmalloc(task_t); + uint32 *SP; + + t->kstack = kgetpages(1); + t->cr3 = team->aspace->pdirphys; + + t->esp = (uint32) ( ((char *) t->kstack) + 4092 ); + t->esp0 = t->esp; + t->scount = 0; + t->stack_area = NULL; + t->team = team; + + t->node.data = t; + + /* prep the kernel stack for first switch + ** SS + ** ESP + ** EFLAGS + ** CS + ** EIP -- thread_bootstrap will iret into the thread + ** + ** <thread_bootstrap> + ** EFLAGS + ** EBP (0) + ** ESI (0) + ** EDI (0) -- stuff for _context_switch to pop off / return to + ** EBX (0) + */ + + SP = (uint32*) t->esp; + + if(kernel) { + SP--; *SP = SEL_KDATA; + SP--; *SP = sp - 4*5; + SP--; *SP = 0x3202; + SP--; *SP = SEL_KCODE; + SP--; *SP = ip; + SP--; *SP = (uint32) thread_bootstrap; + } else { + SP--; *SP = SEL_UDATA | 3; + SP--; *SP = sp - 4*5; + SP--; *SP = 0x3202; + SP--; *SP = SEL_UCODE | 3; + SP--; *SP = ip; + SP--; *SP = (uint32) thread_bootstrap; + } + SP--; *SP = 0x3002; + SP--; *SP = 0; + SP--; *SP = 0; + SP--; *SP = 0; + SP--; *SP = 0; + + t->esp = (uint32) SP; + +// kprintf("thr:%x/%x:%d",sp,ip,(kernel ? SEL_KCODE : (SEL_UCODE | 3))); + + t->irq = 0; + t->flags = tREADY; + t->waiting_on = NULL; + team->refcount++; + + TSETMAGIC(t); + return t; +} + + +int thr_wait(int thr_id) +{ + task_t *task = rsrc_find_task(thr_id); + + if(task) { + wait_on((resource_t *)task); + return ERR_NONE; + } else { + return ERR_RESOURCE; + } +} + +int thr_spawn(uint32 ip, uint32 sp, + uint32 area0, uint32 vaddr0, + uint32 area1, uint32 vaddr1, + const char *name) +{ + aspace_t *aspace; + task_t *task; + team_t *team; + area_t *area; + int id; + void *addr; + + team = team_create(); + aspace = team->aspace; + task = task_create(team, ip, sp, 0); + task->ustack = 0; + rsrc_bind(&task->rsrc, RSRC_TASK, team); + + id = area_clone(aspace, area0, vaddr0, &addr, 0); + team->heap_id = id; + + if(area = rsrc_find_area(id)) { + rsrc_set_owner(&area->rsrc, team); + } + + id = area_clone(aspace, area1, vaddr1, &addr, 0); + if(area = rsrc_find_area(id)) rsrc_set_owner(&area->rsrc, team); + + rsrc_set_name(&task->rsrc, name); + rsrc_set_name(&team->rsrc, name); + rsrc_enqueue(run_queue, task); + live_tasks++; + + return task->rsrc.id; +} + + diff --git a/kernel/task.h b/kernel/task.h @@ -0,0 +1,84 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _TASK_H_ +#define _TASK_H_ + +#include "resource.h" +#include "list.h" +#include "team.h" + +#define tKERNEL 0 +#define tRUNNING 1 +#define tREADY 2 +#define tDEAD 3 +#define tWAITING 4 +#define tSLEEP_IRQ 5 +#define tSLEEP_TIMER 6 +#define tSLEEP_PAGING 7 + +#define PARANOID 0 + +#if PARANOID +#define TMAGIC1 0x327610ae +#define TMAGIC2 0x55716621 +#endif + +struct __task_t { + resource_t rsrc; + +#if PARANOID + uint32 magic1; +#endif + + /* wait_queue support */ + resource_t *waiting_on; + node_t node; + int status; /* status code for the task that has just been awakened */ + uint32 wait_time; /* for timer queues */ + + uint32 flags; + uint32 irq; + uint32 esp; /* saved stack */ + uint32 esp0; /* kernel entry stack -- to stuff in the TSS */ +#if PARANOID + uint32 magic2; +#endif + uint32 cr3; + uint32 scount; + void *kstack, *ustack; + area_t *stack_area; + team_t *team; /* team to which this task belongs */ + +#ifdef __SMP__ + int has_cpu, processor, last_processor; +#endif +}; + +#if PARANOID +#define TSETMAGIC(t) { t->magic1 = TMAGIC1; t->magic2 = TMAGIC2; } +#define TCLRMAGIC(t) { t->magic1 = 0; t->magic2 = 0; } +#define TCHKMAGIC(t) { if((t->magic1 != TMAGIC1) || (t->magic2 != TMAGIC2)) panic("bad thread magic");} +#else +#define TSETMAGIC(t) ((void)0) +#define TCLRMAGIC(t) ((void)0) +#define TCHKMAGIC(t) ((void)0) +#endif + +task_t *task_create(team_t *team, uint32 ip, uint32 sp, int kernel); +void task_destroy(task_t *task); +void task_wait_on(task_t *task, resource_t *rsrc); +void task_wake(task_t *task, int status); +int wait_on(resource_t *rsrc); + +void task_call(task_t *t); + +int thr_kill(int task_id); +int thr_wait(int task_id); +int thr_spawn(uint32 ip, uint32 sp, + uint32 area0, uint32 vaddr0, + uint32 area1, uint32 vaddr1, + const char *name); +#endif + diff --git a/kernel/team.c b/kernel/team.c @@ -0,0 +1,66 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "kernel.h" +#include "memory.h" +#include "list.h" + +team_t *team_create(void) +{ + team_t *team = kmalloc(team_t); + + if(!(team->aspace = aspace_create())) return NULL; + + list_init(&team->resources); + team->refcount = 0; + team->text_area = 0; + team->heap_id = 0; + + rsrc_bind(&team->rsrc, RSRC_TEAM, kernel_team); + rsrc_set_owner(&team->aspace->rsrc, team); + + return team; +} + +void team_destroy(team_t *team) +{ + resource_t *rsrc; + +// kprintf("death to team #%d (%s)",team->rsrc.id,team->rsrc.name); +// DEBUGGER(); + + while(rsrc = list_remove_head(&team->resources)){ + rsrc->owner = NULL; +// kprintf("- %x %s %d",rsrc,rsrc_typename(rsrc),rsrc->id); + + switch(rsrc->type){ + case RSRC_TASK: + kprintf("oops... cannot destroy team %d because of task %d!?", + team->rsrc.id,rsrc->id); + DEBUGGER(); + case RSRC_PORT: + port_destroy(rsrc->id); + break; + case RSRC_SEM: + sem_destroy(rsrc->id); + break; + case RSRC_ASPACE: + aspace_destroy((aspace_t*) rsrc); + break; + case RSRC_AREA: + case RSRC_QUEUE: + case RSRC_TEAM: + /* skip for now - teams don't get destroyed, areas and queues get + destroyed with their relatives */ + break; + + default: + kprintf("what the hell is %d (type %d)?",rsrc->id,rsrc->type); + } + } + + rsrc_release(team); + kfree(team_t, team); +} + diff --git a/kernel/team.h b/kernel/team.h @@ -0,0 +1,25 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _TEAM_H +#define _TEAM_H + +#include "resource.h" + +struct __team_t { + resource_t rsrc; + + list_t resources; /* all resources owned by the team */ + int refcount; /* number of attached tasks */ + + aspace_t *aspace; /* address space which it all exists in */ + + int heap_id; + int text_area; +}; + +team_t *team_create(void); +void team_destroy(team_t *team); + +#endif diff --git a/kernel/trampoline.S b/kernel/trampoline.S @@ -0,0 +1,92 @@ +/* $Id: //depot/blt/kernel/trampoline.S#2 $ +** +** Copyright 1998 Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +/* + * This is the initial bootstrap code for the application processors. When + * we get here, we are running on the AP in 16-bit real mode with a stack + * allocated at 0x1000 * my_cpu_num by the kernel which we are not set up + * to use yet. Our text is at the bottom of this stack. We have to be + * careful until things are fixed up. + * + * Basically, we just set protected mode with a temporary GDT, and call + * C code. The IDT and paging are set up later since we can't reference + * any global variable here declared outside this file. + * + * Memory map at this stage is + * + * 0x9000 location of our stack + * 0x9004 null descriptor + * 0x9008 + * 0x900c kernel text descriptor + * 0x9010 + * 0x9014 kernel data descriptor + * 0x9018 + * 0x901c gdt limit << 16 + * 0x9020 gdt base + * 0x9024 address of page directory + */ + +.globl trampoline +.globl trampoline_end +.globl flush + +.code16 +trampoline: + cli # paranoia + xor %ax, %ax + mov %ax, %ds + mov %ax, %ss + + movl $0x9000, %eax # find the location of our stack + mov (%eax), %ebx + + xor %eax, %eax + mov %ax, %ss + add $0x1000, %ebx + mov %bx, %sp + + movl $0x18, %eax # i[0] = limit << 16; (limit is 24 dec.) + movl $0x10, %ecx + shl %cl, %eax + mov $0x901c, %ebx + mov %eax, (%ebx) + mov $0x9004, %eax # i[1] = base; (base = 0x9004) + mov %eax, 4(%ebx) + mov $0x901e, %eax + lgdt (%eax) + + movl $0x9024, %eax + mov (%eax), %eax + mov %eax, %cr3 + + movl $0x80000001, %eax # turn on paging and protected mode + mov %eax, %cr0 + + /* + * Do a long jump to the kernel text segment to serialise the processor. + * A jump to flush won't work since we are being linked to run at a + * different address, so we calculate the offset in the segment ourselves. + */ + ljmp $0x8, $(0x1000 + flush - trampoline) + +.code32 +flush: + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + mov $0x66, %ax + mov $0x1000, %dx + mov %eax, (%edx) + cld # supposedly good for gcc > 2 + movl $0x80000074, %eax # jmp _start does not work for some reason + jmp *%eax + +trampoline_end: + diff --git a/kernel/types.h b/kernel/types.h @@ -0,0 +1,24 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +#include <blt/types.h> + +typedef struct __resource_t resource_t; +typedef struct __right_t right_t; +typedef struct __port_t port_t; +typedef struct __sem_t sem_t; +typedef struct __task_t task_t; +typedef struct __aspace_t aspace_t; +typedef struct __area_t area_t; +typedef struct __team_t team_t; + +typedef struct __list_t list_t; +typedef struct __node_t node_t; + +typedef struct __pager_fault_t pager_fault_t; + +#endif diff --git a/lib/Makefile b/lib/Makefile @@ -0,0 +1,28 @@ +BLTHOME := ../ +include $(BLTHOME)make.conf + +PRETARGETS := obj crt0.o crtb.o c++rt0.o version.o +TARGETS := subdirs + +SUBDIRS := libc libblt libposix libconsole libdl libwin + +obj: + mkdir obj + ln -fs ../libblt/libblt.a obj + ln -fs ../libblt/libblt.so obj + ln -fs ../libc/libc.a obj + ln -fs ../libc/libc.so obj + ln -fs ../libc/libkern.a obj + ln -fs ../libconsole/libconsole.a obj + ln -fs ../libconsole/libconsole.so obj + ln -fs ../libposix/libposix.a obj + ln -fs ../libposix/libposix.so obj + ln -fs ../libdl/libdl.a obj + ln -fs ../libdl/libdl.so obj + ln -fs ../libwin/libwin.a obj + ln -fs ../libwin/libwin.so obj + +clean:: + @rm -rf obj + +include $(BLTHOME)make.actions diff --git a/lib/c++rt0.c b/lib/c++rt0.c @@ -0,0 +1,141 @@ +/* $Id: //depot/blt/lib/c++rt0.c#5 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** Copyright 1998-1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> +#include <elf.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> + +int main(int argc, char **argv); +static void _init(void); + +char *__progname; + +void _start(int argc, char **argv) +{ + _init(); + __progname = *argv; + os_terminate (main (argc, argv)); +} + +#define MAXINIT 8 + +void __libc_init_memory(unsigned int top_of_binary, + unsigned int start_bss, unsigned int bss_length); + +static void _init(void) +{ + char *strtab; + int symtablen, top, i, j, p; + elf32_hdr_t *hdr; + elf32_sym_t *symtab; + elf32_sec_hdr_t *last; + init_info *inits[MAXINIT]; + + hdr = (elf32_hdr_t *) 0x1000; + symtab = _elf_find_section_data (hdr, ".symtab"); + strtab = _elf_find_section_data (hdr, ".strtab"); + symtablen = _elf_section_size (hdr, ".symtab") / sizeof (elf32_sym_t); + last = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shentsize * (hdr->e_shnum - 1)); + top = (unsigned int) hdr + last->sh_offset + last->sh_size; + + /* Find any __init_... symbols and build a list of 'em + ** These will all be called before main(), but after + ** the .bss is zero'd + */ + for (j = 0, i = 0; i < symtablen; i++){ + if (!strncmp(strtab + symtab[i].st_name, "__init_", 7) && + (symtab[i].st_shndx != SHN_UNDEF)){ + inits[j++] = (init_info *) symtab[i].st_value; + if(j == MAXINIT) break; + } + } + + __libc_init_memory((unsigned int) top, (unsigned int) + _elf_find_section_data (hdr, ".bss"), _elf_section_size (hdr, ".bss")); + + for(p=0;p<5;p++){ + for(i = 0; i < j; i++){ + if(inits[i]->priority == p) inits[i]->func(); + } + } +} + +elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name) +{ + char *section_name; + int i; + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shstrndx * hdr->e_shentsize); + section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset); + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff); + for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *) + ((unsigned int) sec_hdr + hdr->e_shentsize)) + if (!strcmp (section_name + sec_hdr->sh_name, name)) + return sec_hdr; + return NULL; +} + +void *_elf_find_section_data (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = _elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr + + sec_hdr->sh_offset); +} + +int _elf_section_size (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = _elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size; +} + +/****** this crap is to make ld happy when we build shared executables ******/ + +int ___brk_addr; +int __environ; + +void __attribute__ ((noreturn)) abort () +{ + for (;;) ; +} + +void atexit () +{ +} + +/********************************* end crap *********************************/ + diff --git a/lib/crt0.c b/lib/crt0.c @@ -0,0 +1,142 @@ +/* $Id: //depot/blt/lib/crt0.c#20 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** Copyright 1998-1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> +#include <elf.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> +#include <blt/os.h> + +int main(int argc, char **argv); +static void _init(void); + +char *__progname; + +void _start(int argc, char **argv) +{ + _init(); + __progname = *argv; + os_terminate (main (argc, argv)); +} + +#define MAXINIT 8 + +void __libc_init_memory(unsigned int top_of_binary, + unsigned int start_bss, unsigned int bss_length); + +static void _init(void) +{ + char *strtab; + int symtablen, top, i, j, p; + elf32_hdr_t *hdr; + elf32_sym_t *symtab; + elf32_sec_hdr_t *last; + init_info *inits[MAXINIT]; + + hdr = (elf32_hdr_t *) 0x1000; + symtab = _elf_find_section_data (hdr, ".symtab"); + strtab = _elf_find_section_data (hdr, ".strtab"); + symtablen = _elf_section_size (hdr, ".symtab") / sizeof (elf32_sym_t); + last = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shentsize * (hdr->e_shnum - 1)); + top = (unsigned int) hdr + last->sh_offset + last->sh_size; + + /* Find any __init_... symbols and build a list of 'em + ** These will all be called before main(), but after + ** the .bss is zero'd + */ + for (j = 0, i = 0; i < symtablen; i++){ + if (!strncmp(strtab + symtab[i].st_name, "__init_", 7) && + (symtab[i].st_shndx != SHN_UNDEF)){ + inits[j++] = (init_info *) symtab[i].st_value; + if(j == MAXINIT) break; + } + } + + __libc_init_memory((unsigned int) top, (unsigned int) + _elf_find_section_data (hdr, ".bss"), _elf_section_size (hdr, ".bss")); + + for(p=0;p<5;p++){ + for(i = 0; i < j; i++){ + if(inits[i]->priority == p) inits[i]->func(); + } + } +} + +elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name) +{ + char *section_name; + int i; + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shstrndx * hdr->e_shentsize); + section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset); + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff); + for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *) + ((unsigned int) sec_hdr + hdr->e_shentsize)) + if (!strcmp (section_name + sec_hdr->sh_name, name)) + return sec_hdr; + return NULL; +} + +void *_elf_find_section_data (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = _elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr + + sec_hdr->sh_offset); +} + +int _elf_section_size (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = _elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size; +} + +/****** this crap is to make ld happy when we build shared executables ******/ + +int ___brk_addr; +int __environ; + +void __attribute__ ((noreturn)) abort () +{ + for (;;) ; +} + +void atexit () +{ +} + +/********************************* end crap *********************************/ + diff --git a/lib/crtb.c b/lib/crtb.c @@ -0,0 +1,124 @@ +/* $Id: //depot/blt/lib/crtb.c#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** Copyright 1998-1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> +#include <elf.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> + +int main(int argc, char **argv); +void __libc_init_memory(unsigned int top_of_binary, + unsigned int start_bss, unsigned int bss_length); + +static char *strtab = NULL; +static int symtablen = 0, top = 0; +static elf32_hdr_t *hdr = NULL; +static elf32_sym_t *symtab = NULL; +static void run_all (const char *name); + +void _start(int argc, char **argv) +{ + elf32_sec_hdr_t *last; + + hdr = (elf32_hdr_t *) 0x1000; + symtab = _elf_find_section_data (hdr, ".symtab"); + strtab = _elf_find_section_data (hdr, ".strtab"); + symtablen = _elf_section_size (hdr, ".symtab") / sizeof (elf32_sym_t); + last = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shentsize * (hdr->e_shnum - 1)); + top = (unsigned int) hdr + last->sh_offset + last->sh_size; + + __libc_init_memory((unsigned int) top, (unsigned int) + _elf_find_section_data (hdr, ".bss"), _elf_section_size (hdr, ".bss")); + + run_all ("_init"); + os_terminate (main (argc, argv)); +} + +static void run_all (const char *name) +{ + int i; + + for (i = 0; i < symtablen; i++) + if (!strcmp (strtab + symtab[i].st_name, name) && + (symtab[i].st_shndx != SHN_UNDEF)) + (*((void (*)(void)) symtab[i].st_value)) (); +} + +elf32_sec_hdr_t *_elf_find_section_hdr (elf32_hdr_t *hdr, char *name) +{ + char *section_name; + int i; + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shstrndx * hdr->e_shentsize); + section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset); + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff); + for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *) + ((unsigned int) sec_hdr + hdr->e_shentsize)) + if (!strcmp (section_name + sec_hdr->sh_name, name)) + return sec_hdr; + return NULL; +} + +void *_elf_find_section_data (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = _elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr + + sec_hdr->sh_offset); +} + +int _elf_section_size (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = _elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size; +} + +/****** this crap is to make ld happy when we build shared executables ******/ + +int ___brk_addr; +int __environ; + +void __attribute__ ((noreturn)) abort () +{ + for (;;) ; +} + +void atexit () +{ +} + +/********************************* end crap *********************************/ + diff --git a/lib/libblt/Connection.cpp b/lib/libblt/Connection.cpp @@ -0,0 +1,113 @@ +/* Copyright 1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <blt/Connection.h> +#include <blt/Message.h> +#include <blt/namer.h> +#include <blt/syscall.h> + +#include <string.h> + +using namespace BLT; + +Connection::~Connection() +{ + port_destroy(_local_port); +} + +int +Connection::Send(const Message *msg) +{ + msg_hdr_t mh; + const void *data; + uint32 len; + int res; + + msg->GetPackedData(&data,&len); + + mh.flags = 0; + mh.src = _local_port; + mh.dst = _remote_port; + mh.data = (void*) data; + mh.size = len; + + res = old_port_send(&mh); + if(res != len) { + return res; + } else { + return 0; + } +} + +int +Connection::Recv(Message *msg) +{ + msg_hdr_t mh; + int res; + char buf[1024]; + + mh.flags = 0; + mh.dst = _local_port; + mh.size = 1024; + mh.data = buf; + + if((res = old_port_recv(&mh)) < 0) return res; + + return msg->PutPackedData(buf,res,mh.src); +} + +int +Connection::Call(const Message *send, Message *recv) +{ + int res; + if((res = Send(send))) { + return res; + } else { + return Recv(recv); + } +} + +Connection * +Connection::FindService(const char *name) +{ + Connection *cnxn; + int port; + + if(!strcmp(name,"namer")){ + port = NAMER_PORT; + } else { + port = namer_find(name, 0); + } + if(port < 1) return 0; + + cnxn = new Connection(); + cnxn->_remote_port = port; + + return cnxn; +} + +Connection * +Connection::CreateService(const char *name) +{ + Connection *cnxn = new Connection(); + + if(!strcmp(name,"namer")){ + port_destroy(cnxn->_local_port); + cnxn->_local_port = NAMER_PORT; + } else { + if(namer_register(cnxn->_local_port, (char*) name)){ + delete cnxn; + cnxn = 0; + } + } + + return cnxn; +} + + +Connection::Connection() +{ + _local_port = port_create(0,"cnxn:local_port"); + _remote_port = 0; +} diff --git a/lib/libblt/Makefile b/lib/libblt/Makefile @@ -0,0 +1,11 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +LIBRARY := libblt.a +SHLIB := libblt.so +SHLIB_MAJOR := 1 +SHLIB_MINOR := 0 +OBJS := hash.o tell.o blkdev.o disk.o \ + namer.o Message.o Connection.o + +include $(BLTHOME)make.actions diff --git a/lib/libblt/Message.cpp b/lib/libblt/Message.cpp @@ -0,0 +1,312 @@ +// Copyright 1999, Brian J. Swetland. All Rights Reserved. +// This file is provided under the terms of the OpenBLT License + +#include <stdlib.h> +#include <string.h> + +#include <blt/Message.h> +#include <blt/syscall.h> + +#define GROW_BY 128 +#define BLT_ID_MESSAGE 0x42023017 + +using namespace BLT; + +struct chunk +{ + uint32 type; + uint32 id; + uint32 len; + uchar data[4]; +}; + +Message::Message() +{ + chunk *c; + + _data = malloc(GROW_BY); + _length = 12; + _available = GROW_BY - 12; + + c = (chunk*) _data; + + c->type = BLT_TYPE_MESSAGE; + c->id = BLT_ID_MESSAGE; + c->len = 0; + + _reply_port = 0; +} + + +Message::~Message() +{ + if(_data) free(_data); +} + +int +Message::PutData(uint32 type, uint32 id, const void *data, uint32 len) +{ + chunk *c; + uint32 size = 12 + ((len + 3) & ~3); + + if(_available < size) { + while(_available < size) { + _available += GROW_BY; + } + _data = realloc(_data, (_length + _available)); + } + + c = (chunk*) ((char*) _data + _length); + c->type = type; + c->id = id; + c->len = len; + memcpy(c->data, data, len); + + _length += size; + ((chunk*)_data)->len = _length - 12; +} + +int +Message::GetData(uint32 type, uint32 id, void *data, uint32 len) const +{ + chunk *c; + char *x = (char *) _data + 12; + uint32 count = _length - 12; + uint32 size; + + while(count > 12){ + c = (chunk*) x; + size = (12 + ((c->len + 3) & ~3)); + if((type == c->type) && (id == c->id) && (len == c->len)){ + memcpy(data, c->data, c->len); + return 0; + } + + x += size; + count -= size; + } + + return -1; +} + +int +Message::GetData(uint32 type, uint32 id, const void **data, uint32 *len) const +{ + chunk *c; + char *x = (char *) _data + 12; + uint32 count = _length - 12; + uint32 size; + + while(count > 12){ + c = (chunk*) x; + size = (12 + ((c->len + 3) & ~3)); + if((type == c->type) && (id == c->id)){ + *data = (void*) c->data; + *len = c->len; + return 0; + } + + x += size; + count -= size; + } + + *data = NULL; + return -1; +} + +int +Message::GetEntry(uint32 n, uint32 *type, uint32 *id, const void **data, uint32 *len) const +{ + chunk *c; + char *x = (char *) _data + 12; + uint32 count = _length - 12; + uint32 size; + uint32 _n = 0; + + while(count > 12){ + c = (chunk*) x; + if(_n == n){ + *type = c->type; + *id = c->id; + *len = c->len; + *data = (void*) c->data; + } + + size = (12 + ((c->len + 3) & 3)); + x += size; + count -= size; + } + + *data = NULL; + return -1; +} + +int +Message::GetPackedData(const void **data, uint32 *length) const +{ + *data = _data; + *length = _length; + + return 0; +} + +int +Message::PutPackedData(const void *data, uint32 length, int reply_port) +{ + chunk *c = (chunk*) data; + + if(length < 12) return -1; + + if(c->type != BLT_TYPE_MESSAGE) return -1; + if(c->id != BLT_ID_MESSAGE) return -1; + if(c->len != (length - 12)) return -1; + + if(_data) free(_data); + _data = malloc(length); + + memcpy(_data, data, length); + _available = 0; + _length = length; + + _reply_port = reply_port; + + return 0; +} + +int +Message::PutInt32(uint32 id, int32 data) +{ + return PutData(BLT_TYPE_INT32, id, &data, sizeof(int32)); +} + +int +Message::PutString(uint32 id, const char *data) +{ + return PutData(BLT_TYPE_STRING, id, data, strlen(data)+1); +} + +int +Message::PutPointer(uint32 id, void *data) +{ + return PutData(BLT_TYPE_POINTER, id, data, sizeof(void*)); +} + +int +Message::PutMessage(uint32 id, Message *msg) +{ + return PutData(BLT_TYPE_MESSAGE, id, msg->_data, msg->_length); +} + +int +Message::GetInt32(uint32 id, int32 *data) const +{ + return GetData(BLT_TYPE_INT32, id, (void*) data, sizeof(int32)); +} + +int +Message::GetString(uint32 id, const char **data) const +{ + uint32 discard; + return GetData(BLT_TYPE_STRING, id, (const void**) data, &discard); +} + +int +Message::GetPointer(uint32 id, void **ptr) const +{ + return GetData(BLT_TYPE_POINTER, id, (void*) ptr, sizeof(void *)); +} + +int +Message::GetMessage(uint32 id, Message *msg) const +{ + const void *data; + uint32 len; + + GetData(BLT_TYPE_MESSAGE, id, &data, &len); + return msg->PutPackedData(data,len); +} + +void +Message::Empty() +{ + _available += _length - 12; + _length = 12; + _reply_port = 0; + ((chunk*)_data)->len = 0; +} + +int +Message::Reply(const Message *msg) const +{ + msg_hdr_t mh; + int res; + + if(_reply_port > 0){ + if((res = port_create(0,"reply_port")) < 0) return res; + mh.flags = 0; + mh.src = res; + mh.dst = _reply_port; + mh.size = msg->_length; + mh.data = msg->_data; + res = old_port_send(&mh); + port_destroy(mh.src); + if(res == msg->_length) { + return 0; + } else { + return res; + } + } else { + return -1; + } +} + +#if 0 + +void Message::dump() +{ + int i,j; + fprintf(stderr,"bMessage - %d of %d\n",_length,_length+_available); + + for(i=0;i<_length;i+=16){ + fprintf(stderr,"%04x: ",i); + for(j=0;j<16;j++){ + if((i+j) < _length){ + fprintf(stderr,"%02x ",((uchar*)_data)[i+j]); + } else { + fprintf(stderr," "); + } + } + fprintf(stderr," "); + for(j=0;j<16;j++){ + if((i+j) < _length){ + uchar c = ((uchar*)_data)[i+j]; + if((c<' ')||(c>126)) c = '.'; + fprintf(stderr,"%c",c); + } else { + fprintf(stderr," "); + } + } + fprintf(stderr,"\n"); + } + +} + +int main(int argc, char *argv[]) +{ + int32 n; + const char *s; + + Message msg; + msg.PutInt32('foob',42); + msg.PutString('blah',"Hello, Message"); + + if(msg.GetInt32('foob',&n)) exit(1); + fprintf(stderr,"foob = %d\n",n); + + if(msg.GetString('blah',&s)) exit(1); + fprintf(stderr,"blah = %s\n",s); + + msg.dump(); + return 0; +} +#endif diff --git a/lib/libblt/blkdev.c b/lib/libblt/blkdev.c @@ -0,0 +1,117 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <blt/libsyms.h> +#include <blt/blkdev.h> +#include <blt/namer.h> +#include <blt/syscall.h> + +weak_alias (_blk_open, blk_open) +weak_alias (_blk_close, blk_close) +weak_alias (_blk_read, blk_read) +weak_alias (_blk_write, blk_write) + +int __blk_ref; + +int _blk_open (const char *name, int flags, blkdev_t **retdev) +{ + char *server; + int i, len; + msg_hdr_t mh; + blkdev_t *dev; + blktxn_t *txn; + blkres_t res; + + for (i = 0; name[i] && (name[i] != '/') && i < BLT_MAX_NAME_LENGTH; i++) ; + server = malloc (i); + strncpy (server, name, i); + server[i] = 0; + + dev = malloc (sizeof (blkdev_t)); + dev->remote_port = namer_find (server, 1); + + txn = malloc (len = sizeof (blktxn_t) + strlen (name) - i + 1); + txn->cmd = BLK_CMD_OPEN; + strcpy ((char *) (txn + 1), name + i + 1); + + mh.src = dev->local_port = port_create (dev->remote_port, "blkdev"); + mh.dst = dev->remote_port; + mh.data = txn; + mh.size = len; + old_port_send (&mh); + + mh.src = dev->remote_port; + mh.dst = dev->local_port; + mh.data = &res; + mh.size = sizeof (blkres_t); + old_port_recv (&mh); + + if (res.status) + { + free (dev); + *retdev = NULL; + return res.status; + } + + dev->blksize = res.data[0]; + dev->devno = res.data[1]; + *retdev = dev; + return 0; +} + +int _blk_close (blkdev_t *dev) +{ + free (dev); + return 0; +} + +int _blk_read (blkdev_t *dev, void *buf, int block, int count) +{ + int len, ret; + msg_hdr_t mh; + blktxn_t txn; + blkres_t *res; + + res = malloc (len = sizeof (blkres_t) + dev->blksize); + + while (count) + { + txn.device = dev->devno; + txn.cmd = BLK_CMD_READ; + txn.block = block; + txn.count = count; + mh.src = dev->local_port; + mh.dst = dev->remote_port; + mh.data = &txn; + mh.size = sizeof (blktxn_t); + old_port_send (&mh); + + mh.src = dev->remote_port; + mh.dst = dev->local_port; + mh.data = res; + mh.size = len; + old_port_recv (&mh); + + if (res->status) + goto done; + memcpy (buf, res + 1, dev->blksize); + buf = (char *) buf + dev->blksize; + block++; + count--; + } + +done: + ret = res->status; + free (res); + return ret; +} + +int _blk_write (blkdev_t *dev, const void *buf, int block, int count) +{ + return 0; +} + diff --git a/lib/libblt/disk.c b/lib/libblt/disk.c @@ -0,0 +1,167 @@ +/* $Id: //depot/blt/lib/libblt/disk.c#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <blt/disk.h> + +static int blt_internal_code (int fdisk, int fstype) +{ + if (fdisk == FDISK_TYPE_FREEBSD) + if (fstype == BSD_FS_BSDFFS) + return FREEBSD_FFS; + else if (fstype == BSD_FS_SWAP) + return FREEBSD_SWAP; + else + return 0; + else if (fdisk == FDISK_TYPE_OPENBSD) + if (fstype == BSD_FS_BSDFFS) + return OPENBSD_FFS; + else if (fstype == BSD_FS_SWAP) + return OPENBSD_SWAP; + else + return 0; + else + return 0; +} + +disk_t *disk_alloc (blkdev_t *dev) +{ + unsigned char *mbr, *label; + int i, j, x; + disk_t *disk; + fdisk_partition *fp; + bsd_disklabel *slice; + + disk = malloc (sizeof (disk_t)); + disk->dev = dev; + disk->numparts = 0; + mbr = malloc (dev->blksize); + label = malloc (dev->blksize); + slice = (bsd_disklabel *) label; + + /* count fdisk partitions */ + blk_read (dev, mbr, 0, 1); + for (i = 0; i < 4; i++) + { + fp = (fdisk_partition *) (mbr + 0x1be) + i; + if (fp->type) + switch (fp->type) + { + case FDISK_TYPE_EMPTY: + break; + + case FDISK_TYPE_FREEBSD: + case FDISK_TYPE_OPENBSD: + disk->numparts++; + blk_read (dev, label, fp->start_sect_num + 1, 1); + for (j = 0; j < BSD_MAXSLICES; j++) + if (slice->d_partitions[j].p_fstype != BSD_FS_UNUSED) + disk->numparts++; + break; + + default: + disk->numparts++; + break; + } + } + disk->partition = malloc (sizeof (partition_t) * disk->numparts); + + /* create partition data, fdisk partitions first */ + for (i = x = 0; i < 4; i++) + { + fp = (fdisk_partition *) (mbr + 0x1be) + i; + if (fp->type) + { + disk->partition[x].name[0] = '0' + i; + disk->partition[x].name[1] = 0; + disk->partition[x].start = fp->start_sect_num; + disk->partition[x].size = fp->num_sects; + disk->partition[x].type = fp->type; + x++; + } + } + + /* create data for bsd slices */ + for (i = 0; i < 4; i++) + { + fp = (fdisk_partition *) (mbr + 0x1be) + i; + switch (fp->type) + { + case FDISK_TYPE_FREEBSD: + case FDISK_TYPE_OPENBSD: + blk_read (dev, label, fp->start_sect_num + 1, 1); + for (j = 0; j < BSD_MAXSLICES; j++) + if (slice->d_partitions[j].p_fstype != BSD_FS_UNUSED) + { + disk->partition[x].name[0] = '0' + i; + disk->partition[x].name[1] = 'a' + j; + disk->partition[x].name[2] = 0; + disk->partition[x].start = + slice->d_partitions[j].p_offset; + disk->partition[x].size = + slice->d_partitions[j].p_size; + disk->partition[x].type = blt_internal_code (fp->type, + slice->d_partitions[j].p_fstype); + x++; + } + break; + } + } + + free (mbr); + free (label); + return disk; +} + +void disk_free (disk_t *disk) +{ + free (disk->partition); + free (disk); +} + +const char *disk_partition_name (disk_t *disk, int partition) +{ + return disk->partition[partition].name; +} + +unsigned long long disk_partition_start (disk_t *disk, int partition) +{ + return disk->partition[partition].start; +} + +unsigned long long disk_partition_size (disk_t *disk, int partition) +{ + return disk->partition[partition].size; +} + +unsigned int disk_partition_type (disk_t *disk, int partition) +{ + return disk->partition[partition].type; +} + diff --git a/lib/libblt/hash.c b/lib/libblt/hash.c @@ -0,0 +1,234 @@ +/* $Id: //depot/blt/lib/libblt/hash.c#3 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * these algorithms are based on knuth's algorithm 6.4d, as described in + * vol. 3, p. 529 of taocp. + * + * XXX - keys must be unique! + */ + +/* + +the primes were computed by using the following program: + +int main (void) +{ + unsigned int i, j, good, last; + + for (i = 17, last = 0; i < 65536 * 16384 - 1; i++) + { + for (j = 2, good = 1; (j <= floor (sqrt ((double) i))) && good; j++) + if (!(i % j)) + good = 0; + if (good) + { + if (last == i - 2) + { + printf ("%d %d\n", last, i); + i *= 2; + } + last = i; + } + } + + return 0; +} + +*/ + +#include <stddef.h> +#include <stdlib.h> +#include <blt/hash.h> + +static unsigned int table_size[] = { 7, 19, 43, 103, 229, 463, 1021, 2083, 4219, + 8539, 17191, 34471, 69031, 138079, 276373, 552751, 1105549, 2211259, + 4422619, 8845453, 17691043, 35382091, 70764259, 141528559, 283057213, + 566115259 }; + +static int hash (int key, int size); +static int rehash (int key, int size); +static void hashtable_rebuild (hashtable_t *t, int dir); + +static int hash (int key, int size) +{ + return key % table_size[size]; +} + +static int rehash (int key, int size) +{ + return 1 + (key % (table_size[size] - 2)); +} + +hashtable_t *hashtable_new (float max_load) +{ + int i; + hashtable_t *t; + + t = (hashtable_t *) malloc (sizeof (hashtable_t)); + t->size_index = 0; + t->used = t->dirty = 0; + t->max_load = max_load; + t->table = (hashnode_t *) malloc (sizeof (hashnode_t) * *table_size); + for (i = 0; i < table_size[t->size_index]; i++) + t->table[i].valid = t->table[i].dirty = 0; + return t; +} + +void hashtable_del (hashtable_t *t) +{ + free (t->table); +} + +void hashtable_insert (hashtable_t *t, int key, void *data, int dsize) +{ + int i, c; + + if (t->used > (t->max_load * table_size[t->size_index])) + hashtable_rebuild (t, 1); + + i = hash (key, t->size_index); + if (t->table[i].valid) + do + { + c = rehash (key, t->size_index); + i -= c; + if (i < 0) + i += table_size[t->size_index]; + } + while (t->table[i].valid && !t->table[i].dirty); + if (!t->table[i].dirty) + t->used++; + t->table[i].valid = 1; + t->table[i].dirty = 0; + t->table[i].key = key; + t->table[i].dsize = dsize; + t->table[i].data = data; +} + +static void hashtable_rebuild (hashtable_t *t, int dir) +{ + int i, old_index; + hashnode_t *old; + + old = t->table; + old_index = t->size_index; + switch (dir) + { + case -1: + t->size_index = t->size_index ? t->size_index - 1 : 0; + break; + case 0: + break; + case 1: + t->size_index++; + break; + default: + return; + } + + t->used = t->dirty = 0; + t->table = (hashnode_t *) malloc (sizeof (hashnode_t) * + table_size[t->size_index]); + for (i = 0; i < table_size[t->size_index]; i++) + t->table[i].valid = t->table[i].dirty = 0; + for (i = 0; i < table_size[old_index]; i++) + if (old[i].valid && !old[i].dirty) + hashtable_insert (t, old[i].key, old[i].data, old[i].dsize); + free (old); +} + +void *hashtable_lookup (hashtable_t *t, int key, int *dsize) +{ + int i, c; + + i = hash (key, t->size_index); + while (t->table[i].valid) + { + if ((t->table[i].key == key) && !t->table[i].dirty) + { + if (dsize != NULL) + *dsize = t->table[i].dsize; + return t->table[i].data; + } + c = rehash (key, t->size_index); + i -= c; + if (i < 0) + i += table_size[t->size_index]; + } + if (dsize != NULL) + *dsize = 0; + return NULL; +} + +void *hashtable_remove (hashtable_t *t, int key, int *dsize) +{ + int i, c; + void *temp; + + i = hash (key, t->size_index); + while (t->table[i].valid) + { + if ((t->table[i].key == key) && !t->table[i].dirty) + { + if (dsize != NULL) + *dsize = t->table[i].dsize; + temp = t->table[i].data; + t->table[i].dirty = 1; + t->dirty++; + if ((t->dirty > ((1 - t->max_load) * + table_size[t->size_index])) && t->size_index) + hashtable_rebuild (t, -1); + return temp; + } + c = rehash (key, t->size_index); + i -= c; + if (i < 0) + i += table_size[t->size_index]; + } + if (dsize != NULL) + *dsize = 0; + return NULL; +} + +/* +void hashtable_print (hashtable_t *t) +{ + int i; + + printf ("used: %d\ndirty: %d\n\n", t->used, t->dirty); + for (i = 0; i < table_size[t->size_index]; i++) + printf ("%3d: %d %d %3d %3d %3d\n", i, t->table[i].valid, + t->table[i].dirty, t->table[i].key, + t->table[i].data, t->table[i].dsize); +} +*/ + diff --git a/lib/libblt/namer.cpp b/lib/libblt/namer.cpp @@ -0,0 +1,52 @@ +/* Copyright 1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <blt/Connection.h> +#include <blt/Message.h> +#include <blt/namer.h> +#include <blt/syscall.h> + +#include <string.h> + +using namespace BLT; + +int namer_register(int port, const char *name) +{ + int32 res = -1; + Connection *cnxn = Connection::FindService("namer"); + + if(cnxn){ + Message msg; + msg.PutInt32('code',NAMER_REGISTER); + msg.PutInt32('port',port); + msg.PutString('name',name); + cnxn->Call(&msg,&msg); + msg.GetInt32('resp',&res); + delete cnxn; + } + + return res; +} + +int namer_find(const char *name, int blocking) +{ + int32 res = -1; + Connection *cnxn; + + cnxn = Connection::FindService("namer"); + + if(cnxn){ + Message msg; + msg.PutInt32('code',NAMER_FIND); + msg.PutString('name',name); + cnxn->Call(&msg,&msg); + msg.GetInt32('resp',&res); + delete cnxn; + } + + return res; +} + + + diff --git a/lib/libblt/tell.c b/lib/libblt/tell.c @@ -0,0 +1,56 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> +#include <blt/namer.h> +#include <blt/tell.h> + +static char *name; +static volatile int ready = 0; +static void (*callback)(const char *); + +weak_alias (_tell_init, tell_init) + +void __tell_impl (void) +{ + char *buf, junk; + int port, len; + msg_hdr_t mh; + + port = port_create (0, "tell_listen_port"); + buf = malloc (len = TELL_MAX_LEN); + strlcpy (buf, name, len); + strlcat (buf, ":tell", len); + namer_register (port, buf); + ready = 1; + + for (;;) + { + mh.src = 0; + mh.dst = port; + mh.data = buf; + mh.size = len; + old_port_recv (&mh); + (*callback) (buf); + mh.dst = mh.src; + mh.src = port; + mh.data = &junk; + mh.size = 1; + old_port_send (&mh); + } +} + +int _tell_init (char *n, void (*c)(const char *)) +{ + name = n; + callback = c; + os_thread (__tell_impl); + while (!ready) ; + return ready; +} + diff --git a/lib/libc/Makefile b/lib/libc/Makefile @@ -0,0 +1,19 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +MINIMAL = string.o snprintf.o strcmp.o strcpy.o strlen.o strlcat.o strlcpy.o +EXTRA = malloc.o memory.o errno.o qsort.o stdlib.o ctype.o \ + qsem.o atomic.o syscalls.o cppglue.o + +TARGETS := libkern.a +LIBRARY := libc.a +SHLIB := libc.so +SHLIB_MAJOR := 1 +SHLIB_MINOR := 0 +OBJS := $(MINIMAL) $(EXTRA) + +libkern.a: $(MINIMAL) + @rm -f libkern.a + $(AR) r libkern.a $(MINIMAL) + +include $(BLTHOME)make.actions diff --git a/lib/libc/atomic.S b/lib/libc/atomic.S @@ -0,0 +1,45 @@ +/* $Id: //depot/blt/lib/libc/atomic.S#1 $ +** +** Copyright 1999 Jeff Bush +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +.globl atomic_add + +# long atomic_add(long *var, long amount) + +atomic_add: + pushl %ebx + movl 8(%esp), %ecx # pointer to variable +try_add: + movl (%ecx), %eax # get original value + movl 12(%esp), %ebx # get amount to add + addl %eax, %ebx # what result should be + lock + cmpxchg %ebx, (%ecx) + jne try_add # failed, try again + popl %ebx + ret + diff --git a/lib/libc/cppglue.cpp b/lib/libc/cppglue.cpp @@ -0,0 +1,33 @@ +#include <stdlib.h> + +void* operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void *ptr) +{ + free(ptr); +} + +void* operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete[](void *ptr) +{ + free(ptr); +} + +extern "C" { +void __pure_virtual(); +} + +/* + * This needs to do something a little more useful! + */ +void __pure_virtual() +{ + *((char*) 0) = 0; +} diff --git a/lib/libc/ctype.c b/lib/libc/ctype.c @@ -0,0 +1,38 @@ +/* $Id: //depot/blt/lib/libc/ctype.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <ctype.h> +#include <blt/libsyms.h> + +weak_alias (_isdigit, isdigit) + +int _isdigit (int c) +{ + return ((c >= '0') && (c <= '9')) ? 1 : 0; +} + diff --git a/lib/libc/errno.c b/lib/libc/errno.c @@ -0,0 +1,56 @@ +/* $Id: //depot/blt/lib/libc/errno.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> +#include <stddef.h> +#include <errno.h> +#include <blt/libsyms.h> + +int errno; + +static char *msgs[] = +{ + NULL, + "permission denied", + "no such file or directory", + "no such process", + "interrupted system call", + "i/o error", + "device not configured", + "argument list too long", + "exec format error" +}; + +weak_alias (_strerror, strerror) + +char *_strerror (int errnum) +{ + return (errnum < (sizeof (msgs) / sizeof (char *))) ? msgs[errnum] : + NULL; +} + diff --git a/lib/libc/malloc.c b/lib/libc/malloc.c @@ -0,0 +1,2878 @@ +/* $Id: //depot/blt/lib/malloc.c#2 $ */ + +/* ---------- To make a malloc.h, start cutting here ------------ */ + +/* + A version of malloc/free/realloc written by Doug Lea and released to the + public domain. Send questions/comments/complaints/performance data + to dl@cs.oswego.edu + +* VERSION 2.6.5 Wed Jun 17 15:55:16 1998 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://g.oswego.edu/pub/misc/malloc.c + Check before installing! + + Note: This version differs from 2.6.4 only by correcting a + statement ordering error that could cause failures only + when calls to this malloc are interposed with calls to + other memory allocators. + +* Why use this malloc? + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and tunable. + Consistent balance across these factors results in a good general-purpose + allocator. For a high-level description, see + http://g.oswego.edu/dl/html/malloc.html + +* Synopsis of public routines + + (Much fuller descriptions are contained in the program documentation below.) + + malloc(size_t n); + Return a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. + free(Void_t* p); + Release the chunk of memory pointed to by p, or no effect if p is null. + realloc(Void_t* p, size_t n); + Return a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. The returned pointer may or may not be + the same as p. If p is null, equivalent to malloc. Unless the + #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + memalign(size_t alignment, size_t n); + Return a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument, which must be a power of + two. + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system (or as near to this as can be figured out from + all the includes/defines below.) + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + calloc(size_t unit, size_t quantity); + Returns a pointer to quantity * unit bytes, with all locations + set to zero. + cfree(Void_t* p); + Equivalent to free(p). + malloc_trim(size_t pad); + Release all but pad bytes of freed top-most memory back + to the system. Return 1 if successful, else 0. + malloc_usable_size(Void_t* p); + Report the number usable allocated bytes associated with allocated + chunk p. This may or may not report more bytes than were requested, + due to alignment and minimum size constraints. + malloc_stats(); + Prints brief summary statistics on stderr. + mallinfo() + Returns (by copy) a struct containing various summary statistics. + mallopt(int parameter_number, int parameter_value) + Changes one of the tunable parameters described below. Returns + 1 if successful in changing the parameter, else 0. + +* Vital statistics: + + Alignment: 8-byte + 8 byte alignment is currently hardwired into the design. This + seems to suffice for all current machines and C compilers. + + Assumed pointer representation: 4 or 8 bytes + Code for 8-byte pointers is untested by me but has worked + reliably by Wolfram Gloger, who contributed most of the + changes supporting this. + + Assumed size_t representation: 4 or 8 bytes + Note that size_t is allowed to be 4 bytes even if pointers are 8. + + Minimum overhead per allocated chunk: 4 or 8 bytes + Each malloced chunk has a hidden overhead of 4 bytes holding size + and status information. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) + 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) + + When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte + ptrs but 4 byte size) or 24 (for 8/8) additional bytes are + needed; 4 (8) for a trailing size field + and 8 (16) bytes for free list pointers. Thus, the minimum + allocatable size is 16/24/32 bytes. + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + + Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes + 8-byte size_t: 2^63 - 16 bytes + + It is assumed that (possibly signed) size_t bit values suffice to + represent chunk sizes. `Possibly signed' is due to the fact + that `size_t' may be defined on a system as either a signed or + an unsigned type. To be conservative, values that would appear + as negative numbers are avoided. + Requests for sizes with a negative sign bit will return a + minimum-sized chunk. + + Maximum overhead wastage per allocated chunk: normally 15 bytes + + Alignnment demands, plus the minimum allocatable size restriction + make the normal worst-case wastage 15 bytes (i.e., up to 15 + more bytes will be allocated than were requested in malloc), with + two exceptions: + 1. Because requests for zero bytes allocate non-zero space, + the worst case wastage for a request of zero bytes is 24 bytes. + 2. For requests >= mmap_threshold that are serviced via + mmap(), the worst case wastage is 8 bytes plus the remainder + from a system page (the minimal mmap unit); typically 4096 bytes. + +* Limitations + + Here are some features that are NOT currently supported + + * No user-definable hooks for callbacks and the like. + * No automated mechanism for fully checking that all accesses + to malloced memory stay within their bounds. + * No support for compaction. + +* Synopsis of compile-time options: + + People have reported using previous versions of this malloc on all + versions of Unix, sometimes by tweaking some of the defines + below. It has been tested most extensively on Solaris and + Linux. It is also reported to work on WIN32 platforms. + People have also reported adapting this malloc for use in + stand-alone embedded systems. + + The implementation is in straight, hand-tuned ANSI C. Among other + consequences, it uses a lot of macros. Because of this, to be at + all usable, this code should be compiled using an optimizing compiler + (for example gcc -O2) that can simplify expressions and control + paths. + + __STD_C (default: derived from C compiler defines) + Nonzero if using ANSI-standard C compiler, a C++ compiler, or + a C compiler sufficiently close to ANSI to get away with it. + DEBUG (default: NOT defined) + Define to enable debugging. Adds fairly extensive assertion-based + checking to help track down memory errors, but noticeably slows down + execution. + REALLOC_ZERO_BYTES_FREES (default: NOT defined) + Define this if you think that realloc(p, 0) should be equivalent + to free(p). Otherwise, since malloc returns a unique pointer for + malloc(0), so does realloc(p, 0). + HAVE_MEMCPY (default: defined) + Define if you are not otherwise using ANSI STD C, but still + have memcpy and memset in your C library and want to use them. + Otherwise, simple internal versions are supplied. + USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) + Define as 1 if you want the C library versions of memset and + memcpy called in realloc and calloc (otherwise macro versions are used). + At least on some platforms, the simple macro versions usually + outperform libc versions. + HAVE_MMAP (default: defined as 1) + Define to non-zero to optionally make malloc() use mmap() to + allocate very large blocks. + HAVE_MREMAP (default: defined as 0 unless Linux libc set) + Define to non-zero to optionally make realloc() use mremap() to + reallocate very large blocks. + malloc_getpagesize (default: derived from system #includes) + Either a constant or routine call returning the system page size. + HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) + Optionally define if you are on a system with a /usr/include/malloc.h + that declares struct mallinfo. It is not at all necessary to + define this even if you do, but will ensure consistency. + INTERNAL_SIZE_T (default: size_t) + Define to a 32-bit type (probably `unsigned int') if you are on a + 64-bit machine, yet do not want or need to allow malloc requests of + greater than 2^31 to be handled. This saves space, especially for + very small chunks. + INTERNAL_LINUX_C_LIB (default: NOT defined) + Defined only when compiled as part of Linux libc. + Also note that there is some odd internal name-mangling via defines + (for example, internally, `malloc' is named `mALLOc') needed + when compiling in this case. These look funny but don't otherwise + affect anything. + WIN32 (default: undefined) + Define this on MS win (95, nt) platforms to compile in sbrk emulation. + LACKS_UNISTD_H (default: undefined) + Define this if your system does not have a <unistd.h>. + MORECORE (default: sbrk) + The name of the routine to call to obtain more memory from the system. + MORECORE_FAILURE (default: -1) + The value returned upon failure of MORECORE. + MORECORE_CLEARS (default 1) + True (1) if the routine mapped to MORECORE zeroes out memory (which + holds for sbrk). + DEFAULT_TRIM_THRESHOLD + DEFAULT_TOP_PAD + DEFAULT_MMAP_THRESHOLD + DEFAULT_MMAP_MAX + Default values of tunable parameters (described in detail below) + controlling interaction with host system routines (sbrk, mmap, etc). + These values may also be changed dynamically via mallopt(). The + preset defaults are those that give best performance for typical + programs/systems. + + +*/ + +/* Preliminaries */ + +#ifndef __STD_C +#ifdef __STDC__ +#define __STD_C 1 +#else +#if __cplusplus +#define __STD_C 1 +#else +#define __STD_C 0 +#endif /*__cplusplus*/ +#endif /*__STDC__*/ +#endif /*__STD_C*/ + +#ifndef Void_t +#if __STD_C +#define Void_t void +#else +#define Void_t char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include <stddef.h> /* for size_t */ +#else +#include <sys/types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> /* needed for malloc_stats */ + +/* + Compile-time options +*/ + +/* + Debugging: + + Because freed chunks may be overwritten with link fields, this + malloc will often die when freed memory is overwritten by user + programs. This can be very effective (albeit in an annoying way) + in helping track down dangling pointers. + + If you compile with -DDEBUG, a number of assertion checks are + enabled that will catch more memory errors. You probably won't be + able to make much sense of the actual assertion errors, but they + should help you locate incorrectly overwritten memory. The + checking is fairly extensive, and will slow down execution + noticeably. Calling malloc_stats or mallinfo with DEBUG set will + attempt to check every non-mmapped allocated and free chunk in the + course of computing the summmaries. (By nature, mmapped regions + cannot be checked very much automatically.) + + Setting DEBUG may also be helpful if you are trying to modify + this code. The assertions in the check routines spell out in more + detail the assumptions and invariants underlying the algorithms. + +*/ + +#if DEBUG +#include <assert.h> +#else +#define assert(x) ((void)0) +#endif + +/* + INTERNAL_SIZE_T is the word-size used for internal bookkeeping + of chunk sizes. On a 64-bit machine, you can reduce malloc + overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' + at the expense of not being able to handle requests greater than + 2^31. This limitation is hardly ever a concern; you are encouraged + to set this. However, the default version is the same as size_t. +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* + REALLOC_ZERO_BYTES_FREES should be set if a call to + realloc with zero bytes should be the same as a call to free. + Some people think it should. Otherwise, since this malloc + returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + + +/* #define REALLOC_ZERO_BYTES_FREES */ + +/* + HAVE_MEMCPY should be defined if you are not otherwise using + ANSI STD C, but still have memcpy and memset in your C library + and want to use them in calloc and realloc. Otherwise simple + macro versions are defined here. + + USE_MEMCPY should be defined as 1 if you actually want to + have memset and memcpy called. People report that the macro + versions are often enough faster than libc versions on many + systems that it is better to use them. + +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +#else +Void_t* memset(); +Void_t* memcpy(); +#endif +#endif + +#if USE_MEMCPY + +/* The following macros are only invoked with (2n+1)-multiples of + INTERNAL_SIZE_T units, with a positive integer n. This is exploited + for fast inline execution when n is small. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T mzsz = (nbytes); \ + if(mzsz <= 9*sizeof(mzsz)) { \ + INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ + if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; \ + if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; \ + if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; }}} \ + *mz++ = 0; \ + *mz++ = 0; \ + *mz = 0; \ + } else memset((charp), 0, mzsz); \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T mcsz = (nbytes); \ + if(mcsz <= 9*sizeof(mcsz)) { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ + if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; }}} \ + *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + *mcdst = *mcsrc ; \ + } else memcpy(dest, src, mcsz); \ +} while(0) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mzp++ = 0; \ + case 7: *mzp++ = 0; \ + case 6: *mzp++ = 0; \ + case 5: *mzp++ = 0; \ + case 4: *mzp++ = 0; \ + case 3: *mzp++ = 0; \ + case 2: *mzp++ = 0; \ + case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mcdst++ = *mcsrc++; \ + case 7: *mcdst++ = *mcsrc++; \ + case 6: *mcdst++ = *mcsrc++; \ + case 5: *mcdst++ = *mcsrc++; \ + case 4: *mcdst++ = *mcsrc++; \ + case 3: *mcdst++ = *mcsrc++; \ + case 2: *mcdst++ = *mcsrc++; \ + case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#endif + +/* + Define HAVE_MMAP to optionally make malloc() use mmap() to + allocate very large blocks. These will be returned to the + operating system immediately after a free(). +*/ + +#ifndef HAVE_MMAP +#define HAVE_MMAP 0 +#endif + +/* + Define HAVE_MREMAP to make realloc() use mremap() to re-allocate + large blocks. This is currently only possible on Linux with + kernel versions newer than 1.3.77. +*/ + +#ifndef HAVE_MREMAP +#ifdef INTERNAL_LINUX_C_LIB +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif +#endif + +#if HAVE_MMAP + +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + +#endif /* HAVE_MMAP */ + +/* + Access to system page size. To the extent possible, this malloc + manages memory from the system in page-size units. + + The following mechanics for getpagesize were adapted from + bsd/gnu getpagesize.h +*/ + +#ifndef LACKS_UNISTD_H +# include <unistd.h> +#endif + +#if 0 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# include <sys/param.h> +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else +# define malloc_getpagesize (4096) /* just guess */ +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + +#define malloc_getpagesize (0x1000) + +/* + + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing the same kind of + information you can get from malloc_stats. It should work on + any SVID/XPG compliant system that has a /usr/include/malloc.h + defining struct mallinfo. (If you'd like to install such a thing + yourself, cut out the preliminary declarations as described above + and below and save them in a malloc.h file. But there's no + compelling reason to bother to do this.) + + The main declaration needed is the mallinfo struct that is returned + (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + bunch of fields, most of which are not even meaningful in this + version of malloc. Some of these fields are are instead filled by + mallinfo() with other numbers that might possibly be of interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else an SVID2/XPG2 compliant + version is declared below. These must be precisely the same for + mallinfo() to work. + +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#if HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { + int arena; /* total space allocated from system */ + int ordblks; /* number of non-inuse chunks */ + int smblks; /* unused -- always zero */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* total space in mmapped regions */ + int usmblks; /* unused -- always zero */ + int fsmblks; /* unused -- always zero */ + int uordblks; /* total allocated space */ + int fordblks; /* total non-inuse space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* SVID2/XPG mallopt options */ + +#define M_MXFAST 1 /* UNUSED in this malloc */ +#define M_NLBLKS 2 /* UNUSED in this malloc */ +#define M_GRAIN 3 /* UNUSED in this malloc */ +#define M_KEEP 4 /* UNUSED in this malloc */ + +#endif + +/* mallopt options that actually do something */ + +#define M_TRIM_THRESHOLD -1 +#define M_TOP_PAD -2 +#define M_MMAP_THRESHOLD -3 +#define M_MMAP_MAX -4 + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + +/* + M_TRIM_THRESHOLD is the maximum amount of unused top-most memory + to keep before releasing via malloc_trim in free(). + + Automatic trimming is mainly useful in long-lived programs. + Because trimming via sbrk can be slow on some systems, and can + sometimes be wasteful (in cases where programs immediately + afterward allocate more large chunks) the value should be high + enough so that your overall system performance would improve by + releasing. + + The trim threshold and the mmap control parameters (see below) + can be traded off with one another. Trimming and mmapping are + two different ways of releasing unused memory back to the + system. Between these two, it is often possible to keep + system-level demands of a long-lived program down to a bare + minimum. For example, in one test suite of sessions measuring + the XF86 X server on Linux, using a trim threshold of 128K and a + mmap threshold of 192K led to near-minimal long term resource + consumption. + + If you are using this malloc in a long-lived program, it should + pay to experiment with these values. As a rough guide, you + might set to a value close to the average size of a process + (program) running on your system. Releasing this much memory + would allow such a process to run in memory. Generally, it's + worth it to tune for trimming rather tham memory mapping when a + program undergoes phases where several large chunks are + allocated and released in ways that can reuse each other's + storage, perhaps mixed with phases where there are no such + chunks at all. And in well-behaved long-lived programs, + controlling release of large blocks via trimming versus mapping + is usually faster. + + However, in most programs, these parameters serve mainly as + protection against the system-level effects of carrying around + massive amounts of unneeded memory. Since frequent calls to + sbrk, mmap, and munmap otherwise degrade performance, the default + parameters are set to relatively high values that serve only as + safeguards. + + The default trim value is high enough to cause trimming only in + fairly extreme (by current memory consumption standards) cases. + It must be greater than page size to have any useful effect. To + disable trimming completely, you can set to (unsigned long)(-1); +*/ + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD (0) +#endif + +/* + M_TOP_PAD is the amount of extra `padding' space to allocate or + retain whenever sbrk is called. It is used in two ways internally: + + * When sbrk is called to extend the top of the arena to satisfy + a new malloc request, this much padding is added to the sbrk + request. + + * When malloc_trim is called automatically from free(), + it is used as the `pad' argument. + + In both cases, the actual amount of padding is rounded + so that the end of the arena is always a system page boundary. + + The main reason for using padding is to avoid calling sbrk so + often. Having even a small pad greatly reduces the likelihood + that nearly every malloc request during program start-up (or + after trimming) will invoke sbrk, which needlessly wastes + time. + + Automatic rounding-up to page-size units is normally sufficient + to avoid measurable overhead, so the default is 0. However, in + systems where sbrk is relatively slow, it can pay to increase + this value, at the expense of carrying around more memory than + the program needs. + +*/ + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + M_MMAP_THRESHOLD is the request size threshold for using mmap() + to service a request. Requests of at least this size that cannot + be allocated using already-existing space will be serviced via mmap. + (If enough normal freed space already exists it is used instead.) + + Using mmap segregates relatively large chunks of memory so that + they can be individually obtained and released from the host + system. A request serviced through mmap is never reused by any + other request (at least not directly; the system may just so + happen to remap successive requests to the same locations). + + Segregating space in this way has the benefit that mmapped space + can ALWAYS be individually released back to the system, which + helps keep the system level memory demands of a long-lived + program low. Mapped memory can never become `locked' between + other chunks, as can happen with normally allocated chunks, which + menas that even trimming via malloc_trim would not release them. + + However, it has the disadvantages that: + + 1. The space cannot be reclaimed, consolidated, and then + used to service later requests, as happens with normal chunks. + 2. It can lead to more wastage because of mmap page alignment + requirements + 3. It causes malloc performance to be more dependent on host + system memory management support routines which may vary in + implementation quality and may impose arbitrary + limitations. Generally, servicing a request via normal + malloc steps is faster than going through a system's mmap. + + All together, these considerations should lead you to use mmap + only for relatively large requests. +*/ + +#ifndef DEFAULT_MMAP_MAX +#if HAVE_MMAP +#define DEFAULT_MMAP_MAX (64) +#else +#define DEFAULT_MMAP_MAX (0) +#endif +#endif + +/* + M_MMAP_MAX is the maximum number of requests to simultaneously + service using mmap. This parameter exists because: + + 1. Some systems have a limited number of internal tables for + use by mmap. + 2. In most systems, overreliance on mmap can degrade overall + performance. + 3. If a program allocates many large regions, it is probably + better off using normal sbrk-based allocation routines that + can reclaim and reallocate normal heap memory. Using a + small value allows transition into this mode after the + first few allocations. + + Setting to 0 disables all use of mmap. If HAVE_MMAP is not set, + the default value is 0, and attempts to set it to non-zero values + in mallopt will fail. +*/ + +/* + + Special defines for linux libc + + Except when compiled using these special defines for Linux libc + using weak aliases, this malloc is NOT designed to work in + multithreaded applications. No semaphores or other concurrency + control are provided to ensure that multiple malloc or free calls + don't run at the same time, which could be disasterous. A single + semaphore could be used across malloc, realloc, and free (which is + essentially the effect of the linux weak alias approach). It would + be hard to obtain finer granularity. +*/ + +#ifdef INTERNAL_LINUX_C_LIB + +#if __STD_C + +Void_t * __default_morecore_init (ptrdiff_t); +Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; + +#else + +Void_t * __default_morecore_init (); +Void_t *(*__morecore)() = __default_morecore_init; + +#endif + +#define MORECORE (*__morecore) +#define MORECORE_FAILURE 0 +#define MORECORE_CLEARS 1 + +#else /* INTERNAL_LINUX_C_LIB */ + +#if __STD_C +extern Void_t* sbrk(int ptrdiff_t); +#else +extern Void_t* sbrk(); +#endif + +#ifndef MORECORE +#define MORECORE sbrk +#endif + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE -1 +#endif + +#ifndef MORECORE_CLEARS +#define MORECORE_CLEARS 1 +#endif + +#endif /* INTERNAL_LINUX_C_LIB */ + +#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) + +#define cALLOc __libc_calloc +#define fREe __libc_free +#define mALLOc __libc_malloc +#define mEMALIGn __libc_memalign +#define rEALLOc __libc_realloc +#define vALLOc __libc_valloc +#define pvALLOc __libc_pvalloc +#define mALLINFo __libc_mallinfo +#define mALLOPt __libc_mallopt + +#pragma weak calloc = __libc_calloc +#pragma weak free = __libc_free +#pragma weak cfree = __libc_free +#pragma weak malloc = __libc_malloc +#pragma weak memalign = __libc_memalign +#pragma weak realloc = __libc_realloc +#pragma weak valloc = __libc_valloc +#pragma weak pvalloc = __libc_pvalloc +#pragma weak mallinfo = __libc_mallinfo +#pragma weak mallopt = __libc_mallopt + +#else + + +#define cALLOc __calloc +#define fREe __free +#define mALLOc __malloc +#define mEMALIGn __memalign +#define rEALLOc __realloc +#define vALLOc __valloc +#define pvALLOc __pvalloc +#define mALLINFo __mallinfo +#define mALLOPt __mallopt + +#endif + +/* Public routines */ + +#if __STD_C + +Void_t* mALLOc(size_t); +void fREe(Void_t*); +Void_t* rEALLOc(Void_t*, size_t); +Void_t* mEMALIGn(size_t, size_t); +Void_t* vALLOc(size_t); +Void_t* pvALLOc(size_t); +Void_t* cALLOc(size_t, size_t); +void cfree(Void_t*); +int malloc_trim(size_t); +size_t malloc_usable_size(Void_t*); +void malloc_stats(); +int mALLOPt(int, int); +struct mallinfo mALLINFo(void); +#else +Void_t* mALLOc(); +void fREe(); +Void_t* rEALLOc(); +Void_t* mEMALIGn(); +Void_t* vALLOc(); +Void_t* pvALLOc(); +Void_t* cALLOc(); +void cfree(); +int malloc_trim(); +size_t malloc_usable_size(); +void malloc_stats(); +int mALLOPt(); +struct mallinfo mALLINFo(); +#endif + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +/* ---------- To make a malloc.h, end cutting here ------------ */ + +/* + Type declarations +*/ + +struct malloc_chunk +{ + INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk* mchunkptr; + +/* + malloc_chunk details: + + (The following includes lightly edited explanations by Colin Plumb.) + + Chunks of memory are maintained using a `boundary tag' method as + described in e.g., Knuth or Standish. (See the paper by Paul + Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a + survey of such techniques.) Sizes of free chunks are stored both + in the front of each chunk and at the end. This makes + consolidating fragmented chunks into bigger chunks very fast. The + size fields also hold bits representing whether chunks are free or + in use. + + An allocated chunk looks like this: + + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk, if allocated | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | User data starts here... . + . . + . (malloc_usable_space() bytes) . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Where "chunk" is the front of the chunk for the purpose of most of + the malloc code, but "mem" is the pointer that is returned to the + user. "Nextchunk" is the beginning of the next contiguous chunk. + + Chunks always begin on even word boundries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus double-word aligned. + + Free chunks are stored in circular doubly-linked lists, and look like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The P (PREV_INUSE) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + (The very first chunk allocated always has this bit set, + preventing access to non-existent (or non-owned) memory.) + + Note that the `foot' of the current chunk is actually represented + as the prev_size of the NEXT chunk. (This makes it easier to + deal with alignments etc). + + The two exceptions to all this are + + 1. The special chunk `top', which doesn't bother using the + trailing size field since there is no + next contiguous chunk that would have to index off it. (After + initialization, `top' is forced to always exist. If it would + become less than MINSIZE bytes long, it is replenished via + malloc_extend_top.) + + 2. Chunks allocated via mmap, which have the second-lowest-order + bit (IS_MMAPPED) set in their size fields. Because they are + never merged or traversed from any other chunk, they have no + foot size or inuse information. + + Available chunks are kept in any of several places (all declared below): + + * `av': An array of chunks serving as bin headers for consolidated + chunks. Each bin is doubly linked. The bins are approximately + proportionally (log) spaced. There are a lot of these bins + (128). This may look excessive, but works very well in + practice. All procedures maintain the invariant that no + consolidated chunk physically borders another one. Chunks in + bins are kept in size order, with ties going to the + approximately least recently used chunk. + + The chunks in each bin are maintained in decreasing sorted order by + size. This is irrelevant for the small bins, which all contain + the same-sized chunks, but facilitates best-fit allocation for + larger chunks. (These lists are just sequential. Keeping them in + order almost never requires enough traversal to warrant using + fancier ordered data structures.) Chunks of the same size are + linked with the most recently freed at the front, and allocations + are taken from the back. This results in LRU or FIFO allocation + order, which tends to give each chunk an equal opportunity to be + consolidated with adjacent freed chunks, resulting in larger free + chunks and less fragmentation. + + * `top': The top-most available chunk (i.e., the one bordering the + end of available memory) is treated specially. It is never + included in any bin, is used only if no other chunk is + available, and is released back to the system if it is very + large (see M_TRIM_THRESHOLD). + + * `last_remainder': A bin holding only the remainder of the + most recently split (non-top) chunk. This bin is checked + before other non-fitting chunks, so as to provide better + locality for runs of sequentially allocated chunks. + + * Implicitly, through the host system's memory mapping tables. + If supported, requests greater than a threshold are usually + serviced via calls to mmap, and then later released via munmap. + +*/ + +/* sizes, alignments */ + +#define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) +#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ) +#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) +#define MINSIZE (sizeof(struct malloc_chunk)) + +/* conversion from malloc headers to user pointers, and back */ + +#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) + +/* pad request bytes into a usable size */ + +#define request2size(req) \ + (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \ + (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \ + (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK))) + +/* Check if m has acceptable alignment */ + +#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) + +/* + Physical chunk operations +*/ + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ + +#define PREV_INUSE 0x1 + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ + +#define IS_MMAPPED 0x2 + +/* Bits to mask off when extracting size */ + +#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) + +/* Ptr to next physical malloc_chunk. */ + +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) + +/* Ptr to previous physical malloc_chunk */ + +#define prev_chunk(p)\ + ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) + +/* Treat space at ptr + offset as a chunk */ + +#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) + +/* + Dealing with use bits +*/ + +/* extract p's inuse bit */ + +#define inuse(p)\ +((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) + +/* extract inuse bit of previous chunk */ + +#define prev_inuse(p) ((p)->size & PREV_INUSE) + +/* check for mmap()'ed chunk */ + +#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) + +/* set/clear chunk as in use without otherwise disturbing */ + +#define set_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE + +#define clear_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) + +/* check/set/clear inuse bits in known places */ + +#define inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) + +/* + Dealing with size fields +*/ + +/* Get size, ignoring use bits */ + +#define chunksize(p) ((p)->size & ~(SIZE_BITS)) + +/* Set size at head, without disturbing its use bit */ + +#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) + +/* Set size/use ignoring previous bits in header */ + +#define set_head(p, s) ((p)->size = (s)) + +/* Set size at footer (only when chunk is not in use) */ + +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) + +/* + Bins + + The bins, `av_' are an array of pairs of pointers serving as the + heads of (initially empty) doubly-linked lists of chunks, laid out + in a way so that each pair can be treated as if it were in a + malloc_chunk. (This way, the fd/bk offsets for linking bin heads + and chunks are the same). + + Bins for sizes < 512 bytes contain chunks of all the same size, spaced + 8 bytes apart. Larger bins are approximately logarithmically + spaced. (See the table below.) The `av_' array is never mentioned + directly in the code, but instead via bin access macros. + + Bin layout: + + 64 bins of size 8 + 32 bins of size 64 + 16 bins of size 512 + 8 bins of size 4096 + 4 bins of size 32768 + 2 bins of size 262144 + 1 bin of size what's left + + There is actually a little bit of slop in the numbers in bin_index + for the sake of speed. This makes no difference elsewhere. + + The special chunks `top' and `last_remainder' get their own bins, + (this is implemented via yet more trickery with the av_ array), + although `top' is never properly linked to its bin since it is + always handled specially. + +*/ + +#define NAV 128 /* number of bins */ + +typedef struct malloc_chunk* mbinptr; + +/* access macros */ + +#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ)) +#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr))) +#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr))) + +/* + The first 2 bins are never indexed. The corresponding av_ cells are instead + used for bookkeeping. This is not to save space, but to simplify + indexing, maintain locality, and avoid some initialization tests. +*/ + +#define top (bin_at(0)->fd) /* The topmost chunk */ +#define last_remainder (bin_at(1)) /* remainder from last split */ + +/* + Because top initially points to its own bin with initial + zero size, thus forcing extension on the first malloc request, + we avoid having any special code in malloc to check whether + it even exists yet. But we still need to in malloc_extend_top. +*/ + +#define initial_top ((mchunkptr)(bin_at(0))) + +/* Helper macro to initialize bins */ + +#define IAV(i) bin_at(i), bin_at(i) + +static mbinptr av_[NAV * 2 + 2] = { + 0, 0, + IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), + IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), + IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23), + IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31), + IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39), + IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47), + IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55), + IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63), + IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71), + IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79), + IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87), + IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95), + IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103), + IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), + IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), + IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +}; + +/* field-extraction macros */ + +#define first(b) ((b)->fd) +#define last(b) ((b)->bk) + +/* + Indexing into bins +*/ + +#define bin_index(sz) \ +(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \ + ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \ + ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \ + ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \ + ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \ + ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \ + 126) +/* + bins for chunks < 512 are all spaced 8 bytes apart, and hold + identically sized chunks. This is exploited in malloc. +*/ + +#define MAX_SMALLBIN 63 +#define MAX_SMALLBIN_SIZE 512 +#define SMALLBIN_WIDTH 8 + +#define smallbin_index(sz) (((unsigned long)(sz)) >> 3) + +/* + Requests are `small' if both the corresponding and the next bin are small +*/ + +#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH) + +/* + To help compensate for the large number of bins, a one-level index + structure is used for bin-by-bin searching. `binblocks' is a + one-word bitvector recording whether groups of BINBLOCKWIDTH bins + have any (possibly) non-empty bins, so they can be skipped over + all at once during during traversals. The bits are NOT always + cleared as soon as all bins in a block are empty, but instead only + when all are noticed to be empty during traversal in malloc. +*/ + +#define BINBLOCKWIDTH 4 /* bins per block */ + +#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */ + +/* bin<->block macros */ + +#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH)) +#define mark_binblock(ii) (binblocks |= idx2binblock(ii)) +#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii))) + +/* Other static bookkeeping data */ + +/* variables holding tunable values */ + +static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD; +static unsigned long top_pad = DEFAULT_TOP_PAD; +static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX; +static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD; + +/* The first value returned from sbrk */ +static char* sbrk_base = (char*)(-1); + +/* The maximum memory obtained from system via sbrk */ +static unsigned long max_sbrked_mem = 0; + +/* The maximum via either sbrk or mmap */ +static unsigned long max_total_mem = 0; + +/* internal working copy of mallinfo */ +static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* The total memory obtained from system via sbrk */ +#define sbrked_mem (current_mallinfo.arena) + +/* Tracking mmaps */ + +static unsigned int n_mmaps = 0; +static unsigned long mmapped_mem = 0; + +/* + Debugging support +*/ + +#if DEBUG + +/* + These routines make a number of assertions about the states + of data structures that should be true at all times. If any + are not true, it's very likely that a user program has somehow + trashed memory. (It's also possible that there is a coding error + in malloc. In which case, please report it!) +*/ + +#if __STD_C +static void do_check_chunk(mchunkptr p) +#else +static void do_check_chunk(p) mchunkptr p; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + + /* No checkable chunk is mmapped */ + assert(!chunk_is_mmapped(p)); + + /* Check for legal address ... */ + assert((char*)p >= sbrk_base); + if (p != top) + assert((char*)p + sz <= (char*)top); + else + assert((char*)p + sz <= sbrk_base + sbrked_mem); +} + +#if __STD_C +static void do_check_free_chunk(mchunkptr p) +#else +static void do_check_free_chunk(p) mchunkptr p; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + mchunkptr next = chunk_at_offset(p, sz); + + do_check_chunk(p); + + /* Check whether it claims to be free ... */ + assert(!inuse(p)); + + /* Unless a special marker, must have OK fields */ + if ((long)sz >= (long)MINSIZE) + { + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(aligned_OK(chunk2mem(p))); + /* ... matching footer field */ + assert(next->prev_size == sz); + /* ... and is fully consolidated */ + assert(prev_inuse(p)); + assert (next == top || inuse(next)); + + /* ... and has minimally sane links */ + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_SZ */ + assert(sz == SIZE_SZ); +} + +#if __STD_C +static void do_check_inuse_chunk(mchunkptr p) +#else +static void do_check_inuse_chunk(p) mchunkptr p; +#endif +{ + mchunkptr next = next_chunk(p); + do_check_chunk(p); + + /* Check whether it claims to be in use ... */ + assert(inuse(p)); + + /* ... and is surrounded by OK chunks. + Since more things can be checked with free chunks than inuse ones, + if an inuse chunk borders them and debug is on, it's worth doing them. + */ + if (!prev_inuse(p)) + { + mchunkptr prv = prev_chunk(p); + assert(next_chunk(prv) == p); + do_check_free_chunk(prv); + } + if (next == top) + { + assert(prev_inuse(next)); + assert(chunksize(next) >= MINSIZE); + } + else if (!inuse(next)) + do_check_free_chunk(next); +} + +#if __STD_C +static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + long room = sz - s; + + do_check_inuse_chunk(p); + + /* Legal size ... */ + assert((long)sz >= (long)MINSIZE); + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(room >= 0); + assert(room < (long)MINSIZE); + + /* ... and alignment */ + assert(aligned_OK(chunk2mem(p))); + + /* ... and was allocated at front of an available chunk */ + assert(prev_inuse(p)); +} + +#define check_free_chunk(P) do_check_free_chunk(P) +#define check_inuse_chunk(P) do_check_inuse_chunk(P) +#define check_chunk(P) do_check_chunk(P) +#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) +#else +#define check_free_chunk(P) +#define check_inuse_chunk(P) +#define check_chunk(P) +#define check_malloced_chunk(P,N) +#endif + +/* + Macro-based internal utilities +*/ + +/* + Linking chunks in bin lists. + Call these only with variables, not arbitrary expressions, as arguments. +*/ + +/* + Place chunk p of size s in its bin, in size order, + putting it ahead of others of same size. +*/ + +#define frontlink(P, S, IDX, BK, FD) \ +{ \ + if (S < MAX_SMALLBIN_SIZE) \ + { \ + IDX = smallbin_index(S); \ + mark_binblock(IDX); \ + BK = bin_at(IDX); \ + FD = BK->fd; \ + P->bk = BK; \ + P->fd = FD; \ + FD->bk = BK->fd = P; \ + } \ + else \ + { \ + IDX = bin_index(S); \ + BK = bin_at(IDX); \ + FD = BK->fd; \ + if (FD == BK) mark_binblock(IDX); \ + else \ + { \ + while (FD != BK && S < chunksize(FD)) FD = FD->fd; \ + BK = FD->bk; \ + } \ + P->bk = BK; \ + P->fd = FD; \ + FD->bk = BK->fd = P; \ + } \ +} + +/* take a chunk off a list */ + +#define unlink(P, BK, FD) \ +{ \ + BK = P->bk; \ + FD = P->fd; \ + FD->bk = BK; \ + BK->fd = FD; \ +} \ + +/* Place p as the last remainder */ + +#define link_last_remainder(P) \ +{ \ + last_remainder->fd = last_remainder->bk = P; \ + P->fd = P->bk = last_remainder; \ +} + +/* Clear the last_remainder bin */ + +#define clear_last_remainder \ + (last_remainder->fd = last_remainder->bk = last_remainder) + +/* Routines dealing with mmap(). */ + +#if HAVE_MMAP + +#if __STD_C +static mchunkptr mmap_chunk(size_t size) +#else +static mchunkptr mmap_chunk(size) size_t size; +#endif +{ + size_t page_mask = malloc_getpagesize - 1; + mchunkptr p; + +#ifndef MAP_ANONYMOUS + static int fd = -1; +#endif + + if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */ + + /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because + * there is no following chunk whose prev_size field could be used. + */ + size = (size + SIZE_SZ + page_mask) & ~page_mask; + +#ifdef MAP_ANONYMOUS + p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +#else /* !MAP_ANONYMOUS */ + if (fd < 0) + { + fd = open("/dev/zero", O_RDWR); + if(fd < 0) return 0; + } + p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); +#endif + + if(p == (mchunkptr)-1) return 0; + + n_mmaps++; + if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps; + + /* We demand that eight bytes into a page must be 8-byte aligned. */ + assert(aligned_OK(chunk2mem(p))); + + /* The offset to the start of the mmapped region is stored + * in the prev_size field of the chunk; normally it is zero, + * but that can be changed in memalign(). + */ + p->prev_size = 0; + set_head(p, size|IS_MMAPPED); + + mmapped_mem += size; + if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) + max_mmapped_mem = mmapped_mem; + if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) + max_total_mem = mmapped_mem + sbrked_mem; + return p; +} + +#if __STD_C +static void munmap_chunk(mchunkptr p) +#else +static void munmap_chunk(p) mchunkptr p; +#endif +{ + INTERNAL_SIZE_T size = chunksize(p); + int ret; + + assert (chunk_is_mmapped(p)); + assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); + assert((n_mmaps > 0)); + assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0); + + n_mmaps--; + mmapped_mem -= (size + p->prev_size); + + ret = munmap((char *)p - p->prev_size, size + p->prev_size); + + /* munmap returns non-zero on failure */ + assert(ret == 0); +} + +#if HAVE_MREMAP + +#if __STD_C +static mchunkptr mremap_chunk(mchunkptr p, size_t new_size) +#else +static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size; +#endif +{ + size_t page_mask = malloc_getpagesize - 1; + INTERNAL_SIZE_T offset = p->prev_size; + INTERNAL_SIZE_T size = chunksize(p); + char *cp; + + assert (chunk_is_mmapped(p)); + assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); + assert((n_mmaps > 0)); + assert(((size + offset) & (malloc_getpagesize-1)) == 0); + + /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */ + new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask; + + cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1); + + if (cp == (char *)-1) return 0; + + p = (mchunkptr)(cp + offset); + + assert(aligned_OK(chunk2mem(p))); + + assert((p->prev_size == offset)); + set_head(p, (new_size - offset)|IS_MMAPPED); + + mmapped_mem -= size + offset; + mmapped_mem += new_size; + if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) + max_mmapped_mem = mmapped_mem; + if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) + max_total_mem = mmapped_mem + sbrked_mem; + return p; +} + +#endif /* HAVE_MREMAP */ + +#endif /* HAVE_MMAP */ + +/* + Extend the top-most chunk by obtaining memory from system. + Main interface to sbrk (but see also malloc_trim). +*/ + +#if __STD_C +static void malloc_extend_top(INTERNAL_SIZE_T nb) +#else +static void malloc_extend_top(nb) INTERNAL_SIZE_T nb; +#endif +{ + char* brk; /* return value from sbrk */ + INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */ + INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */ + char* new_brk; /* return of 2nd sbrk call */ + INTERNAL_SIZE_T top_size; /* new size of top chunk */ + + mchunkptr old_top = top; /* Record state of old top */ + INTERNAL_SIZE_T old_top_size = chunksize(old_top); + char* old_end = (char*)(chunk_at_offset(old_top, old_top_size)); + + /* Pad request with top_pad plus minimal overhead */ + + INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE; + unsigned long pagesz = malloc_getpagesize; + + /* If not the first time through, round to preserve page boundary */ + /* Otherwise, we need to correct to a page size below anyway. */ + /* (We also correct below if an intervening foreign sbrk call.) */ + + if (sbrk_base != (char*)(-1)) + sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1); + + brk = (char*)(MORECORE (sbrk_size)); + + /* Fail if sbrk failed or if a foreign sbrk call killed our space */ + if (brk == (char*)(MORECORE_FAILURE) || + (brk < old_end && old_top != initial_top)) + return; + + sbrked_mem += sbrk_size; + + if (brk == old_end) /* can just add bytes to current top */ + { + top_size = sbrk_size + old_top_size; + set_head(top, top_size | PREV_INUSE); + } + else + { + if (sbrk_base == (char*)(-1)) /* First time through. Record base */ + sbrk_base = brk; + else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */ + sbrked_mem += brk - (char*)old_end; + + /* Guarantee alignment of first new chunk made from this space */ + front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) + { + correction = (MALLOC_ALIGNMENT) - front_misalign; + brk += correction; + } + else + correction = 0; + + /* Guarantee the next brk will be at a page boundary */ + correction += pagesz - ((unsigned long)(brk + sbrk_size) & (pagesz - 1)); + + /* Allocate correction */ + new_brk = (char*)(MORECORE (correction)); + if (new_brk == (char*)(MORECORE_FAILURE)) return; + + sbrked_mem += correction; + + top = (mchunkptr)brk; + top_size = new_brk - brk + correction; + set_head(top, top_size | PREV_INUSE); + + if (old_top != initial_top) + { + /* There must have been an intervening foreign sbrk call. */ + /* A double fencepost is necessary to prevent consolidation */ + + /* If not enough space to do this, then user did something very wrong */ + if (old_top_size < MINSIZE) + { + set_head(top, PREV_INUSE); /* will force null return from malloc */ + return; + } + + /* Also keep size a multiple of MALLOC_ALIGNMENT */ + old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; + set_head_size(old_top, old_top_size); + chunk_at_offset(old_top, old_top_size )->size = + SIZE_SZ|PREV_INUSE; + chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size = + SIZE_SZ|PREV_INUSE; + /* If possible, release the rest. */ + if (old_top_size >= MINSIZE) + fREe(chunk2mem(old_top)); + } + } + + if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem) + max_sbrked_mem = sbrked_mem; + if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) + max_total_mem = mmapped_mem + sbrked_mem; + + /* We always land on a page boundary */ + assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0); +} + +/* Main public routines */ + +/* + Malloc Algorthim: + + The requested size is first converted into a usable form, `nb'. + This currently means to add 4 bytes overhead plus possibly more to + obtain 8-byte alignment and/or to obtain a size of at least + MINSIZE (currently 16 bytes), the smallest allocatable size. + (All fits are considered `exact' if they are within MINSIZE bytes.) + + From there, the first successful of the following steps is taken: + + 1. The bin corresponding to the request size is scanned, and if + a chunk of exactly the right size is found, it is taken. + + 2. The most recently remaindered chunk is used if it is big + enough. This is a form of (roving) first fit, used only in + the absence of exact fits. Runs of consecutive requests use + the remainder of the chunk used for the previous such request + whenever possible. This limited use of a first-fit style + allocation strategy tends to give contiguous chunks + coextensive lifetimes, which improves locality and can reduce + fragmentation in the long run. + + 3. Other bins are scanned in increasing size order, using a + chunk big enough to fulfill the request, and splitting off + any remainder. This search is strictly by best-fit; i.e., + the smallest (with ties going to approximately the least + recently used) chunk that fits is selected. + + 4. If large enough, the chunk bordering the end of memory + (`top') is split off. (This use of `top' is in accord with + the best-fit search rule. In effect, `top' is treated as + larger (and thus less well fitting) than any other available + chunk since it can be extended to be as large as necessary + (up to system limitations). + + 5. If the request size meets the mmap threshold and the + system supports mmap, and there are few enough currently + allocated mmapped regions, and a call to mmap succeeds, + the request is allocated via direct memory mapping. + + 6. Otherwise, the top of memory is extended by + obtaining more space from the system (normally using sbrk, + but definable to anything else via the MORECORE macro). + Memory is gathered from the system (in system page-sized + units) in a way that allows chunks obtained across different + sbrk calls to be consolidated, but does not require + contiguous memory. Thus, it should be safe to intersperse + mallocs with other sbrk calls. + + + All allocations are made from the the `lowest' part of any found + chunk. (The implementation invariant is that prev_inuse is + always true of any allocated chunk; i.e., that each allocated + chunk borders either a previously allocated and still in-use chunk, + or the base of its memory arena.) +*/ + +#if __STD_C +Void_t* mALLOc(size_t bytes) +#else +Void_t* mALLOc(bytes) size_t bytes; +#endif +{ + mchunkptr victim; /* inspected/selected chunk */ + INTERNAL_SIZE_T victim_size; /* its size */ + int idx; /* index for bin traversal */ + mbinptr bin; /* associated bin */ + mchunkptr remainder; /* remainder from a split */ + long remainder_size; /* its size */ + int remainder_index; /* its bin index */ + unsigned long block; /* block traverser bit */ + int startidx; /* first bin of a traversed block */ + mchunkptr fwd; /* misc temp for linking */ + mchunkptr bck; /* misc temp for linking */ + mbinptr q; /* misc temp */ + + INTERNAL_SIZE_T nb = request2size(bytes); /* padded request size; */ + + /* Check for exact match in a bin */ + + if (is_small_request(nb)) /* Faster version for small requests */ + { + idx = smallbin_index(nb); + + /* No traversal or size check necessary for small bins. */ + + q = bin_at(idx); + victim = last(q); + + /* Also scan the next one, since it would have a remainder < MINSIZE */ + if (victim == q) + { + q = next_bin(q); + victim = last(q); + } + if (victim != q) + { + victim_size = chunksize(victim); + unlink(victim, bck, fwd); + set_inuse_bit_at_offset(victim, victim_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */ + + } + else + { + idx = bin_index(nb); + bin = bin_at(idx); + + for (victim = last(bin); victim != bin; victim = victim->bk) + { + victim_size = chunksize(victim); + remainder_size = victim_size - nb; + + if (remainder_size >= (long)MINSIZE) /* too big */ + { + --idx; /* adjust to rescan below after checking last remainder */ + break; + } + + else if (remainder_size >= 0) /* exact fit */ + { + unlink(victim, bck, fwd); + set_inuse_bit_at_offset(victim, victim_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + ++idx; + } + + /* Try to use the last split-off remainder */ + + if ( (victim = last_remainder->fd) != last_remainder) + { + victim_size = chunksize(victim); + remainder_size = victim_size - nb; + + if (remainder_size >= (long)MINSIZE) /* re-split */ + { + remainder = chunk_at_offset(victim, nb); + set_head(victim, nb | PREV_INUSE); + link_last_remainder(remainder); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + clear_last_remainder; + + if (remainder_size >= 0) /* exhaust */ + { + set_inuse_bit_at_offset(victim, victim_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* Else place in bin */ + + frontlink(victim, victim_size, remainder_index, bck, fwd); + } + + /* + If there are any possibly nonempty big-enough blocks, + search for best fitting chunk by scanning bins in blockwidth units. + */ + + if ( (block = idx2binblock(idx)) <= binblocks) + { + + /* Get to the first marked block */ + + if ( (block & binblocks) == 0) + { + /* force to an even block boundary */ + idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH; + block <<= 1; + while ((block & binblocks) == 0) + { + idx += BINBLOCKWIDTH; + block <<= 1; + } + } + + /* For each possibly nonempty block ... */ + for (;;) + { + startidx = idx; /* (track incomplete blocks) */ + q = bin = bin_at(idx); + + /* For each bin in this block ... */ + do + { + /* Find and use first big enough chunk ... */ + + for (victim = last(bin); victim != bin; victim = victim->bk) + { + victim_size = chunksize(victim); + remainder_size = victim_size - nb; + + if (remainder_size >= (long)MINSIZE) /* split */ + { + remainder = chunk_at_offset(victim, nb); + set_head(victim, nb | PREV_INUSE); + unlink(victim, bck, fwd); + link_last_remainder(remainder); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + else if (remainder_size >= 0) /* take */ + { + set_inuse_bit_at_offset(victim, victim_size); + unlink(victim, bck, fwd); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + } + + bin = next_bin(bin); + + } while ((++idx & (BINBLOCKWIDTH - 1)) != 0); + + /* Clear out the block bit. */ + + do /* Possibly backtrack to try to clear a partial block */ + { + if ((startidx & (BINBLOCKWIDTH - 1)) == 0) + { + binblocks &= ~block; + break; + } + --startidx; + q = prev_bin(q); + } while (first(q) == q); + + /* Get to the next possibly nonempty block */ + + if ( (block <<= 1) <= binblocks && (block != 0) ) + { + while ((block & binblocks) == 0) + { + idx += BINBLOCKWIDTH; + block <<= 1; + } + } + else + break; + } + } + + + /* Try to use top chunk */ + + /* Require that there be a remainder, ensuring top always exists */ + if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) + { + +#if HAVE_MMAP + /* If big and would otherwise need to extend, try to use mmap instead */ + if ((unsigned long)nb >= (unsigned long)mmap_threshold && + (victim = mmap_chunk(nb)) != 0) + return chunk2mem(victim); +#endif + + /* Try to extend */ + malloc_extend_top(nb); + if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) + { + return 0; /* propagate failure */ + } + } + + victim = top; + set_head(victim, nb | PREV_INUSE); + top = chunk_at_offset(victim, nb); + set_head(top, remainder_size | PREV_INUSE); + check_malloced_chunk(victim, nb); + + return chunk2mem(victim); +} + +/* + + free() algorithm : + + cases: + + 1. free(0) has no effect. + + 2. If the chunk was allocated via mmap, it is release via munmap(). + + 3. If a returned chunk borders the current high end of memory, + it is consolidated into the top, and if the total unused + topmost memory exceeds the trim threshold, malloc_trim is + called. + + 4. Other chunks are consolidated as they arrive, and + placed in corresponding bins. (This includes the case of + consolidating with the current `last_remainder'). + +*/ + + +#if __STD_C +void fREe(Void_t* mem) +#else +void fREe(mem) Void_t* mem; +#endif +{ + mchunkptr p; /* chunk corresponding to mem */ + INTERNAL_SIZE_T hd; /* its head field */ + INTERNAL_SIZE_T sz; /* its size */ + int idx; /* its bin index */ + mchunkptr next; /* next contiguous chunk */ + INTERNAL_SIZE_T nextsz; /* its size */ + INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */ + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + int islr; /* track whether merging with last_remainder */ + + if (mem == 0) /* free(0) has no effect */ + return; + + p = mem2chunk(mem); + hd = p->size; + +#if HAVE_MMAP + if (hd & IS_MMAPPED) /* release mmapped memory. */ + { + munmap_chunk(p); + return; + } +#endif + + check_inuse_chunk(p); + + sz = hd & ~PREV_INUSE; + next = chunk_at_offset(p, sz); + nextsz = chunksize(next); + + if (next == top) /* merge with top */ + { + sz += nextsz; + + if (!(hd & PREV_INUSE)) /* consolidate backward */ + { + prevsz = p->prev_size; + p = chunk_at_offset(p, -prevsz); + sz += prevsz; + unlink(p, bck, fwd); + } + + set_head(p, sz | PREV_INUSE); + top = p; + if ((unsigned long)(sz) >= (unsigned long)trim_threshold) + malloc_trim(top_pad); + return; + } + + set_head(next, nextsz); /* clear inuse bit */ + + islr = 0; + + if (!(hd & PREV_INUSE)) /* consolidate backward */ + { + prevsz = p->prev_size; + p = chunk_at_offset(p, -prevsz); + sz += prevsz; + + if (p->fd == last_remainder) /* keep as last_remainder */ + islr = 1; + else + unlink(p, bck, fwd); + } + + if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */ + { + sz += nextsz; + + if (!islr && next->fd == last_remainder) /* re-insert last_remainder */ + { + islr = 1; + link_last_remainder(p); + } + else + unlink(next, bck, fwd); + } + + + set_head(p, sz | PREV_INUSE); + set_foot(p, sz); + if (!islr) + frontlink(p, sz, idx, bck, fwd); +} + +/* + + Realloc algorithm: + + Chunks that were obtained via mmap cannot be extended or shrunk + unless HAVE_MREMAP is defined, in which case mremap is used. + Otherwise, if their reallocation is for additional space, they are + copied. If for less, they are just left alone. + + Otherwise, if the reallocation is for additional space, and the + chunk can be extended, it is, else a malloc-copy-free sequence is + taken. There are several different ways that a chunk could be + extended. All are tried: + + * Extending forward into following adjacent free chunk. + * Shifting backwards, joining preceding adjacent space + * Both shifting backwards and extending forward. + * Extending into newly sbrked space + + Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + + If the reallocation is for less space, and the new request is for + a `small' (<512 bytes) size, then the newly unused space is lopped + off and freed. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is no longer supported. + I don't know of any programs still relying on this feature, + and allowing it would also allow too many other incorrect + usages of realloc to be sensible. + + +*/ + + +#if __STD_C +Void_t* rEALLOc(Void_t* oldmem, size_t bytes) +#else +Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + + mchunkptr oldp; /* chunk corresponding to oldmem */ + INTERNAL_SIZE_T oldsize; /* its size */ + + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + Void_t* newmem; /* corresponding user mem */ + + mchunkptr next; /* next contiguous chunk after oldp */ + INTERNAL_SIZE_T nextsize; /* its size */ + + mchunkptr prev; /* previous contiguous chunk before oldp */ + INTERNAL_SIZE_T prevsize; /* its size */ + + mchunkptr remainder; /* holds split off extra space from newp */ + INTERNAL_SIZE_T remainder_size; /* its size */ + + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { fREe(oldmem); return 0; } +#endif + + + /* realloc of null is supposed to be same as malloc */ + if (oldmem == 0) return mALLOc(bytes); + + newp = oldp = mem2chunk(oldmem); + newsize = oldsize = chunksize(oldp); + + + nb = request2size(bytes); + +#if HAVE_MMAP + if (chunk_is_mmapped(oldp)) + { +#if HAVE_MREMAP + newp = mremap_chunk(oldp, nb); + if(newp) return chunk2mem(newp); +#endif + /* Note the extra SIZE_SZ overhead. */ + if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */ + /* Must alloc, copy, free. */ + newmem = mALLOc(bytes); + if (newmem == 0) return 0; /* propagate failure */ + MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); + munmap_chunk(oldp); + return newmem; + } +#endif + + check_inuse_chunk(oldp); + + if ((long)(oldsize) < (long)(nb)) + { + + /* Try expanding forward */ + + next = chunk_at_offset(oldp, oldsize); + if (next == top || !inuse(next)) + { + nextsize = chunksize(next); + + /* Forward into top only if a remainder */ + if (next == top) + { + if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE)) + { + newsize += nextsize; + top = chunk_at_offset(oldp, nb); + set_head(top, (newsize - nb) | PREV_INUSE); + set_head_size(oldp, nb); + return chunk2mem(oldp); + } + } + + /* Forward into next chunk */ + else if (((long)(nextsize + newsize) >= (long)(nb))) + { + unlink(next, bck, fwd); + newsize += nextsize; + goto split; + } + } + else + { + next = 0; + nextsize = 0; + } + + /* Try shifting backwards. */ + + if (!prev_inuse(oldp)) + { + prev = prev_chunk(oldp); + prevsize = chunksize(prev); + + /* try forward + backward first to save a later consolidation */ + + if (next != 0) + { + /* into top */ + if (next == top) + { + if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE)) + { + unlink(prev, bck, fwd); + newp = prev; + newsize += prevsize + nextsize; + newmem = chunk2mem(newp); + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + top = chunk_at_offset(newp, nb); + set_head(top, (newsize - nb) | PREV_INUSE); + set_head_size(newp, nb); + return newmem; + } + } + + /* into next chunk */ + else if (((long)(nextsize + prevsize + newsize) >= (long)(nb))) + { + unlink(next, bck, fwd); + unlink(prev, bck, fwd); + newp = prev; + newsize += nextsize + prevsize; + newmem = chunk2mem(newp); + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + goto split; + } + } + + /* backward only */ + if (prev != 0 && (long)(prevsize + newsize) >= (long)nb) + { + unlink(prev, bck, fwd); + newp = prev; + newsize += prevsize; + newmem = chunk2mem(newp); + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + goto split; + } + } + + /* Must allocate */ + + newmem = mALLOc (bytes); + + if (newmem == 0) /* propagate failure */ + return 0; + + /* Avoid copy if newp is next chunk after oldp. */ + /* (This can only happen when new chunk is sbrk'ed.) */ + + if ( (newp = mem2chunk(newmem)) == next_chunk(oldp)) + { + newsize += chunksize(newp); + newp = oldp; + goto split; + } + + /* Otherwise copy, free, and exit */ + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + fREe(oldmem); + return newmem; + } + + + split: /* split off extra room in old or expanded chunk */ + + if (newsize - nb >= MINSIZE) /* split off remainder */ + { + remainder = chunk_at_offset(newp, nb); + remainder_size = newsize - nb; + set_head_size(newp, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_inuse_bit_at_offset(remainder, remainder_size); + fREe(chunk2mem(remainder)); /* let free() deal with it */ + } + else + { + set_head_size(newp, newsize); + set_inuse_bit_at_offset(newp, newsize); + } + + check_inuse_chunk(newp); + return chunk2mem(newp); +} + +/* + memalign algorithm: + + memalign requests more than enough space from malloc, finds a spot + within that chunk that meets the alignment request, and then + possibly frees the leading and trailing space. + + The alignment argument must be a power of two. This property is not + checked by memalign, so misuse may result in random runtime errors. + + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ + + +#if __STD_C +Void_t* mEMALIGn(size_t alignment, size_t bytes) +#else +Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + char* m; /* memory returned by malloc call */ + mchunkptr p; /* corresponding chunk */ + char* brk; /* alignment point within p */ + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */ + mchunkptr remainder; /* spare room at end to split off */ + long remainder_size; /* its size */ + + /* If need less alignment than we give anyway, just relay to malloc */ + + if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); + + /* Otherwise, ensure that it is at least a minimum chunk size */ + + if (alignment < MINSIZE) alignment = MINSIZE; + + /* Call malloc with worst case padding to hit alignment. */ + + nb = request2size(bytes); + m = (char*)(mALLOc(nb + alignment + MINSIZE)); + + if (m == 0) return 0; /* propagate failure */ + + p = mem2chunk(m); + + if ((((unsigned long)(m)) % alignment) == 0) /* aligned */ + { +#if HAVE_MMAP + if(chunk_is_mmapped(p)) + return chunk2mem(p); /* nothing more to do */ +#endif + } + else /* misaligned */ + { + /* + Find an aligned spot inside chunk. + Since we need to give back leading space in a chunk of at + least MINSIZE, if the first calculation places us at + a spot with less than MINSIZE leader, we can move to the + next aligned spot -- we've allocated enough total room so that + this is always possible. + */ + + brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -alignment); + if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment; + + newp = (mchunkptr)brk; + leadsize = brk - (char*)(p); + newsize = chunksize(p) - leadsize; + +#if HAVE_MMAP + if(chunk_is_mmapped(p)) + { + newp->prev_size = p->prev_size + leadsize; + set_head(newp, newsize|IS_MMAPPED); + return chunk2mem(newp); + } +#endif + + /* give back leader, use the rest */ + + set_head(newp, newsize | PREV_INUSE); + set_inuse_bit_at_offset(newp, newsize); + set_head_size(p, leadsize); + fREe(chunk2mem(p)); + p = newp; + + assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0); + } + + /* Also give back spare room at the end */ + + remainder_size = chunksize(p) - nb; + + if (remainder_size >= (long)MINSIZE) + { + remainder = chunk_at_offset(p, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_head_size(p, nb); + fREe(chunk2mem(remainder)); + } + + check_inuse_chunk(p); + return chunk2mem(p); + +} + +/* + valloc just invokes memalign with alignment argument equal + to the page size of the system (or as near to this as can + be figured out from all the includes/defines above.) +*/ + +#if __STD_C +Void_t* vALLOc(size_t bytes) +#else +Void_t* vALLOc(bytes) size_t bytes; +#endif +{ + return mEMALIGn (malloc_getpagesize, bytes); +} + +/* + pvalloc just invokes valloc for the nearest pagesize + that will accommodate request +*/ + +#if __STD_C +Void_t* pvALLOc(size_t bytes) +#else +Void_t* pvALLOc(bytes) size_t bytes; +#endif +{ + size_t pagesize = malloc_getpagesize; + return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1)); +} + +/* + calloc calls malloc, then zeroes out the allocated chunk. +*/ + +#if __STD_C +Void_t* cALLOc(size_t n, size_t elem_size) +#else +Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; +#endif +{ + mchunkptr p; + INTERNAL_SIZE_T csz; + + INTERNAL_SIZE_T sz = n * elem_size; + + /* check if expand_top called, in which case don't need to clear */ +#if MORECORE_CLEARS + mchunkptr oldtop = top; + INTERNAL_SIZE_T oldtopsize = chunksize(top); +#endif + Void_t* mem = mALLOc (sz); + + if (mem == 0) + return 0; + else + { + p = mem2chunk(mem); + + /* Two optional cases in which clearing not necessary */ + +#if HAVE_MMAP + if (chunk_is_mmapped(p)) return mem; +#endif + + csz = chunksize(p); + +#if MORECORE_CLEARS + if (p == oldtop && csz > oldtopsize) + { + /* clear only the bytes from non-freshly-sbrked memory */ + csz = oldtopsize; + } +#endif + + MALLOC_ZERO(mem, csz - SIZE_SZ); + return mem; + } +} + +/* + cfree just calls free. It is needed/defined on some systems + that pair it with calloc, presumably for odd historical reasons. +*/ + +#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__) +#if __STD_C +void cfree(Void_t *mem) +#else +void cfree(mem) Void_t *mem; +#endif +{ + fREe(mem); +} +#endif + +/* + Malloc_trim gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. You can call this after freeing large blocks of + memory to potentially reduce the system-level memory requirements + of a program. However, it cannot guarantee to reduce memory. Under + some allocation patterns, some large free blocks of memory will be + locked between two used chunks, so they cannot be given back to + the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, + only the minimum amount of memory to maintain internal data + structures will be left (one page or less). Non-zero arguments + can be supplied to maintain enough trailing space to service + future expected allocations without having to re-obtain memory + from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ + +#if __STD_C +int malloc_trim(size_t pad) +#else +int malloc_trim(pad) size_t pad; +#endif +{ + long top_size; /* Amount of top-most memory */ + long extra; /* Amount to release */ + char* current_brk; /* address returned by pre-check sbrk call */ + char* new_brk; /* address returned by negative sbrk call */ + + unsigned long pagesz = malloc_getpagesize; + + top_size = chunksize(top); + extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; + + if (extra < (long)pagesz) /* Not enough memory to release */ + return 0; + + else + { + /* Test to make sure no one else called sbrk */ + current_brk = (char*)(MORECORE (0)); + if (current_brk != (char*)(top) + top_size) + return 0; /* Apparently we don't own memory; must fail */ + + else + { + new_brk = (char*)(MORECORE (-extra)); + + if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */ + { + /* Try to figure out what we have */ + current_brk = (char*)(MORECORE (0)); + top_size = current_brk - (char*)top; + if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */ + { + sbrked_mem = current_brk - sbrk_base; + set_head(top, top_size | PREV_INUSE); + } + check_chunk(top); + return 0; + } + + else + { + /* Success. Adjust top accordingly. */ + set_head(top, (top_size - extra) | PREV_INUSE); + sbrked_mem -= extra; + check_chunk(top); + return 1; + } + } + } +} + +/* + malloc_usable_size: + + This routine tells you how many bytes you can actually use in an + allocated chunk, which may be more than you requested (although + often not). You can use this many bytes without worrying about + overwriting other allocated objects. Not a particularly great + programming practice, but still sometimes useful. +*/ + +#if __STD_C +size_t malloc_usable_size(Void_t* mem) +#else +size_t malloc_usable_size(mem) Void_t* mem; +#endif +{ + mchunkptr p; + if (mem == 0) + return 0; + else + { + p = mem2chunk(mem); + if(!chunk_is_mmapped(p)) + { + if (!inuse(p)) return 0; + check_inuse_chunk(p); + return chunksize(p) - SIZE_SZ; + } + return chunksize(p) - 2*SIZE_SZ; + } +} + +/* Utility to update current_mallinfo for malloc_stats and mallinfo() */ + +static void malloc_update_mallinfo() +{ + int i; + mbinptr b; + mchunkptr p; +#if DEBUG + mchunkptr q; +#endif + + INTERNAL_SIZE_T avail = chunksize(top); + int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0; + + for (i = 1; i < NAV; ++i) + { + b = bin_at(i); + for (p = last(b); p != b; p = p->bk) + { +#if DEBUG + check_free_chunk(p); + for (q = next_chunk(p); + q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; + q = next_chunk(q)) + check_inuse_chunk(q); +#endif + avail += chunksize(p); + navail++; + } + } + + current_mallinfo.ordblks = navail; + current_mallinfo.uordblks = sbrked_mem - avail; + current_mallinfo.fordblks = avail; + current_mallinfo.hblks = n_mmaps; + current_mallinfo.hblkhd = mmapped_mem; + current_mallinfo.keepcost = chunksize(top); + +} + +/* + + malloc_stats: + + Prints on stderr the amount of space obtain from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), the maximum + number of simultaneous mmap regions used, and the current number + of bytes allocated via malloc (or realloc, etc) but not yet + freed. (Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead.) + +*/ + +void malloc_stats() +{ + malloc_update_mallinfo(); +/* + This commented out since we don't have a printf(1) in userspace yet + + printf("max system bytes = %10u\n", + (unsigned int)(max_total_mem)); + printf("system bytes = %10u\n", + (unsigned int)(sbrked_mem + mmapped_mem)); + printf("in use bytes = %10u\n", + (unsigned int)(current_mallinfo.uordblks + mmapped_mem)); +#if HAVE_MMAP + printf("max mmap regions = %10u\n", + (unsigned int)max_n_mmaps); +#endif +*/ +} + +/* + mallinfo returns a copy of updated current mallinfo. +*/ + +struct mallinfo mALLINFo() +{ + malloc_update_mallinfo(); + return current_mallinfo; +} + +/* + mallopt: + + mallopt is the general SVID/XPG interface to tunable parameters. + The format is to provide a (parameter-number, parameter-value) pair. + mallopt then sets the corresponding parameter to the argument + value if it can (i.e., so long as the value is meaningful), + and returns 1 if successful else 0. + + See descriptions of tunable parameters above. + +*/ + +#if __STD_C +int mALLOPt(int param_number, int value) +#else +int mALLOPt(param_number, value) int param_number; int value; +#endif +{ + switch(param_number) + { + case M_TRIM_THRESHOLD: + trim_threshold = value; return 1; + case M_TOP_PAD: + top_pad = value; return 1; + case M_MMAP_THRESHOLD: + mmap_threshold = value; return 1; + case M_MMAP_MAX: +#if HAVE_MMAP + n_mmaps_max = value; return 1; +#else + if (value != 0) return 0; else n_mmaps_max = value; return 1; +#endif + + default: + return 0; + } +} + +/* + +History: + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ + diff --git a/lib/libc/malloc.h b/lib/libc/malloc.h @@ -0,0 +1,46 @@ +/* $Id: //depot/blt/lib/malloc.h#2 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _MALLOC_H_ +#define _MALLOC_H_ + +void *__malloc (size_t); +void __free (void *); +void *__realloc (void *, size_t); +void *__memalign (size_t, size_t); +void *__valloc (size_t); +void *__pvalloc (size_t); +void *__calloc (size_t); +void __cfree (void *); +int malloc_trim (size_t); +size_t malloc_usable_size (void *); +void malloc_stats (void); +int __mallopt (int, int); + +#endif + diff --git a/lib/libc/memory.c b/lib/libc/memory.c @@ -0,0 +1,113 @@ +/* $Id: //depot/blt/lib/memory.c#4 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <blt/types.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> +#include "malloc.h" + +weak_alias (_sbrk, sbrk) +weak_alias (_malloc, malloc) +weak_alias (_free, free) +weak_alias (_realloc, realloc) + +static unsigned int __sbrk_max; +static unsigned int __sbrk_cur; +static int sem_malloc; + +void *_sbrk(int size) +{ + if(size < 0 ){ + __sbrk_cur -= size; + return (void *) __sbrk_cur; + } else { + unsigned int tmp = __sbrk_cur; + __sbrk_cur += size; + if(__sbrk_cur > __sbrk_max){ + __sbrk_max = __sbrk_cur; + os_brk(__sbrk_max); + } + return (void *) tmp; + } + + return (void *) __sbrk_cur; +} + +void *_malloc(size_t size) +{ + void *r; + sem_acquire(sem_malloc); + r = __malloc(size); + sem_release(sem_malloc); + return r; +} + +void _free(void *ptr) +{ + sem_acquire(sem_malloc); + __free(ptr); + sem_release(sem_malloc); +} + +void *_realloc(void *ptr, size_t size) +{ + void *r; + sem_acquire(sem_malloc); + r = __realloc(ptr,size); + sem_release(sem_malloc); + return r; +} + + +void * _default_morecore(long size) +{ + void *result; + + result = sbrk(size); + if (result == (void *) -1) + return NULL; + return result; +} + +void __libc_init_memory(unsigned int top_of_binary, + unsigned int start_bss, unsigned int bss_length) +{ + int i; + unsigned char *x = (unsigned char *) start_bss; + unsigned int tob = (top_of_binary/4096+2)*4096; + os_brk(tob); + + for (i = 0; i < bss_length; i++) + x[i] = 0; + + __sbrk_max = __sbrk_cur = tob; + + sem_malloc = sem_create(1,"libc_malloc_sem"); +} diff --git a/lib/libc/qsem.c b/lib/libc/qsem.c @@ -0,0 +1,78 @@ +/* $Id: //depot/blt/lib/libc/qsem.c#1 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <blt/syscall.h> +#include <blt/qsem.h> + +qsem_t *qsem_create (int count) +{ + qsem_t *s; + + s = (qsem_t *) malloc (sizeof (qsem_t)); +#ifdef I386 + s->mutex = sem_create (count, "qsem_mutex"); + s->count = 0; +#else + s->mutex = sem_create (0, "qsem_mutex"); + s->count = count; +#endif + return s; +} + +void qsem_destroy (qsem_t *s) +{ + sem_destroy (s->mutex); + free (s); +} + +void qsem_acquire (qsem_t *s) +{ +#ifdef I386 + /* no atomic_add() in i386 */ + sem_acquire(s->mutex); +#else + if (atomic_add (&s->count, -1) <= 0) + sem_acquire (s->mutex); +#endif +} + +void qsem_release (qsem_t *s) +{ +#ifdef I386 + /* no atomic_add() in i386 */ + sem_release(s->mutex); +#else + if (atomic_add (&s->count, 1) < 0) + sem_release (s->mutex); +#endif +} + diff --git a/lib/libc/qsort.c b/lib/libc/qsort.c @@ -0,0 +1,174 @@ +/* $Id: //depot/blt/lib/libc/qsort.c#1 $ */ +/* $OpenBSD: qsort.c,v 1.5 1997/06/20 11:19:38 deraadt Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <stdlib.h> + +static __inline char *med3 (char *, char *, char *, int (*)()); +static __inline void swapfunc (char *, char *, int, int); + +#define min(a, b) (a) < (b) ? a : b + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static __inline void +swapfunc(a, b, n, swaptype) + char *a, *b; + int n, swaptype; +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static __inline char * +med3(a, b, c, cmp) + char *a, *b, *c; + int (*cmp)(); +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void +qsort(aa, n, es, cmp) + void *aa; + size_t n, es; + int (*cmp)(); +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + register char *a = aa; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c @@ -0,0 +1,186 @@ +/* $Id: //depot/blt/lib/snprintf.c#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Copyright 1997, Brian J. Swetland <swetland@neog.com> +** Free for non-commercial use. Share and enjoy +** +** Minimal snprintf() function. +** %s - string %d - signed int %x - 32bit hex number (0 padded) +** %c - character %u - unsigned int %X - 8bit hex number (0 padded) +*/ + +#include <stdarg.h> + +static char hexmap[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +void va_snprintf(char *b, int l, char *fmt, va_list pvar) +{ + int n,i; + unsigned u; + unsigned long long ull; + char *t,d[10], mod_l, mod_ll; + + if(!fmt || !b || (l < 1)) return; + + mod_l = mod_ll = 0; + while(l && *fmt) { + if(*fmt == '%'){ + if(!(--l)) break; + again: + fmt++; + + switch(*fmt){ + case 'l': /* long modifier */ + if (!mod_l) + mod_l = 1; + else if (!mod_ll) + { + mod_l = 0; + mod_ll = 1; + } + goto again; + + case 's': /* string */ + t = va_arg(pvar,char *); + while(l && *t) *b++ = *t++, l--; + break; + + case 'c': /* single character */ + *b++ = va_arg(pvar,char); + l--; + break; + + case 'S': /* uint32 as a short ... */ + if(l < 4) { l = 0; break; } + u = va_arg(pvar,unsigned int); + for(i=3;i>=0;i--){ + b[i] = hexmap[u & 0x0F]; + u >>= 4; + } + b+=4; + l-=4; + break; + + case 'x': + case 'p': + if (!mod_ll) { /* 8 digit, unsigned 32-bit hex integer */ + if(l < 8) { l = 0; break; } + u = va_arg(pvar,unsigned int); + for(i=7;i>=0;i--){ + b[i] = hexmap[u & 0x0F]; + u >>= 4; + } + b+=8; + l-=8; + } + else if (mod_ll) { /* 16 digit, unsigned 64-bit hex integer */ + if (l < 16) { l = 0; break; } + ull = va_arg (pvar, unsigned long long); + for (i = 15; i >= 0; i--) { + b[i] = hexmap[ull & 0x0f]; + ull >>= 4; + } + b += 16; + l -= 16; + } + mod_l = mod_ll = 0; + break; + + case 'd': /* signed integer */ + n = va_arg(pvar,int); + if(n < 0) { + u = -n; + *b++ = '-'; + if(!(--l)) break; + } else { + u = n; + } + goto u2; + + case 'u': /* unsigned integer */ + u = va_arg(pvar,unsigned int); + u2: + i = 9; + do { + d[i] = (u % 10) + '0'; + u /= 10; + i--; + } while(u && i >= 0); + while(++i < 10){ + *b++ = d[i]; + if(!(--l)) break; + } + break; + + case 'U': + u = va_arg(pvar,unsigned int); + i = 9; + d[8] = d[7] = d[6] = ' '; + do { + d[i] = (u % 10) + '0'; + u /= 10; + i--; + } while(u && i >= 0); + i = 5; + while(++i < 10){ + *b++ = d[i]; + if(!(--l)) break; + } + break; + + case 'X': /* 2 digit, unsigned 8bit hex int */ + if(l < 2) { l = 0; break; } + n = va_arg(pvar,int); + *b++ = hexmap[(n & 0xF0) >> 4]; + *b++ = hexmap[n & 0x0F]; + l-=2; + break; + default: + *b++ = *fmt; + } + } else { + *b++ = *fmt; + l--; + } + fmt++; + } + *b = 0; +} + +void snprintf(char *str, int len, char *fmt, ...) +{ + va_list pvar; + va_start(pvar,fmt); + va_snprintf(str,len,fmt,pvar); + va_end(pvar); +} + + diff --git a/lib/libc/stdlib.c b/lib/libc/stdlib.c @@ -0,0 +1,46 @@ +/* $Id: //depot/blt/lib/libc/stdlib.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <string.h> +#include <blt/libsyms.h> + +weak_alias (_atoi, atoi) + +int _atoi (const char *a) +{ + int x, i, power = 1; + + for (x = strlen (a) - 1, i = 0; x >= 0; x--, power *= 10) + if (!x && (a[x] == '-')) + i *= -1; + else + i += power * (a[x] - '0'); + return i; +} + diff --git a/lib/libc/strcmp.S b/lib/libc/strcmp.S @@ -0,0 +1,84 @@ +/* $Id: //depot/blt/lib/strcmp.S#1 $ */ + +/* $OpenBSD: strcmp.S,v 1.2 1996/09/27 06:47:49 mickey Exp $ */ + +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + */ + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +#include <i386/asm.h> + +FUNCTION (strcmp) + movl 0x04(%esp),%eax + movl 0x08(%esp),%edx + jmp L2 /* Jump into the loop! */ + + .align 2,0x90 +L1: incl %eax + incl %edx +L2: movb (%eax),%cl + testb %cl,%cl /* null terminator??? */ + jz L3 + cmpb %cl,(%edx) /* chars match??? */ + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%edx) + je L1 + .align 2, 0x90 +L3: movzbl (%eax),%eax /* unsigned comparison */ + movzbl (%edx),%edx + subl %edx,%eax + ret diff --git a/lib/libc/strcpy.S b/lib/libc/strcpy.S @@ -0,0 +1,59 @@ +/* $Id: //depot/blt/lib/strcpy.S#1 $ */ + +/* $OpenBSD: strcpy.S,v 1.2 1996/09/27 06:47:50 mickey Exp $ */ + +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + */ + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +#include <i386/asm.h> + +FUNCTION (strcpy) + movl 4(%esp),%ecx /* dst address */ + movl 8(%esp),%edx /* src address */ + pushl %ecx /* push dst address */ + + .align 2,0x90 +L1: movb (%edx),%al /* unroll loop, but not too much */ + movb %al,(%ecx) + testb %al,%al + jz L2 + movb 1(%edx),%al + movb %al,1(%ecx) + testb %al,%al + jz L2 + movb 2(%edx),%al + movb %al,2(%ecx) + testb %al,%al + jz L2 + movb 3(%edx),%al + movb %al,3(%ecx) + testb %al,%al + jz L2 + movb 4(%edx),%al + movb %al,4(%ecx) + testb %al,%al + jz L2 + movb 5(%edx),%al + movb %al,5(%ecx) + testb %al,%al + jz L2 + movb 6(%edx),%al + movb %al,6(%ecx) + testb %al,%al + jz L2 + movb 7(%edx),%al + movb %al,7(%ecx) + addl $8,%edx + addl $8,%ecx + testb %al,%al + jnz L1 +L2: popl %eax /* pop dst address */ + ret diff --git a/lib/libc/string.c b/lib/libc/string.c @@ -0,0 +1,128 @@ +/* $Id: //depot/blt/lib/libc/string.c#4 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> + +char *strncpy(char *dst, const char *src, size_t size) +{ + char *d = dst; + + while(size && *src) size--, *dst++ = *src++; + if(size) *dst = 0; + + return d; +} + +int strncmp(const char *s1, const char *s2, size_t n) +{ + while(n && *s1 && *s2){ + if(*s1 != *s2) return -1; + s1++; + s2++; + n--; + + } + if(n) return -1; + + return 0; +} + +char *strchr (const char *cs, int c) +{ + const char *s; + + s = cs; + while (*s) + { + if (*s == c) + return (char *) s; + s++; + } + return NULL; +} + +void *memset(void *s, int c, size_t n) +{ + unsigned char *u = (unsigned char *) s; + while(n) { + *u = c; + u++; + n--; + } + return s; +} + +void *memmove(void *dest, const void *src, size_t n) +{ + unsigned char *d; + unsigned char *s; + + if(dest < src){ + d = (unsigned char *)dest; + s = (unsigned char *)src; + while(n){ + *d = *s; + d++; + s++; + n--; + } + } else { + d = ((unsigned char *) dest)+n; + s = ((unsigned char *) src)+n; + while(n){ + d--; + s--; + *d = *s; + n--; + } + } + return dest; +} + +int memcmp(const void *dst, const void *src, size_t size) +{ + while(size) { + if(*((char *)dst) != *((char *)src)) return 1; + ((char *) dst)++; + ((char *) src)++; + size--; + } + return 0; +} + +void *memcpy(void *dst, const void *src, size_t size) +{ + void *r = dst; + + while(size) { + *(((unsigned char *) dst)++) = *(((unsigned char *) src)++); + size--; + } + return r; +} + diff --git a/lib/libc/strlcat.c b/lib/libc/strlcat.c @@ -0,0 +1,68 @@ +/* $Id: //depot/blt/lib/libc/strlcat.c#1 $ */ +/* $OpenBSD: strlcat.c,v 1.1 1998/07/01 01:29:45 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t strlcat(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left */ + while (*d != '\0' && n != 0) + d++; + dlen = d - dst; + n -= dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + diff --git a/lib/libc/strlcpy.c b/lib/libc/strlcpy.c @@ -0,0 +1,65 @@ +/* $Id: //depot/blt/lib/libc/strlcpy.c#1 $ */ +/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t strlcpy(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + diff --git a/lib/libc/strlen.S b/lib/libc/strlen.S @@ -0,0 +1,23 @@ +/* $Id: //depot/blt/lib/strlen.S#1 $ */ + +/* $OpenBSD: strlen.S,v 1.2 1996/09/27 06:47:51 mickey Exp $ */ + +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + */ + +#include <i386/asm.h> + +FUNCTION (strlen) + pushl %edi + movl 8(%esp),%edi /* string address */ + cld /* set search forward */ + xorl %eax,%eax /* set search for null terminator */ + movl $-1,%ecx /* set search for lots of characters */ + repne /* search! */ + scasb + notl %ecx /* get length by taking complement */ + leal -1(%ecx),%eax /* and subtracting one */ + popl %edi + ret diff --git a/lib/libc/syscalls.S b/lib/libc/syscalls.S @@ -0,0 +1,76 @@ +/* $Id: //depot/blt/lib/libc/syscalls.S#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <blt/syscall_id.h> +#include <i386/asm.h> + +#define SYSCALL(name) \ + FUNCTION(name) ; \ + movl $BLT_SYS_##name, %eax ; \ + int $0x20 ; \ + ret + +SYSCALL(os_meta) +SYSCALL(os_terminate) +SYSCALL(os_console) +SYSCALL(os_brk) +SYSCALL(os_handle_irq) +SYSCALL(os_sleep_irq) +SYSCALL(os_debug) +SYSCALL(os_sleep) + +SYSCALL(sem_create) +SYSCALL(sem_destroy) +SYSCALL(sem_acquire) +SYSCALL(sem_release) + +SYSCALL(port_create) +SYSCALL(port_destroy) +SYSCALL(port_option) +SYSCALL(port_send) +SYSCALL(port_recv) + +SYSCALL(os_identify) + +SYSCALL(right_create) +SYSCALL(right_destroy) +SYSCALL(right_revoke) +SYSCALL(right_attach) +SYSCALL(right_grant) + +SYSCALL(thr_create) +SYSCALL(thr_spawn) +SYSCALL(thr_resume) +SYSCALL(thr_suspend) +SYSCALL(thr_kill) +SYSCALL(thr_wait) + +SYSCALL(area_create) +SYSCALL(area_clone) +SYSCALL(area_destroy) +SYSCALL(area_resize) diff --git a/lib/libconsole/Makefile b/lib/libconsole/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := conio.c +LIBRARY := libconsole.a +SHLIB := libconsole.so + +include $(BLTHOME)make.actions diff --git a/lib/libconsole/conio.c b/lib/libconsole/conio.c @@ -0,0 +1,162 @@ +/* $Id: //depot/blt/lib/conio.c#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <blt/conio.h> + +static int attr = 1, px = 0, py = 24; +static char *screen = (char *) CON_SCREEN; +static char *posn = (char *) CON_SCREEN + 80*24*2; + +static void scrollup(void) +{ + for(posn = screen + 160; posn <= screen + 80*25*2; posn++) + *(posn - 160) = *posn; + for(posn = screen + 80*24*2; posn <= screen + 80*25*2; posn++){ + *posn++ = ' '; + *posn = attr; + } +} + +void con_attr(int a) +{ + attr = a; +} + +#define con_init() { con_attr(CON_WHITE); con_clear(); } + +void con_start(unsigned int video) +{ + screen = (char *) video; + con_attr(CON_WHITE); + con_clear(); +} + + +void con_clear(void) +{ + int i; + + for(posn = screen, i=0;i<80*25;i++){ + *posn++ = ' '; + *posn++ = attr; + } + px = 0; + py = 24; + posn = screen + (24*80)*2; +} + +void con_goto(int x, int y) +{ + posn = screen + ((y*80)+x)*2; + px = x; + py = y; + +} + +/* +void con_putc(char ch) +{ + if(ch == '\n'){ + goto roll0; + } + *posn++ = ch; + *posn++ = attr; + px++; + if(px == 80){ +roll0: + px = 0; + if(py == 24) + scrollup(); + else + py++; + posn = screen + (py*80+px)*2; + } +} +*/ +void con_puts(char *s) +{ + while(*s){ + if(*s == '\n'){ + s++; + goto roll1; + } + *posn++ = *s++; + *posn++ = attr; + px++; + if(px == 80){ + roll1: + px = 0; + if(py == 24) + scrollup(); + else + py++; + posn = screen + (py*80+px)*2; + } + } +} +/* +static char pbuf[9]; + +void con_putp(unsigned int p) +{ + int i; + + pbuf[8] = 0; + + for(i=7;i>=0;i--){ + pbuf[i] = (0x0F & p); + if(pbuf[i] > 9) pbuf[i] += 'A'-10; + else pbuf[i] += '0'; + p >>= 4; + } + con_puts(pbuf); +} + +void con_putx(unsigned char x) +{ + pbuf[0] = (x & 0xF0) >> 4; + if(pbuf[0] > 9) pbuf[0] += 'A'-10; + else pbuf[0] += '0'; + pbuf[1] = (x & 0x0F); + if(pbuf[1] > 9) pbuf[1] += 'A'-10; + else pbuf[1] += '0'; + pbuf[2] = 0; + con_puts(pbuf); +} +*/ + +void cprintf(char *fmt, ...) +{ + char buf[256]; + va_list pvar; + va_start(pvar,fmt); + va_snprintf(buf,256,fmt,pvar); + va_end(pver); + con_puts(buf); +} + diff --git a/lib/libdl/Makefile b/lib/libdl/Makefile @@ -0,0 +1,16 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +TARGETS := rtld +SRCS := load.c sym.c elf.c +LIBRARY := libdl.a +SHLIB := libdl.so +SHLIB_MAJOR := 1 +SHLIB_MINOR := 0 + +RTLD_OBJS = rtld.o sym.o elf.o + +rtld: $(RTLD_OBJS) + ld -dN -Ttext 0x200074 -o rtld $(RTLD_OBJS) -L../../lib/obj -lc -lblt -lc + +include $(BLTHOME)make.actions diff --git a/lib/libdl/dl-int.h b/lib/libdl/dl-int.h @@ -0,0 +1,48 @@ +/* $Id: //depot/blt/lib/libdl/dl-int.h#3 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef DL_INT_H +#define DL_INT_H + +#include <elf.h> + +typedef struct __lib_t +{ + elf32_hdr_t *hdr; + elf32_sec_hdr_t *strtab, *symtab, *dynstr, *dynsym; + elf32_sym_t *symtab_data, *dynsym_data; + char *strtab_data, *dynstr_data; + int area, strtab_size, symtab_size, dynsym_size, dynstr_size; + struct __lib_t *next; +} lib_t; + +unsigned int __dl_lookup_sym (lib_t *lib, const char *name); +int __dl_patchup (lib_t *lib); + +#endif + diff --git a/lib/libdl/elf.c b/lib/libdl/elf.c @@ -0,0 +1,67 @@ +/* $Id: //depot/blt/lib/libdl/elf.c#3 $ +** +** Copyright 1998-1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stddef.h> +#include <string.h> +#include <elf.h> +#include <blt/libsyms.h> + +elf32_sec_hdr_t *elf_find_section_hdr (elf32_hdr_t *hdr, char *name) +{ + char *section_name; + int i; + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff + + hdr->e_shstrndx * hdr->e_shentsize); + section_name = (char *) ((unsigned int) hdr + sec_hdr->sh_offset); + sec_hdr = (elf32_sec_hdr_t *) ((unsigned int) hdr + hdr->e_shoff); + for (i = 0; i < hdr->e_shnum; i++, sec_hdr = (elf32_sec_hdr_t *) + ((unsigned int) sec_hdr + hdr->e_shentsize)) + if (!strcmp (section_name + sec_hdr->sh_name, name)) + return sec_hdr; + return NULL; +} + +void *elf_find_section_data (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? NULL : (void *) ((unsigned int) hdr + + sec_hdr->sh_offset); +} + +int elf_section_size (elf32_hdr_t *hdr, char *name) +{ + elf32_sec_hdr_t *sec_hdr; + + sec_hdr = elf_find_section_hdr (hdr, name); + return (sec_hdr == NULL) ? 0 : sec_hdr->sh_size; +} + diff --git a/lib/libdl/load.c b/lib/libdl/load.c @@ -0,0 +1,188 @@ +/* $Id: //depot/blt/lib/libdl/load.c#8 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <dlfcn.h> +#include <sys/stat.h> +#include <blt/libsyms.h> +#include <blt/syscall.h> +#include "dl-int.h" + +weak_alias (_dlopen, dlopen) +weak_alias (_dlclose, dlclose) +weak_alias (_dlerror, dlerror) + +const char *__dl_error = NULL; +static volatile char initialised = 0; +lib_t *file; + +/* + * Initialise the list of loaded images with our binary. + * + * XXX this will break when the executable is at least partially + * dynamically linked. + */ +void __dlinit (void) +{ + initialised = 1; + file = malloc (sizeof (lib_t)); + file->hdr = (elf32_hdr_t *) 0x1000; + file->strtab = elf_find_section_hdr (file->hdr, ".strtab"); + file->strtab_data = elf_find_section_data (file->hdr, ".strtab"); + file->strtab_size = elf_section_size (file->hdr, ".strtab"); + file->symtab = elf_find_section_hdr (file->hdr, ".symtab"); + file->symtab_data = elf_find_section_data (file->hdr, ".symtab"); + file->symtab_size = elf_section_size (file->hdr, ".symtab"); +/* + file->dynstr = elf_find_section_hdr (file->hdr, ".dynstr"); + file->dynstr_data = elf_find_section_data (file->hdr, ".dynstr"); + file->dynstr_size = elf_section_size (file->hdr, ".dynstr"); + file->dynsym = elf_find_section_hdr (file->hdr, ".dynsym"); + file->dynsym_data = elf_find_section_data (file->hdr, ".dynsym"); + file->dynsym_size = elf_section_size (file->hdr, ".dynsym"); +*/ + file->next = NULL; +} + +/* + * Loading is not completely straightforward. There is only one hack here, + * in that we guess that we will only need one page more memory than the + * size of the library. This seems to work on all libraries I can get my + * hands on (both OpenBLT and Linux shared libraries). + * + * The memmove loop may look like a hack because you might think I'm not + * completely parsing the program headers. It's not because file offsets + * and virtual addresses in an ELF file are equal, modulo 4k or larger + * powers of two. Read page 2-7 of the ELF specification for more + * information. + */ +void *_dlopen (const char *filename, int flag) +{ + char *c; + int i, size, fd, res, len; + struct stat buf; + lib_t *lib, *p; + elf32_pgm_hdr_t *pgm; + int (*fn)(void); + + if (!initialised) + __dlinit (); + + __dl_error = NULL; + if (_stat (filename, &buf)) + { + errno = ENOENT; + return NULL; + } + size = buf.st_size; + size = (size & ~3) ? (size & ~3) + 0x1000 : size; + fd = _open (filename, O_RDONLY, 0); + if (fd < 0) + return NULL; + lib = malloc (sizeof (lib_t)); + lib->area = area_create (size, 0, (void **) &c, 0); + len = 0; + while ((res = _read (fd, c + len, 0x2000)) > 0) + len += res; + _close (fd); + + lib->hdr = (elf32_hdr_t *) c; + pgm = (elf32_pgm_hdr_t *) ((unsigned int) lib->hdr + lib->hdr->e_phoff); + for (i = lib->hdr->e_phnum - 1; i >= 0; i--) + memmove ((void *) ((unsigned int) lib->hdr + pgm[i].p_vaddr), + (void *) ((unsigned int) lib->hdr + pgm[i].p_offset), + pgm[i].p_filesz); + lib->strtab = elf_find_section_hdr (lib->hdr, ".strtab"); + lib->strtab_data = elf_find_section_data (lib->hdr, ".strtab"); + lib->strtab_size = elf_section_size (lib->hdr, ".strtab"); + lib->symtab = elf_find_section_hdr (lib->hdr, ".symtab"); + lib->symtab_data = elf_find_section_data (lib->hdr, ".symtab"); + lib->symtab_size = elf_section_size (lib->hdr, ".symtab"); + lib->dynstr = elf_find_section_hdr (lib->hdr, ".dynstr"); + lib->dynstr_data = elf_find_section_data (lib->hdr, ".dynstr"); + lib->dynstr_size = elf_section_size (file->hdr, ".dynstr"); + lib->dynsym = elf_find_section_hdr (lib->hdr, ".dynsym"); + lib->dynsym_data = elf_find_section_data (lib->hdr, ".dynsym"); + lib->dynsym_size = elf_section_size (file->hdr, ".dynsym"); + + if (__dl_patchup (lib)) + { + area_destroy (lib->area); + free (lib); + return NULL; + } + if ((fn = (int (*)(void)) (__dl_lookup_sym (lib, "_init") + + (unsigned int) lib->hdr))) + res = (*fn) (); + if ((flag & ~RTLD_GLOBAL) || res) + { + p = file; + while (p->next != NULL) + p = p->next; + p->next = lib; + lib->next = NULL; + } + else + lib->next = NULL; + return lib; +} + +int _dlclose (void *handle) +{ + lib_t *lib, *p; + void (*fn)(void); + + lib = handle; + if (file == lib) + file = file->next; + else + { + p = file; + while ((p->next != lib) && (p->next != NULL)) + p = p->next; + if (p->next != NULL) + p->next = lib->next; + } + if ((fn = (void (*)(void)) (__dl_lookup_sym (lib, "_fini") + + (unsigned int) lib->hdr))) + (*fn) (); + area_destroy (lib->area); + free (handle); + return 0; +} + +const char *_dlerror (void) +{ + return __dl_error; +} + diff --git a/lib/libdl/rtld.c b/lib/libdl/rtld.c @@ -0,0 +1,14 @@ +/* $Id: //depot/blt/lib/libdl/rtld.c#1 $ +** +** Copyright 1999 Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License. +*/ + +#include "dl-int.h" + +lib_t *file; + +void _start (void) +{ +} + diff --git a/lib/libdl/sym.c b/lib/libdl/sym.c @@ -0,0 +1,139 @@ +/* $Id: //depot/blt/lib/libdl/sym.c#8 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <elf.h> +#include <dlfcn.h> +#include <blt/libsyms.h> +#include "dl-int.h" + +weak_alias (_dlsym, dlsym) + +extern lib_t *file; + +void *_dlsym (void *handle, const char *symbol) +{ + int i; + lib_t *lib; + + lib = handle; + for (i = 0; i < lib->dynsym_size / sizeof (elf32_sym_t); i++) + if (!strcmp (lib->dynstr_data + lib->dynsym_data[i].st_name, symbol)) + return (void *) ((unsigned int) lib->hdr + + lib->dynsym_data[i].st_value); + for (i = 0; i < lib->symtab_size / sizeof (elf32_sym_t); i++) + if (!strcmp (lib->strtab_data + lib->symtab_data[i].st_name, symbol)) + return (void *) ((unsigned int) lib->hdr + + lib->symtab_data[i].st_value); + return NULL; +} + +unsigned int __dl_lookup_sym (lib_t *lib, const char *name) +{ + int i; + + for (i = 0; i < lib->symtab_size / sizeof (elf32_sym_t); i++) + if (!strcmp (lib->strtab_data + lib->symtab_data[i].st_name, name)) + return lib->symtab_data[i].st_value; + return 0; +} + +int __dl_patch_section (lib_t *lib, elf32_rel_t *rel, int size) +{ + char *name; + int i; + unsigned int *word, sym = 0; + lib_t *p; + + for (i = 0; i < size; i++) + { + //_printf ("patching at %x, type %d\n", rel[i].r_offset, + // ELF32_R_TYPE (rel[i].r_info)); + word = (unsigned int *) ((unsigned int) lib->hdr + rel[i].r_offset); + if (ELF32_R_SYM (rel[i].r_info)) + { + name = lib->dynstr_data + + lib->dynsym_data[ELF32_R_SYM (rel[i].r_info)].st_name; + if (!(sym = __dl_lookup_sym (lib, name))) + { + p = file; + while ((p != NULL) && !sym) + if (!(sym = __dl_lookup_sym (p, name))) + p = p->next; + if (!sym) + { + //_printf ("unresolved symbol %s\n", name); + return -1; + } + if (p != file) + sym += (unsigned int) p->hdr; + } + else + sym += (unsigned int) lib->hdr; + } + switch (ELF32_R_TYPE (rel[i].r_info)) + { + case R_386_32: + *word += sym; + break; + + case R_386_PC32: + *word += sym - (unsigned int) word; + break; + + case R_386_RELATIVE: + *word += (unsigned int) lib->hdr; + break; + + default: + //_printf ("unknown relocation type %d; crashing soon...\n", + // ELF32_R_TYPE (rel[i].r_info)); + break; + } + } + return 0; +} + +int __dl_patchup (lib_t *lib) +{ + int size; + elf32_rel_t *rel; + + rel = (elf32_rel_t *) elf_find_section_data (lib->hdr, ".rel.text"); + size = elf_section_size (lib->hdr, ".rel.text") / sizeof (elf32_rel_t); + if (__dl_patch_section (lib, rel, size)) + return -1; + rel = (elf32_rel_t *) elf_find_section_data (lib->hdr, ".rel.data"); + size = elf_section_size (lib->hdr, ".rel.data") / sizeof (elf32_rel_t); + if (__dl_patch_section (lib, rel, size)) + return -1; + return 0; +} + diff --git a/lib/libposix/Makefile b/lib/libposix/Makefile @@ -0,0 +1,10 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +LIBRARY := libposix.a +SHLIB := libposix.so +SHLIB_MAJOR := 1 +SHLIB_MINOR := 0 +OBJS := exec.o fdl.o vfs.o printf.o stdio.o getopt.o console.o + +include $(BLTHOME)make.actions diff --git a/lib/libposix/console.c b/lib/libposix/console.c @@ -0,0 +1,74 @@ +/* Copyright 2000, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <string.h> +#include <blt/namer.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> + +static int __libc_console_local_port = -1; +static int __libc_console_out_port = -1; + +/* 0 = register, 1 = send, 2 = recv */ + +int __libc_bind_console (void) +{ + if(__libc_console_local_port < 0) { + __libc_console_out_port = namer_find("console",1); + __libc_console_local_port = port_create(0, "console_io"); + + if(port_send(__libc_console_local_port, + __libc_console_out_port, + NULL, 0, 0) == 0) { + return 0; + } + + port_destroy(__libc_console_local_port); + __libc_console_local_port = -1; + } + return -1; +} + +size_t __libc_write_console(const void *buf, size_t len) +{ + const char *x = (const char *) buf; + ssize_t l = len; + + while(len > 0){ + if(len > 255) { + port_send(__libc_console_local_port, __libc_console_out_port, + (void*) x, 255, 1); + len -= 255; + x += 255; + } else { + port_send(__libc_console_local_port, __libc_console_out_port, + (void*) x, len, 1); + len = 0; + } + } + return l; +} + +ssize_t __libc_read_console(void *buf, ssize_t len) +{ + char *x = (char *) buf; + ssize_t r, t; + + t = 0; + while(len) { + r = port_recv(__libc_console_local_port, NULL, x, 1, NULL); + if(r < 0) return 0; + x++; + t++; + len--; + } + + return t; +} + +void grab_console(void) +{ + port_send(__libc_console_local_port, __libc_console_out_port, + NULL, 0, 0); +} diff --git a/lib/libposix/exec.c b/lib/libposix/exec.c @@ -0,0 +1,107 @@ +/* $Id: //depot/blt/lib/libposix/exec.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <elf.h> +#include <sys/stat.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> + +weak_alias (_execve, execve) + +int _execve (const char *path, char * const *argv, char * const *envp) +{ + char *ptr, *c; + char **n_argv; + int i, j, fd, area, sarea, res, size, total; + unsigned int *magic; + struct stat buf; + uint32 *stack, *top; + + res = _stat (path, &buf); + if (res) + { + errno = ENOENT; + return -1; + } + size = (buf.st_size & 0xfff) ? (buf.st_size & 0xfffff000) + 0x1000 : + buf.st_size; + fd = _open (path, O_RDONLY, 0); + if (fd < 0) + { + errno = ENOENT; + return -1; + } + area = area_create (size, 0, (void **) &ptr, 0); + res = _read (fd, ptr, size); + magic = (unsigned int *) ptr; + if (*magic != ELF_MAGIC) + { + errno = ENOEXEC; + area_destroy (area); + return -1; + } + // _close(fd); + + /* compute how much stack we need for arguments */ + for (i = total = 0; argv[i] != NULL; i++) + total += strlen (argv[i]) + 1; + total = (total & ~3) ? (total & ~3) + 4 : total; + + /* create stack */ + sarea = area_create (0x1000, 0, (void **) &stack, 0); + + /* copy arguments and set up the argv array */ + c = (char *) stack + 0xffc - total; + n_argv = (char **) (c - i * sizeof (char *)); + for (j = 0; j < i; j++) + { + strcpy (c, argv[j]); + n_argv[j] = (char *) (0x3ff000 + ((unsigned int) c & 0xfff)); + c += strlen (argv[j]) + 1; + } + + /* drop argc and argv on the top */ + top = (uint32 *) ((unsigned int) stack + 0x1000 - (total + (i + 3) * + sizeof (char *))); + top[0] = i; + top[1] = 0x3ff000 + (((uint32) top + 8) & 0xfff); + + /* off we go */ + res = thr_spawn (0x1074, 0x3ff000 + ((unsigned int) top & 0xfff) + 0x10, + area, 0x1000, sarea, 0x3ff000, argv[0]); + + /* clean up */ + area_destroy (area); + area_destroy (sarea); + return res; +} + diff --git a/lib/libposix/fdl.c b/lib/libposix/fdl.c @@ -0,0 +1,139 @@ +/* $Id: //depot/blt/lib/libposix/fdl.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <blt/qsem.h> +#include <blt/libsyms.h> +#include <blt/fdl.h> +#include <blt/os.h> + +static __filedesc **fd_table; +static qsem_t *fd_table_lock; + +weak_alias (_read, read) +weak_alias (_write, write) +weak_alias (_ioctl, ioctl) +weak_alias (_close, close) + +void __libc_init_fdl (void) +{ + int i; + + fd_table = malloc (sizeof (__filedesc *) * MAX_FDS); + for (i = 0; i < MAX_FDS; i++) + fd_table[i] = NULL; + fd_table_lock = qsem_create (1); +} + +init_info __init_posix_fdl = { + &__libc_init_fdl, + 1 +}; + +void __libc_fini_fdl (void) +{ + free (fd_table); + qsem_destroy (fd_table_lock); +} + +int _fdl_alloc_descriptor (fdl_type *handler, void *cookie) +{ + int i; + + qsem_acquire (fd_table_lock); + for (i = 0; i < MAX_FDS; i++) + if (fd_table[i] == NULL) + { + fd_table[i] = malloc (sizeof (__filedesc)); + fd_table[i]->imp = handler; + fd_table[i]->cookie = cookie; + qsem_release (fd_table_lock); + return i; + } + qsem_release (fd_table_lock); + return -1; +} + +void _fdl_free_descriptor (int desc) +{ + fd_table[desc] = NULL; +} + +ssize_t _read (int fd, void *buf, size_t count) +{ + if (fd_table[fd]->imp->read != NULL) + return fd_table[fd]->imp->read (fd_table[fd]->cookie, buf, count); + else + { + errno = ENOSYS; + return -1; + } +} + +ssize_t _write (int fd, const void *buf, size_t count) +{ + if (fd_table[fd]->imp->write != NULL) + return fd_table[fd]->imp->write (fd_table[fd]->cookie, buf, count); + else + { + errno = ENOSYS; + return -1; + } +} + +int _ioctl (int fd, unsigned long request, char *argp) +{ + if (fd_table[fd]->imp->ioctl != NULL) + return fd_table[fd]->imp->ioctl (fd_table[fd]->cookie, request, argp); + else + { + errno = ENOSYS; + return -1; + } +} + +int _close (int fd) +{ + int res; + + if (fd_table[fd]->imp->close != NULL) + { + res = fd_table[fd]->imp->close (fd_table[fd]->cookie); + fd_table[fd] = NULL; + return res; + } + else + { + errno = ENOSYS; + return -1; + } +} + diff --git a/lib/libposix/getopt.c b/lib/libposix/getopt.c @@ -0,0 +1,122 @@ +/* $Id: //depot/blt/lib/libposix/getopt.c#1 $ +** OpenBSD: getopt.c,v 1.2 1996/08/19 08:33:32 tholo Exp $ +** +** Copyright (c) 1987, 1993, 1994 +** The Regents of the University of California. All rights reserved. +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. All advertising materials mentioning features or use of this software +** must display the following acknowledgement: +** This product includes software developed by the University of +** California, Berkeley and its contributors. +** 4. Neither the name of the University nor the names of its contributors +** may be used to endorse or promote products derived from this software +** without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <blt/libsyms.h> + +weak_alias (_getopt, getopt) + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +extern char *__progname; + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +#define fprintf(file, format, a...) _printf (format, ## a) + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int _getopt (int nargc, char * const *nargv, const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + diff --git a/lib/libposix/printf.c b/lib/libposix/printf.c @@ -0,0 +1,44 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdarg.h> +#include <string.h> +#include <blt/namer.h> +#include <blt/syscall.h> +#include <blt/libsyms.h> + +void va_snprintf (char *s, int len, const char *fmt, ...); + +void __libc_bind_console(void); +ssize_t __libc_write_console(const void *buf, ssize_t len); +ssize_t __libc_read_console(void *buf, ssize_t); + +void __libc_init_console (void) +{ + __libc_bind_console (); +} + +weak_alias (_printf, __libc_printf) +weak_alias (_printf, printf) +link_warning (__libc_printf, "warning: __libc_printf is deprecated; use printf instead.") + +init_info __init_posix_console = { + &__libc_init_console, + 2 +}; + +int _printf(char *fmt,...) +{ + char buf[256]; + + va_list pvar; + va_start(pvar,fmt); + va_snprintf(buf,256,fmt,pvar); + va_end(pvar); + + __libc_write_console(buf, strlen(buf)); + + return 0; +} + diff --git a/lib/libposix/stdio.c b/lib/libposix/stdio.c @@ -0,0 +1,55 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <blt/fdl.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <blt/libsyms.h> + +int __libc_bind_console(void); +ssize_t __libc_write_console(const void *buf, ssize_t len); +ssize_t __libc_read_console(void *buf, ssize_t); + +static fdl_type console_input_fdl_imp = { "console_input", _console_read, + NULL, NULL, NULL }; + +FILE *stdin, *stdout, *stderr; + +weak_alias (_getc, getc) +weak_alias (_getchar, getchar) + +void __libc_init_console_input () +{ + int fd; + + __libc_bind_console(); + + fd = _fdl_alloc_descriptor (&console_input_fdl_imp, NULL); + if (fd) + _printf ("__libc_init_input: console input not on fd 0\n"); + stdin = malloc (sizeof (FILE)); + stdin->fd = 0; +} + +int _console_read (void *cookie, void *buf, size_t count) +{ + return __libc_read_console(buf, count); +} + +int _getc (FILE *stream) +{ + char c; + + _read (stream->fd, &c, 1); + return c; +} + +int _getchar (void) +{ + return _getc (stdin); +} + diff --git a/lib/libposix/vfs.c b/lib/libposix/vfs.c @@ -0,0 +1,353 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> +#include <blt/os.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <blt/fdl.h> +#include <blt/libsyms.h> +#include <blt/vfs.h> + +static int vfs_public_port, vfs_local_port, vfs_remote_port, filename_area; +static char *nameptr; + +static void __vfs_openconn (int src_port, int filename_area); +ssize_t _vfs_read (void *cookie, void *buf, size_t count); +int _vfs_close (void *cookie); + +static fdl_type vfs_fdl_handler = { "vfs", _vfs_read, NULL, NULL, _vfs_close }; + +weak_alias (_opendir, opendir) +weak_alias (_readdir, readdir) +weak_alias (_closedir, closedir) +weak_alias (_open, open) +weak_alias (_stat, stat) +weak_alias (_mkdir, mkdir) + +void __libc_init_vfs (void) +{ + vfs_public_port = namer_find ("vfs", 1); + vfs_local_port = port_create (vfs_public_port,"vfs_public_port"); + + filename_area = area_create (0x1000, 0, (void **) &nameptr, 0); + __vfs_openconn (vfs_local_port, filename_area); +} + +init_info __init_posix_vfs = { + &__libc_init_vfs, + 3 +}; + +void __libc_fini_vfs (void) +{ +} + +static void __vfs_openconn (int src_port, int filename_area) +{ + msg_hdr_t mh; + vfs_cmd_t vc; + vfs_res_t vr; + + vc.cmd = VFS_OPENCONN; + vc.data[0] = filename_area; + + mh.src = vfs_local_port; + mh.dst = vfs_public_port; + mh.data = &vc; + mh.size = sizeof (vc); + old_port_send (&mh); + + mh.src = 0; /* XXX */ + mh.dst = vfs_local_port; + mh.data = &vr; + mh.size = sizeof (vr); + old_port_recv (&mh); + + if (vr.status != VFS_OK) + { + _printf ("libc: couldn't open connection to vfs\n"); + vfs_local_port = vfs_remote_port = -1; + } + vfs_remote_port = vr.data[0]; +} + +DIR *_opendir (const char *name) +{ + int area; + void *ptr; + msg_hdr_t msg; + vfs_cmd_t vc; + vfs_res_t vr; + DIR *dirp; + + strlcpy (nameptr, name, BLT_MAX_NAME_LENGTH); + area = area_create (0x2000, 0, &ptr, 0); + + vc.cmd = VFS_OPENDIR; + vc.data[0] = 0; + vc.data[1] = area; + vc.data[2] = 0; + vc.data[3] = 0x2000; + msg.src = vfs_local_port; + msg.dst = vfs_remote_port; + msg.data = &vc; + msg.size = sizeof (vfs_cmd_t); + old_port_send (&msg); + + msg.src = vfs_remote_port; + msg.dst = vfs_local_port; + msg.data = &vr; + msg.size = sizeof (vfs_res_t); + old_port_recv (&msg); + + if (vr.status != VFS_OK) + { + errno = vr.errno; + return NULL; + } + //_printf ("libc: opendir got fd %d\n", vr.data[0]); + dirp = malloc (sizeof (DIR)); + dirp->fd = vr.data[0]; + dirp->hoffset = 0; + dirp->head = ptr; + dirp->current = ptr; + dirp->more = vr.data[2]; + dirp->len = vr.data[1]; + dirp->left = dirp->len; + return dirp; +} + +struct dirent *_readdir (DIR *dirp) +{ + if (dirp == NULL) + return NULL; + else + return (dirp->left-- > 0) ? dirp->current++ : NULL; +} + +int _closedir (DIR *dirp) +{ + msg_hdr_t msg; + vfs_cmd_t vc; + vfs_res_t vr; + + if (dirp == NULL) + { + errno = EBADF; + return -1; + } + vc.cmd = VFS_CLOSEDIR; + vc.data[0] = dirp->fd; + msg.src = vfs_local_port; + msg.dst = vfs_remote_port; + msg.data = &vc; + msg.size = sizeof (vfs_cmd_t); + old_port_send (&msg); + + msg.src = vfs_remote_port; + msg.dst = vfs_local_port; + msg.data = &vr; + msg.size = sizeof (vfs_res_t); + old_port_recv (&msg); + + errno = vr.errno; + return (vr.status == VFS_OK) ? 0 : 1; +} + +int _open (const char *path, int flags, mode_t mode) +{ + int i, area; + void *ptr; + msg_hdr_t msg; + vfs_cmd_t vc; + vfs_res_t vr; + vfs_fd *fd; + + strlcpy (nameptr, path, BLT_MAX_NAME_LENGTH); + area = area_create (0x2000, 0, &ptr, 0); + + vc.cmd = VFS_OPEN; + vc.data[0] = 0; + vc.data[1] = area; + vc.data[2] = 0; + vc.data[3] = 0x2000; + msg.src = vfs_local_port; + msg.dst = vfs_remote_port; + msg.data = &vc; + msg.size = sizeof (vfs_cmd_t); + old_port_send (&msg); + + msg.src = vfs_remote_port; + msg.dst = vfs_local_port; + msg.data = &vr; + msg.size = sizeof (vfs_res_t); + old_port_recv (&msg); + + if (vr.status != VFS_OK) + { + errno = vr.errno; + return -1; + } + //_printf ("libc: open got %d %d %d\n", vr.data[0], vr.data[1], vr.data[2]); + fd = malloc (sizeof (vfs_fd)); + i = _fdl_alloc_descriptor (&vfs_fdl_handler, fd); + fd->buf = ptr; + fd->offset = 0; + fd->srv_fd = vr.data[0]; + fd->length = vr.data[1]; + fd->more = vr.data[2]; + return i; +} + +int _vfs_close (void *cookie) +{ + msg_hdr_t mh; + vfs_cmd_t vc; + vfs_res_t vr; + vfs_fd *vfd; + + vfd = cookie; + vc.cmd = VFS_CLOSE; + vc.data[0] = vfd->srv_fd; + mh.src = vfs_local_port; + mh.dst = vfs_remote_port; + mh.data = &vc; + mh.size = sizeof (vfs_cmd_t); + old_port_send (&mh); + + mh.src = vfs_remote_port; + mh.dst = vfs_local_port; + mh.data = &vr; + mh.size = sizeof (vfs_res_t); + old_port_recv (&mh); + + if (vr.status != VFS_OK) + { + errno = vr.errno; + return -1; + } + return 0; +} + +ssize_t _vfs_read (void *cookie, void *buf, size_t count) +{ + int i, len; + msg_hdr_t mh; + vfs_cmd_t vc; + vfs_res_t vr; + register vfs_fd *vfd; + + vfd = cookie; + vc.cmd = VFS_READ; + vc.data[0] = vfd->srv_fd; + vc.data[1] = count; + mh.src = vfs_local_port; + mh.dst = vfs_remote_port; + mh.data = &vc; + mh.size = sizeof (vfs_cmd_t); + old_port_send (&mh); + + mh.src = 0; + mh.dst = vfs_local_port; + mh.data = &vr; + mh.size = sizeof (vfs_res_t); + old_port_recv (&mh); + len = vr.data[0]; + if (!len) + return errno = 0; + + if (len < 0x1000) + { + mh.data = buf; + mh.size = count; + old_port_recv (&mh); + errno = vr.errno; + return len; + } + else + { + for (i = 0; len > 0x1000; i += 0x1000, len -= 0x1000) + { + mh.data = (char *) buf + i; + mh.size = 0x1000; + old_port_recv (&mh); + } + mh.data = (char *) buf + i; + mh.size = len; + old_port_recv (&mh); + errno = vr.errno; + return i + len; + } +} + +int _stat (const char *filename, struct stat *buf) +{ + msg_hdr_t msg; + vfs_cmd_t vc; + vfs_res_t *vr; + + strlcpy (nameptr, filename, BLT_MAX_NAME_LENGTH); + vc.cmd = VFS_RSTAT; + vc.data[0] = 0; + msg.src = vfs_local_port; + msg.dst = vfs_remote_port; + msg.data = &vc; + msg.size = sizeof (vfs_cmd_t); + old_port_send (&msg); + + vr = malloc (sizeof (vfs_res_t) + sizeof (struct stat)); + msg.dst = vfs_local_port; + msg.data = vr; + msg.size = sizeof (vfs_res_t) + sizeof (struct stat); + old_port_recv (&msg); + + if (vr->status == VFS_OK) + { + memcpy (buf, (void *) vr + sizeof (vfs_res_t), sizeof (struct stat)); + return 0; + } + else + { + errno = vr->errno; + return -1; + } +} + +int _mkdir (const char *path, mode_t mode) +{ + msg_hdr_t mh; + vfs_cmd_t vc; + vfs_res_t vr; + + strlcpy (nameptr, path, BLT_MAX_NAME_LENGTH); + vc.cmd = VFS_MKDIR; + vc.data[0] = 0; + vc.data[1] = mode; + mh.src = vfs_local_port; + mh.dst = vfs_remote_port; + mh.data = &vc; + mh.size = sizeof (vfs_cmd_t); + old_port_send (&mh); + + mh.src = vfs_remote_port; + mh.dst = vfs_local_port; + mh.data = &vr; + mh.size = sizeof (vfs_res_t); + old_port_recv (&mh); + + if (vr.status != VFS_OK) + { + errno = vr.errno; + return -1; + } + return 0; +} + diff --git a/lib/libwin/Button.cpp b/lib/libwin/Button.cpp @@ -0,0 +1,85 @@ +#include <win/Event.h> +#include <win/Button.h> +#include <stdlib.h> +#include <string.h> + +Button::Button(const char *text) + : fMouseDown(false), + fOverButton(false) +{ + fText = (char*) malloc(strlen(text) + 1); + memcpy(fText, text, strlen(text) + 1); +} + +Button::~Button() +{ + free(fText); +} + +void Button::Invoke() +{ +} + +void Button::Repaint(long, long, long, long) +{ + long left, top, right, bottom; + GetBounds(&left, &top, &right, &bottom); + + if (fMouseDown && fOverButton) { + left++; + top++; + } else { + right--; + bottom--; + } + + SetPenColor(5); + DrawLine(left, top, right, top); + DrawLine(left, bottom, right, bottom); + DrawLine(left, top, left, bottom); + DrawLine(right, top, right, bottom); + SetPenColor(10); + FillRect(left + 1, top + 1, right - 1, bottom - 1); + DrawString(left + 1, top + 1, fText); +} + +void Button::EventReceived(const Event *event) +{ + switch (event->what) { + case EVT_MOUSE_DOWN: + LockMouseFocus(); + fMouseDown = true; + fOverButton = true; + Invalidate(); + break; + + case EVT_MOUSE_UP: + if (fOverButton) + Invoke(); + + fMouseDown = false; + fOverButton = false; + Invalidate(); + break; + + case EVT_MOUSE_ENTER: + if (fMouseDown) { + fOverButton = true; + Invalidate(); + } + + break; + + case EVT_MOUSE_LEAVE: + if (fMouseDown) { + fOverButton = false; + Invalidate(); + } + + break; + + default: + Canvas::EventReceived(event); + } +} + diff --git a/lib/libwin/Canvas.cpp b/lib/libwin/Canvas.cpp @@ -0,0 +1,246 @@ +#include <win/Canvas.h> +#include <win/Window.h> +#include <win/Event.h> +#include "Connection.h" +#include "../../srv/window/protocol.h" + +Canvas::Canvas() + : fID(-1), + fWindow(0), + fInPaint(false), + fShowLevel(0) +{ +} + +Canvas::~Canvas() +{ +} + +void Canvas::DrawLine(long x1, long y1, long x2, long y2) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_DRAW_LINE); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt32(x1); + fWindow->fConnection->WriteInt32(y1); + fWindow->fConnection->WriteInt32(x2); + fWindow->fConnection->WriteInt32(y2); + fWindow->fConnection->EndCommand(); +} + +void Canvas::FillRect(long x1, long y1, long x2, long y2) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_FILL_RECT); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt32(x1); + fWindow->fConnection->WriteInt32(y1); + fWindow->fConnection->WriteInt32(x2); + fWindow->fConnection->WriteInt32(y2); + fWindow->fConnection->EndCommand(); +} + +void Canvas::SetPenColor(char c) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_SET_PEN_COLOR); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt8(c); + fWindow->fConnection->EndCommand(); +} + +void Canvas::SetBackgroundColor(char c) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_SET_BG_COLOR); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt8(c); + fWindow->fConnection->EndCommand(); +} + +void Canvas::DrawString(long x, long y, const char *str) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_DRAW_STRING); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt32(x); + fWindow->fConnection->WriteInt32(y); + while (*str) + fWindow->fConnection->WriteInt8(*str++); + + fWindow->fConnection->WriteInt8(0); + fWindow->fConnection->EndCommand(); +} + +void Canvas::CopyRect(long left, long top, long right, long bottom, + long newLeft, long newTop) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_COPY_RECT); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt32(left); + fWindow->fConnection->WriteInt32(top); + fWindow->fConnection->WriteInt32(right); + fWindow->fConnection->WriteInt32(bottom); + fWindow->fConnection->WriteInt32(newLeft); + fWindow->fConnection->WriteInt32(newTop); + fWindow->fConnection->EndCommand(); +} + + +void Canvas::Hide() +{ + if (fWindow == 0) + return; + + if (--fShowLevel == 0) { + fWindow->fConnection->WriteInt8(OP_HIDE_WINDOW); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->Flush(); + } +} + +void Canvas::Show() +{ + if (fWindow == 0) + return; + + if (++fShowLevel == 1) { + fWindow->fConnection->WriteInt8(OP_SHOW_WINDOW); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->Flush(); + } +} + +void Canvas::BeginPaint(long *out_left, long *out_top, long *out_right, long *out_bottom) +{ + if (fInPaint) + return; + + fInPaint = true; + fWindow->fConnection->WriteInt8(OP_BEGIN_PAINT); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->Flush(); + + *out_left = fWindow->fConnection->ReadInt32(); + *out_top = fWindow->fConnection->ReadInt32(); + *out_right = fWindow->fConnection->ReadInt32(); + *out_bottom = fWindow->fConnection->ReadInt32(); +} + +void Canvas::EndPaint() +{ + if (!fInPaint) + return; + + fInPaint = false; + fWindow->fConnection->WriteInt8(OP_END_PAINT); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->Flush(); +} + +void Canvas::AddChild(Canvas *child, long left, long top, long right, long bottom) +{ + if (fWindow == 0) + return; + + fWindow->fConnection->WriteInt8(OP_CREATE_WINDOW); + fWindow->fConnection->WriteInt32(fID); // My child + fWindow->fConnection->WriteInt32(left); + fWindow->fConnection->WriteInt32(top); + fWindow->fConnection->WriteInt32(right); + fWindow->fConnection->WriteInt32(bottom); + fWindow->fConnection->WriteInt32(fWindow->fEventPort); + fWindow->fConnection->Flush(); + child->fID = fWindow->fConnection->ReadInt32(); + child->fWindow = fWindow; + child->fLeft = 0; + child->fTop = 0; + child->fRight = right - left; + child->fBottom = bottom - top; + + // Stick window in the window's canvas list + child->fWinListNext = fWindow->fCanvasList; + child->fWinListPrev = &fWindow->fCanvasList; + if (fWindow->fCanvasList) + fWindow->fCanvasList->fWinListPrev = &child->fWinListNext; + + fWindow->fCanvasList = child; + + child->Show(); +} + +void Canvas::RemoveChild(Canvas *child) +{ + fWindow->fConnection->WriteInt8(OP_DESTROY_WINDOW); + fWindow->fConnection->WriteInt32(child->fID); + fWindow->fConnection->Flush(); + *child->fWinListPrev = child->fWinListNext; +} + +void Canvas::HandleEvent(Event *event) +{ + switch (event->what) { + case EVT_PAINT: { + long left, top, right, bottom; + BeginPaint(&left, &top, &right, &bottom); + Repaint(left, top, right, bottom); + EndPaint(); + break; + } + + default: + EventReceived(event); + } +} + +Window* Canvas::GetWindow() const +{ + return fWindow; +} + +void Canvas::GetBounds(long *left, long *top, long *right, long *bottom) +{ + *left = fLeft; + *top = fTop; + *right = fRight; + *bottom = fBottom; +} + +void Canvas::Invalidate(long left, long top, long right, long bottom) +{ + fWindow->fConnection->WriteInt8(OP_INVALIDATE); + fWindow->fConnection->WriteInt32(fID); + fWindow->fConnection->WriteInt32(left); + fWindow->fConnection->WriteInt32(top); + fWindow->fConnection->WriteInt32(right); + fWindow->fConnection->WriteInt32(bottom); + fWindow->fConnection->Flush(); +} + +void Canvas::Repaint(long left, long top, long right, long bottom) +{ +} + +void Canvas::EventReceived(const Event *) +{ +} + +void Canvas::LockMouseFocus() +{ + fWindow->fConnection->WriteInt8(OP_LOCK_MOUSE_FOCUS); + fWindow->fConnection->Flush(); +} + diff --git a/lib/libwin/Connection.cpp b/lib/libwin/Connection.cpp @@ -0,0 +1,138 @@ +#include <blt/namer.h> +#include <blt/syscall.h> +#include <blt/conio.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "Connection.h" + +const int kSendBufferSize = 0x1000; +const int kMaxCommandSize = 270; +const int kReceiveBufferSize = 1024; + +Connection::Connection(int sendPort, int receivePort) + : fSendPort(sendPort), + fReceivePort(receivePort), + fSendBufferSize(0), + fReceiveBufferSize(0), + fReceiveBufferPos(0) +{ + fSendBuffer = (char*) malloc(kSendBufferSize); + fReceiveBuffer = (char*) malloc(kReceiveBufferSize); +} + +Connection::~Connection() +{ + free(fSendBuffer); + free(fReceiveBuffer); + port_destroy(fReceivePort); +} + +void Connection::Write(const void *data, int size) +{ + int sizeWritten = 0; + while (sizeWritten < size) { + int sizeToWrite = size - sizeWritten; + if (fSendBufferSize + sizeToWrite > kSendBufferSize) + sizeToWrite = kSendBufferSize - fSendBufferSize; + + if (sizeToWrite == 0) { + Flush(); + continue; + } + + memcpy((void*) (fSendBuffer + fSendBufferSize), (const void*) ((const char*) data + + sizeWritten), sizeToWrite); + fSendBufferSize += sizeToWrite; + sizeWritten += sizeToWrite; + } +} + +void Connection::Read(void *data, int size) +{ + int sizeRead = 0; + while (sizeRead < size) { + int sizeToRead = size - sizeRead; + + if (fReceiveBufferSize - fReceiveBufferPos < sizeToRead) + sizeToRead = fReceiveBufferSize - fReceiveBufferPos; + + if (sizeToRead == 0) { + Receive(); + continue; + } + + memcpy((void*) ((char*) data + sizeRead), + (void*) (fReceiveBuffer + fReceiveBufferPos), sizeToRead); + fReceiveBufferPos += sizeToRead; + sizeRead += sizeToRead; + } +} + +void Connection::EndCommand() +{ + if (fSendBufferSize > kSendBufferSize - kMaxCommandSize) + Flush(); +} + +void Connection::Flush() +{ + msg_hdr_t header; + header.src = fReceivePort; + header.dst = fSendPort; + header.data = fSendBuffer; + header.size = fSendBufferSize; + + old_port_send(&header); + + fSendBufferSize = 0; +} + +void Connection::Receive() +{ + msg_hdr_t header; + header.src = 0; + header.dst = fReceivePort; + header.data = fReceiveBuffer; + header.size = kReceiveBufferSize; + + fReceiveBufferSize = old_port_recv(&header); + fReceiveBufferPos = 0; +} + +int Connection::ReadInt32() +{ + int outval; + Read(&outval, 4); + return outval; +} + +short Connection::ReadInt16() +{ + short outval; + Read(&outval, 2); + return outval; +} + +char Connection::ReadInt8() +{ + char outval; + Read(&outval, 1); + return outval; +} + +void Connection::WriteInt32(int i) +{ + Write(&i, 4); +} + +void Connection::WriteInt16(short s) +{ + Write(&s, 2); +} + +void Connection::WriteInt8(char c) +{ + Write(&c, 1); +} + diff --git a/lib/libwin/Connection.h b/lib/libwin/Connection.h @@ -0,0 +1,34 @@ +#ifndef _CONNECTION_H +#define _CONNECTION_H + +class Connection { +public: + Connection(int sendPort, int receivePort); + ~Connection(); + + int ReadInt32(); + short ReadInt16(); + char ReadInt8(); + void WriteInt32(int); + void WriteInt16(short); + void WriteInt8(char); + + void Write(const void*, int); + void Flush(); + void EndCommand(); + void Read(void*, int); + +private: + void Receive(); + + int fSendPort; + int fReceivePort; + char *fSendBuffer; + char *fReceiveBuffer; + int fSendBufferSize; + int fReceiveBufferSize; + int fReceiveBufferPos; +}; + + +#endif +\ No newline at end of file diff --git a/lib/libwin/Makefile b/lib/libwin/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +CFLAGS += -fno-pic -fno-exceptions -fno-rtti +SRCS := Connection.cpp Window.cpp Canvas.cpp Button.cpp +LIBRARY := libwin.a +SHLIB := libwin.so + +include $(BLTHOME)make.actions diff --git a/lib/libwin/Window.cpp b/lib/libwin/Window.cpp @@ -0,0 +1,198 @@ +#include <blt/namer.h> +#include <blt/syscall.h> +#include <win/Window.h> +#include <win/Canvas.h> +#include <win/Event.h> +#include <stdio.h> +#include "../../srv/window/protocol.h" +#include "Connection.h" + +Window::Window(long left, long top, long right, long bottom) + : fShowLevel(0), + fCanvasList(0) +{ + int windowServerPort; + windowServerPort = namer_find ("window_server", 0); + if (windowServerPort <= 0) { + printf("couldn't connect to window server\n"); + return; + } + + int localReplyPort = port_create(0, "client_syncport"); + fEventPort = port_create(0, "client_eventport"); + + fConnection = new Connection(windowServerPort, localReplyPort); + fConnection->WriteInt8(OP_CREATE_WINDOW); + fConnection->WriteInt32(0); // Child of root window + fConnection->WriteInt32(left); + fConnection->WriteInt32(top); + fConnection->WriteInt32(right); + fConnection->WriteInt32(bottom); + fConnection->WriteInt32(fEventPort); + fConnection->Flush(); + fID = fConnection->ReadInt32(); + + fLock = qsem_create(1); + + thr_create((void*) EventLoop, this, "win_thread"); +} + +Window::~Window() +{ + qsem_acquire(fLock); + while (fCanvasList) { + Canvas *child = fCanvasList; + fCanvasList = fCanvasList->fWinListNext; + fConnection->WriteInt8(OP_DESTROY_WINDOW); + fConnection->WriteInt32(child->fID); + fConnection->Flush(); + delete child; + } + + fConnection->WriteInt8(OP_DESTROY_WINDOW); + fConnection->WriteInt32(fID); + fConnection->Flush(); + delete fConnection; + + qsem_destroy(fLock); +} + + +void Window::MakeFocus() +{ + fConnection->WriteInt8(OP_MAKE_FOCUS); + fConnection->WriteInt32(fID); + fConnection->Flush(); +} + +void Window::Flush() +{ + fConnection->Flush(); +} + +void Window::WaitEvent(Event *event) +{ + msg_hdr_t header; + header.src = 0; + header.dst = fEventPort; + header.data = event; + header.size = sizeof(Event); + old_port_recv(&header); +} + +void Window::AddChild(Canvas *child, long left, long top, long right, long bottom) +{ + fConnection->WriteInt8(OP_CREATE_WINDOW); + fConnection->WriteInt32(fID); // My child + fConnection->WriteInt32(left); + fConnection->WriteInt32(top); + fConnection->WriteInt32(right); + fConnection->WriteInt32(bottom); + fConnection->WriteInt32(fEventPort); + fConnection->Flush(); + child->fID = fConnection->ReadInt32(); + child->fWindow = this; + child->fLeft = 0; + child->fTop = 0; + child->fRight = right - left; + child->fBottom = bottom - top; + child->Show(); + + // Stick window in my canvas list + child->fWinListNext = fCanvasList; + child->fWinListPrev = &fCanvasList; + if (fCanvasList) + fCanvasList->fWinListPrev = &child->fWinListNext; + + fCanvasList = child; +} + +void Window::RemoveChild(Canvas *child) +{ + Lock(); + fConnection->WriteInt8(OP_DESTROY_WINDOW); + fConnection->WriteInt32(child->fID); + fConnection->Flush(); + *child->fWinListPrev = child->fWinListNext; + if (child->fWinListNext) + child->fWinListNext->fWinListPrev = child->fWinListPrev; + + Unlock(); +} + +void Window::Lock() +{ + qsem_acquire(fLock); +} + +void Window::Unlock() +{ + qsem_release(fLock); +} + +void Window::Hide() +{ + if (--fShowLevel == 0) { + fConnection->WriteInt8(OP_HIDE_WINDOW); + fConnection->WriteInt32(fID); + fConnection->Flush(); + } +} + +void Window::Show() +{ + if (++fShowLevel == 1) { + fConnection->WriteInt8(OP_SHOW_WINDOW); + fConnection->WriteInt32(fID); + fConnection->Flush(); + } +} + +Canvas* Window::FindChild(int id) +{ + for (Canvas *canvas = fCanvasList; canvas; canvas = canvas->fWinListNext) + if (canvas->fID == id) + return canvas; + + return 0; +} + +void Window::DispatchEvent(Event *event) +{ + Canvas *canvas = FindChild(event->target); + if (canvas) + canvas->HandleEvent(event); +} + +int Window::EventLoop(void *_window) +{ + Window *window = (Window*) _window; + while (true) { + Event event; + window->WaitEvent(&event); + if (event.what == EVT_QUIT) { + delete window; + os_terminate(0); + } + + window->Lock(); + window->DispatchEvent(&event); + window->Unlock(); + } +} + +void Window::Quit() +{ + Event event; + event.what = EVT_QUIT; + event.target = fID; + + msg_hdr_t header; + header.src = fEventPort; // May break someday + header.dst = fEventPort; + header.data = &event; + header.size = sizeof(Event); + old_port_send(&header); +} + + diff --git a/lib/version.c b/lib/version.c @@ -0,0 +1,3 @@ +char *ostype = "OpenBLT"; +char *osrelease = "R1"; +char *osversion = "VULCAN#2"; diff --git a/make.actions b/make.actions @@ -0,0 +1,143 @@ +# +# For inclusion at the end of a makefile +# + +ifeq ($(QUIET),true) +SHUSH := @ +endif + +# If OBJS unspecified, convert SRCS into OBJS +# +ifeq ($(OBJS),) +OBJS := $(SRCS_TO_OBJS) +endif + +DEPS := $(OBJS:.o=.d) +include $(DEPS) + +ifneq ($(LIBRARY),) +$(LIBRARY): $(OBJS) +ifeq ($(QUIET),true) + @echo "### Linking: $@" +endif + @rm -f $(LIBRARY) + $(SHUSH)$(AR) cr $(LIBRARY) $(OBJS) $(LIBOBJS) +endif + +ifneq ($(SHLIB),) +ifeq ($(origin SHLIB_MAJOR), undefined) +SHLIB_NAME := $(SHLIB) +SHLIB_SONAME := +else +ifeq ($(origin SHLIB_MINOR), undefined) +SHLIB_NAME := $(SHLIB).$(SHLIB_MAJOR) +else +SHLIB_NAME := $(SHLIB).$(SHLIB_MAJOR).$(SHLIB_MINOR) +endif +SHLIB_SONAME := -soname $(SHLIB).$(SHLIB_MAJOR) +endif +$(SHLIB_NAME): $(OBJS) +ifeq ($(QUIET),true) + @echo "### Linking: $@" +endif + $(SHUSH)$(LD) -Bshareable -o $(SHLIB_NAME) $(SHLIB_SONAME) $(OBJS) $(LIBBASE) $(LIBS) +ifneq ($(SHLIB), $(SHLIB_NAME)) + ln -sf $(SHLIB_NAME) $(SHLIB) +endif +endif + +ifneq ($(BINARY),) +$(BINARY): $(OBJS) +ifeq ($(QUIET),true) + @echo "### Linking: $@" +endif + $(SHUSH)$(LD) -dN -Ttext $(ENTRY) -o $(BINARY) $(CRT0) $(OBJS) $(LIBBASE) $(LIBS) +ifeq ($(STRIP),true) + $(SHUSH)$(CP) $(BINARY).bin $(BINARY).debug + $(SHUSH)$(ST) $(BINARY).bin +endif +endif + +subdirs:: +ifneq ($(SUBDIRS),) +ifeq ($(BUILDLOG),) + @for i in $(SUBDIRS) ; \ + do echo "--- Directory: $$i"; \ + $(MAKE) -C $$i ; \ + done +else + @for i in $(SUBDIRS) ; \ + do echo "--- Directory: $$i"; \ + export BUILDLOG=$(BUILDLOG) ; \ + if $(MAKE) -C $$i ; then \ + echo "OKAY `pwd`/$$i" >> $(BUILDLOG); \ + else \ + echo "FAIL `pwd`/$$i" >> $(BUILDLOG); \ + fi ; \ + done +endif +endif + +subclean:: +ifneq ($(SUBDIRS),) + @for i in $(SUBDIRS) ; \ + do echo "--- Cleaning: $$i"; \ + $(MAKE) -C $$i clean ; \ + done +endif + +all:: check_path $(PRETARGETS) subdirs $(BINARY) $(LIBRARY) $(SHLIB_NAME) $(TARGETS) + +clean:: check_path subclean + @rm -f $(OBJS) $(LIBOBJS) $(BINARY) $(LIBRARY) $(SHLIB) $(SHLIB_NAME) $(PRETARGETS) $(TARGETS) *.debug *.d + +realclean:: clean + @rm -f *.d + +############################################# +# rules for compilation of individual files +############################################# +DEP_FLAGS := -M -MG $(CFLAGS) + +%.o: %.cpp +ifeq ($(QUIET),true) + @echo "### Compiling: $<" +endif + $(SHUSH)$(C++) $(CXXFLAGS) -c $< + +%.o: %.c +ifeq ($(QUIET),true) + @echo "### Compiling: $<" +endif + $(SHUSH)$(CC) $(CFLAGS) -c $< + +%.o: %.S +ifeq ($(QUIET),true) + @echo "### Assembling: $<" +endif + $(SHUSH)$(CC) $(CFLAGS) -S -o $@ $< + +%.o: %.S +ifeq ($(QUIET),true) + @echo "### Assembling: $<" +endif + $(SHUSH)$(CC) $(CFLAGS) -D__ASM__ -c $< + +%.d: %.c +ifeq ($(QUIET),true) + @echo "### MakeDeps: $<" +endif + $(SHUSH)$(CC) $(DEP_FLAGS) $< > $@ + +%.d: %.S +ifeq ($(QUIET),true) + @echo "### MakeDeps: $<" +endif + $(SHUSH)$(CC) -D__ASM__ $(DEP_FLAGS) $< > $@ + +%.d: %.cpp +ifeq ($(QUIET),true) + @echo "### MakeDeps: $<" +endif + $(SHUSH)$(C++) $(DEP_FLAGS) $< > $@ + diff --git a/make.conf b/make.conf @@ -0,0 +1,100 @@ +# Target host for "make run" +# +#IP = 10.0.0.5 +#IP = 128.174.252.78 +#IP = 10.113.194.70 +IP = 10.0.0.43 + +# List of .ini files to pass to bootmaker +# +INIFILES := boot/openblt.ini boot/misc.ini boot/window.ini boot/fs.ini +# LOCALINIFILES := + +############################################################################## +# KERNEL OPTIONS +############################################################################## +# Debug options for monochrome display or serial io +# +#VIDMODE = -DMONO +#SERIAL += -DSERIAL +#SERIAL += -DSERIAL_DEBUG +#SERIAL += -DDPRINTF +#SERIAL += -DPORT_E9 + +# Uncomment at most one machine type. The default will be equivalent to I386. +# A sensible choice will get you better performance. Kernels are not +# guaranteed to run on a lower processor than that which they were built for. +# Your choice does not affect your ability to do SMP. +# +CPU = -DI386 +#CPU = -DI486 +#CPU = -DI586 +#CPU = -DI686 + +# Uncomment this to build an SMP-capable kernel. SMP kernels will still run +# on UP machines. +# +#SMP = -D__SMP__ + +############################################################################## +# END KERNEL OPTIONS +############################################################################## + +# Cross-compilation prefix / postfix stuff +# +#PREFIX = i586-beoself- +#POSTFIX = 386 + +# Linker arg stuff +# +ENTRY_KERNEL = 80000074 +ENTRY_USER = 01074 +ENTRY_BOOTSTRAP = 101074 +ENTRY_ROM = 90074 + +CC = $(PREFIX)gcc$(POSTFIX) +C++ = $(PREFIX)g++$(POSTFIX) +LD = $(PREFIX)ld$(POSTFIX) +NM = $(PREFIX)nm$(POSTFIX) +ST = $(PREFIX)strip$(POSTFIX) +AR = $(PREFIX)ar$(POSTFIX) + +OPTIMIZER := -O2 +WARNINGS := -Wall + +# Optionally strip all binaries (save some space) +# .debug versions of binaries will be also made in this case +# +STRIP := false + +define SRCS_TO_OBJS + $(addsuffix .o, $(foreach file, $(SRCS), $(basename $(notdir $(file))))) +endef + + +# Adjust our paths based on the BLTHOME variable +# +# +ENTRY := $(ENTRY_USER) +INCLUDES := -I$(BLTHOME)include +LIBBASE := -L$(BLTHOME)lib/obj +CRT0 := $(BLTHOME)lib/crt0.o + + +CFLAGS := -nostdinc -fno-builtin $(WARNINGS) -Wno-multichar $(OPTIMIZER) $(INCLUDES) $(VIDMODE) $(CPU) + +CXXFLAGS := -nostdinc -fno-rtti -fno-exceptions -fno-builtin $(WARNINGS) -Wno-multichar $(OPTIMIZER) $(INCLUDES) $(VIDMODE) $(CPU) + +# Prevent rule confusion... +# + +default: all + +# Used to insure BLTHOME is actually set +# +check_path: +ifeq ($(BLTHOME),) + @echo error: BLTHOME is not set + @/bin/false +endif + diff --git a/netboot/Makefile b/netboot/Makefile @@ -0,0 +1,37 @@ +BLTHOME := ../ +include $(BLTHOME)make.conf + +CFLAGS := -I$(BLTHOME)include -fno-pic -O2 +LIBS := -L$(BLTHOME)lib/obj -lconsole -lkern +ST := strip + +all: netrom.hex + +load: netrom.hex + ./sersend -b 115200 /dev/ports/serial1 < netrom.hex + +makerom: makerom.c + gcc -o makerom makerom.c + +netrom: netrom.asm + nasm netrom.asm + +netrom.hex: netrom netboot.raw makerom + cat netrom netboot.raw > temp.raw + ./makerom temp.raw netrom.hex + +OBJS = crt0.o netboot.o pci.o ne2000.o + +netboot.raw: $(OBJS) + $(LD) -dN -Ttext 0x90000 -o netboot.bin $(OBJS) $(LIBS) + $(NM) -nC netboot.bin > netboot.map + objcopy -O binary netboot.bin netboot.raw + +download: download.c + cc -o download download.c + +install: download netrom.hex + ./download < netrom.hex + +clean: + rm -f *.o *~ os.* core *.core *.s *.map netboot.bin temp.raw netboot.raw netrom.hex *.boot makerom download diff --git a/netboot/crt0.c b/netboot/crt0.c @@ -0,0 +1,33 @@ +/* $Id: //depot/blt/netboot/crt0.c#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +void main(int mem); + +void _start(int mem) +{ + main(mem); +} diff --git a/netboot/err.h b/netboot/err.h @@ -0,0 +1,115 @@ +/* $Id: //depot/blt/netboot/err.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __ERR +#define __ERR + +/* NOTE If ret is negative then it is an error otherwise it returns a +// success code. */ + +#define NUM_ERR 19 +#define NOERR 0 +#define ERR -1 +#define ERRNOMEM -2 +#define ERRRESOURCE -3 +#define ERRMEMCORRUPT -4 +#define ERRFORMAT -5 +#define ERRNOTFOUND -6 +#define ERRTYPE -7 +#define ERRTIMEOUT -8 +#define ERRNOTSUPPORTED -9 +#define ERROUTOFRANGE -10 +#define ERRPRIV -11 +#define ERRNOTREADY -12 +#define ERRNONEFREE -13 +#define ERRARG -14 +#define ERRINVALID -15 +#define ERRNOTOPEN -16 +#define ERRALREADYDONE -17 +#define ERRVER -18 + +#define SFOUND 1 +#define SNOTFOUND 2 +#define SALT 3 + +/* Bits 16-31 are reserved for the facility code. */ +#define OWNOS 0x70 +#define OWNNOMAD 0x70 + +#define MAX_ERR_MSG 32 +const char err_msg[NUM_ERR][MAX_ERR_MSG] = { "success", + "error", + "out of memory", + "resource allocation", + "memory corrupt!!!", + "format", + "not found", + "type", + "timeout", + "not supported", + "out of range", + "access denied", + "not ready", + "none free", + "bad argument", + "invalid", + "not open", + "already done", + "incorrect version" }; + +#ifdef __CPP_BINDING +extern "C" void kprintf(char *, ...); +class ret { + private: + int val; + public: + ret() { val=ERR; } + ret(int src) { val=src; } + ret operator=(const ret& src) { return val=src.val; } + ret operator=(int src) { return val=src; } + int operator==(const ret& cmp) { return val==cmp.val; } + int operator!() { return val<0; } + // returns 1 if error, 0 if success + int operator<(int cmp) { +//kprintf(" %d < %d\n",val,cmp); + // TODO implement some severity check + return (val<cmp); } + int operator<(ret& cmp) { +//kprintf(" %d < %d\n",val,cmp.val); +return (val<cmp.val); } + operator int() const { return val; } +// operator bool() { return (val<0); } + const char *disp() { + if(((val & 0x70) != 0x70) && ((val & 0x70) != 0x00)) + return "Unknown facility"; + return err_msg[-val]; } +}; +#else +typedef int ret; +#endif /* __CPP_BINDING */ + +#endif /* __ERR */ diff --git a/netboot/go b/netboot/go @@ -0,0 +1,5 @@ +#!/bin/zsh +cat netrom.bin netboot.bin > test.bin +./makerom test.bin test.hex +cp test.hex /dev/cua0 + diff --git a/netboot/io.h b/netboot/io.h @@ -0,0 +1,192 @@ +/* $Id: //depot/blt/netboot/io.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +#define SLOW_IO_BY_JUMPING + +/* + * This file contains the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl and the "string versions" of the same + * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" + * versions of the single-IO instructions (inb_p/inw_p/..). + * + * This file is not meant to be obfuscating: it's just complicated + * to (a) handle it all in a way that makes gcc able to optimize it + * as well as possible and (b) trying to avoid writing the same thing + * over and over again with slight variations and possibly making a + * mistake somewhere. + */ + +/* + * Thanks to James van Artsdalen for a better timing-fix than + * the two short jumps: using outb's to a nonexistent port seems + * to guarantee better timings even on fast machines. + * + * On the other hand, I'd like to be sure of a non-existent port: + * I feel a bit unsafe about using 0x80 (should be safe, though) + * + * Linus + */ + +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") +#else +#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") +#endif + +#define SLOW_DOWN_IO __SLOW_DOWN_IO + +/* + * Talk about misusing macros.. + */ + +#define __OUT1(s,x) \ +extern inline void __out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ +__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ +__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; } + +#define __IN1(s) \ +extern inline RETURN_TYPE __in##s(unsigned short port) { RETURN_TYPE _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ +__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ +__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; } + +#define __INS(s) \ +extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define __OUTS(s) \ +extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define RETURN_TYPE unsigned char +/* __IN(b,"b","0" (0)) */ +__IN(b,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned short +/* __IN(w,"w","0" (0)) */ +__IN(w,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned int +__IN(l,"") +#undef RETURN_TYPE + +__OUT(b,"b",char) +__OUT(w,"w",short) +__OUT(l,,int) + +__INS(b) +__INS(w) +__INS(l) + +__OUTS(b) +__OUTS(w) +__OUTS(l) + +/* + * Note that due to the way __builtin_constant_p() works, you + * - can't use it inside a inline function (it will never be true) + * - you don't have to worry about side effects within the __builtin.. + */ +#define outb(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc((val),(port)) : \ + __outb((val),(port))) + +#define inb(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc(port) : \ + __inb(port)) + +#define outb_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc_p((val),(port)) : \ + __outb_p((val),(port))) + +#define inb_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc_p(port) : \ + __inb_p(port)) + +#define outw(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc((val),(port)) : \ + __outw((val),(port))) + +#define inw(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc(port) : \ + __inw(port)) + +#define outw_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc_p((val),(port)) : \ + __outw_p((val),(port))) + +#define inw_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc_p(port) : \ + __inw_p(port)) + +#define outl(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outlc((val),(port)) : \ + __outl((val),(port))) + +#define inl(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inlc(port) : \ + __inl(port)) + +#define outl_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outlc_p((val),(port)) : \ + __outl_p((val),(port))) + +#define inl_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inlc_p(port) : \ + __inl_p(port)) + +#endif diff --git a/netboot/makerom.c b/netboot/makerom.c @@ -0,0 +1,105 @@ +/* $Id: //depot/blt/netboot/makerom.c#4 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#define ROMSIZE 0x4000 + +unsigned char rom[ROMSIZE]; +unsigned int sum; + +void makehex(char *n) +{ + FILE *fp; + int chk,chk2; + int l,i; + + if(fp = fopen(n,"w")){ + for(l=0;l<ROMSIZE;l+=32) { + fprintf(fp,":%02X%04X00",32,l); + + chk = 32; + + chk += ((l & 0xFF00) >> 8); + chk += ((l & 0x00FF)); + + for(i=0;i<32;i++){ + fprintf(fp,"%02X",rom[l+i]); + chk += rom[l+i]; + } + chk &= 0xFF; + chk2 = 0x100 - chk; + + fprintf(fp,"%02X\r\n",(chk2 & 0xFF)); + } + fprintf(fp,":00000001FF\r\n"); + + fclose(fp); + } +} + + +int main(int argc, char *argv[]) +{ + int i, fd; + if (argc < 2) { + fprintf(stderr,"usage: %s rom-file hex-file\n",argv[0]); + exit(2); + } + if ((fd = open(argv[1], O_RDWR)) < 0) { + perror("unable to open file"); + return 1; + } + bzero(rom, ROMSIZE); + + if (read(fd, rom, ROMSIZE) < 0) { + perror("read error"); + return 1; + } + + /* store size in ROM header */ + rom[2] = ROMSIZE / 512; + + /* store size in PCI ROM header */ + rom[0x18 + 0x10 + 4] = ROMSIZE / 512; + + rom[5] = 0; + for (i=0,sum=0; i<ROMSIZE; i++) sum += rom[i]; + rom[5] = -sum; + + for (i=0,sum=0; i<ROMSIZE; i++) sum += rom[i]; + if (sum & 0x00FF) printf("checksum fails.\n"); + + close(fd); + + makehex(argv[2]); + + return 0; +} diff --git a/netboot/ne2000.c b/netboot/ne2000.c @@ -0,0 +1,627 @@ +/* $Id: //depot/blt/netboot/ne2000.c#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* This file contains the shared code base for the 1997 SigOps NE2000 +// network driver. Use at your own risk! (C) Copyright 1997, +// Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97 +// ... +// derived from National Semiconductor datasheets and application notes +// as well as the Linux driver by Donald Becker */ + +/* Change Log: +10-25-97 Setup under CVS drarmstr +10-27-97 Added alloc_buffer() and free_buffer() drarmstr +*/ + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ +#include "io.h" +#include "ne2000.h" +#include "ne2k.h" +#include "err.h" + +extern void idle(); +extern long ticks; /* replace with a better timeout method, like wait() */ + +/* we may have to change inb and outb to inb_p and outb_p. +// Note, none of this code is gauranteed to be reentrant. + +// Note, don't create to nics to the same card and then try to use both +// of them. The results will be unpredictable. + +// This violates IO resource manegment if your OS handles that, but it +// works for now. Make sure that the driver has privlige access to the +// mapped I/O space and the IRQ.*/ +static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 }; + +/* internal procedure, don't call this directly.*/ +int nic_probe(int addr) { + uint regd; + uint state=inb(addr); /* save command state */ + + if(inb(addr==0xff)) return ERRNOTFOUND; + + outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); + regd=inb(addr + 0x0d); + outb(0xff, addr + 0x0d); + outb(NIC_DMA_DISABLE | NIC_PAGE0, addr); + inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/ + if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/ + outb(state,addr); /* restore command state*/ + outb(regd,addr + 0x0d); + return ERRNOTFOUND; } + + return addr; /* network card detected at io addr;*/ +} + +/* Detects for presence of NE2000 card. Will check given io addr that +// is passed to it as well as the default_ports array. Returns ERRNOTFOUND +// if no card is found, i/o address otherwise. This does conduct an ISA +// probe, so it's not always a good idea to run it. If you already have +// the information, then you can just use that with nic_init().*/ +int nic_detect(int given) { + int found; + if((found=nic_probe(given))!=ERRNOTFOUND) { return found; } + return ERRNOTFOUND; +} + +/* This initializes the NE2000 card. If it turns out the card is not +// really a NE2000 after all then it will return ERRNOTFOUND, else NOERR +// It also dumps the prom into buffer prom for the upper layers.. +// Pass it a nic with a null iobase and it will initialize the structure for +// you, otherwise it will just reinitialize it. */ +int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) { + uint f; + if(!nic->iobase) { + nic->iobase=addr; + nic_stat_clear(&nic->stat); + nic->pstart=0; nic->pstop=0; nic->wordlength=0; + nic->current_page=0; + nic->notify=NULL; + for(f=0;f<MAX_TX;f++) nic->tx_packet[f].len=0; + nic->last_tx=NULL; + nic->busy=0; + } else { + if(!nic->iobase || nic->iobase!=addr) return ERR; + } + + outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/ + while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) { + /* TODO insert timeout code here.*/ + } + + outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/ + + // Initialize registers + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/ + outb_p(DCR_DEFAULT, addr + DATACONFIGURATION); + outb_p(0x00, addr + REMOTEBYTECOUNT0); + outb_p(0x00, addr + REMOTEBYTECOUNT1); + outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ + outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ + outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/ + outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/ + + nic->wordlength=nic_dump_prom(nic,prom); + if(prom[14]!=0x57 || prom[15]!=0x57) { + return ERRNOTFOUND; + } + + /* if the wordlength for the NE2000 card is 2 bytes, then + // we have to setup the DP8390 chipset to be the same or + // else all hell will break loose.*/ + if(nic->wordlength==2) { + outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION); + } + nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART; + nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP; + + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); + outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/ + outb_p(nic->pstart + TXPAGES, addr + PAGESTART); + outb_p(nic->pstop - 1, addr + BOUNDARY); + outb_p(nic->pstop, addr + PAGESTOP); + outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ + outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ + nic->current_page=nic->pstart + TXPAGES; + + /* put physical address in the registers */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */ + if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f); + else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f); + + /* setup multicast filter to accept all packets*/ + for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f); + + outb_p(nic->pstart+TXPAGES, addr + CURRENT); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */ + + return NOERR; +} + +/* This registers the function that will be called when a new packet +// comes in. */ +void nic_register_notify(snic *nic, void (*newnotify)(packet_buffer *newpacket)){ + nic->notify=newnotify; +} + +/* start the NIC so it can actually recieve or transmit packets */ +void nic_start(snic *nic, int promiscuous) { + int iobase; + if(!nic || !nic->iobase) { + return; } + iobase=nic->iobase; + outb(0xff, iobase + INTERRUPTSTATUS); + outb(IMR_DEFAULT, iobase + INTERRUPTMASK); + outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); + if(promiscuous) + outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION); + else + outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION); +} + +/* stops the NIC */ +void nic_stop(snic *nic) { + unsigned char tmp_buffer[16]; + if(!nic || !nic->iobase) return; /* make sure card was initialized */ + nic_init(nic,nic->iobase,tmp_buffer,NULL); +} + +void nic_isr(snic *nic) { + uint isr; /* Illinois Sreet Residence Hall */ + uint overload; + if(!nic || !nic->iobase) return; /* make sure card was initialized */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); + overload=MAX_LOAD+1; + while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) { + if((--overload)<=0) break; + if(isr & ISR_OVW) nic_overrun(nic); + else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic); + if(isr & ISR_PTX) nic_tx(nic); + else if(isr & ISR_TXE) nic_tx_err(nic); +// if(isr & ISR_CNT) nic_counters(nic); + if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); + } + if(isr) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); + if(!overload) { + + outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear + } else { + outb_p(0xff, nic->iobase + INTERRUPTSTATUS); + // Ack it anyway + } + } +} + +/* You should call this before you just read the stats directlly from the +// snic struct. This procedure updates the counters */ +nic_stat nic_get_stats(snic *nic) { + nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY); + nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY); + nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY); + return nic->stat; +} + +void nic_stat_clear(nic_stat *that) { + that->rx_packets=0; + that->tx_buffered=0; that->tx_packets=0; + that->errors.frame_alignment=0; that->errors.crc=0; + that->errors.missed_packets=0; that->errors.rx=0; + that->errors.rx_size=0; that->errors.rx_dropped=0; + that->errors.rx_fifo=0; that->errors.rx_overruns=0; + that->errors.tx_collisions=0; +} + +/* Since this could be called by more than one other device, it should +// be properly protected for reentrancy. We should put in a proper +// semaphore or something, look into this. +// NOTE: It is your responsibility to clean up the packet_buffer when you +// are done calling this. Also note that the buffer.ptr may change if +// you gave us a packet that was too small and we had to pad the data. +// UPDATE: we now never change buffer.ptr, but create a whole new +// packet_buffer instead. We take care of deleting this, so you don't +// have to worry about it. +// This is done so we can avoid using dynamic memory allocation ourselves. */ +int nic_send_packet(snic *nic, packet_buffer* buffer) { + uint timeout; uint f; int iobase=nic->iobase; + packet_buffer *pad=NULL; + if(!buffer->len || !buffer->ptr) return ERR; + if(!nic || !nic->iobase) return ERR; + if(buffer->len>MAX_LENGTH) return ERRFORMAT; + /* the following wait for anyother tasks that are calling + // nic_send_packet() right now. Note that this doesn't use + // an atomic semaphore, so something MAY leak through. */ + timeout=ticks+10; // wait 10 ticks + while(nic->busy && ticks<=timeout) idle(); + /* Replace this with a proper timeout thing that doesn't use the + // ticks method which will be diffrent on each OS. */ + if(nic->busy) { + return ERRTIMEOUT; + } + nic->busy=1; /* mark as busy, replace with semaphore */ + +/* XXX should not have to copy the data --- modify nic_block_output to + optionally add padding 0's */ + if(buffer->len<MIN_LENGTH) { +/* unsigned char *newbuffer=(unsigned char*)kalloc(MIN_LENGTH); + if(!newbuffer) return ERRNOMEM; */ + pad=alloc_buffer(MIN_LENGTH); + if(!pad) { + nic->busy=0; /* V() */ + return ERRNOMEM; } + for(f=0;f<buffer->len;f++) pad->ptr[f]=buffer->ptr[f]; + for(;f<MIN_LENGTH;f++) pad->ptr[f]='\0'; + /* pad the data to the minimum size. */ + buffer=pad; + } + + outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */ + for(f=0;f<MAX_TX;f++) { + if(nic->tx_packet[f].len==0) { + nic->tx_packet[f]=*buffer; + nic->tx_packet[f].page=nic->pstart + (f * MAX_PAGESPERPACKET); + /*output page */ + + nic_block_output(nic,nic->tx_packet[f].ptr, + nic->tx_packet[f].len, + nic->tx_packet[f].page ); + + nic->send=f; + /* now let's actually trigger the transmitter to send */ + if(nic_send(nic,f)<0) break; + /* note, the nic_tx() interrupt will mark this + // tx_packet buffer as free again once it + // confirms that the packet was sent. */ + + nic->stat.tx_buffered++; + outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ + nic->busy=0; /* V() */ + if(pad) free_buffer(pad); + return NOERR; + } + } + + outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ + nic->busy=0; /* V() */ + if(pad) free_buffer(pad); + return ERR; + /* since we passed with nic->busy not busy then we should + // always have at least one buffer free. */ +} + +/* dumps the prom into a 16 byte buffer and returns the wordlength of +// the card. +// You should be able to make this procedure a wrapper of nic_block_input(). */ +int nic_dump_prom(snic *nic, unsigned char *prom) { + uint f; + int iobase=nic->iobase; + char wordlength=2; /* default wordlength of 2 */ + unsigned char dump[32]; + outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */ + outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */ + outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */ + outb_p(0x00, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + for(f=0;f<32;f+=2) { + dump[f]=inb_p(iobase + NE_DATA); + dump[f+1]=inb_p(iobase + NE_DATA); + if(dump[f]!=dump[f+1]) wordlength=1; + } + /* if wordlength is 2 bytes, then collapse prom to 16 bytes */ + for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)]; + + return wordlength; +} + +void nic_overrun(snic *nic) { + uint tx_status; int iobase=nic->iobase; + long starttime; uint resend=0; + if(!nic || !nic->iobase) return; + tx_status=inb_p(iobase) & NIC_TRANSMIT; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase); + nic->stat.errors.rx_overruns++; + + starttime=ticks; +/*kprintf("BEFORE\n");*/ + while(ticks-starttime<=10/*ticks to wait*/) idle(); + /* Arrgh! TODO: Replace this whole crappy code with a decent + // wait method. We need to wait at least 1.6ms as per National + // Semiconductor datasheets, but we should probablly wait a + // little more to be safe. +//kprintf("AFTER\n"); */ + + outb_p(0x00, iobase + REMOTEBYTECOUNT0); + outb_p(0x00, iobase + REMOTEBYTECOUNT1); + if(tx_status) { + uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) & + (ISR_PTX | ISR_TXE); + if(!tx_completed) resend=1; + } + + outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + nic_rx(nic); /* cleanup RX ring */ + outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */ + + outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); + if(resend) + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT, + iobase); +} + +/* This is the procedure that markst the transmit buffer as available again */ +void nic_tx(snic *nic) { + uint f; int iobase=nic->iobase; + uint status; + if(!nic || !nic->iobase) return; + status=inb(iobase + TRANSMITSTATUS); + + if(!nic->tx_packet[nic->send].len) { + return; + } + nic->tx_packet[nic->send].len=0; /* mark buffer as available */ + + for(f=0;f<MAX_TX;f++) { + if(nic->tx_packet[f].len) { + nic->stat.tx_buffered++; + nic_send(nic,f); /* send a back-to-back buffer */ + break; + } + } + + if(status & TSR_COL) nic->stat.errors.tx_collisions++; + if(status & TSR_PTX) nic->stat.tx_packets++; + else { + if(status & TSR_ABT) { + nic->stat.errors.tx_aborts++; + nic->stat.errors.tx_collisions+=16; } + if(status & TSR_CRS) nic->stat.errors.tx_carrier++; + if(status & TSR_FU) nic->stat.errors.tx_fifo++; + if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++; + if(status & TSR_OWC) nic->stat.errors.tx_window++; + } + + outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */ +} + +void nic_tx_err(snic *nic) { + unsigned char tsr; int iobase=nic->iobase; + if(!nic || !nic->iobase) return; + tsr=inb_p(nic->iobase); +/* kprintf("NE2000: ERROR: TX error: "); + if(tsr & TSR_ABT) kprintf("Too many collisions.\n"); + if(tsr & TSR_ND) kprintf("Not deffered.\n"); + if(tsr & TSR_CRS) kprintf("Carrier lost.\n"); + if(tsr & TSR_FU) kprintf("FIFO underrun.\n"); + if(tsr & TSR_CDH) kprintf("Heart attack!\n"); + */ + outb_p(ISR_TXE, iobase + INTERRUPTSTATUS); + if(tsr & (TSR_ABT | TSR_FU)) { + nic_tx(nic); + } +} + +void nic_rx(snic *nic) { + uint packets=0; uint frame; uint rx_page; uint rx_offset; + uint len; uint next_pkt; uint numpages; + int iobase=nic->iobase; + buffer_header header; + if(!nic || !nic->iobase) return; + while(packets<MAX_RX) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */ + rx_page=inb_p(iobase + CURRENT); /* get current page */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase); + frame=inb(iobase + BOUNDARY)+1; + /* we add one becuase boundary is a page behind + // as pre NS notes to help in overflow problems */ + if(frame>=nic->pstop) frame=nic->pstart+TXPAGES; + /* circual buffer */ + + if(frame==rx_page) break; /* all frames read */ + + rx_offset=frame << 8; /* current ptr in bytes(not pages) */ + + nic_get_header(nic,frame,&header); + len=header.count - sizeof(buffer_header); + /* length of packet */ + next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */ + + numpages=nic->pstop-(nic->pstart+TXPAGES); + if( (header.next!=next_pkt) + && (header.next!=next_pkt + 1) + && (header.next!=next_pkt - numpages) + && (header.next != next_pkt +1 - numpages)){ +/* kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n", + header.next,next_pkt,frame);*/ + nic->current_page=frame; + outb(nic->current_page-1, iobase + BOUNDARY); + nic->stat.errors.rx++; + continue; + } + + if(len<60 || len>1518) { +/* kprintf("NE2000: invalid packet size:%d\n",len);*/ + nic->stat.errors.rx_size++; + } else if((header.status & 0x0f) == RSR_PRX) { + /* We have a good packet, so let's recieve it! */ + + packet_buffer *newpacket=alloc_buffer(len); + if(!newpacket) { +/* kprintf("NE2000: ERROR: out of memory!\n");*/ + nic->stat.errors.rx_dropped++; + break; + } + + nic_block_input(nic,newpacket->ptr,newpacket->len, + rx_offset+sizeof(buffer_header)); + /* read it */ + + if(nic->notify) nic->notify(newpacket); + /* NOTE: you are responsible for deleting this buffer. */ + + nic->stat.rx_packets++; + + } else { +/* kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n", + header.status,header.next,header.count); */ + if(header.status & RSR_FO) nic->stat.errors.rx_fifo++; + } +/* kprintf("frame:%x header.next:%x next_pkt:%x\n", +// frame,header.next,next_pkt); */ + next_pkt=header.next; + + if(next_pkt >= nic->pstop) { +/* kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n", + next_pkt);*/ + next_pkt=nic->pstart+TXPAGES; + } + + nic->current_page=next_pkt; + outb_p(next_pkt-1, iobase + BOUNDARY); + } + outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */ +} + +/* You should be able to make this procedure a wrapper of nic_block_input */ +void nic_get_header(snic *nic, uint page, buffer_header *header) { + int iobase=nic->iobase; uint f; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0); + outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */ + outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */ + outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */ + outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */ + + if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++) + ((unsigned short *)header)[f]=inw(iobase+NE_DATA); + else for(f=0;f<sizeof(buffer_header);f++) + ((unsigned char *)header)[f]=inb(iobase+NE_DATA); + /* Do these need to be *_p variants??? */ + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} + +int nic_send(snic *nic, uint buf) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); + if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) { +/* kprintf("NE2000: ERROR: Transmitor busy.\n");*/ + nic->tx_packet[buf].len=0; /* mark as free again */ + return ERRTIMEOUT; } + outb_p(nic->tx_packet[buf].len & 0xff,nic->iobase+TRANSMITBYTECOUNT0); + outb_p(nic->tx_packet[buf].len >> 8,nic->iobase+TRANSMITBYTECOUNT1); + outb_p(nic->tx_packet[buf].page,nic->iobase+TRANSMITPAGE); + outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase); + return NOERR; +} + +void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) { + int iobase=nic->iobase; uint f; + uint xfers=len; + uint timeout=TIMEOUT_DMAMATCH; uint addr; +/* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset);*/ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); + outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); + outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0); + outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + + if(nic->wordlength==2) { + for(f=0;f<(len>>1);f++) + ((unsigned short *)buf)[f]=inw(iobase+NE_DATA); + if(len&0x01) { + ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA); + xfers++; + } + } else for(f=0;f<len;f++) + ((unsigned char *)buf)[f]=inb(iobase+NE_DATA); + /* Do these need to be *_p variants??? */ + +/* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n");*/ + /* TODO: make this timeout a constant */ + for(f=0;f<timeout;f++) { + uint high=inb_p(iobase + REMOTESTARTADDRESS1); + uint low=inb_p(iobase + REMOTESTARTADDRESS0); + addr=(high<<8)+low; + if(((offset+xfers)&0xff)==low) break; + } +/* if(f>=timeout) + kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", + offset+xfers, addr);*/ + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} + +void nic_block_output(snic *nic, unsigned char *buf, uint len, uint page) { + int iobase=nic->iobase; + int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int w; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + + /* this next part is to supposedly fix a "read-before-write" bug... */ + outb_p(0x42, iobase + REMOTEBYTECOUNT0); + outb_p(0x00, iobase + REMOTEBYTECOUNT1); + outb_p(0x42, iobase + REMOTESTARTADDRESS0); + outb_p(0x00, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */ + + outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); + outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); + outb_p(0x00, iobase + REMOTESTARTADDRESS0); + outb_p(page, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_WRITE | NIC_START, iobase); + + if(nic->wordlength==2) { + for(w=0;w<(len>>1);w++) + outw(((unsigned short *)buf)[w],iobase+NE_DATA); + if(len & 0x01) { + short tmp=buf[len-1]; //so we can output a whole 16-bits + // if buf were on the end of something, we would die. + outw(tmp,iobase+NE_DATA); + } + } else for(f=0;f<len;f++) + outb(((unsigned char *)buf)[f],iobase+NE_DATA); + + for(f=0;f<timeout;f++) { + uint high=inb_p(iobase + REMOTESTARTADDRESS1); + uint low=inb_p(iobase + REMOTESTARTADDRESS0); + addr=(high<<8)+low; + if(( (((page<<8)+(nic->wordlength==2 && (len&0x01))?len:len+1)) + &0xff)==low) + break; + } +/* if(f>=timeout) + kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", + page<<8, addr);*/ + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} diff --git a/netboot/ne2000.h b/netboot/ne2000.h @@ -0,0 +1,186 @@ +/* $Id: //depot/blt/netboot/ne2000.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __NE2000_SHARED_CODE_BASE +#define __NE2000_SHARED_CODE_BASE +typedef unsigned int uint; +typedef struct snic snic; +typedef struct nic_stat nic_stat; +typedef struct buffer_header buffer_header; +typedef struct packet_buffer packet_buffer; +typedef struct nic_error_stat nic_error_stat; + +/* internal implementation procedures */ +int nic_probe(int addr); +int nic_dump_prom(snic *nic, unsigned char *prom); +void nic_overrun(snic *nic); +void nic_tx(snic *nic); +void nic_tx_err(snic *nic); +void nic_rx(snic *nic); +void nic_counters(snic *nic); +void nic_get_header(snic *nic, uint page, buffer_header *header); +int nic_send(snic *nic, uint buf); +void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset); +void nic_block_output(snic *nic, unsigned char *buf, uint len, uint page); + +#define PSTART 0x20 /* if NE2000 is byte length */ +#define PSTOP 0x40 +#define PSTARTW 0x40 /* if NE2000 is wordlength */ +#define PSTOPW 0x80 +#define MAX_LOAD 12 /* maximum services per IRQ request*/ +#define MAX_RX 10 /* maximum packets recieve per call*/ +#define MIN_LENGTH 60 /* minimum length for packet data */ +#define MAX_LENGTH 1500 /* maximum length for packet data area */ +#define TIMEOUT_DMAMATCH 40 /* for nic_block_input() */ +#define TIMEOUT_TX 40 + +/* DP8390 NIC Registers*/ +#define COMMAND 0x00 +#define STATUS COMMAND+0 +#define PHYSICAL COMMAND+1 /* page 1 */ +#define MULTICAST COMMAND+8 /* page 1 */ +#define PAGESTART COMMAND+1 /* page 0 */ +#define PAGESTOP COMMAND+2 +#define BOUNDARY COMMAND+3 +#define TRANSMITSTATUS COMMAND+4 +#define TRANSMITPAGE COMMAND+4 +#define TRANSMITBYTECOUNT0 COMMAND+5 +#define NCR COMMAND+5 +#define TRANSMITBYTECOUNT1 COMMAND+6 +#define INTERRUPTSTATUS COMMAND+7 +#define CURRENT COMMAND+7 /* page 1 */ +#define REMOTESTARTADDRESS0 COMMAND+8 +#define CRDMA0 COMMAND+8 +#define REMOTESTARTADDRESS1 COMMAND+9 +#define CRDMA1 COMMAND+9 +#define REMOTEBYTECOUNT0 COMMAND+10 /* how many bytes we will */ +#define REMOTEBYTECOUNT1 COMMAND+11 /* read through remote DMA->IO */ +#define RECEIVESTATUS COMMAND+12 +#define RECEIVECONFIGURATION COMMAND+12 +#define TRANSMITCONFIGURATION COMMAND+13 +#define FAE_TALLY COMMAND+13 /* page 0 */ +#define DATACONFIGURATION COMMAND+14 +#define CRC_TALLY COMMAND+14 +#define INTERRUPTMASK COMMAND+15 +#define MISS_PKT_TALLY COMMAND+15 + +/* NE2000 specific implementation registers */ +#define NE_RESET 0x1f /* Reset */ +#define NE_DATA 0x10 /* Data port (use for PROM) */ + +#define PAR0 COMMAND+1 +#define PAR1 COMMAND+2 +#define PAR2 COMMAND+3 +#define PAR3 COMMAND+4 +#define PAR4 COMMAND+5 +#define PAR5 COMMAND+6 + +/* NIC Commands */ +#define NIC_STOP 0x01 /* STOP */ +#define NIC_START 0x02 /* START */ +#define NIC_PAGE0 0x00 +#define NIC_PAGE1 0x40 +#define NIC_PAGE2 0x80 +#define NIC_TRANSMIT 0x04 /* Transmit a frame */ +#define NIC_REM_READ 0x08 /* Remote Read */ +#define NIC_REM_WRITE 0x10 /* Remote Write */ +#define NIC_DMA_DISABLE 0x20 /* Disable DMA */ + +/* Data Configuration Register */ +#define DCR_WTS 0x01 /* Word Transfer Select (0=byte, 1=word) */ +#define DCR_BOS 0x02 /* Byte Order Select (0=big-endian) */ +#define DCR_LAS 0x04 /* Long Address Select (0=dual 16-bit DMA) */ +#define DCR_LS 0x08 /* Loopback Select (0=loopback) */ +#define DCR_AR 0x10 /* Auto Initialize Remote */ +#define DCR_FT 0x60 /* (FT0 & FT1) FIFO Threshhold (see datasheet) */ +/*#define DCR_DEFAULT 0x58 /* Standard value for the DCR register */ +#define DCR_DEFAULT 0x48 /* don't use Automatic send packet */ +#define DCR_DEFAULT_WORD 0x49 /* defuault with wold length transfer */ + +/* Recieve Configure Register */ +#define RCR_SEP 0x01 /* Save Errored Packets */ +#define RCR_AR 0x02 /* Accept Runt Packets */ +#define RCR_AB 0x04 /* Accept Broadcast */ +#define RCR_AM 0x08 /* Accept Multicast */ +#define RCR_PRO 0x10 /* Promiscuous Physical */ +#define RCR_MON 0x20 /* Monitor Mode */ +/*#define RCR_DEFAULT 0x00 /* Standard value for the RCR register */ +#define RCR_DEFAULT 0x0c /* Accept Broadcast/Multicast Packets */ + +/* Recieve Status Register */ +/* note, this is also stored in the status byte in the buffer header. */ +/* That's the 4 byte entry in the local buffer, not the packet header. */ +#define RSR_PRX 0x01 /* Pakcet Received Intact */ +#define RSR_CRC 0x02 /* CRC Error */ +#define RSR_FAE 0x04 /* Frame Alignment Error */ +#define RSR_FO 0x08 /* FIFO Overrun */ +#define RSR_MPA 0x10 /* Missed Packet */ +#define RSR_PHY 0x20 /* Physical/Multicast Address (0=physical) */ +#define RSR_DIS 0x40 /* Receiver Disabled */ +#define RSR_DFR 0x80 /* Deferring */ + +/* Transmit Configure Register */ +#define TCR_CRC 0x01 /* Inhibit CRC (0=CRC active) */ +#define TCR_LB 0x06 /* (LB0 & LB1) Encoded Loopback Control */ +#define TCR_ATD 0x08 /* Auto Transmit Disable (0=normal) */ +#define TCR_OFST 0x10 /* Collision Offset Enable (1=low priority) */ +#define TCR_DEFAULT 0x00 /* Standard value for the TCR register */ +#define TCR_INTERNAL_LOOPBACK 0x02 /* Internal loopback configuration */ + +/* Transmit Status Register */ +#define TSR_PTX 0x01 /* Packet Transmitted */ +#define TSR_ND 0x02 /* Non-Deferral (Documented???) */ +#define TSR_COL 0x04 /* Transmit Collided */ +#define TSR_ABT 0x08 /* Transmit Aborted */ +#define TSR_CRS 0x10 /* Carrier Sense Lost */ +#define TSR_FU 0x20 /* FIFO Underrun */ +#define TSR_CDH 0x40 /* CD Heartbeat */ +#define TSR_OWC 0x80 /* Oout of Window Collision */ + +/* Interrupt Status Register */ +#define ISR_PRX 0x01 /* Packet Received */ +#define ISR_PTX 0x02 /* Packet Transmitted */ +#define ISR_RXE 0x04 /* Receive Error */ +#define ISR_TXE 0x08 /* Transmit Error */ +#define ISR_OVW 0x10 /* Overwrite Warning */ +#define ISR_CNT 0x20 /* Counter Overflow */ +#define ISR_RDC 0x40 /* Remote DMA Complete */ +#define ISR_RST 0x80 /* Reset Status */ +#define ISR_DEFAULT 0x00 /* Standard value for the ISR register */ +#define ISR_ALL 0x3f /* The services that we handle in the isr */ + +/* Interrupt Mask Register */ +#define IMR_PRXE 0x01 /* Packet Received Interrupt Enable */ +#define IMR_PTXE 0x02 /* Packet Transmitted Interrupt Enable */ +#define IMR_RXEE 0x04 /* Receive Error Interrupt Enable */ +#define IMR_TXEE 0x08 /* Transmit Error Interrupt Enable */ +#define IMR_OVWE 0x10 /* Overwrite Warning Interrupt Enable */ +#define IMR_CNTE 0x20 /* Counter Overflow Interrupt Enable */ +#define IMR_RDCE 0x40 /* DMA Complete Interrupt Enable */ +#define IMR_DEFAULT 0x3f /* CNTE | OVWE | TXEE | RXEE | PTXE | PRXE */ + +#endif diff --git a/netboot/ne2k.h b/netboot/ne2k.h @@ -0,0 +1,103 @@ +/* $Id: //depot/blt/netboot/ne2k.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __NE2000_INTERFACE +#define __NE2000_INTERFACE +#ifndef __NE2000_SHARED_CODE_BASE +typedef unsigned int uint; +typedef struct snic snic; +typedef struct nic_stat nic_stat; +typedef struct buffer_header buffer_header; +typedef struct packet_buffer packet_buffer; +typedef struct nic_error_stat nic_error_stat; +#endif /* NE2000_SHARED_CODE_BASE */ + +#define LEN_ADDR 6 +#define MAX_TX 2 /* be careful with this (dual buffers) */ +#define MAX_PAGESPERPACKET 6 +#define TXPAGES (MAX_TX*MAX_PAGESPERPACKET) +#define LEN_PROM 16 +#define LEN_HEADER 14 + +#ifdef __CPP_BINDING +extern "C" { +#endif + +/* external interface */ +int nic_detect(int given); +int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual); +void nic_register_notify(snic *nic, void (*newnotify)(packet_buffer *newpacket)); +void nic_start(snic *nic, int promiscuous); +void nic_stop(snic *nic); +void nic_isr(snic *nic); +nic_stat nic_get_stats(snic *nic); +void nic_stat_clear(nic_stat *that); +int nic_send_packet(snic *nic, packet_buffer*); + +/* Your implementation */ +packet_buffer *alloc_buffer(uint size); +void free_buffer(packet_buffer *ptr); + +#ifdef __CPP_BINDING +}; +#endif + +struct buffer_header { + unsigned char status; + unsigned char next; + unsigned short count; /* length of header and packet */ +}; + +struct nic_error_stat { + long frame_alignment, crc, missed_packets; + long rx, rx_size, rx_dropped, rx_fifo, rx_overruns; + long tx_collisions; + long tx_aborts, tx_carrier, tx_fifo, tx_heartbeat, tx_window; +}; + +struct nic_stat { + long rx_packets; + long tx_buffered, tx_packets; + nic_error_stat errors; +}; + +struct packet_buffer { + uint len; + uint page; + unsigned char *ptr; +}; + +struct snic { + int iobase; /* NULL if uninitialized */ + int pstart, pstop, wordlength, current_page; + nic_stat stat; + void (*notify)(packet_buffer *newpacket); + packet_buffer tx_packet[MAX_TX], *last_tx; + char busy, send; +}; + +#endif /* __NE2000_INTERFACE */ diff --git a/netboot/net.h b/netboot/net.h @@ -0,0 +1,173 @@ +/* $Id: //depot/blt/netboot/net.h#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#pragma pack(2) + +/* +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +*/ + +typedef struct +{ + uint8 dst[6]; + uint8 src[6]; + uint16 type; +} net_ether; + +typedef struct +{ + uint8 ip_hdr_len:4; + uint8 ip_version:4; + uint8 ip_tos; + uint16 ip_len; + + uint16 ip_id; + uint16 ip_off; + + uint8 ip_ttl; + uint8 ip_proto; + uint16 ip_chk; + + uint32 ip_src; + uint32 ip_dst; +} net_ip; + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 + +#define IP_TOS_MIN_DELAY 0x10 +#define IP_TOS_MAX_THRU 0x08 +#define IP_TOS_MAX_RELY 0x04 +#define IP_TOS_MIN_COST 0x02 + +#define IP_FLAG_CE 0x8000 +#define IP_FLAG_DF 0x4000 +#define IP_FLAG_MF 0x2000 +#define IP_FLAG_MASK 0x1FFF + +typedef struct +{ + uint16 udp_src; + uint16 udp_dst; + + uint16 udp_len; + uint16 udp_chk; +} net_udp; + +typedef struct +{ + uint8 icmp_type; + uint8 icmp_code; + uint16 icmp_chk; +} net_icmp; + +typedef struct +{ + net_icmp ping_icmp; + uint16 ping_id; + uint16 ping_seq; +} net_icmp_ping; + +typedef struct +{ + uint16 arp_hard_type; + uint16 arp_prot_type; + uint8 arp_hard_size; + uint8 arp_prot_size; + uint16 arp_op; + uint8 arp_enet_sender[6]; + uint32 arp_ip_sender; + uint8 arp_enet_target[6]; + uint32 arp_ip_target; +} net_arp; + +#define ARP_OP_REQUEST 1 +#define ARP_OP_REPLY 2 +#define RARP_OP_REQUEST 3 +#define RARP_OP_REPLY 4 + +/* yeah, ugly as shit */ +#define ntohs(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) ) +#define htons(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) ) +#define ntohl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) ) +#define htonl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) ) + +/* +typedef struct +{ + uint32 ip; + uint16 flags; + uint8 hw[6]; +} net_arp_table; + +typedef struct +{ + uint32 dest; + uint32 gw; + uint32 mask; + uint16 flags; + net_iface *iface; +} net_route_table; + + +typedef struct +{ + char name[8]; + uint32 addr; + uint32 bcast; + uint32 mask; + uint16 flags; + uint16 mtu; + uint32 metric; + + uint32 stat_rx_packets; + uint32 stat_rx_errors; + uint32 stat_rx_dropped; + uint32 stat_rx_overruns; + + uint32 stat_tx_packets; + uint32 stat_tx_errors; + uint32 stat_tx_dropped; + uint32 stat_tx_overruns; + + void (*send)(void); + void (*init)(void); + void (*add_proto)(net_proto *proto, uint16 id); + +} net_iface; + +#define IF_UP 0x0001 +#define IF_BROADCAST 0x0002 +#define IF_PROMISC 0x0004 +#define IF_LOOPBACK 0x0008 +#define IF_MULTICAST 0x0010 +#define IF_RUNNING 0x0020 +*/ diff --git a/netboot/netboot.c b/netboot/netboot.c @@ -0,0 +1,701 @@ +/* $Id: //depot/blt/netboot/netboot.c#8 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "string.h" + +#include <blt/conio.h> + +#include "net.h" +#include "boot.h" + +#define NULL ((void *) 0) + +#include "ne2k.h" +#include "io.h" + +snic TheSNIC; + +int nic_addr = 0x300; + +char blah[1500]; /* inbound packet buffer */ + +char defaults[] = "ip=0.0.0.0"; + +char zz[] = "128.174.38.207"; + +char param[80]; + +extern char end[]; + +#define printf cprintf + +int got_server = 0; + +int id = 1; + +int memsize = 0; + +int reset = 0; + +int got_ip = 0; +char *ipmsg = ""; + +unsigned char prom[32]; + +unsigned char ip0[8] = { 'i', 'p', '=', 0, 0, 0, 0, 0 }; +unsigned char *ip = ip0 + 3; + +unsigned char server_ip[4] = { 0, 0, 0, 0 }; +unsigned char server_mac[6] = { 0, 0, 0, 0, 0, 0 }; +unsigned short port = 0; + +#define SKIP 0 +#define LHS 1 +#define RHS 2 + +void read_ip(char *s, unsigned char *ip) +{ + int i=4; + int v; + + for(i=4;i>0;i--,ip++){ + v = 0; + while(*s && *s != '.') { + v = v*10 + *s-'0'; + s++; + } + *ip = v; + if(!*s) break; + s++; + } +} + +void option(char *lhs, char *rhs) +{ + if(!strcmp(lhs,"ip")){ + read_ip(rhs,ip); + ipmsg = "(manual)"; + return; + } +/* if(!strcmp(lhs,"server")){ + read_ip(rhs,server_ip); + return; + } + if(!strcmp(lhs,"gateway")){ + read_ip(rhs,gateway_ip); + return; + } + if(!strcmp(lhs,"port")){ + port = 0; + while(*rhs){ + port = port*10 + *rhs - '0'; + rhs++; + } + } */ + printf("netboot: option %s=\"%s\" unknown\n",lhs,rhs); +} + +void parse(char *p) +{ + int state = SKIP; + char *lhs; + char *rhs; + + while(*p){ + switch(state){ + case SKIP : + if(*p > ' '){ + lhs = p; + state = LHS; + } else { + p++; + break; + } + case LHS : + if(*p == '='){ + *p = 0; + rhs = ++p; + state = RHS; + } else { + p++; + } + break; + case RHS : + if(*p <= ' '){ + *p = 0; + option(lhs,rhs); + state = SKIP; + } + p++; + break; + } + } + if(state == RHS){ + option(lhs,rhs); + } +} + +#define ESC 27 +#define BS 8 +#define TAB 9 +#define CR 13 + +char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r', + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR, ' ', + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n', + 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '}; +char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*', + '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR, ' ', + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N', + 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '}; +#define LSHIFT 42 +#define RSHIFT 54 + +char linebuf[80]; +int lp; + + +void newline(void) +{ + memcpy(linebuf,"netboot> ",9); + + for(lp=9;lp<79;lp++) linebuf[lp]=' '; + linebuf[79]=0; + lp = 9; + con_goto(0,24); + con_puts(linebuf); + +} + +int command(char *cmd) +{ + if(cmd[0] == 'g' && cmd[1] == 'o' && cmd[2] == 0) return 1; + + if(cmd[0] == 'b' && cmd[1] == 'o' && cmd[2] == 'o' && + cmd[3] == 't' && cmd[4] == '='){ + char *p = param; + cmd+=5; + while(*cmd) { + *p = *cmd; + cmd++; + p++; + } + *p = 0; + return 0; + + } + + parse(cmd); + + return 0; +} + +int keypress(int key) +{ + switch(key){ + case ESC: + for(lp=9;lp<79;lp++) linebuf[lp]=' '; + lp = 9; + break; + case CR: + printf("\n"); + linebuf[lp]=0; + if(command(linebuf+9)) return 1; + newline(); + break; + case BS: + if(lp > 9){ + linebuf[lp-1]=' '; + lp--; + } + break; + default: + if(lp < 79){ + linebuf[lp]=key; + lp++; + } + break; + } + con_goto(0,24); + con_puts(linebuf); + return 0; +} + +/* keyboard crap */ +int console(void) +{ + int key; + int shift = 0; + newline(); + + for(;;){ + while(inb(0x64) & 0x01) { + key = inb(0x60); + + switch(key){ + case LSHIFT: + case RSHIFT: + shift = 1; + break; + case LSHIFT | 0x80: + case RSHIFT | 0x80: + shift = 0; + break; + default: + if(key & 0x80){ + /* break */ + } else { + if(key < 59){ + key = shift ? ShiftTable[key] : ScanTable[key]; + if(keypress(key)) return 1; + } + } + } + } + } +} + + + +/* end keyboard crap */ +packet_buffer *alloc_buffer(uint size) +{ + static packet_buffer pb; + + pb.len = size; + pb.page = 0; + pb.ptr = (unsigned char *) blah; + return &pb; +} + +void free_buffer(packet_buffer *ptr) +{ + int i; + return; +} + +int ticks = 0; + +void idle(void) +{ + int i; + for(i=0;i<10000;i++); + ticks++; +} + +int memcmp(const void *dst, const void *src, size_t size) +{ + while(size) { + if(*(((unsigned char *) dst)++) != *(((unsigned char *) src)++)) + return 1; + size--; + } + return 0; +} + +void *memcpy(void *dst, const void *src, size_t size) +{ + while(size) { + *(((unsigned char *) dst)++) = *(((unsigned char *) src)++); + size--; + } + return NULL; /* XXX */ +} + +typedef struct +{ + net_ether ether; + net_arp arp; +} arp_packet; + +typedef struct +{ + net_ether ether; + net_ip ip; +} ip_packet; + +typedef struct +{ + net_ether ether; + net_ip ip; + net_udp udp; +} udp_packet; + +#include "netboot.h" + +typedef struct +{ + net_ether ether; + net_ip ip; + net_udp udp; + net_boot boot; +} netboot_packet; + + +int ipchksum(unsigned short *ip, int len) +{ + unsigned long sum = 0; + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return((~sum) & 0x0000FFFF); +} + +static netboot_packet nbr; + +void handle_udp(udp_packet *pkt) +{ + packet_buffer pbuf; + +/* printf("handle_udp: %d -> %d, l=%d, ck=%d\n", + ntohs(pkt->udp.udp_src), + ntohs(pkt->udp.udp_dst), + ntohs(pkt->udp.udp_len), + ntohs(pkt->udp.udp_chk));*/ + + if(ntohs(pkt->udp.udp_dst) == NETBOOT_PORT){ + netboot_packet *nb = (netboot_packet *) pkt; + unsigned int addr = ntohs(nb->boot.blk) * 1024 + NETBOOT_BASE; + + if(ntohs(nb->boot.cmd) != NETBOOT_CMD_LOAD && + ntohs(nb->boot.cmd) != NETBOOT_CMD_EXEC){ + printf("netboot: invalid command %d\n", + ntohs(nb->boot.cmd)); + return; + } + + if(!got_server){ + memcpy(&server_mac,&(pkt->ether.src),6); + memcpy(&server_ip,&(pkt->ip.ip_src),4); + printf("netboot: server %d.%d.%d.%d @ %X:%X:%X:%X:%X:%X\n", + server_ip[0],server_ip[1],server_ip[2],server_ip[3], + server_mac[0],server_mac[1],server_mac[2],server_mac[3], + server_mac[4],server_mac[5]); + got_server = 1; + } + if(ntohs(nb->boot.cmd) == NETBOOT_CMD_LOAD){ +/* printf("netboot: loading 1024 bytes, net -> 0x%x\n", + addr);*/ + if(addr == NETBOOT_BASE) { + printf("loading "); + } else { + printf("."); + } + + memcpy(((void *) addr), &(nb->boot.data), 1024); + } + + memcpy(&(nbr.ether.src),&(prom),6); + memcpy(&(nbr.ether.dst),&(server_mac),6); + nbr.ether.type = ntohs(0x0800); + + memcpy(&(nbr.ip.ip_src),&ip,4); + memcpy(&(nbr.ip.ip_dst),&(server_ip),4); + nbr.ip.ip_hdr_len = 5; + nbr.ip.ip_version = 4; + nbr.ip.ip_tos = 0; + nbr.ip.ip_len = ntohs(20+8+8); + nbr.ip.ip_id = ntohs(id++); + nbr.ip.ip_off = 0; + nbr.ip.ip_ttl = 128; + nbr.ip.ip_proto = IP_PROTO_UDP; + nbr.ip.ip_chk = 0; + nbr.ip.ip_chk = ipchksum(&(nbr.ip),sizeof(net_ip)); + + nbr.udp.udp_dst = pkt->udp.udp_src; + nbr.udp.udp_src = pkt->udp.udp_dst; + nbr.udp.udp_chk = 0; + nbr.udp.udp_len = ntohs(8 + 4); + + nbr.boot.cmd = htons(NETBOOT_CMD_ACK); + nbr.boot.blk = nb->boot.blk; + pbuf.ptr = (unsigned char *) &nbr; + pbuf.page = 0; + pbuf.len = 14 + 20 + 8 + 4; + + if(ntohs(nb->boot.cmd) == NETBOOT_CMD_EXEC){ + boot_dir *bd = (boot_dir *) NETBOOT_BASE; + volatile void (*start)(int, char *, boot_dir *) = + bd->bd_entry[1].be_code_ventr + + 0x1000 + NETBOOT_BASE; + + printf("\nnetboot: executing at 0x%x\n", (int) start); + start(memsize, param[0] ? param : (char *) ip0, bd); + asm("hlt"); + } else { + nic_send_packet(&TheSNIC, &pbuf); + } + + } +} + + +void handle_ip(ip_packet *pkt) +{ + unsigned char *src = (unsigned char *) &( pkt->ip.ip_src ); + unsigned char *dst = (unsigned char *) &( pkt->ip.ip_dst ); + int i; + +/* printf("handle_ip: IP: %d.%d.%d.%d -> %d.%d.%d.%d\n", + src[0],src[1],src[2],src[3], + dst[0],dst[1],dst[2],dst[3]);*/ + + if(!memcmp(dst,ip,4)){ + if(ipchksum(&(pkt->ip),sizeof(net_ip))) { + return; + } +/* printf("handle_ip: for me? whoah!\n");*/ + if(pkt->ip.ip_proto == IP_PROTO_UDP) handle_udp((udp_packet *) pkt); + + } + +} + +void print_arp(unsigned char *p); + + +unsigned char bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +unsigned char zilch[6] = { 0, 0, 0, 0, 0, 0 }; + +void issue_rarp_request(void) +{ + arp_packet req; + packet_buffer pbuf; + + req.ether.type = htons(0x8035); + memcpy(&(req.ether.src),prom,6); + memcpy(&(req.ether.dst),bcast,6); + req.arp.arp_hard_type = htons(1); + req.arp.arp_prot_type = htons(0x0800); + req.arp.arp_hard_size = 6; + req.arp.arp_prot_size = 4; + req.arp.arp_op = htons(RARP_OP_REQUEST); + memcpy(&(req.arp.arp_enet_sender),prom,6); + memcpy(&(req.arp.arp_ip_sender),bcast,4); + memcpy(&(req.arp.arp_enet_target),prom,6); + memcpy(&(req.arp.arp_ip_target),bcast,4); + + pbuf.ptr = (unsigned char *) &req; + pbuf.page = 0; + pbuf.len = sizeof(arp_packet); + nic_send_packet(&TheSNIC, &pbuf); +} + +void handle_rarp(arp_packet *req) +{ + unsigned char *x; + + if(htons(req->arp.arp_op) == RARP_OP_REPLY){ + if(!memcmp(&(req->arp.arp_enet_target),prom,6)){ + if(memcmp(&(req->arp.arp_ip_target),ip,4)){ + x = &(req->arp.arp_ip_target); + ip[0] = x[0]; + ip[1] = x[1]; + ip[2] = x[2]; + ip[3] = x[3]; + got_ip = 1; + ipmsg = "(RARP'd)"; + reset = 1; + } + } + } +} + +void handle_arp(arp_packet *req) +{ + if(htons(req->arp.arp_op) == ARP_OP_REQUEST){ + if(!memcmp(&(req->arp.arp_ip_target),ip,4)){ + packet_buffer pbuf; + arp_packet resp; +/* printf("handle_arp: IS the one!\n");*/ +/* printf("handle_arp: replying to arp request\n"); */ + memcpy(&(resp.ether.src),prom,6); + memcpy(&(resp.ether.dst),&(req->ether.src),6); + resp.ether.type = htons(0x0806); + resp.arp.arp_hard_type = htons(1); + resp.arp.arp_prot_type = htons(0x0800); + resp.arp.arp_hard_size = 6; + resp.arp.arp_prot_size = 4; + resp.arp.arp_op = htons(ARP_OP_REPLY); + memcpy(&(resp.arp.arp_enet_sender),prom,6); + memcpy(&(resp.arp.arp_ip_sender),ip,4); + memcpy(&(resp.arp.arp_enet_target),&(req->arp.arp_enet_sender),6); + memcpy(&(resp.arp.arp_ip_target),&(req->arp.arp_ip_sender),4); +/* print_arp((unsigned char *) &(resp.arp));*/ + pbuf.ptr = (unsigned char *) &resp; + pbuf.page = 0; + pbuf.len = sizeof(arp_packet); + nic_send_packet(&TheSNIC, &pbuf); + } else { +/* printf("handle_arp: NOT the one.\n"); */ + } + return; + } +} + +void print_arp(unsigned char *p) +{ +#ifdef ARP_DEBUG + net_arp *arp = (net_arp *) p; + unsigned char *b; + unsigned short t; + + printf(" ARP: "); + t = htons(arp->arp_op); + if(t == ARP_OP_REQUEST) printf("req "); + else if(t == ARP_OP_REPLY) printf("rep "); + else printf("??? "); + + b = (unsigned char *) &(arp->arp_enet_sender); + printf("source: %X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]); + b = (unsigned char *) &(arp->arp_ip_sender); + printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]); + + printf(" ARP: target: "); + + b = (unsigned char *) &(arp->arp_enet_target); + printf("%X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]); + b = (unsigned char *) &(arp->arp_ip_target); + printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]); +#endif +} + + +void receive(packet_buffer *packet) +{ + unsigned char *b = packet->ptr; + int i; + + if(b[12] == 0x80 && b[13] == 0x35) { + handle_rarp((arp_packet *) b); + return; + } + if(b[12] != 0x08) return; /* ignore non IP/ARP packets */ + + if(b[12] == 0x08 && b[13] == 0x06) { +/* print_arp(b+14);*/ + handle_arp((arp_packet *) b); + return; + } + + if(b[12] == 0x08 && b[13] == 0x00) { + handle_ip((ip_packet *) b); + return; + } +} + +void find_8390(int *addr); + +extern char *blagh; + +void main(int mem) +{ + int i,mono; + int nh; + char buf[128]; + int snic_irq = 3; + char *x; + + memsize = mem; + param[0] = 0; + + mono = (((*((unsigned char *) 0x410)) & 0x30) == 0x30); + + parse(defaults); + + find_8390(&nic_addr); + + ipmsg = "(default)"; + ip[0] = ip[1] = ip[2] = ip[3] = 10; + + for(;;){ + reset = 0; + + TheSNIC.iobase = 0; + nic_init(&TheSNIC, nic_addr, prom, NULL); + + con_start( mono ? 0xB0000 : 0xB8000); + + if(!mono){ + con_fgbg(CON_WHITE, CON_BLUE /*WHITE,CON_BLUE*/); + } +/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */ + printf("\n"); + printf(" ## ## ###### ###### ###### ##### ##### ######\n"); + printf(" ### ## ## ## ## ## ## ## ## ## ##\n"); + printf(" ## # ## ##### ## ###### ## ## ## ## ##\n"); + printf(" ## ### ## ## ## ## ## ## ## ## ## Version 1.5\n"); + printf(" ## ## ###### ## ###### ##### ##### ## " __DATE__); + + if(!mono){ + con_fgbg(CON_WHITE,CON_BLACK); + } + printf("\n\n\n"); + printf("0x00090000 - bootloader start\n"); + printf("0x%x - bootloader end\n", (int) end); + printf("0x00100000 - target load address\n"); + printf("0x%x - top of memory\n",mem); + printf("\n"); + + printf("NE2000 @ 0x%S (%X:%X:%X:%X:%X:%X)\n", nic_addr, + prom[0],prom[1],prom[2],prom[3],prom[4],prom[5]); + + printf("ip = %d.%d.%d.%d %s\n",ip[0],ip[1],ip[2],ip[3], + ipmsg); + if(param[0]) printf("boot = \"%s\"\n",param); + + nic_register_notify(&TheSNIC,receive); + + nic_start(&TheSNIC,0); + + printf("\nready. (ESC for console)\n"); + + if(!got_ip){ + issue_rarp_request(); + issue_rarp_request(); + issue_rarp_request(); + } + + while(!reset){ + nic_isr(&TheSNIC); + if(inb(0x64) & 0x01) { + if(inb(0x60) == 1){ + con_fgbg(CON_YELLOW,CON_BLACK); + if(console()) break; + } + } + } + nic_stop(&TheSNIC); + } +} diff --git a/netboot/netboot.h b/netboot/netboot.h @@ -0,0 +1,43 @@ +/* $Id: //depot/blt/netboot/netboot.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#pragma pack(2) + +typedef struct +{ + unsigned short cmd; + unsigned short blk; + unsigned char data[1024]; +} net_boot; + +#define NETBOOT_CMD_LOAD 1 +#define NETBOOT_CMD_EXEC 2 +#define NETBOOT_CMD_ACK 3 + +#define NETBOOT_PORT 4242 + +#define NETBOOT_BASE 0x00100000 diff --git a/netboot/netrom.asm b/netboot/netrom.asm @@ -0,0 +1,265 @@ + + +; 0x02000 [dword] Memory Size +; 0x02004 [dword] ptable addr +; 0x03000 page table +; +; 0x80000 reloc addr +; +; 0x90000 prot mode targ +; 0x93FFF + +memamt equ 0x2000 +ptaddr equ 0x2004 +entry equ 0x90000 +romsize equ 0x4000 + + bits 16 + +rom_start: + dw 0xaa55 ; rom signature + db 0x20 ; rom size (512 byte units) + jmp short s1 ; entrypoint + db 0x42 ; checksum (dummy) + + times 0x18 - ($ - rom_start) db 0 + + dw pci_header ; PCI Header Offset + dw 0x0000 ; PNP Gunk + +pci_header: + db 'PCIR' + dw 0x10ec ; vendor + dw 0x8029 ; device + dw 0x0000 ; vital data + dw 0x0018 ; length + db 0 ; pci_header version (0) + db 0 ; protocol + db 0 ; subclass (ethernet) + db 2 ; class (network) + dw 0x0000 ; image length + dw 0x0000 ; revision + db 0 ; code type (x86) + db 0x80 ; indicates this is last image + dw 0x0000 ; reserved + +s1: + push ds ; hook into the boot sequence + + xor ax, ax + mov ds, ax + + mov word [0x19 * 4], start + mov word [0x19 * 4 + 2], cs + + pop ds + retf + +start: + cli + cld + + xor di,di ; relocate to 8000:0000 + xor si,si + + mov ax,0x8000 + mov es,ax + + mov cx,romsize/4 + cs + rep + movsd + + xor ax,ax + mov ss,ax + mov sp,0xfffc + + mov ax,0x8000 + mov ds,ax + + jmp 0x8000:start_reloc + +start_reloc: + +; mov ax, 0x4f02 ; VESA Gunk +; mov bx, (0x8000 + 0x4000 + 0x105) +; int 0x10 + + call enableA20 + + lgdt [unGDT] + + mov eax,cr0 + or al, 1 + mov cr0, eax + +; jump dword 0x8:(0x80000 + setsegs) + db 0x66, 0xea + dw setsegs + dw 0x0008 + dw 0x0008 + +setsegs: + mov bx,0x10 + mov ds,bx + mov es,bx + mov ss,bx + + and al,0xfe + mov cr0, eax + + jmp 0x8000:newip + +newip: + xor ax,ax + mov es,ax + mov ds,ax + mov ss,ax + + mov edi,0x90000 ; relocate rom to just below 1MB + mov esi, eof + 0x80000 + mov ecx, romsize/4 + rep a32 movsd + + call countmemory + + mov dword [memamt], eax + mov dword [ptaddr], 0x3000 + +; make some pages tables + mov ecx, eax + shr ecx, 12 + mov edi, [ptaddr] + add ecx, 0x1000/4 + + xor eax, eax + rep a32 stosd + + mov ebx, [ptaddr] + mov ecx, [memamt] + + shr ecx, 12 + mov eax, 0x0003 + mov edi, 0x1000 + +l1: + mov [ebx+edi],eax + add eax, 0x1000 + add edi, 4 + loop l1 + + mov ecx, [memamt] + shr ecx, 22 + inc ecx + + mov eax, [ptaddr] + add eax, 0x1003 + xor edi, edi + +l2: + mov [ebx+edi], eax + mov [ebx+edi+0xf00], eax + add eax, 0x1000 + add edi, 4 + loop l2 + + + mov eax, [ptaddr] + mov ecx, eax + or al, 3 + + mov [ebx+0xffc], eax + + mov ebx, 0x90000 + +goprot: + push dword 0x0002 + popfd + + lgdt [cs:GDT] + + mov cr3, ecx + mov eax, 0x80000001 + mov cr0, eax + +; jmp far prot + db 0x66, 0xea + dw 0x0000 + prot, 0x0008, 0x0008 + +prot: + bits 32 + + mov eax, 0x10 + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + + mov esp, ecx + sub esp, 4 + + push dword [memamt] ; memory amount + + call ebx + jmp $ + + align 8 + +unGDT: + dw 0xffff, unGDT + 0x0000, 0x0008, 0x0000 ; offset unGDT + db 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0x8f, 0x00 ; kCS (0x08) CPL0 + db 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00 ; kDS (0x10) + +GDT: + dw 0xffff, GDT + 0x0000, 0x0008, 0x0000 ; offset GDT + db 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 ; kCS (0x08) + db 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 ; kDS (0x10) + + bits 16 + +enableA20: + call enableA20o1 + jnz short enableA20done + mov al,0xd1 + out 0x64,al + call enableA20o1 + jnz short enableA20done + mov al,0xdf + out 0x60,al +enableA20o1: + mov ecx,0x20000 +enableA20o1l: + jmp short enableA20next +enableA20next: + in al,0x64 + test al,2 + loopnz enableA20o1l +enableA20done: + ret + +countmemory: + mov ax, '12' + mov ebx, 0x100ff0 + +b0: + mov dx, [ebx] ; save contents + mov [ebx], ax ; write signature + + mov di, [ebx] ; read back + mov [ebx], dx ; restore contents + + cmp di, ax ; did it stick? + jnz b1 ; nope, no more memory + + add ebx, 0x1000 + jmp b0 + +b1: + mov eax, ebx + sub eax, 0x1000 + add eax, 0x10 + + ret + +eof: diff --git a/netboot/netrom.bin b/netboot/netrom.bin Binary files differ. diff --git a/netboot/pci.c b/netboot/pci.c @@ -0,0 +1,67 @@ +#include <blt/types.h> +#include <i386/io.h> + + +typedef struct confadd +{ + uchar reg:8; + uchar func:3; + uchar dev:5; + uchar bus:8; + uchar rsvd:7; + uchar enable:1; +} confadd; + +uint32 pci_read(int bus, int dev, int func, int reg, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + outl(u.n,0xCF8); + + base = 0xCFC + (reg & 0x03); + + switch(bytes){ + case 1: return inb(base); + case 2: return inw(base); + case 4: return inl(base); + default: return 0; + } +} + +void find_8390(int *addr) +{ + union { + struct { + uint16 vendor; + uint16 device; + } id; + uint32 n; + } u; + uint32 n; + int bus; + int dev; + + for(bus=0;bus<8;bus++){ + for(dev=0;dev<32;dev++){ + u.n = pci_read(bus, dev, 0, 0, 4); + if((u.id.vendor == 0x10ec) && (u.id.device == 0x8029)){ + n = pci_read(bus, dev, 0, 0x10, 4); + n &= 0xFFF0; + *addr = (int) n; + return; + } + } + } +} diff --git a/srv/Makefile b/srv/Makefile @@ -0,0 +1,6 @@ +BLTHOME := ../ +include $(BLTHOME)make.conf + +SUBDIRS := namer console2 ne2000 vfs init fish ide window pci + +include $(BLTHOME)make.actions diff --git a/srv/console2/Makefile b/srv/console2/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := console.c vt100.c +CRT0 := $(BLTHOME)lib/crtb.o +BINARY := console.bin +LIBS := -lconsole -lblt -lc + +include $(BLTHOME)make.actions diff --git a/srv/console2/console.c b/srv/console2/console.c @@ -0,0 +1,368 @@ +/* $Id: //depot/blt/srv/console2/console.c#15 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <blt/syscall.h> +#include <blt/error.h> +#include <blt/namer.h> +#include <blt/conio.h> +#include <blt/qsem.h> +#include <i386/io.h> +#include <string.h> + +#include "vt100.h" + +int console_port = -1; +int send_port = -1; +int remote_port = -1; + +volatile int ready = 0; + +#define CLEAR "\033[2J" +#define FG_BLACK "\033[30m" +#define FG_BLUE "\033[31m" +#define FG_GREEN "\033[32m" +#define FG_CYAN "\033[33m" +#define FG_RED "\033[34m" +#define FG_PURPLE "\033[35m" +#define FG_BROWN "\033[36m" +#define FG_WHITE "\033[37m" + +#define BG_BLACK "\033[40m" +#define BG_BLUE "\033[41m" +#define BG_GREEN "\033[42m" +#define BG_CYAN "\033[43m" +#define BG_RED "\033[44m" +#define BG_PURPLE "\033[45m" +#define BG_BROWN "\033[46m" +#define BG_WHITE "\033[47m" + + +#define MONOx + +#ifdef MONO +#define SCREEN 0xB0000 +#else +#define SCREEN 0xB8000 +#endif +void *screen = (void *) SCREEN; + +void movecursor (int x, int y) +{ + int offset; + + offset = 80 * y + x; + outb (0xe, 0x3d4); + outb (offset / 256, 0x3d5); + outb (0xf, 0x3d4); + outb (offset % 256, 0x3d5); +} + +struct virtscreen con[10]; +struct virtscreen statbar; +struct virtscreen *active; + +void move_cursor(struct virtscreen *cur) +{ + if(cur == active) movecursor(cur->xpos,cur->ypos); +} + +void vprintf(struct virtscreen *vscr, char *fmt, ...); +void printf(char *fmt, ...); + +void keypress(int key) +{ + char c; + + sem_acquire(active->lock); + char_to_virtscreen(active, key); + sem_release(active->lock); + if(remote_port > 0) { + c = key; + port_send(send_port, remote_port, &c, 1, 0); + } +} + +void vputs(struct virtscreen *vscr, char *s) +{ + sem_acquire(vscr->lock); + while(*s) { + char_to_virtscreen(vscr, *s); + if(*s == '\n') char_to_virtscreen(vscr, '\r'); + s++; + } + sem_release(vscr->lock); +} + + +void printf(char *fmt, ...) +{ + static char line[128]; + va_list pvar; + va_start(pvar,fmt); + va_snprintf(line,128,fmt,pvar); + line[127]=0; + va_end(pvar); + vputs(active,line); +} + +void vprintf(struct virtscreen *vscr, char *fmt, ...) +{ + static char line[128]; + va_list pvar; + va_start(pvar,fmt); + va_snprintf(line,128,fmt,pvar); + line[127]=0; + va_end(pvar); + vputs(vscr,line); +} + +void status(int n) +{ + vprintf(&statbar,FG_WHITE BG_BLUE CLEAR "### OpenBLT Console mkII ### VC %d",n); +} + +#define ESC 27 +#define BS 8 +#define TAB 9 +#define CR 13 +#define LF 10 + +char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r', + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', LF, ' ', + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n', + 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '}; +char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*', + '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', LF, ' ', + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N', + 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '}; +#define LSHIFT 42 +#define RSHIFT 54 +#define CONTROL 0x1d +#define ALT 0x38 + +#define F1 0x3b +#define F2 0x3c +#define F3 0x3d +#define F4 0x3e +#define F5 0x3f +#define F6 0x40 +#define F7 0x41 +#define F8 0x42 +#define F9 0x43 +#define F10 0x44 + +void movecursor (int x, int y); +void keypress(int key); + +void save(struct virtscreen *vscr) +{ + sem_acquire(vscr->lock); + if(vscr->data != vscr->back) { + memcpy(vscr->back,vscr->data,vscr->num_bytes); + vscr->data = vscr->back; + } + sem_release(vscr->lock); +} + +void load(struct virtscreen *vscr) +{ + sem_acquire(vscr->lock); + if(vscr->data == vscr->back) { + vscr->data = screen; + memcpy(vscr->data,vscr->back,vscr->num_bytes); + } + active = vscr; + movecursor(vscr->xpos,vscr->ypos); + sem_release(vscr->lock); + status(vscr - con); +} + +void function(int number) +{ + save(active); + active = &con[number]; + load(active); +} + +void keyboard_irq_thread(void) +{ + int shift = 0; + int control = 0; + int alt = 0; + + int key; + + os_handle_irq(1); + + for(;;) { + os_sleep_irq(); +#ifdef MULTI + while(inb(0x64) & 0x01) { +#endif + key = inb(0x60); + if(alt && (key == 1)) { + save(active); + os_debug(); + load(active); + alt = 0; + continue; + } + + switch(key){ + case F1: + case F2: + case F3: + case F4: + case F5: + case F6: + case F7: + case F8: + case F9: + case F10: + function(key - F1); + break; + + case ALT: + alt = 1; + break; + case ALT | 0x80: + alt = 0; + break; + case CONTROL: + control = 1; + break; + case CONTROL | 0x80: + control = 0; + break; + case LSHIFT: + case RSHIFT: + shift = 1; + break; + case LSHIFT | 0x80: + case RSHIFT | 0x80: + shift = 0; + break; + default: + if(key & 0x80){ + /* break */ + } else { + if(key < 59){ + if(control){ + key = ScanTable[key]; + if(key >= 'a' && key <= 'z'){ + keypress(key - 'a' + 1); + } + } else { + key = shift ? ShiftTable[key] : ScanTable[key]; + keypress(key); + } + } + } + } +#ifdef MULTI + } +#endif + } + +} + +void console_thread(void) +{ + int l, src; + uint32 code; + char data[257]; + +#ifdef CONSOLE_DEBUG + vprintf(active, "console: " FG_GREEN "listener ready" FG_WHITE " (port %d)\n",console_port); +#endif + + while((l = port_recv(console_port, &src, data, 256, &code)) >= 0){ + if(code == 0) { + remote_port = src; + } else { + data[l] = 0; + vputs(active, data); + } + } + vprintf(active, "console: output listener has left the building (%d)\n",l); + os_terminate(0); +} + +int console_main(void) +{ + int err,i; + area_create(0x2000, 0, &screen, AREA_PHYSMAP); + + console_port = port_create(0,"console_listen_port"); + send_port = port_create(0,"console_send_port"); + port_option(send_port, PORT_OPT_NOWAIT, 1); + + err = namer_register(console_port,"console"); + + init_virtscreen(&statbar, 1, 80); + statbar.back = statbar.data; + statbar.data = (unsigned short *) (((uint32) screen) + 80*24*2); + statbar.lock = sem_create(1,"statbar_lock"); + + for(i=0;i<10;i++){ + init_virtscreen(&con[i], 24, 80); + con[i].back = con[i].data; + con[i].lock = sem_create(1,"vscr_lock"); + vputs(&con[i],CLEAR); + } + load(&con[0]); + + status(0); + if(err) vprintf(active,"console: the namer hates us\n"); + else +#ifdef CONSOLE_DEBUG + vprintf(active,"console: " FG_GREEN "online." FG_WHITE "\n"); +#else + ; +#endif + + thr_create(keyboard_irq_thread, NULL, "console:kbd"); + ready = 1; + console_thread(); + + return 0; +} + +int main(void) +{ + thr_create(console_main, NULL, "console:main"); + while(!ready) ; + return 0; +} + diff --git a/srv/console2/vt100.c b/srv/console2/vt100.c @@ -0,0 +1,464 @@ +/* $Id: //depot/blt/srv/console2/vt100.c#1 $ */ +/* VT100 Engine Copyright 1997 Daniel Marks <dmarks@uiuc.edu> */ + +#include "vt100.h" +#include <stdlib.h> + +#define STRICT_VT100 + +/* struct virtscreen newscr; */ + +void std_interpret_char(struct virtscreen *cur, unsigned char ch); +void std_interpret_ansi(struct virtscreen *cur, unsigned char ch); +void special_reading_ansi(struct virtscreen *cur, unsigned char ch); +void special_ansi_charset_0(struct virtscreen *cur, unsigned char ch); +void special_ansi_charset_1(struct virtscreen *cur, unsigned char ch); + +void clear_region(struct virtscreen *cur, int y1, int x1, int y2, int x2, int atrb); + +int init_virtscreen(struct virtscreen *cur, int rows, int columns) +{ + + cur->num_bytes = ((sizeof(unsigned short) * rows * columns)); + + if (!(cur->data=malloc(cur->num_bytes))) + return (-1); + + cur->data_off_scr = cur->data; + + cur->bottom_scroll = cur->rows = rows; + cur->columns = columns; + cur->cur_ansi_number = cur->top_scroll = 0; + cur->ansi_elements = cur->ansi_reading_number = 0; + cur->next_char_send = std_interpret_char; + cur->old_attrib = cur->attrib = 0x07; + cur->next_char_send = std_interpret_char; + clear_region(cur,0,0,rows-1,columns-1,cur->attrib); + cur->old_xpos = cur->old_ypos = 0; + + return (0); +} + +void clear_region(struct virtscreen *cur, int y1, int x1, int y2, int x2, int atrb) +{ + ushort *ch = loc_in_virtscreen(cur,y1,x1); + ushort *tr = loc_in_virtscreen(cur,y2,x2); + int dt = 0x20 | (atrb << 8); + + while (ch<=tr) + *ch++ = dt; +} + +void clear_virtscreen(struct virtscreen *cur, int mode) +{ + switch (mode) + { + case 0: clear_region(cur,cur->ypos,cur->xpos, + cur->rows-1,cur->columns-1,cur->attrib); + break; + case 1: clear_region(cur,0,0,cur->ypos,cur->xpos,cur->attrib); + break; + default: clear_region(cur,0,0,cur->rows-1,cur->columns-1,cur->attrib); + cur->xpos = cur->ypos = 0; + break; + } +} + +void clear_to_eol(struct virtscreen *cur, int mode) +{ + switch(mode) + { + case 0: + clear_region(cur,cur->ypos,cur->xpos,cur->ypos, + cur->columns-1,cur->attrib); + break; + case 1: + clear_region(cur,cur->ypos,0,cur->ypos,cur->xpos, + cur->attrib); + break; + default: + clear_region(cur,cur->ypos,0,cur->ypos,cur->columns-1, + cur->attrib); + } +} + + +void move_cursor(struct virtscreen *cur); +/* +{ +} +*/ + +void position_console(struct virtscreen *cur, int ypos, int xpos, int rel) +{ + if (rel) + { + cur->xpos += xpos; + cur->ypos += ypos; + } else + { + cur->xpos = xpos; + cur->ypos = ypos; + } + if (cur->xpos < 0) cur->xpos = 0; + if (cur->xpos >= cur->columns) cur->xpos = cur->columns-1; + if (cur->ypos < 0) cur->ypos = 0; + if (cur->ypos >= cur->rows) cur->ypos = cur->rows-1; + move_cursor(cur); +} + +void delete_chars_in_line(struct virtscreen *cur, int char_move) +{ + ushort *next_move; + ushort *end_move; + ushort *start_move; + ushort clr_with; + + clr_with = (cur->attrib << 8) | 0x20; + start_move = loc_in_virtscreen(cur,cur->ypos,cur->xpos); + end_move = loc_in_virtscreen(cur,cur->ypos,cur->columns); + if ((cur->xpos + char_move) < cur->columns) + { + next_move = loc_in_virtscreen(cur,cur->ypos,cur->xpos+char_move); + while (next_move<end_move) + *start_move++ = *next_move++; + } + while (start_move<end_move) *start_move++ = clr_with; +} + +void scroll_virt_up_at_cursor(struct virtscreen *cur, int dir) +{ + ushort clr_with; + ushort *beginScr; + ushort *endofScr; + ushort *lastLine; + ushort *nextLine; + unsigned int real_scroll_length; + + if ((cur->ypos >= cur->top_scroll) && + (cur->ypos < cur->bottom_scroll)) + { + clr_with = (cur->attrib << 8) | 0x20; + beginScr = loc_in_virtscreen(cur,cur->ypos,0); + endofScr = loc_in_virtscreen(cur,cur->bottom_scroll,0); + lastLine = endofScr - cur->columns; + nextLine = beginScr + cur->columns; + real_scroll_length = ((unsigned int) lastLine) - + ((unsigned int) beginScr); + + if (dir) + { + memmove(beginScr,nextLine,real_scroll_length); + while (lastLine < endofScr) + *lastLine++ = clr_with; + } else + { + memmove(nextLine,beginScr,real_scroll_length); + while (beginScr < nextLine) + *beginScr++ = clr_with; + } + } +} + +void scroll_virtscreen(struct virtscreen *cur) + { + int clr_with = (cur->attrib << 8) | 0x20; + ushort *beginScr = loc_in_virtscreen(cur,cur->top_scroll,0); + ushort *endofScr = loc_in_virtscreen(cur,cur->bottom_scroll,0); + ushort *lastLine = endofScr - cur->columns; + ushort *nextLine = beginScr + cur->columns; + unsigned int real_scroll_length = ((unsigned int) lastLine) - + ((unsigned int) beginScr); + + memmove(beginScr,nextLine,real_scroll_length); + while (lastLine < endofScr) + *lastLine++ = clr_with; + }; + +void set_scroll_region(struct virtscreen *cur, int low, int high) +{ + low--; + high = (high >= cur->rows) ? cur->rows : high; + low = (low < 0) ? 0 : low; + + cur->top_scroll = low; + cur->bottom_scroll = high; +} + +void change_attribute(struct virtscreen *cur, int attrib) +{ + cur->attrib = attrib; +} + +void change_character(struct virtscreen *cur, int ch) +{ + *(loc_in_virtscreen(cur,cur->ypos,cur->xpos)) = + ch | (cur->attrib << 8); +} + +void special_ansi_charset_0(struct virtscreen *cur, unsigned char ch) +{ + cur->next_char_send = std_interpret_char; +} + +void special_ansi_charset_1(struct virtscreen *cur, unsigned char ch) +{ + cur->next_char_send = std_interpret_char; +} + +void std_interpret_ansi(struct virtscreen *cur, unsigned char ch) +{ + switch (ch) + { + case '(': cur->next_char_send = special_ansi_charset_0; + return; + case ')': cur->next_char_send = special_ansi_charset_1; + return; + case '[': cur->cur_ansi_number = 0; + cur->ansi_elements = 0; + cur->ansi_reading_number = 0; + cur->next_char_send = special_reading_ansi; + return; + case '7': cur->old_attrib = cur->attrib; + cur->old_xpos = cur->xpos; + cur->old_ypos = cur->ypos; + break; + case '8': change_attribute(cur,cur->old_attrib); + position_console(cur,cur->ypos,cur->xpos,0); + break; + case 'E': cur->xpos = 0; + case 'D': cur->ypos++; + if (cur->ypos >= cur->bottom_scroll) + { + scroll_virtscreen(cur); + cur->ypos--; + } + move_cursor(cur); + break; + case 'M': cur->ypos--; + if (cur->ypos < cur->top_scroll) + { + cur->ypos++; + scroll_virt_up_at_cursor(cur,0); + } + move_cursor(cur); + break; /* recalculate screen pos */ + } + if (ch != 27) + cur->next_char_send = std_interpret_char; +} + +void std_interpret_char(struct virtscreen *cur, unsigned char ch) +{ + switch (ch) + { + case 27: cur->next_char_send = std_interpret_ansi; + return; + case 12: clear_virtscreen(cur,2); + break; + case 13: cur->xpos = 0; /* return = back to begin */ + break; + case 10: cur->ypos++; + if (cur->ypos >= cur->bottom_scroll) + /* if we're at bottom */ + { + if (cur->ypos == cur->bottom_scroll) + scroll_virtscreen(cur); /* and scroll it! */ + cur->ypos--; /* go back up a line */ + } + cur->xpos=0; + break; + case 9: position_console(cur,cur->ypos,cur->xpos+(8-(cur->xpos % 8)),0); + break; + case 8: cur->xpos--; /* backspace on screen */ + if (cur->xpos<0) + { + cur->xpos = cur->columns - 1; + cur->ypos; + if (cur->ypos<0) + cur->ypos=0; + } + break; + default: if (!ch) + break; + change_character(cur,ch); + cur->xpos++; + if (cur->xpos >= cur->columns) + { +#ifdef STRICT_VT100 + cur->xpos = cur->columns-1; +#else + cur->xpos = 0; + cur->ypos++; + if (cur->ypos == cur->bottom_scroll) + { + cur->ypos--; + scroll_virtscreen(cur); + } +#endif + } + break; + } + move_cursor(cur); +} + +void special_reading_ansi(struct virtscreen *cur, unsigned char ch) +{ + if ((ch>='0') && (ch<='9')) + { + cur->cur_ansi_number = (cur->cur_ansi_number * 10) + (ch - '0'); + cur->ansi_reading_number = 1; + return; + } + + if ((cur->ansi_reading_number) || (ch == ';')) + { + if (cur->ansi_elements<MAX_ANSI_ELEMENTS) + cur->ansi_element[cur->ansi_elements++] = cur->cur_ansi_number; + cur->ansi_reading_number = 0; + } + cur->cur_ansi_number = 0; + switch (ch) + { + case '?': + case ';': return; + case 'D': position_console(cur,0,(cur->ansi_elements) ? + -cur->ansi_element[0] : -1,1); + break; + case 'a': + case 'C': position_console(cur,0,(cur->ansi_elements) ? + cur->ansi_element[0] : 1,1); + break; + case 'A': position_console(cur,(cur->ansi_elements) ? + -cur->ansi_element[0] : -1,0,1); + break; + case 'e': + case 'B': position_console(cur,(cur->ansi_elements) ? + cur->ansi_element[0] : 1,0,1); + break; + case '`': + case 'G': + { + int temp = cur->ansi_elements ? cur->ansi_element[0] : 1; + if (temp) + temp--; + position_console(cur,cur->ypos,temp,0); + } + break; + case 'E': position_console(cur,cur->ypos + + ((cur->ansi_elements) ? cur->ansi_element[0] : 1), + 0,0); + break; + case 'F': position_console(cur,cur->ypos - + ((cur->ansi_elements) ? cur->ansi_element[0] : 1), + 0,0); + break; + case 'd': + { + int temp = cur->ansi_elements ? cur->ansi_element[0] : 1; + if (temp) + temp--; + position_console(cur,temp,cur->xpos,0); + } + break; + case 'f': + case 'H': + { + int row = (cur->ansi_elements > 0) ? cur->ansi_element[0] : 1; + int col = (cur->ansi_elements > 1) ? cur->ansi_element[1] : 1; + if (row) + row--; + if (col) + col--; + position_console(cur,row,col,0); + } + break; + case 'J': clear_virtscreen(cur,(cur->ansi_elements) ? + cur->ansi_element[0]: 0); + break; + case 'L': { + int lines = (cur->ansi_elements) ? + cur->ansi_element[0] : 1; + while (lines>0) + { + scroll_virt_up_at_cursor(cur,0); + lines--; + } + } + break; + case 'M': { + int lines = (cur->ansi_elements) ? + cur->ansi_element[0] : 1; + while (lines>0) + { + scroll_virt_up_at_cursor(cur,1); + lines--; + } + } + break; + case 'P': delete_chars_in_line(cur,(cur->ansi_elements) ? + cur->ansi_element[0] : 1); + break; + case 'K': clear_to_eol(cur,cur->ansi_elements ? + cur->ansi_element[0] : 0); + break; + case 's': cur->old_xpos = cur->xpos; + cur->old_ypos = cur->ypos; + break; + case 'u': position_console(cur,cur->old_ypos,cur->old_xpos,0); + break; + case 'r': { + int low = (cur->ansi_elements > 0) ? + cur->ansi_element[0] : 1; + int high = (cur->ansi_elements > 1) ? + cur->ansi_element[1] : cur->rows; + if (low<=high) + set_scroll_region(cur,low,high); + } + break; + case 'm': + { + int count = 0; + int cthing; + if (!cur->ansi_elements) + change_attribute(cur,0x07); + while (count < cur->ansi_elements) + { + cthing = cur->ansi_element[count]; + switch (cthing) + { + case 0: + case 27: change_attribute(cur,0x07); + break; + case 1: change_attribute(cur,cur->attrib | 0x08); + break; + case 5: change_attribute(cur,cur->attrib | 0x80); + break; + case 7: change_attribute(cur,0x70); + break; + case 21: + case 22: change_attribute(cur,cur->attrib & 0xF7); + break; + case 25: change_attribute(cur,cur->attrib & 0x7F); + break; + default: + if ((cthing>=30) && (cthing<=37)) + { + change_attribute(cur,(cur->attrib & 0xF8) | (cthing-30)); + } + if ((cthing>=40) && (cthing<=47)) + { + change_attribute(cur,(cur->attrib & 0x8F) | + ((cthing-40) << 4)); + } + break; + } + count++; + } + } + break; + + } + cur->next_char_send = std_interpret_char; +} + diff --git a/srv/console2/vt100.h b/srv/console2/vt100.h @@ -0,0 +1,45 @@ +/* $Id: //depot/blt/srv/console2/vt100.h#4 $ */ +/* VT100 Engine Copyright 1997 Daniel Marks <dmarks@uiuc.edu> */ + +#ifndef _VT_100_H +#define _VT_100_H + +#include <blt/qsem.h> + +typedef unsigned short ushort; + +#define loc_in_virtscreen(cur,y,x) (((cur)->data)+(((y)*((cur)->columns))+(x))) +#define MAX_ANSI_ELEMENTS 16 +#define char_to_virtscreen(cur,ch) (((cur)->next_char_send)((cur),(ch))) + +struct virtscreen +{ + int rows; + int columns; + int num_bytes; + ushort *data; + ushort *back; + ushort *data_off_scr; + + int xpos; + int ypos; + int top_scroll; + int bottom_scroll; + int attrib; + int old_attrib; + int old_xpos; + int old_ypos; + + int cur_ansi_number; + int ansi_elements; + int ansi_reading_number; + int ansi_element[MAX_ANSI_ELEMENTS]; + + void (*next_char_send)(struct virtscreen *cur, unsigned char ch); + + int lock; +}; + + +int init_virtscreen(struct virtscreen *cur, int rows, int columns); +#endif /* _VT_100_h */ diff --git a/srv/fb/Makefile b/srv/fb/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := pci.c fb.c mga1x64.c +CRT0 := $(BLTHOME)lib/crt0.o +BINARY := fb.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/srv/fb/fb.c b/srv/fb/fb.c @@ -0,0 +1,46 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdarg.h> +#include <blt/syscall.h> +#include "fb.h" + +#define SERIAL_DEBUG 0 + +void va_snprintf(char *b, int l, char *fmt, va_list pvar); + + +void dprintf(const char *fmt, ...) +{ + char buf[256]; + va_list ap; + va_start(ap,fmt); + va_snprintf(buf,256,fmt,ap); + va_end(pvar); +#if SERIAL_DEBUG + os_console(buf); +#else + printf(buf); + printf("\n"); +#endif +} + +extern fb_info fb_mga1x64; + +int main (int argc, char **argv) +{ + void *cookie; + fb_info *fb = &fb_mga1x64; + + if(fb->find(&cookie) == 0){ + printf("Frame Buffer \"%s\" found.\n",fb->name); + fb->init(cookie); + } + + return 0; +} + diff --git a/srv/fb/fb.h b/srv/fb/fb.h @@ -0,0 +1,21 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _FB_H +#define _FB_H + +#include <blt/types.h> + +void dprintf(const char *fmt, ...); + +typedef struct fb_info +{ + const char *name; + int32 (*find)(void **cookie); + int32 (*init)(void *cookie); +} fb_info; + +#endif diff --git a/srv/fb/mga1x64.c b/srv/fb/mga1x64.c @@ -0,0 +1,67 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include "pci.h" +#include "fb.h" + +#include <stdlib.h> +#include <blt/syscall.h> + +#include "mga1x64.h" + + +static int32 mga_find(void **cookie) +{ + pci_cfg cfg; + mga1x64 *mga; + int i; + + if(pci_find(&cfg,VENDOR,DEVICE)) return -1; + + dprintf("mga_find(): card @ %d/%d/%d",cfg.bus,cfg.dev,cfg.func); + + if(!(mga = (mga1x64*) malloc(sizeof(mga1x64)))) return -1; + *cookie = mga; + + mga->regs = (uint32 *) (cfg.base[REGS] & 0xfffffff0); + if(area_create(0x4000, 0, (void**) &(mga->regs), AREA_PHYSMAP) < 0){ + dprintf("mga_find(): CANNOT MAP REGISTERS!?"); + free(mga); + return -1; + } + + mga->fb = (uchar *) (cfg.base[FB] & 0xfffffff0); + mga->fbsize = 0x100000; + if(area_create(mga->fbsize, 0, (void**) &(mga->fb), AREA_PHYSMAP) < 0){ + dprintf("mga_find(): CANNOT MAP FRAMEBUFFER!?"); + free(mga); + return -1; + } + + dprintf("mga_find(): registers @ %xv, %xp", + mga->regs,cfg.base[REGS]&0xfffffff0); + dprintf("mga_find(): framebuffer @ %xv, %xp (sz %x)", + mga->fb,cfg.base[FB]&0xfffffff0,mga->fbsize); + + dprintf("mga_find(): FIFOSTATUS = %x",RD(FIFOSTATUS)); + + return 0; +} + +static int32 mga_init(void *cookie) +{ + mga1x64 *mga = (mga1x64*) cookie; + + dprintf("mga_init()"); +} + +fb_info fb_mga1x64 = +{ + "MGA-1x64", + &mga_find, + &mga_init +}; + diff --git a/srv/fb/mga1x64.h b/srv/fb/mga1x64.h @@ -0,0 +1,30 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _MGA_1X64_H +#define _MGA_1X64_H + +#define VENDOR 0x102b +#define DEVICE 0x051a + +typedef struct mga1x64 +{ + volatile uint32 *regs; + volatile uchar *fb; + int32 fbsize; +} mga1x64; + +/* base registers to use */ +#define REGS 1 +#define FB 2 + +/* registers */ +#define FIFOSTATUS 0x1e10 + +#define RD(r) (mga->regs[(r)/4]) +#define WR(r,v) (mga->regs[(r)/4] = v) + +#endif diff --git a/srv/fb/pci.c b/srv/fb/pci.c @@ -0,0 +1,157 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> + +#include <i386/io.h> + +#include "pci.h" + +typedef struct +{ + uchar reg:8; + uchar func:3; + uchar dev:5; + uchar bus:8; + uchar rsvd:7; + uchar enable:1; +} confadd; + +uint32 pci_read(int bus, int dev, int func, int reg, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + outl(u.n,0xCF8); + + base = 0xCFC + (reg & 0x03); + + switch(bytes){ + case 1: return inb(base); + case 2: return inw(base); + case 4: return inl(base); + default: return 0; + } +} + +void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + base = 0xCFC + (reg & 0x03); + outl(u.n,0xCF8); + switch(bytes){ + case 1: outb(v,base); break; + case 2: outw(v,base); break; + case 4: outl(v,base); break; + } + +} + +int pci_probe(int bus, int dev, int func, pci_cfg *cfg) +{ + uint32 *word = (uint32 *) cfg; + uint32 v; + int i; + for(i=0;i<4;i++){ + word[i] = pci_read(bus,dev,func,4*i,4); + } + if(cfg->vendor_id == 0xffff) return 1; + + cfg->bus = bus; + cfg->dev = dev; + cfg->func = func; +#if 0 + printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func); + printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n", + cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface); + printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n", + cfg->status, cfg->command, cfg->bist, cfg->header_type, + cfg->latency_timer, cfg->cache_line_size); +#endif + + switch(cfg->header_type & 0x7F){ + case 0: /* normal device */ + for(i=0;i<6;i++){ + v = pci_read(bus,dev,func,i*4 + 0x10, 4); + if(v) { + int v2; + pci_write(bus,dev,func,i*4 + 0x10, 0xffffffff, 4); + v2 = pci_read(bus,dev,func,i*4+0x10, 4) & 0xfffffff0; + pci_write(bus,dev,func,i*4 + 0x10, v, 4); + v2 = 1 + ~v2; + if(v & 1) { +// printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff); + cfg->base[i] = v & 0xffff; + cfg->size[i] = v2 & 0xffff; + } else { +// printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2); + cfg->base[i] = v; + cfg->size[i] = v2; + } + } else { + cfg->base[i] = 0; + cfg->size[i] = 0; + } + + } + v = pci_read(bus,dev,func,0x3c,1); +// if((v != 0xff) && (v != 0)) printf(" * Interrupt Line: %X\n",v); + break; + case 1: +// printf(" * PCI <-> PCI Bridge\n"); + break; + default: +// printf(" * Unknown Header Type\n"); + } + return 0; +} + +int pci_find(pci_cfg *cfg, uint16 vendor_id, uint16 device_id) +{ + int bus,dev,func; + + for(bus=0;bus<255;bus++){ + for(dev=0;dev<32;dev++) { + if(pci_probe(bus,dev,0,cfg)) continue; + if((cfg->vendor_id == vendor_id) && + (cfg->device_id == device_id)) return 0; + if(cfg->header_type & 0x80){ + for(func=1;func<8;func++){ + if(!pci_probe(bus,dev,func,cfg) && + (cfg->vendor_id == vendor_id) && + (cfg->device_id == device_id)) return 0; + } + } + } + } +} + diff --git a/srv/fb/pci.h b/srv/fb/pci.h @@ -0,0 +1,49 @@ +/* $Id$ +** +** Copyright 1999 Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _PCI_H +#define _PCI_H + +#include <blt/types.h> + +typedef struct +{ + /* normal header stuff */ + uint16 vendor_id; + uint16 device_id; + + uint16 command; + uint16 status; + + uint8 revision_id; + uint8 interface; + uint8 sub_class; + uint8 base_class; + + uint8 cache_line_size; + uint8 latency_timer; + uint8 header_type; + uint8 bist; + + /* device info */ + uint8 bus; + uint8 dev; + uint8 func; + uint8 _pad; + + /* base registers */ + uint32 base[6]; + uint32 size[6]; + +} pci_cfg; + +int pci_find(pci_cfg *cfg, uint16 vendor_id, uint16 device_id); + +uint32 pci_read(int bus, int dev, int func, int reg, int bytes); +void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes); + + +#endif diff --git a/srv/fish/Makefile b/srv/fish/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := fish.c vga.c +BINARY := fish.bin +LIBS := -lblt -lc + +include $(BLTHOME)make.actions + diff --git a/srv/fish/dfp.h b/srv/fish/dfp.h @@ -0,0 +1,127 @@ +/* $Id: //depot/blt/srv/fish/dfp.h#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* +** Distributed Fish Protocol +** Version 1.0 +** +** Special Interest Group for Operating Systems +** Association for Computing Machinery +** University of Illinios at Urbana-Champaign +*/ + +#ifndef _DFP_H +#define _DFP_H + +#ifdef _WIN32 +#include <sys/types.h> +#include <winsock.h> +#endif + +#ifdef NEED_TYPES +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +#endif +typedef char sint8; + +#define DFP_VERSION 0x0201 + +#define DEFAULT_DFP_PORT 5049 + +#define DFP_MIN_SUBTANK_X 0 +#define DFP_MAX_SUBTANK_X 3 +#define DFP_MIN_SUBTANK_Y 0 +#define DFP_MAX_SUBTANK_Y 3 + +#define DFP_PKT_PING 0 +#define DFP_PKT_PONG 1 +#define DFP_PKT_SEND_FISH 2 +#define DFP_PKT_ACK_FISH 3 +#define DFP_PKT_NACK_FISH 4 +#define DFP_PKT_SYNC_FISH 5 + +/* pack everything along byte boundaries */ +#pragma pack( 1 ) + +typedef struct +{ + uint16 version; + uint8 src_tank_x; + uint8 src_tank_y; + uint8 dst_tank_x; + uint8 dst_tank_y; + uint8 type; /* one of DFP_PKT_* */ + uint8 pad; /* should be 0 */ + uint16 size; /* size of entire packet */ +} dfp_base; + +typedef struct +{ + uint8 creator_tank_x; + uint8 creator_tank_y; + uint8 timestamp[4]; +} dfp_uid; + +typedef struct +{ + uint8 x; + uint8 y; + sint8 dx; + sint8 dy; + uint16 ttl; + uint8 name[16]; +} dfp_fish; + + +#define DFP_SIZE_LOCATE 10 +#define DFP_SIZE_CONFIRM 16 +#define DFP_SIZE_TRANSFER 38 + + +typedef struct +{ + dfp_base base; +} dfp_pkt_locate; + +typedef struct +{ + dfp_base base; + dfp_uid uid; +} dfp_pkt_confirm; + +typedef struct +{ + dfp_base base; + dfp_uid uid; + dfp_fish fish; +} dfp_pkt_transfer; + +/* restore default packing */ +#pragma pack() + +#endif /* __DFP_H */ diff --git a/srv/fish/fish.c b/srv/fish/fish.c @@ -0,0 +1,1020 @@ +/* Copyright 1998-1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <i386/io.h> +#include <blt/namer.h> +#include <blt/syscall.h> + +#include "dfp.h" +#include "vga.h" + +static int WITH_NET = 1; + +void keythread(void); + +int myX = 2; +int myY = 2; + +int st_sent = 0; +int st_recv = 0; +int st_rej = 0; +int st_count = 0; +int sticky = 0; +int collision = 0; +int snooze = 5; + +int logsize = 15; + + +int borg = 0; +int logo = 0; +int logging = 1; +int recluse = 0; +int ticks = 0; + +#define LOGGING +#define TIMEOUT 8 + +#define MAXKEYS 64 +static char keybuf2[MAXKEYS+4]; +static char *keybuf = keybuf2+2; +static int keyptr = 0; + +int port_fish, port_net, port_console, port_net_xmit; + +static char kpbuf[512]; +static char *kp = kpbuf; +static char *x; + +typedef struct _msg +{ + struct _msg *next; + char buf[65]; +} msg; +msg *first_msg = NULL, *last_msg = NULL; +int msgcount = 0; + +int sem_fish = 0, sem_msgs = 0; + +void lprintf(char *fmt,...) +{ +#ifdef LOGGING + va_list pvar; + int n; + msg *m = (msg *) malloc(sizeof(msg)); + + va_start(pvar,fmt); + va_snprintf(m->buf,64,fmt,pvar); + va_end(pvar); + + m->buf[60]=0; + m->next = NULL; + sem_acquire(sem_msgs); + msgcount++; + if(last_msg){ + last_msg->next = m; + last_msg = m; + } else { + first_msg = last_msg = m; + } + sem_release(sem_msgs); +#endif +} + +#define DEAD 0 +#define LIVE 1 +#define XMIT 2 +typedef struct _fish +{ + struct _fish *next, *prev; + int x,y; + int dx,dy; + char name[17]; + char *bitmap; + int state; + int xt; + dfp_pkt_transfer xfer; + int dest; +} fish; + +fish *first = NULL; +fish *last = NULL; + + +struct +{ + int live; + int tx, ty; +} cnxn[4] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }; + +#define C_UP 0 +#define C_DN 1 +#define C_LF 2 +#define C_RT 3 +#define NET_CONNECT 1 +#define NET_SEND 2 +#define NET_IP 3 + +void settank(int tx, int ty, int live) +{ + int i; + for(i=0;i<4;i++){ + if(cnxn[i].tx == tx && cnxn[i].ty == ty){ + cnxn[i].live = live; + return; + } + } +} + + +typedef struct +{ + int cmd; + int port; +} net_cmd; + +typedef struct +{ + net_cmd cmd; + dfp_pkt_transfer dfp; +} net_fish; + +void newfish(int x, int y, int dx, int dy, char *n); + +void pingtank(int tx, int ty) +{ + if(WITH_NET){ + net_fish f; + msg_hdr_t msg; + f.cmd.cmd = NET_SEND; + f.cmd.port = 5049; + f.dfp.base.src_tank_x = myX; + f.dfp.base.src_tank_y = myY; + f.dfp.base.dst_tank_x = tx; + f.dfp.base.dst_tank_y = ty; + f.dfp.base.size = htons(DFP_SIZE_LOCATE); + f.dfp.base.type = DFP_PKT_PING; + f.dfp.base.pad = 0; + f.dfp.base.version = htons(DFP_VERSION); + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = sizeof(dfp_base)+8; + msg.data = &f; + old_port_send(&msg); + } +} + +void initiate(dfp_pkt_transfer *send, int tx, int ty) +{ + if(WITH_NET){ + net_fish f; + msg_hdr_t msg; + f.cmd.cmd = NET_SEND; + f.cmd.port = 5049; + f.dfp.base.src_tank_x = myX; + f.dfp.base.src_tank_y = myY; + f.dfp.base.dst_tank_x = tx; + f.dfp.base.dst_tank_y = ty; + f.dfp.base.size = ntohs(DFP_SIZE_TRANSFER); + f.dfp.base.type = DFP_PKT_SEND_FISH; + f.dfp.base.pad = 0; + f.dfp.base.version = htons(DFP_VERSION); + memcpy(&(f.dfp.uid), &(send->uid), 6); + memcpy(&(f.dfp.fish), &(send->fish), sizeof(dfp_fish)); + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = DFP_SIZE_TRANSFER + 8; + msg.data = &f; + old_port_send(&msg); + } + +} + +char *types[] = { "PING", "PING", "SEND", "ACK", "NACK", "SYNC" }; + +void dofish(dfp_pkt_transfer *dfp) +{ + int i; + + net_fish f; + fish *ff; + char n2[17]; + msg_hdr_t msg; + dfp->base.version = ntohs(dfp->base.version); + dfp->base.size = ntohs(dfp->base.size); + + if(!(dfp->base.dst_tank_x == myX && dfp->base.dst_tank_y == myY)){ + return; + } + + + if(dfp->base.type == DFP_PKT_SYNC_FISH) lprintf("fish: s(%d,%d) d(%d,%d) s=%d %s", + dfp->base.src_tank_x, dfp->base.src_tank_y, + dfp->base.dst_tank_x, dfp->base.dst_tank_y, + dfp->base.size, + dfp->base.type < 6 ? types[dfp->base.type] : "????" + ); + + switch(dfp->base.type){ + case DFP_PKT_PING : + f.cmd.cmd = NET_SEND; + f.cmd.port = 5049; + f.dfp.base.src_tank_x = myX; + f.dfp.base.src_tank_y = myY; + f.dfp.base.dst_tank_x = dfp->base.src_tank_x; + f.dfp.base.dst_tank_y = dfp->base.src_tank_y; + f.dfp.base.size = htons(DFP_SIZE_LOCATE); + f.dfp.base.type = DFP_PKT_PONG; + f.dfp.base.pad = 0; + f.dfp.base.version = htons(DFP_VERSION); + settank(dfp->base.src_tank_x,dfp->base.src_tank_y,1); + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = sizeof(dfp_base)+8; + msg.data = &f; + old_port_send(&msg); + + + break; + + case DFP_PKT_PONG : + lprintf("Pong from %d,%d",dfp->base.src_tank_x,dfp->base.src_tank_y); + settank(dfp->base.src_tank_x,dfp->base.src_tank_y,1); +/* for(i=0;i<4;i++){ + if((cnxn[i].tx == dfp->base.src_tank_x) && + (cnxn[i].ty == dfp->base.src_tank_y)) { + cnxn[i].live = 1; + break; + } + }*/ + break; + + case DFP_PKT_SEND_FISH : + dfp->fish.ttl = ntohs(dfp->fish.ttl); + strncpy(n2,dfp->fish.name,16); + n2[16]=0; + if(recluse){ + lprintf("Ignoring \"%s\" from (%d,%d)",n2, + dfp->base.src_tank_x, dfp->base.src_tank_y); + break; + } + /* lprintf(" : UID %X%X%X%X%X%X @(%d,%d) d(%d,%d) ttl=%d, name=\"%s\"", + dfp->uid.creator_tank_x, dfp->uid.creator_tank_y, + dfp->uid.timestamp[0], dfp->uid.timestamp[1], + dfp->uid.timestamp[2], dfp->uid.timestamp[3], + dfp->fish.x, dfp->fish.y, dfp->fish.dx, dfp->fish.dy, + dfp->fish.ttl, n2); + */ + f.cmd.cmd = NET_SEND; + f.cmd.port = 5049; + f.dfp.base.src_tank_x = myX; + f.dfp.base.src_tank_y = myY; + f.dfp.base.dst_tank_x = dfp->base.src_tank_x; + f.dfp.base.dst_tank_y = dfp->base.src_tank_y; + f.dfp.base.size = ntohs(DFP_SIZE_CONFIRM); + f.dfp.base.type = DFP_PKT_ACK_FISH; + f.dfp.base.pad = 0; + f.dfp.base.version = htons(DFP_VERSION); + memcpy(&(f.dfp.uid), &(dfp->uid), 6); + + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = DFP_SIZE_CONFIRM + 8; + msg.data = &f; + old_port_send(&msg); + break; + + case DFP_PKT_ACK_FISH : + /* lprintf(" : UID %X%X%X%X%X%X", + dfp->uid.creator_tank_x, dfp->uid.creator_tank_y, + dfp->uid.timestamp[0], dfp->uid.timestamp[1], + dfp->uid.timestamp[2], dfp->uid.timestamp[3]); + */ + sem_acquire(sem_fish); + for(ff = first; ff; ff=ff->next){ + if((ff->state==XMIT) && + (!memcmp(&(ff->xfer.uid),&(dfp->uid),6))){ + ff->state = DEAD; + st_count--; + sem_release(sem_fish); + lprintf("Goodbye fish \"%s\" (%d,%d)",ff->name, + dfp->base.src_tank_x,dfp->base.src_tank_y); + + f.cmd.cmd = NET_SEND; + f.cmd.port = 5049; + f.dfp.base.src_tank_x = myX; + f.dfp.base.src_tank_y = myY; + f.dfp.base.dst_tank_x = dfp->base.src_tank_x; + f.dfp.base.dst_tank_y = dfp->base.src_tank_y; + f.dfp.base.size = ntohs(DFP_SIZE_TRANSFER); + f.dfp.base.type = DFP_PKT_SYNC_FISH; + f.dfp.base.pad = 0; + f.dfp.base.version = htons(DFP_VERSION); + memcpy(&(f.dfp.uid), &(ff->xfer.uid), 6); + memcpy(&(f.dfp.fish), &(ff->xfer.fish), sizeof(dfp_fish)); + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = DFP_SIZE_TRANSFER + 8; + msg.data = &f; + old_port_send(&msg); + st_sent++; + goto donesync; + } + } + sem_release(sem_fish); +donesync: + break; + + case DFP_PKT_NACK_FISH : + break; + + case DFP_PKT_SYNC_FISH : + dfp->fish.ttl = ntohs(dfp->fish.ttl); + + strncpy(n2,dfp->fish.name,16); + n2[16]=0; + lprintf(" : UID %X%X%X%X%X%X @(%d,%d) d(%d,%d) ttl=%d, name=\"%s\"\n", + dfp->uid.creator_tank_x, dfp->uid.creator_tank_y, + dfp->uid.timestamp[0], dfp->uid.timestamp[1], + dfp->uid.timestamp[2], dfp->uid.timestamp[3], + dfp->fish.x, dfp->fish.y, dfp->fish.dx, dfp->fish.dy, + dfp->fish.ttl, n2); + + newfish(dfp->fish.x, dfp->fish.y, + dfp->fish.dx, dfp->fish.dy, + n2); +/* lprintf("Welcome, \"%s\" from (%d,%d)",n2, + dfp->base.src_tank_x, dfp->base.src_tank_y);*/ + + settank(dfp->base.src_tank_x,dfp->base.src_tank_y,1); + default: + break; + } +} + +void test(int x, int y) +{ + static dfp_pkt_transfer tran; + tran.fish.x = 100; + tran.fish.y = 100; + tran.fish.dx = 3; + tran.fish.dy = 4; + tran.fish.ttl = htons(1600); + tran.uid.creator_tank_x = myX; + tran.uid.creator_tank_y = myY; + *((uint32 *) tran.uid.timestamp) = 0x10203040; + + strcpy(tran.fish.name,"Bitchin Fish"); + + initiate(&tran,x,y); +} + +unsigned char *fish_bm = + ".........XXXXXX.....XXX." + ".....XXXXYYYYYYXX..XYYYX" + "...XXYY.YYYYYYYYYXXYYYYX" + ".XXYYYYYYYYYYYYYYYYYYYX." + "...XXYYYYYYYYYYYYYXXYYYX" + ".....XXXYYYYYYYXXX..XXYX" + "........XXXYYYX.......XX" + "...........XXXXX........" +; + +unsigned char *arrow_up[2] ={ + "....rr...." + "...rrrr..." + "..rrrrrr.." + ".rrrrrrrr." + "rrrrrrrrrr" +, + "....gg...." + "...gggg..." + "..gggggg.." + ".gggggggg." + "gggggggggg" +}; +unsigned char *arrow_dn[2] ={ + "rrrrrrrrrr" + ".rrrrrrrr." + "..rrrrrr.." + "...rrrr..." + "....rr...." +, + "gggggggggg" + ".gggggggg." + "..gggggg.." + "...gggg..." + "....gg...." +}; +unsigned char *arrow_lf[2] ={ + "....r" + "...rr" + "..rrr" + ".rrrr" + "rrrrr" + "rrrrr" + ".rrrr" + "..rrr" + "...rr" + "....r" +, + "....g" + "...gg" + "..ggg" + ".gggg" + "ggggg" + "ggggg" + ".gggg" + "..ggg" + "...gg" + "....g" +}; +unsigned char *arrow_rt[2] = { + "r...." + "rr..." + "rrr.." + "rrrr." + "rrrrr" + "rrrrr" + "rrrr." + "rrr.." + "rr..." + "r...." +, + "g...." + "gg..." + "ggg.." + "gggg." + "ggggg" + "ggggg" + "gggg." + "ggg.." + "gg..." + "g...." +}; + +int dist(int x0, int y0, int x1, int y1) +{ + return((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)); +} + +void sendfish(fish *f, int tx, int ty) +{ + f->xfer.fish.x = f->x; + f->xfer.fish.y = f->y; + f->xfer.fish.dx = f->dx; + f->xfer.fish.dy = f->dy; + f->xfer.fish.ttl = htons(1600); + f->state = XMIT; + f->xt = ticks+TIMEOUT; + initiate(&f->xfer,tx,ty); +} + +void prep(void) +{ + int i; + cnxn[C_LF].tx = myX - 1; + cnxn[C_LF].ty = myY; + cnxn[C_RT].tx = myX + 1; + cnxn[C_RT].ty = myY; + cnxn[C_UP].tx = myX; + cnxn[C_UP].ty = myY - 1; + cnxn[C_DN].tx = myX; + cnxn[C_DN].ty = myY + 1; + for(i=0;i<4;i++){ + cnxn[i].live = 0; + pingtank(cnxn[i].tx,cnxn[i].ty); + } +} + + +void vloop(void) +{ + fish *f,*lf; + fish *f2; + + int x,y,i; + int xx, xy, xd; + msg *m; + + for(i=0;i<4;i++){ + cnxn[i].live = 0; + pingtank(cnxn[i].tx,cnxn[i].ty); + } + + for(;;){ + ticks++; + if(!(ticks % 200)){ + lprintf("pinging now..."); + for(i=0;i<4;i++){ + cnxn[i].live = 0; + pingtank(cnxn[i].tx,cnxn[i].ty); + } + } + os_sleep(snooze * 9000); /* 9ms increments */ + vga_fillX(); +#ifdef LOGGING + sem_acquire(sem_msgs); + if(msgcount > logsize){ + msgcount--; + m = first_msg; + first_msg = first_msg->next; + free(m); + } + if(logging){ + for(y=16,m = first_msg; (y < 161) && m; m=m->next, y +=8){ + vga_blit_str(m->buf,15,y,'#'); + } + } + sem_release(sem_msgs); +#endif + sem_acquire(sem_fish); + for(lf=NULL,f=first;f;f=f->next){ + if(f->state == DEAD && lf){ + lprintf("Expiring \"%s\"",f->name); + lf->next = f->next; + free(f); + f = lf; + continue; + } + if((f->state == XMIT) && (ticks > f->xt)) { + cnxn[f->dest].live = 0; + f->state = LIVE; + st_rej++; + } + if(f->state == LIVE){ + xx = xy = 0; + xd = -1; + x = f->x; + y = f->y; + if(f->x < 0){ + xx = 1; + if(cnxn[C_LF].live) { + xd = C_LF; + f->x = 254; + } + } + if(f->x > 255){ + xx = 1; + if(cnxn[C_RT].live) { + xd = C_RT; + f->x = 1; + } + } + if(f->y < 0){ + xy = 1; + if(cnxn[C_UP].live) { + if(xd == -1) { + xd = C_UP; + f->y = 254; + } + } + } + if(f->y > 255) { + xy = 1; + if(cnxn[C_DN].live) { + if(xd == -1) { + xd = C_DN; + f->y = 1; + } + } + } + if(!sticky && !recluse && (xd != -1)) { + f->dest = xd; + sendfish(f,cnxn[xd].tx,cnxn[xd].ty); + } + if(xx){ + f->dx = - f->dx; + f->x = x + f->dx; + } + if(xy){ + f->dy = - f->dy; + f->y = y + f->dy; + } + if(xd != -1) continue; +#ifdef XXX + /* collision ? */ + { + int xc,yc; + xc = f->x + 12; + yc = f->y + 4; + + for(f2 = first; f2; f2 = f2->next){ + if((f2 == f) || (f2->state != LIVE)) continue; + if(dist(xc,yc,f2->x+12,f2->y+4) < 100){ + if(collision){ + f->dx = - f->dx; + f->dy = - f->dy; + } + if(!strcmp(f->name,"killer")) { + f2->state = DEAD; + } + if(!strcmp(f2->name,"killer")){ + f->state = DEAD; + } + break; + } + } + } + /* collision - */ +#endif + f->x += f->dx; + f->y += f->dy; + x = (f->x * (320-24)) / 256; + y = (f->y * (200-16)) / 256 + 8; + + if(f->dx < 0){ + vga_blit_trans(f->bitmap,x,y,24,8); + } else { + vga_blit_trans_r(f->bitmap,x,y,24,8); + } + vga_blit_str(f->name,x,y-8,'w'); + } + lf = f; + } + sem_release(sem_fish); + + + vga_blit_trans(arrow_up[cnxn[C_UP].live],320/2-5,0,10,5); + vga_blit_trans(arrow_dn[cnxn[C_DN].live],320/2-5,200-9,10,5); + vga_blit_trans(arrow_lf[cnxn[C_LF].live],0,100-5,5,10); + vga_blit_trans(arrow_rt[cnxn[C_RT].live],320-6,100-5,5,10); + /* if(logo) vga_blit_trans(blt,319-blt_w,2,blt_w,blt_h); */ + if(sticky) vga_blit_str("STICKY",0,0,'r'); + if(recluse) vga_blit_str("RECLUSIVE",8*7,0,'r'); + if(borg) vga_blit_str("BORG",320-(8*6),0,'r'); + + if(keybuf[0]){ + vga_fill(320,10,0,179,'b'); + vga_blit_str(keybuf2,1,180,'w'); + } + vga_swap_buffers(); + } +} + +int bc = 0; + +void newfish(int x, int y, int dx, int dy, char *n) +{ + fish *f = (fish *) malloc(sizeof(fish)); + + char bf[16]; + + st_recv++; + if(borg) { + n = bf; + snprintf(n,16,"Borg (%d)",bc++); + bf[15]=0; + } + f->x = x; + f->y = y; + f->dx = dx; + f->dy = dy; + strncpy(f->name,n,16); + f->name[16]=0; + f->bitmap = fish_bm; + f->state = LIVE; + f->xfer.uid.creator_tank_x = myX; + f->xfer.uid.creator_tank_y = myY; + *((uint32 *)f->xfer.uid.timestamp) = 0x1000000 + ticks; + /*XXX */ + + strcpy(f->xfer.fish.name,f->name); + sem_acquire(sem_fish); + f->next = first; + first = f; + sem_release(sem_fish); + st_count++; +} + + + +void vinit(void) +{ + int i; + void *vmem = 0xA0000; + area_create(64*1024, 0, &vmem, AREA_PHYSMAP); + + vga_set_sram(vmem); + vga_set_mode(320,200,8); + + vmem = malloc(64*1024); + vga_set_vram(vmem); + + vga_set_palette('.',0,0,255); + vga_set_palette('w',255,255,255); + vga_set_palette('X',255,0,0); + vga_set_palette('Y',255,255,0); + vga_set_palette('#',0,255,0); + vga_set_palette('g',0,255,0); + vga_set_palette('r',255,0,0); + vga_set_palette('b',0,0,0); + vga_set_palette('L',0,255,0); + for(i=0;i<50;i++){ + vga_set_palette(128+i,0,0,12+i); + } + + vga_fill_grad(320,200,0,0); + vga_swap_buffers(); + + lprintf("fish: vinit()"); + + newfish(160,160,3,3,"fish"); + newfish(100,40,-1,2,"not fish"); +} + +void command(char *str); + +void fishmain(void) +{ + int once = 1; + unsigned char data[1500]; + msg_hdr_t msg; + int i; + int size; + net_cmd cmd; + unsigned char ip[4]; + + sem_fish = sem_create(1, "fish_lock"); + sem_msgs = sem_create(1, "msgs_lock"); + + keybuf2[0] = '>'; + keybuf2[1] = ' '; + + if((port_net = namer_find("net",0)) < 1) WITH_NET = 0; + if((port_net_xmit = namer_find("net_xmit",0)) < 1) WITH_NET = 0; + + port_fish = port_create(0, "fish_tell_port"); + namer_register(port_fish, "fish:tell"); + + vinit(); + + os_thread(vloop); +/* os_thread(restarter); */ + + lprintf("fish: port=%d, console=%d, net=%d\n", + port_fish, port_console, port_net); + + if(WITH_NET){ + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = 8; + msg.data = &cmd; + + cmd.cmd = NET_IP; + cmd.port = 0; + old_port_send(&msg); + msg.src = port_net_xmit; + msg.dst = port_fish; + msg.size = 4; + msg.data = ip; + old_port_recv(&msg); + + lprintf("IP = %d.%d.%d.%d\n",ip[0],ip[1],ip[2],ip[3]); + + myX = (ip[3] >> 3) & 0x07; + myY = (ip[3]) & 0x07; + lprintf("tank @ %d,%d",myX, myY); + + msg.flags = 0; + msg.src = port_fish; + msg.dst = port_net; + msg.size = 8; + msg.data = &cmd; + + cmd.cmd = NET_CONNECT; + cmd.port = 5049; + old_port_send(&msg); + } else { + lprintf("no network support\n"); + } + + prep(); +#if 0 + os_thread(keythread); +#endif + for(;;){ + msg.flags = 0; + msg.src = 0; + msg.dst = port_fish; + msg.size = 1500; + msg.data = data; + + if((size = old_port_recv(&msg)) > 0){ + if(WITH_NET && (msg.src == port_net_xmit)){ + dofish((dfp_pkt_transfer *) data); + } else { + uint32 response = 0; + data[size]=0; + command(data); + msg.dst = msg.src; + msg.src = port_fish; + msg.size = 4; + msg.data = &response; + old_port_send(&msg); + } + } + } +} + +int main(void) +{ + os_thread(fishmain); + return 0; +} + +void command(char *str) +{ + if(!strncmp(str,"tank",4)){ + int x,y; + x = str[5]-'0'; + y = str[6]-'0'; + if(x <0 || x>9 || y<0 || x>9) return; + myX = x; + myY = y; + prep(); + lprintf("relocating tank to %d,%d",myX,myY); + return; + } + if(!strncmp(str,"stats",5)){ + lprintf("count: %d sent: %d recv: %d rej: %d",st_count,st_sent,st_recv,st_rej); + return; + } + if(!strncmp(str,"sticky",6)){ + sticky = !sticky; + lprintf("Sticky mode %s",sticky?"on":"off"); + return; + } + if(!strncmp(str,"recluse",7)){ + recluse = !recluse; + lprintf("Recluse mode %s",recluse?"on":"off"); + return; + } + if(!strncmp(str,"panic",5)){ + fish *f; + sem_acquire(sem_fish); + for(f=first;f;f=f->next) { + f->dx *= 2; + f->dy *= 2; + } + sem_release(sem_fish); + return; + } + if(!strncmp(str,"purge",5)){ + fish *f; + sem_acquire(sem_fish); + for(f=first;f;f=f->next) { + if(f->state == LIVE) f->state = DEAD; + } + st_count = 0; + sem_release(sem_fish); + return; + } + if(!strncmp(str,"logo",4)){ + logo = !logo; + return; + } + if(!strncmp(str,"collision",9)){ + collision = !collision; + return; + } + if(!strncmp(str,"snooze ",7)){ + snooze = str[7]-'0'; + if(snooze < 3 || snooze > 9) snooze = 5; + return; + } + if(!strncmp(str,"borg",4)){ + borg = !borg; + lprintf("Borg mode %s",borg?"on - prepare to assimilate":"off"); + return; + } + if(!strncmp(str,"eject",5)){ + int i; + lprintf("Ejecting all fish now!"); + for(i=0;i<4;i++){ + if(cnxn[i].live){ + fish *f; + sem_acquire(sem_fish); + for(f = first; f; f=f->next){ + if(f->state == LIVE){ + sendfish(f,cnxn[i].tx,cnxn[i].ty); + } + } + sem_release(sem_fish); + return; + } + } + return; + } + if(!strncmp(str,"debug",5)){ + os_debug(); + return; + } + if(!strncmp(str,"log",3)){ + logging = !logging; + return; + } + if(!strncmp(str,"new ",3)) { + str+=4; + str[16]=0; + if(str[0] == '*'){ + newfish(100,100,-3,-5,str+1); + newfish(130,100, 3,-5,str+1); + newfish(160,100,-3, 5,str+1); + newfish(190,100, 3, 5,str+1); + newfish(100,150,-3,-5,str+1); + newfish(130,150, 3,-5,str+1); + newfish(160,150,-3, 5,str+1); + newfish(190,150, 3, 5,str+1); + } else { + newfish(160,160,-3,5,str); + } + } + +} + + +/* keyboard handler */ + +#define ESC 27 +#define BS 8 +#define TAB 9 +#define CR 13 + +char ScanTable [] = {' ', ESC, '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', '-', '=', BS, TAB, 'q', 'w', 'e', 'r', + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', CR, ' ', + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '~', ' ', '\\', 'z', 'x', 'c', 'v', 'b', 'n', + 'm', ',', '.', '/', ' ', ' ', ' ', ' ', ' '}; +char ShiftTable [] = {' ', ESC, '!', '@', '#', '$', '%', '^', '&', '*', + '(', ')', '_', '+', ' ', ' ', 'Q', 'W', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', CR, ' ', + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', ' ', '|', 'Z', 'X', 'C', 'V', 'B', 'N', + 'M', '<', '>', '?', ' ', ' ', ' ', ' ', ' '}; +#define LSHIFT 42 +#define RSHIFT 54 + +void keythread(void) +{ + int shift = 0; + int key; + + os_handle_irq(1); + + for(;;) { + os_sleep_irq(); + key = inb(0x60); + switch(key){ + case LSHIFT: + case RSHIFT: + shift = 1; + break; + case LSHIFT | 0x80: + case RSHIFT | 0x80: + shift = 0; + break; + default: + if(key & 0x80){ + /* break */ + } else { + if(key < 59){ + key = shift ? ShiftTable[key] : ScanTable[key]; + switch(key){ + case CR: + if(keyptr) command(keybuf); + case ESC: + keybuf[0] = 0; + keyptr = 0; + break; + case BS: + if(keyptr){ + keyptr--; + keybuf[keyptr]=0; + } + break; + default: + if(keyptr < MAXKEYS){ + keyptr++; + keybuf[keyptr]=0; + keybuf[keyptr-1]=key; + } + break; + } + } + } + } + } + +} diff --git a/srv/fish/font.h b/srv/fish/font.h @@ -0,0 +1,157 @@ +/* $Id: //depot/blt/srv/fish/font.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +unsigned char *font[128] = { + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + "........................................", + ".......#....#....#....#.........#.......", + "......#.#..#.#..#.#.....................", + ".#.#..#.#.#####.#.#.#####.#.#..#.#......", + "..#...###.#.#...###...#.#.###...#.......", + "......#....#.#...#...#.#....#...........", + "..#...#.#..#.#...#...#.#..#.#...#.#.....", + ".......##...#...#.......................", + "........#...#....#....#.....#...........", + "......#.....#....#....#...#.............", + "......#..#..##..####..##..#..#..........", + ".......#....#..#####..#....#............", + "......................##...#...#........", + ".....................####...............", + "......................#...###...#.......", + ".........#....#...#...#...#....#........", + ".......#...#.#..#.#..#.#..#.#...#.......", + ".......#...##....#....#....#...###......", + ".......##..#..#....#..##..#....####.....", + ".......##..#..#...#.....#.#..#..##......", + "........#...##..#.#..####...#....#......", + "......####.#....###.....#.#..#..##......", + ".......##..#....#.#..##.#.#..#..##......", + "......####....#...#....#...#....#.......", + ".......##..#..#..##..#..#.#..#..##......", + ".......##..#..#.#.##..#.#....#..##......", + ".......##...##........##...##...........", + ".......##...##........##...#...#........", + "........#...#...#....#.....#.....#......", + "...........###.......###................", + "......#.....#.....#....#...#...#........", + ".......#...#.#....#...#.........#.......", + "..##..#..##..###.#.##.#.##..#..#.....##.", + ".......##..#..#.#..#.####.#..#.#..#.....", + "......###..#..#.###..#..#.#..#.###......", + ".......##..#..#.#....#....#..#..##......", + "......###..#..#.#..#.#..#.#..#.###......", + "......####.#....###..#....#....####.....", + "......####.#....###..#....#....#........", + ".......##..#..#.#....#.##.#..#..##......", + "......#..#.#..#.####.#..#.#..#.#..#.....", + "......###...#....#....#....#...###......", + ".......###....#....#....#.#..#..##......", + "......#..#.#.#..##...#.#..#.#..#..#.....", + "......#....#....#....#....#....###......", + "......#..#.####.####.#..#.#..#.#..#.....", + "......#..#.##.#.####.#.##.#.##.#..#.....", + ".......##..#..#.#..#.#..#.#..#..##......", + "......###..#..#.#..#.###..#....#........", + ".......##..#..#.#..#.##.#.#.##..##.....#", + "......###..#..#.#..#.###..#.##.#..#.....", + ".......##..#..#..#.....#..#..#..##......", + ".....#####..#....#....#....#....#.......", + "......#..#.#..#.#..#.#..#.#..#..##......", + "......#..#.#..#.#..#.#..#..##...##......", + "......#..#.#..#.#..#.####.####.#..#.....", + "......#..#.#..#..##...##..#..#.#..#.....", + ".....#...##...#.#.#...#....#....#.......", + "......####....#...#...#...#....####.....", + "......###..#....#....#....#....###......", + "......#....#.....#.....#.....#....#.....", + "......###....#....#....#....#..###......", + ".......#...#.#..#.#.....................", + "....................................####", + "......##...#.....#......................", + ".................#.#.#.##.#.##..#.#.....", + "......#....#....###..#..#.#..#.###......", + ".................##..#....#.....##......", + ".........#....#..#.#.#.##.#.##..#.#.....", + ".................##..####.#.....##......", + "........#...#.#..#...###...#....#.......", + ".................##..#..#..###....#..##.", + "......#....#....###..#..#.#..#.#..#.....", + ".......#........##....#....#...###......", + "........#.........#....#....#..#.#...#..", + "......#....#....#..#.###..#..#.#..#.....", + "......##....#....#....#....#...###......", + "................#.#.#.#.##.#.##...#.....", + "................###..#..#.#..#.#..#.....", + ".................##..#..#.#..#..##......", + "................###..#..#.###..#....#...", + ".................###.#..#..###....#....#", + "................#.#..##.#.#....#........", + "................###..##.....#..###......", + ".......#....#...###...#....#.#...#......", + "................#..#.#..#.#..#..###.....", + "................#.#..#.#..#.#...#.......", + "...............#...##.#.##.#.#.###......", + "................#..#..##...##..#..#.....", + "................#..#.#..#..###.#..#..##.", + "................####...#...#...####.....", + "...##..#.....#..##.....#...#.....##.....", + ".......#....#....#....#....#....#.......", + ".##.....#...#.....##..#.....#..##.......", + ".......#.#.#.#..........................", + "........................................", +}; diff --git a/srv/fish/vga.c b/srv/fish/vga.c @@ -0,0 +1,225 @@ +/* $Id: //depot/blt/srv/fish/vga.c#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "vga.h" + +#include <i386/io.h> + +const int MiscOutputReg = 0x3c2; +const int DataReg = 0x3c0; +const int AddressReg = 0x3c0; + +const char mode13[][32] = { + { 0x03, 0x01, 0x0f, 0x00, 0x0e }, /* 0x3c4, index 0-4*/ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x0e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff }, /* 0x3d4, index 0-0x18*/ + { 0, 0, 0, 0, 0, 0x40, 0x05, 0x0f, 0xff }, /* 0x3ce, index 0-8*/ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0x41, 0, 0x0f, 0, 0 } /* 0x3c0, index 0-0x14*/ +}; + +#define Vga256 0x13 // 320x200x256 +#define TextMode 0x03 // 80x25 text mode +#define PaletteMask 0x3C6 // bit mask register +#define PaletteRegisterRead 0x3C7 // read index +#define PaletteRegisterWrite 0x3C8 // write index +#define PaletteData 0x3C9 // send/receive data here +#define RomCharSegment 0xF000 +#define RomCharOffset 0xFA6E +#define CharWidth 8 +#define CharHeight 8 + + +#define pixel(x,y,c) (((unsigned char *)VRAM)[(y)*320+(x)] = c) + + +void vga_set_palette(int color, int red, int green, int blue) +{ + + outb(0xFF, PaletteMask); + outb(color, PaletteRegisterWrite); + outb(red, PaletteData); + outb(green, PaletteData); + outb(blue, PaletteData); +} + +int vga_set_mode(int xres, int yres, int bitdepth) +{ + int i; + + outb_p(0x63, MiscOutputReg); + outb_p(0x00, 0x3da); + + for (i=0; i < 5; i++) { + outb_p(i, 0x3c4); + outb_p(mode13[0][i], 0x3c4+1); + } + + outw_p(0x0e11, 0x3d4); + + for (i=0; i < 0x19; i++) { + outb_p(i, 0x3d4); + outb_p(mode13[1][i], (0x3d4 + 1)); + } + + for (i=0; i < 0x9; i++) { + outb_p(i, 0x3ce); + outb_p(mode13[2][i], (0x3ce + 1)); + } + + inb_p(0x3da); + + for (i=0; i < 0x15; i++) { + inw(DataReg); + outb_p(i, AddressReg); + outb_p(mode13[3][i], DataReg); + } + + outb_p(0x20, 0x3c0); + + return 1; +} + +#include "font.h" + +static unsigned int VRAM = 0xA0000; +static unsigned int SRAM = 0xA0000; + +void vga_set_sram(void *addr) +{ + SRAM = (unsigned int) addr; +} + +void vga_set_vram(void *addr) +{ + VRAM = (unsigned int) addr; +} + +void vga_swap_buffers(void) +{ + int i; + unsigned int *vram = (unsigned int *) VRAM; + unsigned int *disp = (unsigned int *) SRAM; + + i = 16000; + while(i--) *disp++ = *vram++; +} + + +void vga_blit(char *bitmap, int x, int y, int w, int h) +{ + int i, j; + char *edi = (char *) (VRAM + y*320 + x); + + for (i = 0; i < h; i++, edi += 320 - w) { + for (j = 0; j < w; j++, edi++, bitmap++) + *edi = *bitmap; + } +} + +void vga_blit_trans(char *bitmap, int x, int y, int w, int h) +{ + int i, j; + char *edi = (char *) (VRAM + y*320 + x); + + for (i = 0; i < h; i++, edi += 320 - w) { + for (j = 0; j < w; j++, edi++, bitmap++) + if (*bitmap != '.') *edi = *bitmap; + } +} + +void vga_blit_trans_r(char *bitmap, int x, int y, int w, int h) +{ + int i, j; + char *edi = (char *) (VRAM + y*320 + x + w); + + for (i = 0; i < h; i++, edi += 320 + w) { + for (j = w; j >0; j--, edi--, bitmap++) + if (*bitmap != '.') *edi = *bitmap; + } +} + +void vga_blit_str(char *s, int x, int y, int c) +{ + int w, h, i, j; + char *edi; + char *bitmap; + w = 5; + h = 8; + while(*s) { + bitmap = font[(*s) & 0x7F]; + edi = (char *) (VRAM + y*320 + x); + for (i = 0; i < h; i++, edi += 320 - w) { + for (j = 0; j < w; j++, edi++, bitmap++){ + if (*bitmap != '.') *edi = c; + } + } + x += 5; + s++; + } +} + + + +void vga_fill(int w, int h, int x, int y, int c) +{ + int tx,ty; + + for(ty = y; ty < y+h; ty++){ + for(tx = x; tx < x+w; tx++){ + pixel(tx,ty,c); + } + } + +} + +void vga_fillX(void) +{ + unsigned int f,i,j=50,n=128+49; + unsigned int *addr = (unsigned int *) VRAM; + + while(j--){ + f = (n << 24) | (n << 16) | (n << 8) | n; + n--; + i = 320; + while(i--) *addr++ = f; + } +} + +void vga_fill_grad(int w, int h, int x, int y) +{ + int tx,ty; + + for(ty = y; ty < y+h; ty++){ + for(tx = x; tx < x+w; tx++){ + pixel(tx,ty,128 + ty/4); + } + } + +} diff --git a/srv/fish/vga.h b/srv/fish/vga.h @@ -0,0 +1,49 @@ +/* $Id: //depot/blt/srv/fish/vga.h#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _vga_h +#define _vga_h + +void vga_set_palette(int color, int red, int green, int blue); +int vga_set_mode(int xres, int yres, int bitdepth); +/* only valid parms are (320, 200, 8); */ + +void vga_blit(char *bitmap, int x, int y, int w, int h); +void vga_blit_trans(char *bitmap, int x, int y, int w, int h); +void vga_blit_trans_r(char *bitmap, int x, int y, int w, int h); +void vga_blit_str(char *s, int x, int y, int c); + +void vga_fill(int w, int h, int x, int y, int c); +void vga_fill_grad(int w, int h, int x, int y); + +void vga_set_vram(void *addr); +void vga_set_sram(void *addr); +void vga_swap_buffers(void); +void vga_fillX(void); +void vga_modex(unsigned int w); + +#endif diff --git a/srv/ide/Makefile b/srv/ide/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := main.c identify.c disk.c blkdev.c +BINARY := ide.bin +CFLAGS += -finline-functions +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/srv/ide/TODO b/srv/ide/TODO @@ -0,0 +1,16 @@ +- probe for busses +- support multiple busses +- distinguish between disks and cdroms and such +- error checking +- write support +- proper initialisation of controller + +done +---- + +bugs +---- +- stuff works, turn off machine, go to sleep, wake up, turn on machine, + stuff is broken, boot freebsd, turn off, turn on, stuff works. i have + no idea what causes this. + diff --git a/srv/ide/blkdev.c b/srv/ide/blkdev.c @@ -0,0 +1,64 @@ +/* $Id: //depot/blt/srv/ide/blkdev.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <blt/blkdev.h> +#include "ide-int.h" + +int blk_open (const char *name, int flags, blkdev_t **retdev) +{ + blkdev_t *dev; + + dev = malloc (sizeof (blkdev_t)); + dev->blksize = 512; + dev->devno = (name[4] - '0') * 2 + (name[6] - '0'); + *retdev = dev; + return 0; +} + +int blk_close (blkdev_t *dev) +{ + free (dev); + return 0; +} + +int blk_read (blkdev_t *dev, void *buf, int block, int count) +{ + int i; + + for (i = 0; i < count; i++) + ide_dev[dev->devno]->read ((dev->devno & 0xff) / 2, dev->devno % 2, + (char *) buf + dev->blksize * i, block + i); + return 0; +} + +int blk_write (blkdev_t *dev, const void *buf, int block, int count) +{ + return 0; +} + diff --git a/srv/ide/disk.c b/srv/ide/disk.c @@ -0,0 +1,89 @@ +/* $Id: //depot/blt/srv/ide/disk.c#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ide-int.h" +#include <stdio.h> +#include <i386/io.h> + +int ide_disk_read (int bus, int device, void *data, int block) +{ + unsigned short *buf; + int i, base, cyl, head, sect; + + base = ide_base (bus); + buf = (unsigned short *) data; + ide_btochs (block, ide_dev[bus * 2 + device], &cyl, &head, &sect); + IDE_WAIT_0 (STATUS, 7); + + IDE_SEL_DH (bus, device, head); + IDE_WAIT_0 (STATUS, 7); + //IDE_WAIT_1 (STATUS, 6); + + outb (cyl / 256, IDE_REG_CYLMSB); + outb (cyl % 256, IDE_REG_CYLLSB); + outb (sect + 1, IDE_REG_SECNUM); + outb (1, IDE_REG_SECCNT); + outb (IDE_OP_READ, IDE_REG_COMMAND); + IDE_WAIT_0 (STATUS, 7); + IDE_WAIT_1 (STATUS, 3); + + for (i = 0; i < 256; i++) + buf[i] = inw (IDE_REG_DATA); + return 0; +} + +int ide_disk_write (int bus, int device, const void *data, int block) +{ +#if 0 + short *buf; + int i, base, cyl, head, sect; + + base = ide_base (bus); + buf = (short *) data; + ide_btochs (block, ide_dev[bus * 2 + device], &cyl, &head, &sect); + IDE_WAIT_0 (STATUS, 7); + + /* select device */ + IDE_SEL_DH (bus, device, head); + IDE_WAIT_0 (STATUS, 7); + IDE_WAIT_1 (STATUS, 6); + + outb (cyl / 256, IDE_REG_CYLMSB); + outb (cyl % 256, IDE_REG_CYLLSB); + outb (sect, IDE_REG_SECNUM); + outb (1, IDE_REG_SECCNT); + outb (IDE_OP_WRITE, IDE_REG_COMMAND); + IDE_WAIT_1 (STATUS, 3); + + for (i = 0; i < 256; i++) + outw (buf[i], IDE_REG_DATA); +#endif + + return 0; +} + diff --git a/srv/ide/ide-int.h b/srv/ide/ide-int.h @@ -0,0 +1,148 @@ +/* $Id: //depot/blt/srv/ide/ide-int.h#5 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IDE_INT_H +#define IDE_INT_H + +#include <blt/disk.h> + +#define IDE_PRI_BASE 0x1f0 +#define IDE_SEC_BASE 0x170 +#define IDE_DIGITAL_OUTPUT 0x3f6 +#define IDE_DRIVE_ADDR 0x3f7 + +#define IDE_REG_OFF_DATA 0 /* R/W, 16 bits */ +#define IDE_REG_OFF_ERROR 1 /* R */ +#define IDE_REG_OFF_PRECOMP 1 /* W */ +#define IDE_REG_OFF_SECCNT 2 /* R/W */ +#define IDE_REG_OFF_SECNUM 3 /* R/W */ +#define IDE_REG_OFF_CYLLSB 4 /* R/W */ +#define IDE_REG_OFF_CYLMSB 5 /* R/W */ +#define IDE_REG_OFF_DH 6 /* R/W */ +#define IDE_REG_OFF_STATUS 7 /* R */ +#define IDE_REG_OFF_COMMAND 7 /* W */ + +#define IDE_REG_DATA (base + IDE_REG_OFF_DATA) +#define IDE_REG_ERROR (base + IDE_REG_OFF_ERROR) +#define IDE_REG_PRECOMP (base + IDE_REG_OFF_PRECOMP) +#define IDE_REG_SECCNT (base + IDE_REG_OFF_SECCNT) +#define IDE_REG_SECNUM (base + IDE_REG_OFF_SECNUM) +#define IDE_REG_CYLLSB (base + IDE_REG_OFF_CYLLSB) +#define IDE_REG_CYLMSB (base + IDE_REG_OFF_CYLMSB) +#define IDE_REG_DH (base + IDE_REG_OFF_DH) +#define IDE_REG_STATUS (base + IDE_REG_OFF_STATUS) +#define IDE_REG_COMMAND (base + IDE_REG_OFF_COMMAND) + +#define IDE_SEL_DH(bus, device, head) \ + outb (0x1010000 | (device << 4) | head, IDE_REG_DH) + +#define IDE_WAIT_0(reg, bit) \ + while (inb (IDE_REG_##reg) & (1 << bit)) ; +#define IDE_WAIT_1(reg, bit) \ + while (!(inb (IDE_REG_##reg) & (1 << bit))) ; + +/* XXX - hack */ +#define IDE_WAITFAIL_1(reg, bit) \ + { \ + int __spin__ = 0; \ + while (!(inb (IDE_REG_##reg) & (1 << bit)) && (__spin__ < 10000)) \ + __spin__++; \ + if (__spin__ == 10000) \ + fail = 1; \ + } + +#define IDE_OP_RECALIBRATE 0x10 +#define IDE_OP_READ 0x20 +#define IDE_OP_WRITE 0x30 +#define IDE_OP_IDENTIFY_DEVICE 0xec + +#define IDE_IDENTIFY_DATA_SIZE 256 + +typedef struct +{ + unsigned short config; /* obsolete stuff */ + unsigned short cyls; /* logical cylinders */ + unsigned short _reserved_2; + unsigned short heads; /* logical heads */ + unsigned short _vendor_4; + unsigned short _vendor_5; + unsigned short sectors; /* logical sectors */ + unsigned short _vendor_7; + unsigned short _vendor_8; + unsigned short _vendor_9; + char serial[20]; /* serial number */ + unsigned short _vendor_20; + unsigned short _vendor_21; + unsigned short vend_bytes_long; /* no. vendor bytes on long cmd */ + char firmware[8]; + char model[40]; + unsigned short mult_support; /* vendor stuff and multiple cmds */ + unsigned short _reserved_48; + unsigned short capabilities; + unsigned short _reserved_50; + unsigned short pio; + unsigned short dma; + unsigned short _reserved_53; + unsigned short curr_cyls; /* current logical cylinders */ + unsigned short curr_heads; /* current logical heads */ + unsigned short curr_sectors; /* current logical sectors */ + unsigned int capacity; /* capacity in sectors */ + unsigned short _pad[256-59]; /* don't need this stuff for now */ +} ide_hw_id_t; + +typedef struct +{ + const ide_hw_id_t *hwdev; + int iobase; + disk_t *disk; + int (*read) (int bus, int device, void *buf, int block); + int (*write) (int bus, int device, const void *buf, int block); +} ide_dev_t; + +extern ide_dev_t **ide_dev; +extern int total_busses; + +void ide_btochs (int block, ide_dev_t *dev, int *cyl, int *head, int *sect); + +int ide_probe_devices (void); + +int ide_disk_read (int bus, int device, void *data, int block); +int ide_disk_write (int bus, int device, const void *data, int block); + +static inline int ide_base (int bus) +{ + if (bus == 0) + return IDE_PRI_BASE; + else if (bus == 1) + return IDE_SEC_BASE; + else + return -1; +} + +#endif + diff --git a/srv/ide/identify.c b/srv/ide/identify.c @@ -0,0 +1,173 @@ +/* $Id: //depot/blt/srv/ide/identify.c#6 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <blt/syscall.h> +#include <blt/types.h> +#include <blt/disk.h> +#include <blt/blkdev.h> +#include <i386/io.h> +#include "ide-int.h" + +int total_busses = 0; +ide_dev_t **ide_dev; + +static void ide_string_conv (char *str, int len) +{ + int i; + unsigned short *w; + + w = (unsigned short *) str; + for (i = 0; i < len / sizeof (unsigned short); i++) + w[i] = ntohs (w[i]); + + str[len - 1] = 0; + for (i = len - 1; (i >= 0) && ((str[i] == ' ') || !str[i]); i--) + str[i] = 0; +} + +int ide_reset (int bus, int device) +{ + int i, base, fail = 0; + + outb (6, IDE_DIGITAL_OUTPUT); + for (i = 0; i < 1000000; i++) ; /* XXX */ + outb (0, IDE_DIGITAL_OUTPUT); + //IDE_WAIT_1 (STATUS, 6); + + base = ide_base (bus); + IDE_WAIT_0 (STATUS, 7); + IDE_SEL_DH (bus, device, 0); + IDE_WAIT_0 (STATUS, 7); + IDE_WAITFAIL_1 (STATUS, 6); + if (fail) + return 1; + + outb (0, IDE_REG_CYLLSB); + outb (0, IDE_REG_CYLMSB); + outb (0, IDE_REG_SECNUM); + outb (0, IDE_REG_SECCNT); + outb (IDE_OP_RECALIBRATE, IDE_REG_COMMAND); + return 0; +} + +const ide_hw_id_t *ide_identify_device (int bus, int device) +{ + short *buf; + int i, base, fail, mb; + ide_hw_id_t *hwdev; + + if ((base = ide_base (bus)) < 0) + return NULL; + if ((device < 0) || (device > 1)) + return NULL; + + fail = 0; + buf = (short *) hwdev = malloc (sizeof (ide_hw_id_t)); + IDE_WAIT_0 (STATUS, 7); + + IDE_SEL_DH (bus, device, 0); + IDE_WAIT_0 (STATUS, 7); + IDE_WAITFAIL_1 (STATUS, 6); + if (fail) + return NULL; + + outb (IDE_OP_IDENTIFY_DEVICE, IDE_REG_COMMAND); + IDE_WAIT_1 (STATUS, 3); + + for (i = 0; i < sizeof (ide_hw_id_t) / sizeof (short); i++) + buf[i] = inw (IDE_REG_DATA); + + ide_string_conv (hwdev->serial, sizeof (hwdev->serial)); + ide_string_conv (hwdev->firmware, sizeof (hwdev->firmware)); + ide_string_conv (hwdev->model, sizeof (hwdev->model)); + mb = hwdev->cyls * hwdev->heads * hwdev->sectors * 512 / 1024 / 1024; + + printf ("ide: disk at bus %d, device %d, <%s>\n", bus, device, + hwdev->model); + printf ("ide/%d/%d: %dMB; %d cyl, %d head, %d sec, 512 bytes/sec\n", + bus, device, mb, hwdev->cyls, hwdev->heads, hwdev->sectors); + return hwdev; +} + +int ide_attach_bus (int io, int irq) +{ + total_busses++; + return 0; +} + +int ide_attach_device (int bus, int device) +{ + char name[9]; + int i; + blkdev_t *bdev; + disk_t *disk; + const ide_hw_id_t *hwdev; + ide_dev_t *dev; + + if ((hwdev = ide_identify_device (bus, device)) == NULL) + return 0; + + dev = ide_dev[bus * 2 + device] = malloc (sizeof (ide_dev_t)); + dev->hwdev = hwdev; + dev->iobase = ide_base (bus); + dev->read = ide_disk_read; + dev->write = ide_disk_write; + + snprintf (name, sizeof (name), "ide/%d/%d", bus, device); + printf ("%s: partitions:", name); + blk_open (name, 0, &bdev); + dev->disk = disk = disk_alloc (bdev); + for (i = 0; i < disk->numparts; i++) + printf (" %s", disk_partition_name (disk, i)); + printf ("\n"); + blk_close (bdev); + return 1; +} + +int ide_probe_devices (void) +{ + int i, found; + + found = 0; + os_handle_irq (14); + ide_attach_bus (0x1f0, 14); /* XXX find this properly */ + ide_dev = malloc (sizeof (ide_dev_t *) * total_busses * 2); + + for (i = 0; i < total_busses; i++) + { + //if (!ide_reset (i, 0)) + found += ide_attach_device (i, 0); + //if (!ide_reset (i, 1)) + found += ide_attach_device (i, 1); + } + return found; +} + diff --git a/srv/ide/main.c b/srv/ide/main.c @@ -0,0 +1,140 @@ +/* Copyright 1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <blt/os.h> +#include <blt/blkdev.h> +#include <blt/disk.h> +#include "ide-int.h" + +void ide_btochs (int block, ide_dev_t *dev, int *cyl, int *head, int *sect) +{ + *cyl = block / (dev->hwdev->heads * dev->hwdev->sectors); + block %= dev->hwdev->heads * dev->hwdev->sectors; + *head = block / dev->hwdev->sectors; + block %= dev->hwdev->sectors; + *sect = block; +} + +void ide_main (int *ready) +{ + char *c, dev[3]; + int a, b, i, port, txnlen, reslen, bus, device, offset; + msg_hdr_t mh; + blktxn_t *txn; + blkres_t *res; + disk_t *disk; + + if (!ide_probe_devices ()) + { + printf ("ide: no devices found; exiting.\n"); + os_terminate (1); + } + + port = port_create (0, "ide"); + namer_register (port, "ide"); + txn = malloc (txnlen = sizeof (blktxn_t) + 1024); + res = malloc (reslen = sizeof (blkres_t) + 1024); + *ready = 1; + + for (;;) + { + mh.src = 0; + mh.dst = port; + mh.data = txn; + mh.size = txnlen; + old_port_recv (&mh); + + switch (txn->cmd) + { + case BLK_CMD_OPEN: + c = (char *) (txn + 1); + if (!isdigit (c[0]) || !isdigit (c[2]) || (c[1] != '/') || + (c[3] != '/')) + { + res->status = ENOENT; + break; + } + bus = c[0] - '0'; + device = c[2] - '0'; + if ((bus >= total_busses) || ((device != 0) && (device != 1))) + res->status = ENOENT; + else if (ide_dev[bus * 2 + device] == NULL) + res->status = ENOENT; + else if (!strcmp (c + 4, "raw")) + { + res->status = 0; + res->data[0] = 512; + res->data[1] = (bus * 2 + device) | (0xff << 8); + mh.size = sizeof (blkres_t); + } + else if (isdigit (c[4]) && !c[5]) + { + res->status = 0; + res->data[0] = 512; + res->data[1] = (bus * 2 + device) | ((c[4] - '0' + 1) << 8); + mh.size = sizeof (blkres_t); + } + else if (isdigit (c[4]) && c[5]) + { + res->status = 0; + res->data[0] = 512; + res->data[1] = (bus * 2 + device) | ((c[4] - '0' + 1) << + 8) | ((c[5] - 'a' + 1) << 16); + mh.size = sizeof (blkres_t); + } + else + res->status = ENOENT; + break; + + case BLK_CMD_READ: + if ((txn->device & 0xff) > (total_busses * 2)) + { + res->status = ENOENT; + break; + } + offset = 0; + if ((txn->device >> 8)) + { + a = ((txn->device & 0x0000ff00) >> 8); + b = ((txn->device & 0x00ff0000) >> 16); + dev[0] = a ? a - 1 + '0' : 0; + dev[1] = b ? b - 1 + 'a' : 0; + dev[2] = 0; + disk = ide_dev[txn->device & 0xff]->disk; + for (i = 0; i < disk->numparts; i++) + if (!strcmp (disk_partition_name (disk, i), dev)) + offset = disk_partition_start (disk, i); + txn->device &= 0xff; + } + res->status = ide_dev[txn->device]->read (txn->device / 2, + txn->device % 2, res + 1, txn->block + offset); + mh.size = res->status ? sizeof (blkres_t) : sizeof (blkres_t) + + 512; + break; + } + + mh.dst = mh.src; + mh.src = port; + mh.data = res; + old_port_send (&mh); + } +} + +int main (void) +{ + volatile int ready; + + ready = 0; + thr_create (ide_main, (void *) &ready, "ide"); + while (!ready) ; + return 0; +} + diff --git a/srv/init/Makefile b/srv/init/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := init.c +CRT0 := $(BLTHOME)lib/crtb.o +BINARY := init.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/srv/init/init.c b/srv/init/init.c @@ -0,0 +1,225 @@ +/* $Id: //depot/blt/srv/init/init.c#11 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * Since nothing is running yet, we divide the system startup into two + * phases: starting bootstrap servers and normal initialisation. The + * former requires lots of strange incantations to parse the boot image + * to find rc.boot and run everything it says to; basically we have to + * reimplement what execve and the vfs do for us. Once that stuff gets + * going, we can open rc using the vfs and proceed in a more normal + * fashion. + * + * As rc.boot contains fairly critical stuff, an error from something + * in there will probably result in a wedged system. + * + * Microkernels are fun. + * + * - sc + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <boot.h> +#include <blt/syscall.h> + +static char *copyright = "\ +OpenBLT Release I (built " __DATE__ ", " __TIME__ ") + Copyright (c) 1998-1999 The OpenBLT Dev Team. All rights reserved. +\n"; + +void __libc_init_fdl (void), __libc_init_console (void), + __libc_init_vfs (void); + +int boot_get_num (boot_dir *dir, const char *name) +{ + int i; + + for (i = 0; i < BOOTDIR_MAX_ENTRIES; i++) + if (!strcmp (dir->bd_entry[i].be_name, name)) + return i; + return -1; +} + +char *boot_get_data (boot_dir *dir, int num) +{ + return (char *) dir + dir->bd_entry[num].be_offset * 0x1000; +} + +int main (void) +{ + int area, sarea; + char *c, *rcboot, *line, *boot_servers, **params; + int i, space, p_argc, boot, fd, len, total, prog, filenum; + void *ptr; + boot_dir *dir; + + + line = malloc (256); + boot_servers = malloc (256); + + if (!(boot = area_clone (3, 0, (void **) &dir, 0))) + { + os_console ("no uberarea; giving up"); + os_debug (); + for (;;) ; /* fatal */ + return 0; + } + else if ((filenum = boot_get_num (dir, "rc.boot")) < 0) + { + os_console ("no /boot/rc.boot; do you know what you're doing?"); + os_debug (); + } + else + { + *line = *boot_servers = len = total = 0; + rcboot = boot_get_data (dir, filenum); + + while (total < dir->bd_entry[filenum].be_vsize) + { + line[len++] = *rcboot++; + total++; + + if (line[len - 1] == '\n') + { + line[len-- - 1] = 0; + for (i = space = 0, p_argc = 2; i < len; i++) + if ((line[i] == ' ') && !space) + space = 1; + else if ((line[i] != ' ') && space) + { + p_argc++; + space = 0; + } + if ((*line != '#') && *line) + { + params = malloc (sizeof (char *) * p_argc); + c = line; + for (i = 0; i < p_argc - 1; i++) + { + for (len = 0; c[len] && (c[len] != ' '); len++) ; + params[i] = malloc (len + 1); + strlcpy (params[i], c, len + 1); + c += len + 1; + } + params[i] = NULL; + if (!strcmp (params[0], "exit")) + os_terminate (1); + + prog = boot_get_num (dir, params[0]); + area = area_create (dir->bd_entry[prog].be_vsize, 0, + &ptr, 0); + memcpy (ptr, boot_get_data (dir, prog), + dir->bd_entry[prog].be_vsize); + sarea = area_create (0x1000, 0, &ptr, 0); + strlcat (boot_servers, " ", 256); + strlcat (boot_servers, params[0], 256); + thr_wait (thr_spawn (0x1074, 0x3ffffd, area, 0x1000, + sarea, 0x3ff000, params[0])); + } + len = 0; + } + } + } + + /* say hello */ + __libc_init_fdl (); + __libc_init_console (); + __libc_init_vfs (); + printf (copyright); + printf ("init: bootstrap servers started. [ %s ]\n", boot_servers + 1); + + /* if we one day pass arguments to init, we will parse them here. */ + + /* do some more normal stuff */ + printf ("init: beginning automatic boot.\n\n"); + fd = open ("/boot/rc", O_RDONLY, 0); + if (fd < 0) + printf ("error opening /boot/rc\n"); + else + { + *line = len = 0; + while (read (fd, line + len++, 1) > 0) + { + if (line[len - 1] == '\n') + { +/* + line[len - 1] = 0; + if ((*line != '#') && *line) + { + // printf ("execing `%s'\n", line); + params = malloc (sizeof (char *) * 2); + params[0] = malloc (strlen (line) + 1); + strcpy (params[0], line); + params[1] = NULL; + thr_join (thr_detach (run2), 0); + } + len = 0; +*/ + line[len-- - 1] = 0; + for (i = space = 0, p_argc = 2; i < len; i++) + if ((line[i] == ' ') && !space) + space = 1; + else if ((line[i] != ' ') && space) + { + p_argc++; + space = 0; + } + if ((*line != '#') && *line) + { + params = malloc (sizeof (char *) * p_argc); + c = line; + for (i = 0; i < p_argc - 1; i++) + { + for (len = 0; c[len] && (c[len] != ' '); len++) ; + params[i] = malloc (len + 1); + strlcpy (params[i], c, len + 1); + c += len + 1; + } + params[i] = NULL; + if (!strcmp (params[0], "exit")) + os_terminate (1); + + i = execve (params[0], params, NULL); + if(i>0) thr_wait(i); + else printf("cannot execute \"%s\"\n",params[0]); + } + len = 0; + } + } + close (fd); + } + + printf ("init: nothing left to do\n"); + return 0; +} + diff --git a/srv/namer/Makefile b/srv/namer/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := namer.cpp +BINARY := namer.bin +CRT0 := $(BLTHOME)lib/crtb.o +LIBS := -lblt -lc + +include $(BLTHOME)make.actions diff --git a/srv/namer/namer.cpp b/srv/namer/namer.cpp @@ -0,0 +1,97 @@ +/* Copyright 1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <blt/namer.h> +#include <blt/Message.h> +#include <blt/Connection.h> + +#include <blt/syscall.h> +#include <string.h> +#include <stdlib.h> + +using namespace BLT; + +typedef struct nentry nentry; + +struct nentry +{ + nentry *next; + int32 port; + char name[1]; +}; + +static nentry *first = 0; + +static int32 +do_namer_find(const char *name) +{ + nentry *e; + + if(!name) return -1; + + for(e = first; e; e = e->next){ + if(!strcmp(e->name,name)) return e->port; + } + + return -1; +} + +static int32 +do_namer_register(int32 port, const char *name) +{ + nentry *e; + + if(!name) return -1; + if(port < 1) return -1; + + for(e = first; e; e = e->next){ + if(!strcmp(e->name,name)) return -1; + } + + e = (nentry *) malloc(sizeof(nentry) + strlen(name)); + + if(!e) return -1; + + e->port = port; + strcpy(e->name,name); + e->next = first; + first = e; + + return 0; +} + +int main(void) +{ + Connection *cnxn = Connection::CreateService("namer"); + Message msg, reply; + + do_namer_register(NAMER_PORT,"namer"); + + while(cnxn->Recv(&msg) == 0){ + int32 op = -1; + int32 port = -1; + const char *name = 0; + int32 res = -1; + + msg.GetInt32('code',&op); + msg.GetInt32('port',&port); + msg.GetString('name',&name); + + switch(op){ + case NAMER_FIND: + res = do_namer_find(name); + break; + + case NAMER_REGISTER: + res = do_namer_register(port, name); + break; + } + + reply.Empty(); + reply.PutInt32('resp',res); + msg.Reply(&reply); + } + + return 0; +} diff --git a/srv/ne2000/Makefile b/srv/ne2000/Makefile @@ -0,0 +1,10 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := ne2k.c ne2000.c pciglue.cpp +BINARY := ne2000.bin +LIBS := -lposix -lblt -lc +CFLAGS += -I../pci +CXXFLAGS += -I../pci + +include $(BLTHOME)make.actions diff --git a/srv/ne2000/err.h b/srv/ne2000/err.h @@ -0,0 +1,138 @@ +/* $Id: //depot/blt/srv/ne2000/err.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __ERR +#define __ERR + +/* NOTE If ret is negative then it is an error otherwise it returns a +// success code. */ + +///// +// Error codes +///// + +#define NUM_ERR 22 +#define NOERR 0 +#define ERR -1 +#define ERRNOMEM -2 +#define ERRRESOURCE -3 +#define ERRMEMCORRUPT -4 +#define ERRFORMAT -5 +#define ERRNOTFOUND -6 +#define ERRTYPE -7 +#define ERRTIMEOUT -8 +#define ERRNOTSUPPORTED -9 +#define ERROUTOFRANGE -10 +#define ERRPRIV -11 +#define ERRNOTREADY -12 +#define ERRNONEFREE -13 +#define ERRARG -14 +#define ERRINVALID -15 +#define ERRNOTOPEN -16 +#define ERRALREADYDONE -17 +#define ERRVER -18 +#define ERROVERFLOW -19 +#define ERRINUSE -20 +#define ERRTOOBIG -21 + +///// +// Success codes +///// + +#define SFOUND 1 +#define SNOTFOUND 2 +#define SALT 3 + +///// +// Facility codes +///// + +/* Bits 16-31 are reserved for the facility code. */ +#define OWNOS 0x70 +#define OWNNOMAD 0x70 + +///// +// Error Messages +///// + +#define MAX_ERR_MSG 32 +static const char err_msg[NUM_ERR][MAX_ERR_MSG] = { "success", + "error", + "out of memory", + "resource allocation", + "memory corrupt!!!", + "format", + "not found", + "type", + "timeout", + "not supported", + "out of range", + "access denied", + "not ready", + "none free", + "bad argument", + "invalid", + "not open", + "already done", + "incorrect version", + "overflow", + "in use", + "too big" }; + +///// +// Return code object +///// + +#ifdef __CPP_BINDING +class ret { + private: + int val; + public: + ret() { val=ERR; } + ret(int src) { val=src; } +// ret(const ret& src) { val=src; } + ret operator=(const ret& src) { return val=src.val; } + ret operator=(int src) { return val=src; } + int operator==(const ret& cmp) { return val==cmp.val; } + int operator!() { return val<0; } + // returns 1 if error, 0 if success + int operator<(int cmp) { + // TODO implement some severity check + return (val<cmp); } + int operator<(ret& cmp) { return (val<cmp.val); } + operator int() const { return val; } // cast +// operator bool() { return (val<0); } + const char *disp() { + if(((val & 0x70) != 0x70) && ((val & 0x70) != 0x00)) + return "Unknown facility"; + return err_msg[-val]; } +}; +#else +typedef int ret; +#endif /* __CPP_BINDING */ + +#endif /* __ERR */ diff --git a/srv/ne2000/ne2000.c b/srv/ne2000/ne2000.c @@ -0,0 +1,858 @@ +/* $Id: //depot/blt/srv/ne2000/ne2000.c#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* This file contains a network driver core for the NE2000 card. +// Use at your own risk! (C) Copyright 1997, +// Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97 +// ... +// derived from National Semiconductor datasheets and application notes +// as well as the Linux driver by Donald Becker */ + +/* History Log: +10-25-97 Setup under CVS drarmstr +10-27-97 Added alloc_buffer() and free_buffer() drarmstr +12-08-97 Finished scatter gather drarmstr +03-03-98 Minor bug / Output cleanup drarmstr +03-04-98 snic->tx_buf[] packet_buf -> packet_buf* drarmstr +03-04-98 added passback pointer to notify and snic drarmstr +*/ + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ +#include <i386/io.h> +#include "ne2000.h" +#include "ne2k.h" +#include "err.h" +extern void kprintf(char *, ...); /* Make sure your OS has these...*/ +extern void idle(); +extern unsigned long ticks; + /* replace with a better timeout method, like wait() */ + +#ifdef XXX +static char *BLARGH = 0xB8000 + 160*23 + 152; +#define t(a) { BLARGH[0] = #a[0]; } +#define T(a) { BLARGH[2] = #a[0]; } +#else +#define t(a) {} +#define T(a) {} +#endif + +/* we may have to change inb and outb to inb_p and outb_p. +// Note, none of this code is gauranteed to be reentrant. + +// Note, don't create two nics to the same card and then try to use both +// of them. The results will be unpredictable. + +// This violates IO resource manegment if your OS handles that, but it +// works for now. Make sure that the driver has privlige access to the +// mapped I/O space and the IRQ.*/ +static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 }; + +/* internal procedure, don't call this directly.*/ +int nic_probe(int addr) { + uint regd; + uint state=inb(addr); /* save command state */ + + if(inb(addr==0xff)) return ERRNOTFOUND; + + outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); + regd=inb(addr + 0x0d); + outb(0xff, addr + 0x0d); + outb(NIC_DMA_DISABLE | NIC_PAGE0, addr); + inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/ + if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/ + outb(state,addr); /* restore command state*/ + outb(regd,addr + 0x0d); + return ERRNOTFOUND; } + + return addr; /* network card detected at io addr;*/ +} + +/* Detects for presence of NE2000 card. Will check given io addr that +// is passed to it as well as the default_ports array. Returns ERRNOTFOUND +// if no card is found, i/o address otherwise. This does conduct an ISA +// probe, so it's not always a good idea to run it. If you already have +// the information, then you can just use that with nic_init().*/ +int nic_detect(int given) { + int found; int f; + kprintf("NE2000: detecting card..."); + if(given) if((found=nic_probe(given))!=ERRNOTFOUND) { + kprintf("found at given:0x%x\n",given); + return found; } + + /* probe for PCI clones here.... or not...*/ + + for(f=0;default_ports[f]!='\0';f++) { + // perform resource manegment here + if((found=nic_probe(default_ports[f]))!=ERRNOTFOUND) { + kprintf("found at default:0x%x\n",default_ports[f]); + return found; } + } + kprintf("none found.\n"); + return ERRNOTFOUND; +} + +/* This initializes the NE2000 card. If it turns out the card is not +// really a NE2000 after all then it will return ERRNOTFOUND, else NOERR +// It also dumps the prom into buffer prom for the upper layers.. +// Pass it a nic with a null iobase and it will initialize the structure for +// you, otherwise it will just reinitialize it. */ +int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) { + uint f; + kprintf("NE2000: reseting NIC card..."); + if(!nic->iobase) { + nic->iobase=addr; + nic_stat_clear(&nic->stat); + nic->pstart=0; nic->pstop=0; nic->wordlength=0; + nic->current_page=0; + nic->notify=NULL; + for(f=0;f<MAX_TX;f++) { + nic->tx_packet[f]= NULL; +/* nic->tx_packet[f].count=0; + nic->tx_packet[f].buf=NULL; + nic->tx_packet[f].page=0; */ + } + nic->last_tx=NULL; + nic->busy=0; + nic->sending=0; + } else { + if(!nic->iobase || nic->iobase!=addr) return ERR; + } + + + outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/ + while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) { + /* TODO insert timeout code here.*/ + } + kprintf("done.\n"); + outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/ + + // Initialize registers + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/ + outb_p(DCR_DEFAULT, addr + DATACONFIGURATION); + outb_p(0x00, addr + REMOTEBYTECOUNT0); + outb_p(0x00, addr + REMOTEBYTECOUNT1); + outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ + outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ + outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/ + outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/ + + nic->wordlength=nic_dump_prom(nic,prom); + if(prom[14]!=0x57 || prom[15]!=0x57) { + kprintf("NE2000: PROM signature does not match NE2000 0x57.\n"); + return ERRNOTFOUND; + } + kprintf("NE2000: PROM signature matches NE2000 0x57.\n"); + + /* if the wordlength for the NE2000 card is 2 bytes, then + // we have to setup the DP8390 chipset to be the same or + // else all hell will break loose.*/ + if(nic->wordlength==2) { + outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION); + } + nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART; + nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP; + + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); + outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/ + outb_p(nic->pstart + TXPAGES, addr + PAGESTART); + outb_p(nic->pstop - 1, addr + BOUNDARY); + outb_p(nic->pstop, addr + PAGESTOP); + outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ + outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ + nic->current_page=nic->pstart + TXPAGES; + + /* put physical address in the registers */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */ + if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f); + else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f); + kprintf("NE2000: Physical Address- "); + kprintf("%X:%X:%X:%X:%X:%X\n", + inb(addr+PAR0),inb(addr+PAR1),inb(addr+PAR2), + inb(addr+PAR3),inb(addr+PAR4),inb(addr+PAR5)); + + /* setup multicast filter to accept all packets*/ + for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f); + + outb_p(nic->pstart+TXPAGES, addr + CURRENT); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */ + + return NOERR; +} + +/* This registers the function that will be called when a new packet +// comes in. */ +void nic_register_notify(snic *nic, + void (*newnotify)(void*,packet_data*), void *passback){ + nic->kore= passback; + nic->notify= newnotify; +} + +/* start the NIC so it can actually recieve or transmit packets */ +void nic_start(snic *nic, int promiscuous) { + int iobase; + kprintf("NE2000: Starting NIC.\n"); + if(!nic || !nic->iobase) { + kprintf("NE2000: can't start a non-initialized card.\n"); + return; } + iobase=nic->iobase; + outb(0xff, iobase + INTERRUPTSTATUS); + outb(IMR_DEFAULT, iobase + INTERRUPTMASK); + outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); + if(promiscuous) + outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION); + else + outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION); + + /* The following is debugging code! */ +#ifdef SHIT + kprintf("NE2000: Trying to fire off an IRQ.\n"); + outb_p(0x50,iobase+INTERRUPTMASK); + outb_p(0x00,iobase+REMOTEBYTECOUNT0); + outb_p(0x00,iobase+REMOTEBYTECOUNT1); + outb_p(NIC_REM_READ | NIC_START,iobase); /* this should fire off */ + outb_p(IMR_DEFAULT,iobase+INTERRUPTMASK); /* an interrupt... */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(0xff,iobase+INTERRUPTSTATUS); +#endif + /* End debugging code */ +} + +/* stops the NIC */ +void nic_stop(snic *nic) { + unsigned char tmp_buffer[16]; + if(!nic || !nic->iobase) return; /* make sure card was initialized */ + nic_init(nic,nic->iobase,tmp_buffer,NULL); +} + +void nic_isr(snic *nic) { + uint isr; /* Illinois Sreet Residence Hall */ + uint overload; + if(!nic || !nic->iobase) return; /* make sure card was initialized */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); + overload=MAX_LOAD+1; + while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) { + if((--overload)<=0) break; + if(isr & ISR_OVW) nic_overrun(nic); + else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic); + if(isr & ISR_PTX) nic_tx(nic); + else if(isr & ISR_TXE) nic_tx_err(nic); + if(isr & ISR_CNT) nic_counters(nic); + if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); + } + if(isr) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); + if(!overload) { + kprintf("NE2000: Too many requests in ISR. ISR:%X MaxLoad:%X\n", + isr, MAX_LOAD); + outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear + } else { + kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr); + outb_p(0xff, nic->iobase + INTERRUPTSTATUS); + // Ack it anyway + } + } +} + +/* You should call this before you just read the stats directlly from the +// snic struct. This procedure updates the counters */ +nic_stat nic_get_stats(snic *nic) { + nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY); + nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY); + nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY); + return nic->stat; +} + +void nic_stat_clear(nic_stat *that) { + that->rx_packets=0; + that->tx_buffered=0; that->tx_packets=0; + that->errors.frame_alignment=0; that->errors.crc=0; + that->errors.missed_packets=0; that->errors.rx=0; + that->errors.rx_size=0; that->errors.rx_dropped=0; + that->errors.rx_fifo=0; that->errors.rx_overruns=0; + that->errors.tx_collisions=0; +} + +/* Since this could be called by more than one other device, it should +// be properly protected for reentrancy. We should put in a proper +// semaphore or something, look into this. +// NOTE: It is your responsibility to clean up the packet_buffer when you +// are done calling this. */ +/* TODO- Have it check how lonk a transmission is taking and attempt to + restart the card if it's too long. */ +int nic_send_packet(snic *nic, packet_buffer *buffer) { + uint timeout; uint f; int iobase; +/* kprintf("nic_send_packet()\n"); */ + if(!buffer) return ERRARG; + if(!buffer->count || !buffer->buf) return ERRARG; + if(!nic || !nic->iobase) return ERR; + iobase=nic->iobase; + + t(A); + + buffer->len=0; + for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len; + if(buffer->len>MAX_LENGTH) return ERRTOOBIG; + + t(B); + + /* the following wait for anyother tasks that are calling + // nic_send_packet() right now. Note that this doesn't use + // an atomic semaphore, so something MAY leak through. */ +/* timeout=ticks+10; wait 10 ticks */ + timeout=ticks+100; + while(nic->busy && ticks<=timeout) idle(); + /* Replace this with a proper timeout thing that doesn't use the + // ticks method which will be diffrent on each OS. */ + t(C); + if(nic->busy) { + kprintf("NE2000: ERROR: Card stalled, timeout.\n"); + return ERRTIMEOUT; + } + nic->busy=1; /* mark as busy, replace with semaphore */ + + t(D); + + outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */ + t(E); + + timeout=ticks+TIMEOUT_TX; + while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) { + if(!nic->tx_packet[f]) { + t(F); + +/* nic->tx_packet[f]=*buffer;*/ + nic->tx_packet[f]=buffer; + nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET); + /*output page */ + +/* kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n", + buffer->count,buffer->page,buffer->buf); */ + t(>); + + nic_block_output(nic,nic->tx_packet[f]); + + t(<); + + if(!nic->sending) { + nic->send=f; nic->sending=1; + /* now let's actually trigger the transmitter */ + t(I); + + if(nic_send(nic,f)<0) { + nic->sending=0; + break; } + + /* note, the nic_tx() interrupt will mark this + // tx_packet buffer as free again once it + // confirms that the packet was sent. */ + } + t(J); + + nic->stat.tx_buffered++; + outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ + nic->busy=0; /* V() */ + t(K); + + return NOERR; + } + } + + t(L); + + outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ + nic->busy=0; /* V() */ + kprintf("NE2000: ERROR: Transmitter stalled, card timeout.\n"); + if(f==MAX_TX) { + kprintf("NE2000: ERROR: There are no transmit buffers available. TX stalled.\n"); + return ERRTIMEOUT; + } + return ERR; +} + +/* dumps the prom into a 16 byte buffer and returns the wordlength of +// the card. +// You should be able to make this procedure a wrapper of nic_block_input(). */ +int nic_dump_prom(snic *nic, unsigned char *prom) { + uint f; + int iobase=nic->iobase; + char wordlength=2; /* default wordlength of 2 */ + unsigned char dump[32]; + outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */ + outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */ + outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */ + outb_p(0x00, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + for(f=0;f<32;f+=2) { + dump[f]=inb_p(iobase + NE_DATA); + dump[f+1]=inb_p(iobase + NE_DATA); + if(dump[f]!=dump[f+1]) wordlength=1; + } + /* if wordlength is 2 bytes, then collapse prom to 16 bytes */ + for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)]; +/* kprintf("NE2000: prom dump - "); + for(f=0;f<LEN_PROM;f++) kprintf("%X",prom[f]); + kprintf("\n"); */ + + return wordlength; +} + +void nic_overrun(snic *nic) { + uint tx_status; int iobase=nic->iobase; + long starttime; uint resend=0; + kprintf("NE2000: Receive packet ring overrun!\n"); + if(!nic || !nic->iobase) return; + tx_status=inb_p(iobase) & NIC_TRANSMIT; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase); + nic->stat.errors.rx_overruns++; + + starttime=ticks; +kprintf("BEFORE\n"); + while(ticks-starttime<=10/*ticks to wait*/) idle(); + /* Arrgh! TODO: Replace this whole crappy code with a decent + // wait method. We need to wait at least 1.6ms as per National + // Semiconductor datasheets, but we should probablly wait a + // little more to be safe. */ +kprintf("AFTER\n"); + + outb_p(0x00, iobase + REMOTEBYTECOUNT0); + outb_p(0x00, iobase + REMOTEBYTECOUNT1); + if(tx_status) { + uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) & + (ISR_PTX | ISR_TXE); + if(!tx_completed) resend=1; + } + + outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + nic_rx(nic); /* cleanup RX ring */ + outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */ + + outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); + if(resend) + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT, + iobase); +} + +/* This is the procedure that markst the transmit buffer as available again */ +void nic_tx(snic *nic) { + uint f; int iobase=nic->iobase; + uint status; +/* kprintf("nic_tx()\n"); */ + if(!nic || !nic->iobase) return; + status=inb(iobase + TRANSMITSTATUS); + + if(!nic->tx_packet[nic->send]) { + kprintf("NE2000: ERROR: Invalid transmison packet buffer.\n"); + return; + } + if(!nic->sending) kprintf("NE2000: ERROR: Invalid nic->sending value.\n"); + + free_buffer(nic->tx_packet[nic->send]); + nic->tx_packet[nic->send]= NULL; +/* nic->tx_packet[nic->send].count=0; mark buffer as available */ +/* nic->tx_packet[nic->send].len=0; + nic->tx_packet[nic->send].page=0; */ + + for(f=0;f<MAX_TX;f++) { + if(nic->tx_packet[f]) { + kprintf("NE2000: DEBUG: transmitting secondary buffer:%X\n",f); + nic->stat.tx_buffered++; + nic->send=f; nic->sending=1; + nic_send(nic,f); /* send a back-to-back buffer */ + break; + } + } + if(f==MAX_TX) nic->sending=0; + + if(status & TSR_COL) nic->stat.errors.tx_collisions++; + if(status & TSR_PTX) nic->stat.tx_packets++; + else { + if(status & TSR_ABT) { + nic->stat.errors.tx_aborts++; + nic->stat.errors.tx_collisions+=16; } + if(status & TSR_CRS) nic->stat.errors.tx_carrier++; + if(status & TSR_FU) nic->stat.errors.tx_fifo++; + if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++; + if(status & TSR_OWC) nic->stat.errors.tx_window++; + } + + outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */ +} + +void nic_tx_err(snic *nic) { + unsigned char tsr; int iobase=nic->iobase; + if(!nic || !nic->iobase) return; + tsr=inb_p(nic->iobase); + kprintf("NE2000: ERROR: TX error: "); + if(tsr & TSR_ABT) kprintf("Too many collisions.\n"); + if(tsr & TSR_ND) kprintf("Not deffered.\n"); + if(tsr & TSR_CRS) kprintf("Carrier lost.\n"); + if(tsr & TSR_FU) kprintf("FIFO underrun.\n"); + if(tsr & TSR_CDH) kprintf("Heart attack!\n"); + + outb_p(ISR_TXE, iobase + INTERRUPTSTATUS); + if(tsr & (TSR_ABT | TSR_FU)) { + kprintf("NE2000: DEBUG: Attempting to retransmit packet.\n"); + nic_tx(nic); + } +} + +void nic_rx(snic *nic) { + uint packets=0; uint frame; uint rx_page; uint rx_offset; + uint len; uint next_pkt; uint numpages; + int iobase=nic->iobase; + buffer_header header; + if(!nic || !nic->iobase) return; + while(packets<MAX_RX) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */ + rx_page=inb_p(iobase + CURRENT); /* get current page */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase); + frame=inb(iobase + BOUNDARY)+1; + /* we add one becuase boundary is a page behind + // as pre NS notes to help in overflow problems */ + if(frame>=nic->pstop) frame=nic->pstart+TXPAGES; + /* circual buffer */ + + if(frame != nic->current_page) { + kprintf("NE2000: ERROR: mismatched read page pointers!\n"); + kprintf("NE2000: NIC-Boundary:%x dev-current_page:%x\n", + frame, nic->current_page); } + +/* kprintf("Boundary-%x Current-%x\n",frame-1,rx_page); */ + if(frame==rx_page) break; /* all frames read */ + + rx_offset=frame << 8; /* current ptr in bytes(not pages) */ + + nic_get_header(nic,frame,&header); + len=header.count - sizeof(buffer_header); + /* length of packet */ + next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */ + + numpages=nic->pstop-(nic->pstart+TXPAGES); + if( (header.next!=next_pkt) + && (header.next!=next_pkt + 1) + && (header.next!=next_pkt - numpages) + && (header.next != next_pkt +1 - numpages)){ + kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n", + header.next,next_pkt,frame); + nic->current_page=frame; + outb(nic->current_page-1, iobase + BOUNDARY); + nic->stat.errors.rx++; + continue; + } + + if(len<60 || len>1518) { + kprintf("NE2000: invalid packet size:%d\n",len); + nic->stat.errors.rx_size++; + } else if((header.status & 0x0f) == RSR_PRX) { + /* We have a good packet, so let's recieve it! */ + + packet_data *newpacket=alloc_buffer_data(len); + if(!newpacket) { + kprintf("NE2000: ERROR: out of memory!\n"); + nic->stat.errors.rx_dropped++; + nic_block_input(nic,NULL,len,rx_offset+ + sizeof(buffer_header)); + } else { + nic_block_input(nic,newpacket->ptr,newpacket->len, + rx_offset+sizeof(buffer_header)); + /* read it */ + + if(nic->notify) nic->notify(nic->kore,newpacket); + else free_buffer_data(newpacket); + /* NOTE: you are responsible for deleting this buffer. */ + + nic->stat.rx_packets++; + } + } else { + kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n", + header.status,header.next,header.count); + if(header.status & RSR_FO) nic->stat.errors.rx_fifo++; + } +/* kprintf("frame:%x header.next:%x next_pkt:%x\n", + frame,header.next,next_pkt); */ + next_pkt=header.next; + + if(next_pkt >= nic->pstop) { + kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n", + next_pkt); + next_pkt=nic->pstart+TXPAGES; + } + + nic->current_page=next_pkt; + outb_p(next_pkt-1, iobase + BOUNDARY); + } + outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */ +} + +void nic_counters(snic *nic) { + nic->stat.errors.frame_alignment+=inb_p(nic->iobase+FAE_TALLY); + nic->stat.errors.crc+=inb_p(nic->iobase+CRC_TALLY); + nic->stat.errors.missed_packets+=inb_p(nic->iobase+MISS_PKT_TALLY); + /* reading the counters on the DC8390 clears them. */ + outb_p(ISR_CNT, nic->iobase + INTERRUPTSTATUS); /* ackkowledge int */ +} + +/* You should be able to make this procedure a wrapper of nic_block_input */ +void nic_get_header(snic *nic, uint page, buffer_header *header) { + int iobase=nic->iobase; uint f; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0); + outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */ + outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */ + outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */ + outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */ + + if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++) + ((unsigned short *)header)[f]=inw(iobase+NE_DATA); + else for(f=0;f<sizeof(buffer_header);f++) + ((unsigned char *)header)[f]=inb(iobase+NE_DATA); + /* Do these need to be *_p variants??? */ + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} + +int nic_send(snic *nic, uint buf) { + uint len= (nic->tx_packet[buf]->len<MIN_LENGTH) ? + MIN_LENGTH : nic->tx_packet[buf]->len; +/* kprintf("nic_send()\n"); */ + if(!nic->tx_packet[buf]) return ERR; /* this is bad */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); + if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) { + kprintf("NE2000: ERROR: Transmitor busy.\n"); + free_buffer(nic->tx_packet[buf]); + nic->tx_packet[buf]= NULL; +/* nic->tx_packet[buf].count=0; mark as free again */ + return ERRTIMEOUT; } + outb_p(len & 0xff,nic->iobase+TRANSMITBYTECOUNT0); + outb_p(len >> 8,nic->iobase+TRANSMITBYTECOUNT1); + outb_p(nic->tx_packet[buf]->page,nic->iobase+TRANSMITPAGE); + outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase); + return NOERR; +} + +void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) { + int iobase=nic->iobase; uint f; + uint xfers=len; + uint timeout=TIMEOUT_DMAMATCH; uint addr; +/* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset); */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); + outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); + outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0); + outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + + /* allow for no buffer */ + if(buf){ + if(nic->wordlength==2) { + for(f=0;f<(len>>1);f++) + ((unsigned short *)buf)[f]=inw(iobase+NE_DATA); + if(len&0x01) { + ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA); + xfers++; + } + } else { + for(f=0;f<len;f++) + ((unsigned char *)buf)[f]=inb(iobase+NE_DATA); + } + } else { + if(nic->wordlength==2) { + for(f=0;f<(len>>1);f++) + inw(iobase+NE_DATA); + if(len&0x01) { + inb(iobase+NE_DATA); + xfers++; + } + } else { + for(f=0;f<len;f++) + inb(iobase+NE_DATA); + } + } + /* Do these need to be *_p variants??? */ + +/* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n"); */ + /* TODO: make this timeout a constant */ + for(f=0;f<timeout;f++) { + uint high=inb_p(iobase + REMOTESTARTADDRESS1); + uint low=inb_p(iobase + REMOTESTARTADDRESS0); + addr=(high<<8)+low; + if(((offset+xfers)&0xff)==low) break; + } + /* + if(f>=timeout) + kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", + offset+xfers, addr); HUH WHAT? BJS*/ + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} + +/* Now supports scatter gather */ +void nic_block_output(snic *nic, packet_buffer *pkt) { + int iobase=nic->iobase; + int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int tmplen; + int bufidx, buflen; /* current packet_data in packet_buffer */ + void *bufptr; + char skip=0; /* Ask me about this if you have questions */ + uint deleteme=0; /* delete when done debugging */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + + T(A); + + for(f=0;f<pkt->count;f++) deleteme+=pkt->buf[f].len; + T(B); + + if(pkt->len != deleteme) return; + + if(pkt->len > MAX_LENGTH) return; + /* we should not have gotten this far... Paranoia check */ + + /* this next part is to supposedly fix a "read-before-write" bug... */ + outb_p(0x42, iobase + REMOTEBYTECOUNT0); + outb_p(0x00, iobase + REMOTEBYTECOUNT1); + outb_p(0x42, iobase + REMOTESTARTADDRESS0); + outb_p(0x00, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */ + T(C); + + tmplen=(pkt->len < MIN_LENGTH) ? MIN_LENGTH : pkt->len; + outb_p(tmplen & 0xff, iobase + REMOTEBYTECOUNT0); + outb_p(tmplen >> 8, iobase + REMOTEBYTECOUNT1); + outb_p(0x00, iobase + REMOTESTARTADDRESS0); + outb_p(pkt->page, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_WRITE | NIC_START, iobase); + + T(D); + + /* go through each buffer and transfer it's contents */ + for(bufidx=pkt->count-1; bufidx >= 0; bufidx--) { + char odd; + buflen=pkt->buf[bufidx].len; /* only do derefrence once */ + bufptr=pkt->buf[bufidx].ptr; /* for performance :) */ + + if(nic->wordlength==2) { + + odd=(buflen & 0x01); + buflen>>=1; /* half the transfers */ + + if(skip) ((uint)bufptr)--; /* korewa baka desu */ + + for(f=skip;f<buflen;f++) { /* do we skip? */ + outw(((unsigned short *)bufptr)[f],iobase+NE_DATA); + tmplen -= 2; + } + + /* output 16-bits of the last odd byte */ + skip=0; /* assume we don't skip */ + + if(odd) { + short tmp=((unsigned char *)bufptr)[buflen<<1]; + /* get the byte from the next segment */ + if((bufidx-1)>=0) { + tmp |= ((unsigned char *) pkt->buf[bufidx-1].ptr)[0] << 8; + } + outw(tmp,iobase + NE_DATA); + tmplen -= 2; + skip=1; + } + } else + for(f=0;f<buflen;f++) { + outb(((unsigned char *)bufptr)[f],iobase+NE_DATA); + tmplen--; + } + } + T(E); + + /* If it's too short, pad with 0s */ + if(tmplen > 0) { + T(F); +/* kprintf("Padding runt\n"); */ + if(nic->wordlength==2) { + for(f=0;f<tmplen/2;f++){ + outw(0x00,iobase + NE_DATA); + tmplen -= 2; + } + } + } + if (tmplen > 0) { + for(f=0;f<tmplen;f++) { + outb(0x00,iobase + NE_DATA); + tmplen--; + } + } + + + T(G); +#ifdef SHIT + if(nic->wordlength==2) { + for(w=0;w<(len>>1);w++) + outw(((unsigned short *)buf)[w],iobase+NE_DATA); + if(len & 0x01) { + short tmp=buf[len-1]; //so we can output a whole 16-bits + // if buf were on the end of something, we would die. + outw(tmp,iobase+NE_DATA); + } + } else for(f=0;f<len;f++) + outb(((unsigned char *)buf)[f],iobase+NE_DATA); + +#endif + for(f=0;f<timeout;f++) { + uint high=inb_p(iobase + REMOTESTARTADDRESS1); + uint low=inb_p(iobase + REMOTESTARTADDRESS0); + addr=(high<<8)+low; + if(( (((pkt->page<<8)+(nic->wordlength==2 && (pkt->len&0x01))? +/* pkt->len+1:pkt->len+2))&0xff)==low)*/ + pkt->len+0:pkt->len+1))&0xff)==low) + break; + if( (pkt->len < MIN_LENGTH) && ( (((pkt->page<<8)+MIN_LENGTH) + & 0xff) == low) ) + break; + } + T(H); +#ifdef SHIT + if(f>=timeout) + kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", + ( (pkt->len >= MIN_LENGTH) ? + ((pkt->page<<8)+ + (nic->wordlength==2&&(pkt->len&0x01))? + pkt->len+0:pkt->len+1) +/* pkt->len+1:pkt->len+2)*/ + : ((pkt->page<<8)+MIN_LENGTH) ), + addr); +#endif +/* TODO Check ISR_RDC */ + + T(I); + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} diff --git a/srv/ne2000/ne2000.h b/srv/ne2000/ne2000.h @@ -0,0 +1,187 @@ +/* $Id: //depot/blt/srv/ne2000/ne2000.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __NE2000_SHARED_CODE_BASE +#define __NE2000_SHARED_CODE_BASE +typedef unsigned int uint; +typedef struct snic snic; +typedef struct nic_stat nic_stat; +typedef struct buffer_header buffer_header; +typedef struct packet_data packet_data; +typedef struct packet_buffer packet_buffer; +typedef struct nic_error_stat nic_error_stat; + +/* internal implementation procedures */ +int nic_probe(int addr); +int nic_dump_prom(snic *nic, unsigned char *prom); +void nic_overrun(snic *nic); +void nic_tx(snic *nic); +void nic_tx_err(snic *nic); +void nic_rx(snic *nic); +void nic_counters(snic *nic); +void nic_get_header(snic *nic, uint page, buffer_header *header); +int nic_send(snic *nic, uint buf); +void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset); +void nic_block_output(snic *nic, packet_buffer *pkt); + +#define PSTART 0x20 /* if NE2000 is byte length */ +#define PSTOP 0x40 +#define PSTARTW 0x40 /* if NE2000 is wordlength */ +#define PSTOPW 0x80 +#define MAX_LOAD 12 /* maximum services per IRQ request*/ +#define MAX_RX 10 /* maximum packets recieve per call*/ +#define MIN_LENGTH 60 /* minimum length for packet data */ +#define MAX_LENGTH 1500 /* maximum length for packet data area */ +#define TIMEOUT_DMAMATCH 40 /* for nic_block_input() */ +#define TIMEOUT_TX 40 + +/* DP8390 NIC Registers*/ +#define COMMAND 0x00 +#define STATUS COMMAND+0 +#define PHYSICAL COMMAND+1 /* page 1 */ +#define MULTICAST COMMAND+8 /* page 1 */ +#define PAGESTART COMMAND+1 /* page 0 */ +#define PAGESTOP COMMAND+2 +#define BOUNDARY COMMAND+3 +#define TRANSMITSTATUS COMMAND+4 +#define TRANSMITPAGE COMMAND+4 +#define TRANSMITBYTECOUNT0 COMMAND+5 +#define NCR COMMAND+5 +#define TRANSMITBYTECOUNT1 COMMAND+6 +#define INTERRUPTSTATUS COMMAND+7 +#define CURRENT COMMAND+7 /* page 1 */ +#define REMOTESTARTADDRESS0 COMMAND+8 +#define CRDMA0 COMMAND+8 +#define REMOTESTARTADDRESS1 COMMAND+9 +#define CRDMA1 COMMAND+9 +#define REMOTEBYTECOUNT0 COMMAND+10 /* how many bytes we will */ +#define REMOTEBYTECOUNT1 COMMAND+11 /* read through remote DMA->IO */ +#define RECEIVESTATUS COMMAND+12 +#define RECEIVECONFIGURATION COMMAND+12 +#define TRANSMITCONFIGURATION COMMAND+13 +#define FAE_TALLY COMMAND+13 /* page 0 */ +#define DATACONFIGURATION COMMAND+14 +#define CRC_TALLY COMMAND+14 +#define INTERRUPTMASK COMMAND+15 +#define MISS_PKT_TALLY COMMAND+15 + +/* NE2000 specific implementation registers */ +#define NE_RESET 0x1f /* Reset */ +#define NE_DATA 0x10 /* Data port (use for PROM) */ + +#define PAR0 COMMAND+1 +#define PAR1 COMMAND+2 +#define PAR2 COMMAND+3 +#define PAR3 COMMAND+4 +#define PAR4 COMMAND+5 +#define PAR5 COMMAND+6 + +/* NIC Commands */ +#define NIC_STOP 0x01 /* STOP */ +#define NIC_START 0x02 /* START */ +#define NIC_PAGE0 0x00 +#define NIC_PAGE1 0x40 +#define NIC_PAGE2 0x80 +#define NIC_TRANSMIT 0x04 /* Transmit a frame */ +#define NIC_REM_READ 0x08 /* Remote Read */ +#define NIC_REM_WRITE 0x10 /* Remote Write */ +#define NIC_DMA_DISABLE 0x20 /* Disable DMA */ + +/* Data Configuration Register */ +#define DCR_WTS 0x01 /* Word Transfer Select (0=byte, 1=word) */ +#define DCR_BOS 0x02 /* Byte Order Select (0=big-endian) */ +#define DCR_LAS 0x04 /* Long Address Select (0=dual 16-bit DMA) */ +#define DCR_LS 0x08 /* Loopback Select (0=loopback) */ +#define DCR_AR 0x10 /* Auto Initialize Remote */ +#define DCR_FT 0x60 /* (FT0 & FT1) FIFO Threshhold (see datasheet) */ +/*#define DCR_DEFAULT 0x58 Standard value for the DCR register */ +#define DCR_DEFAULT 0x48 /* don't use Automatic send packet */ +#define DCR_DEFAULT_WORD 0x49 /* defuault with wold length transfer */ + +/* Recieve Configure Register */ +#define RCR_SEP 0x01 /* Save Errored Packets */ +#define RCR_AR 0x02 /* Accept Runt Packets */ +#define RCR_AB 0x04 /* Accept Broadcast */ +#define RCR_AM 0x08 /* Accept Multicast */ +#define RCR_PRO 0x10 /* Promiscuous Physical */ +#define RCR_MON 0x20 /* Monitor Mode */ +/*#define RCR_DEFAULT 0x00 Standard value for the RCR register */ +#define RCR_DEFAULT 0x0c /* Accept Broadcast/Multicast Packets */ + +/* Recieve Status Register */ +/* note, this is also stored in the status byte in the buffer header. */ +/* That's the 4 byte entry in the local buffer, not the packet header. */ +#define RSR_PRX 0x01 /* Pakcet Received Intact */ +#define RSR_CRC 0x02 /* CRC Error */ +#define RSR_FAE 0x04 /* Frame Alignment Error */ +#define RSR_FO 0x08 /* FIFO Overrun */ +#define RSR_MPA 0x10 /* Missed Packet */ +#define RSR_PHY 0x20 /* Physical/Multicast Address (0=physical) */ +#define RSR_DIS 0x40 /* Receiver Disabled */ +#define RSR_DFR 0x80 /* Deferring */ + +/* Transmit Configure Register */ +#define TCR_CRC 0x01 /* Inhibit CRC (0=CRC active) */ +#define TCR_LB 0x06 /* (LB0 & LB1) Encoded Loopback Control */ +#define TCR_ATD 0x08 /* Auto Transmit Disable (0=normal) */ +#define TCR_OFST 0x10 /* Collision Offset Enable (1=low priority) */ +#define TCR_DEFAULT 0x00 /* Standard value for the TCR register */ +#define TCR_INTERNAL_LOOPBACK 0x02 /* Internal loopback configuration */ + +/* Transmit Status Register */ +#define TSR_PTX 0x01 /* Packet Transmitted */ +#define TSR_ND 0x02 /* Non-Deferral (Documented???) */ +#define TSR_COL 0x04 /* Transmit Collided */ +#define TSR_ABT 0x08 /* Transmit Aborted */ +#define TSR_CRS 0x10 /* Carrier Sense Lost */ +#define TSR_FU 0x20 /* FIFO Underrun */ +#define TSR_CDH 0x40 /* CD Heartbeat */ +#define TSR_OWC 0x80 /* Oout of Window Collision */ + +/* Interrupt Status Register */ +#define ISR_PRX 0x01 /* Packet Received */ +#define ISR_PTX 0x02 /* Packet Transmitted */ +#define ISR_RXE 0x04 /* Receive Error */ +#define ISR_TXE 0x08 /* Transmit Error */ +#define ISR_OVW 0x10 /* Overwrite Warning */ +#define ISR_CNT 0x20 /* Counter Overflow */ +#define ISR_RDC 0x40 /* Remote DMA Complete */ +#define ISR_RST 0x80 /* Reset Status */ +#define ISR_DEFAULT 0x00 /* Standard value for the ISR register */ +#define ISR_ALL 0x3f /* The services that we handle in the isr */ + +/* Interrupt Mask Register */ +#define IMR_PRXE 0x01 /* Packet Received Interrupt Enable */ +#define IMR_PTXE 0x02 /* Packet Transmitted Interrupt Enable */ +#define IMR_RXEE 0x04 /* Receive Error Interrupt Enable */ +#define IMR_TXEE 0x08 /* Transmit Error Interrupt Enable */ +#define IMR_OVWE 0x10 /* Overwrite Warning Interrupt Enable */ +#define IMR_CNTE 0x20 /* Counter Overflow Interrupt Enable */ +#define IMR_RDCE 0x40 /* DMA Complete Interrupt Enable */ +#define IMR_DEFAULT 0x3f /* CNTE | OVWE | TXEE | RXEE | PTXE | PRXE */ + +#endif diff --git a/srv/ne2000/ne2k.c b/srv/ne2000/ne2k.c @@ -0,0 +1,609 @@ +/* Copyright 1999, Brian J. Swetland. All Rights Reserved. +** This file is provided under the terms of the OpenBLT License +*/ + +#include "string.h" + +#include <blt/namer.h> +#include <blt/syscall.h> +#include <blt/conio.h> +#include <blt/qsem.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "net.h" + +#define NULL ((void *) 0) + +#include "ne2k.h" + +int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq); + +/* hard code these for now */ +#define NIC_IRQ 5 +#define NIC_ADDR 0x300 + +static snic TheSNIC; +int snic_irq = NIC_IRQ; +int snic_addr = NIC_ADDR; + + +static unsigned char prom[32]; +static unsigned char IP[4] = { 10, 113, 216, 6 }; /* we get our ip from the booter */ + +/* messaging */ +static int port_isr = 0; +static int port_xmit = 0; + +static qsem_t *sem_xmit_done = NULL; +static int port_net = 0; + +qsem_t *mutex = NULL; +qsem_t *sem_ring = NULL; + +#define LOG_LEVEL 9999 + +/* to keep site's ne2000 code happy */ +void kprintf(char *fmt,...) +{ +} + +#define trace(a, b) if (a >= LOG_LEVEL) printf("ne2000: %s\n", b); + +#define RINGSIZE 16 +#define PACKETSIZE 1536 + +typedef struct _pbuf { + struct _pbuf *next; /* 4 */ + packet_buffer pb; /* 16 */ + packet_data pd; /* 8 */ + int n; +} pbuf; + +#define pb_to_ring(x) ((pbuf *) (((char *) (x)) - 4)) +#define pd_to_ring(x) ((pbuf *) (((char *) (x)) - 20)) + +pbuf *p_next = NULL; + +typedef struct pmap pmap; + +struct pmap { + struct pmap *next; + int udp_port; + int blt_port; +}; + +pmap *pmaps = NULL; + +pbuf *p_discard; + +void init_ring(void) +{ + int i; + pbuf *p; + p_next = NULL; + + for(i=0;i<RINGSIZE;i++){ + p = (pbuf *) malloc(sizeof(pbuf)); + p->next = p_next; + p_next = p; + p->pb.count = 1; + p->pb.buf = &(p->pd); + p->pd.ptr = (char *) malloc(PACKETSIZE); + p->n = i; + } + + p_discard = p_next; + p_next = p_next->next; +} + + +/* called by the ne2k core to get a receive buffer */ +packet_data *alloc_buffer_data(uint size) +{ + pbuf *P; + + qsem_acquire(sem_ring); + if(!p_next){ + qsem_release(sem_ring); + printf("ne2000: !!! out of packet ringbuffers (recv)\n"); + return NULL; + } + P = p_next; + p_next = P->next; + qsem_release(sem_ring); + + P->pd.len = size; + return &(P->pd); +} + + +/* called by the us to sem_release a received buffer */ +void free_buffer_data(packet_data *pd) +{ + pbuf *P = pd_to_ring(pd); + qsem_acquire(sem_ring); + P->next = p_next; + p_next = P; + qsem_release(sem_ring); +} + + +/* called by our send data routines to get a send buffer */ +pbuf *get_pbuf(void) +{ + pbuf *P; + qsem_acquire(sem_ring); + if(!p_next){ + qsem_release(sem_ring); + return p_discard; + } + P = p_next; + p_next = P->next; + qsem_release(sem_ring); + return P; +} + +/* called after a pbuf is xmit'd */ +void free_buffer(packet_buffer *ptr) +{ + pbuf *P = pb_to_ring(ptr); + + trace(1, "free_buffer"); + + if(P == p_discard) return; + + qsem_acquire(sem_ring); + P->next = p_next; + p_next = P; + qsem_release(sem_ring); + + qsem_release(sem_xmit_done); +} + +int ticks = 0; +void idle(void) +{ + int i; + for(i=0;i<1000;i++); + ticks++; +} + +typedef struct +{ + net_ether ether; + net_arp arp; +} arp_packet; + +void print_arp(unsigned char *p); + + +void +xmit(pbuf *P) +{ + int i; + msg_hdr_t mh; + /* printf("xmit: P->n = %d\n",P->n);*/ + + if(P == p_discard) return; + + mh.flags = 0; + mh.src = port_isr; + mh.dst = port_xmit; + mh.size = 4; + mh.data = &P; + if((i = old_port_send(&mh)) != 4) printf("xmit: blargh! %d\n",i); + +} + +void handle_arp(arp_packet *req, pbuf *packet) +{ + if(htons(req->arp.arp_op) == ARP_OP_REQUEST){ + if(!memcmp(&(req->arp.arp_ip_target),IP,4)){ + pbuf *P; + arp_packet *resp; + P = get_pbuf(); + resp = (arp_packet *) P->pd.ptr; + +/* printf("handle_arp: IS the one!\n");*/ + memcpy(&(resp->ether.src),prom,6); + memcpy(&(resp->ether.dst),&(req->ether.src),6); + resp->ether.type = htons(0x0806); + resp->arp.arp_hard_type = htons(1); + resp->arp.arp_prot_type = htons(0x0800); + resp->arp.arp_hard_size = 6; + resp->arp.arp_prot_size = 4; + resp->arp.arp_op = htons(ARP_OP_REPLY); + memcpy(&(resp->arp.arp_enet_sender),prom,6); + memcpy(&(resp->arp.arp_ip_sender),IP,4); + memcpy(&(resp->arp.arp_enet_target),&(req->arp.arp_enet_sender),6); + memcpy(&(resp->arp.arp_ip_target),&(req->arp.arp_ip_sender),4); + print_arp((unsigned char *) &(resp->arp)); + + P->pd.len = sizeof(arp_packet); + P->pb.len = sizeof(arp_packet); + + xmit(P); + } else { + /*printf("handle_arp: NOT the one.\n"); */ + } + } +} + +void print_arp(unsigned char *p) +{ + net_arp *arp = (net_arp *) p; + unsigned char *b; + unsigned short t; + + printf(" ARP: "); + t = htons(arp->arp_op); + if(t == ARP_OP_REQUEST) printf("req "); + else if(t == ARP_OP_REPLY) printf("rep "); + else printf("??? "); + + b = (unsigned char *) &(arp->arp_enet_sender); + printf("source: %X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]); + b = (unsigned char *) &(arp->arp_ip_sender); + printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]); + + printf(" ARP: target: "); + + b = (unsigned char *) &(arp->arp_enet_target); + printf("%X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]); + b = (unsigned char *) &(arp->arp_ip_target); + printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]); + +} + +void print_ip(unsigned char *p) +{ +} + +int ipchksum(void *_ip, int len) +{ + register unsigned short *ip = (unsigned short *) _ip; + register unsigned long sum = 0; + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return((~sum) & 0x0000FFFF); +} + + +void +handle_icmp(icmp_packet *icmp) +{ + pbuf *P; + icmp_packet *resp; + + if(icmp->icmp.icmp_type == ICMP_PING_REQ){ + P = get_pbuf(); + resp = (icmp_packet *) P->pd.ptr; + + memcpy(&(resp->ether.src),prom,6); + memcpy(&(resp->ether.dst),&(icmp->ether.src),6); + memcpy(&(resp->ether.type),&(icmp->ether.type),2); + + resp->ip.ip_hdr_len = 5; + resp->ip.ip_version = 4; + resp->ip.ip_tos = 0; + resp->ip.ip_len = icmp->ip.ip_len; + resp->ip.ip_id = 0; + resp->ip.ip_off = 0; + resp->ip.ip_ttl = 64; + resp->ip.ip_proto = 0x01; + resp->ip.ip_chk = 0; + (int) resp->ip.ip_src = *(int *) IP; + resp->ip.ip_dst = icmp->ip.ip_src; + resp->ip.ip_chk = ipchksum(&(resp->ip),sizeof(net_ip)); + + resp->icmp.icmp_type = ICMP_PING_REP; + resp->icmp.icmp_code = 0; + resp->icmp.icmp_chk = 0; + resp->icmp.data.ping.id = icmp->icmp.data.ping.id; + resp->icmp.data.ping.seq = icmp->icmp.data.ping.seq; + memcpy(resp->icmp.data.ping.data,icmp->icmp.data.ping.data, + ntohs(icmp->ip.ip_len) - 28); + + resp->icmp.icmp_chk = ipchksum(&(resp->ip),ntohs(resp->ip.ip_len)); +/* printf("ICMP resp l = %d\n",ntohs(resp->ip.ip_len));*/ + + P->pb.len = P->pd.len = ntohs(resp->ip.ip_len)+14; + + xmit(P); + } +} + + +void +handle_udp(udp_packet *udp, pbuf *packet) +{ + pmap *m; + msg_hdr_t msg; + int i; + + for(m = pmaps; m; m = m->next){ + if(m->udp_port == ntohs(udp->udp.udp_dst)){ + msg.src = port_isr; + msg.dst = m->blt_port; + msg.flags = 0; + msg.size = ntohs(udp->udp.udp_len) - 8; + msg.data = udp->data; + + if((i = old_port_send(&msg)) <0) { + /* XXX: if resource is gone, tear down this mapping */ + /* printf("aieee %d / %d / %x\n",i,msg.size,msg.data); */ + } + } + } + + +/* printf("UDP %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", + src[0],src[1],src[2],src[3],ntohs(udp->udp.udp_src), + dst[0],dst[1],dst[2],dst[3],ntohs(udp->udp.udp_dst) + );*/ +} + + +void +handle_tcp(tcp_packet *tcp, pbuf *packet) +{ + trace(2, "handle_tcp"); + /* full of worms */ +} + + +void +handle_ip(ip_packet *ip, pbuf *packet) +{ + unsigned char *dst = (unsigned char *) &(ip->ip.ip_dst); + + trace(2, "handle_ip"); + + if(!memcmp(dst,IP,4) || (dst[3] == 0xFF)){ /*!memcmp(dst,bcip,4)){*/ +#ifdef DEBUG + printf("IP %d.%d.%d.%d -> %d.%d.%d.%d\n", + src[0],src[1],src[2],src[3], + dst[0],dst[1],dst[2],dst[3] + ); +#endif + + switch(ip->ip.ip_proto){ + case 0x01: + handle_icmp((icmp_packet *) ip); + break; + case 0x11: + handle_udp((udp_packet *) ip, packet); + break; + case 0x6: + handle_tcp((tcp_packet *) ip, packet); + break; + } + } +} + + +void +receive(void *cb, packet_data *_packet) +{ + pbuf *packet = pd_to_ring(_packet); + unsigned char *b = (unsigned char *) packet->pd.ptr; + +trace(1, "receive"); + + if(b[12] == 0x08){ + if(b[13] == 0x00) { + handle_ip((ip_packet *) b, packet); + } else if (b[13] == 0x06) { + handle_arp((arp_packet *) b, packet); + } + } + free_buffer_data(&(packet->pd)); +} + +#define NET_CONNECT 1 +#define NET_SEND 2 +#define NET_IP 3 +typedef struct +{ + int cmd; + int port; + char data[0]; +} net_cmd; + + +unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +void send_udp(int src_port, int dst_port, unsigned char *ip, void *data, int size) +{ + pbuf *P; + udp_packet *udp; + + P = get_pbuf(); + udp = (udp_packet *) P->pd.ptr; + + memcpy(&(udp->ether.src),prom,6); + memcpy(&(udp->ether.dst),bcast,6); + udp->ether.type = ntohs(0x0800); + + udp->ip.ip_hdr_len = 5; + udp->ip.ip_version = 4; + udp->ip.ip_tos = 0; + udp->ip.ip_len = htons(20 + 8 + size); + udp->ip.ip_id = 0; + udp->ip.ip_off = 0; + udp->ip.ip_ttl = 64; + udp->ip.ip_proto = 17; + udp->ip.ip_chk = 0; + memcpy(&(udp->ip.ip_src),IP,4); + memcpy(&(udp->ip.ip_dst),bcast,4); + udp->ip.ip_chk = ipchksum(&(udp->ip),sizeof(net_ip)); + + udp->udp.udp_src = htons(src_port); + udp->udp.udp_dst = htons(dst_port); + udp->udp.udp_len = htons(size + 8); + udp->udp.udp_chk = 0; + + memcpy(udp->data, data, size); + +/* printf("sending UDP to %d / %d\n",port,size);*/ + P->pb.len = P->pd.len = 14 + 20 + 8 + size; + + xmit(P); + +} + +void +control(void) +{ + msg_hdr_t msg; + char cbuf[1500]; + net_cmd *cmd = (net_cmd *) cbuf; + int size; + + msg.flags=0; + + for(;;){ + msg.dst = port_net; + msg.src = 0; + msg.data = cbuf; + msg.size = 1500; + size = old_port_recv(&msg); + + if(size >= 8){ + switch(cmd->cmd){ + case NET_IP: + memcpy(cbuf,IP,4); + msg.size = 4; + msg.data = cbuf; + msg.dst = msg.src; + msg.src = port_isr; + old_port_send(&msg); + break; + + case NET_CONNECT: { + pmap *m = (pmap *) malloc(sizeof(pmap)); + if(m) { + m->udp_port = cmd->port; + m->blt_port = msg.src; + m->next = pmaps; + pmaps = m; + printf("ne2000: routing udp:%d -> blt:%d\n", + cmd->port, msg.src); + } + break; + } + case NET_SEND: { + pmap *m; + for(m = pmaps; m; m = m->next){ + if(msg.src == m->blt_port) { + send_udp(m->udp_port, cmd->port, NULL, cmd->data, size-8); + } + } + break; + } + } + + } + } + +} + +void +sender(void) +{ + msg_hdr_t mh; + pbuf *packet; + + mh.flags = 0; + mh.src = port_isr; + mh.size = 4; + mh.data = &packet; + + for(;;){ + /* wait for a send request */ + mh.dst = port_xmit; + if(old_port_recv(&mh) == 4){ + trace(2, "sender: sending packet"); + /* send the packet */ + qsem_acquire(mutex); + nic_send_packet(&TheSNIC, &(packet->pb)); + qsem_release(mutex); + + qsem_acquire(sem_xmit_done); + } + } +} + +void ISR(void) +{ + os_handle_irq(snic_irq); + + for(;;){ + os_sleep_irq(); + qsem_acquire(mutex); + nic_isr(&TheSNIC); + qsem_release(mutex); + } +} + +int main(int argc, char **argv) +{ + int i; + + if(argc == 5){ + for(i=0;i<4;i++){ + IP[i] = atoi(argv[i+1]); + } + } + + if(find_pci(0x10ec, 0x8029, &snic_addr, &snic_irq)){ + printf("ne2000: found PCI device\n"); + } + + os_brk(RINGSIZE*PACKETSIZE*2); + + sem_ring = qsem_create(1); + mutex = qsem_create(1); + + /* create our send port */ + port_isr = port_create(0,"net_send_port"); + port_set_restrict(port_isr, port_isr); + port_option(port_isr, PORT_OPT_NOWAIT, 1); + + namer_register(port_isr,"net_xmit"); + + init_ring(); + TheSNIC.iobase = 0; + nic_init(&TheSNIC, snic_addr, prom, NULL); + + printf("ne2000: irq %d @ 0x%S mac = %X:%X:%X:%X:%X:%X\n", + snic_irq,snic_addr,prom[0],prom[1],prom[2],prom[3],prom[4],prom[5]); + + nic_register_notify(&TheSNIC,receive,NULL); + printf("ne2000: IP %d.%d.%d.%d\n",IP[0],IP[1],IP[2],IP[3]); + + printf("ne2000: starting sender, dispatcher, and control\n"); + + namer_register(port_net = port_create(0,"net_listen_port"),"net"); + + port_xmit = port_create(port_isr,"net_isr_port"); + sem_xmit_done = qsem_create(0); + + os_thread(sender); + os_thread(control); + + printf("ne2000: starting NIC\n"); + nic_start(&TheSNIC,0); + printf("ne2000: \033[32mready.\033[37m\n"); + + os_thread(ISR); + + return 0; +} diff --git a/srv/ne2000/ne2k.h b/srv/ne2000/ne2k.h @@ -0,0 +1,116 @@ +/* $Id: //depot/blt/srv/ne2000/ne2k.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __NE2000_INTERFACE +#define __NE2000_INTERFACE +#ifndef __NE2000_SHARED_CODE_BASE +typedef unsigned int uint; +typedef struct snic snic; +typedef struct nic_stat nic_stat; +typedef struct buffer_header buffer_header; +typedef struct packet_data packet_data; +typedef struct packet_buffer packet_buffer; +typedef struct nic_error_stat nic_error_stat; +#endif /* NE2000_SHARED_CODE_BASE */ + +#define LEN_ADDR 6 +#define MAX_TX 2 /* be careful with this (dual buffers) */ +#define MAX_PAGESPERPACKET 6 +#define TXPAGES (MAX_TX*MAX_PAGESPERPACKET) +#define LEN_PROM 16 +#define LEN_HEADER 14 +#define MIN_LENGTH 60 /* minimum length for packet data */ +#define MAX_LENGTH 1500 /* maximum length for packet data area */ + +#ifdef __CPP_BINDING +extern "C" { +#endif + +/* external interface */ +int nic_detect(int given); +int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual); +void nic_register_notify(snic *nic, void(*newnotify)(void*,packet_data*),void*); +void nic_start(snic *nic, int promiscuous); +void nic_stop(snic *nic); +void nic_isr(snic *nic); +nic_stat nic_get_stats(snic *nic); +void nic_stat_clear(nic_stat *that); +int nic_send_packet(snic *nic, packet_buffer *buffer); + +/* Your implementation */ +/*packet_buffer *alloc_buffer(uint count); */ /* Optional */ +packet_data *alloc_buffer_data(uint size); +void free_buffer(packet_buffer *ptr); +void cleanup_buffer(packet_buffer *ptr); +void free_buffer_data(packet_data *ptr); /* Optional */ +/* I reserve the right to use the "Option" procedures in the future */ + +#ifdef __CPP_BINDING +}; +#endif + +struct buffer_header { + unsigned char status; + unsigned char next; + unsigned short count; /* length of header and packet */ +}; + +struct nic_error_stat { + long frame_alignment, crc, missed_packets; + long rx, rx_size, rx_dropped, rx_fifo, rx_overruns; + long tx_collisions; + long tx_aborts, tx_carrier, tx_fifo, tx_heartbeat, tx_window; +}; + +struct nic_stat { + long rx_packets; + long tx_buffered, tx_packets; + nic_error_stat errors; +}; + +struct packet_buffer { + uint page; + uint count, len; + packet_data *buf; /* An array of data segments */ +}; + +struct packet_data { /* each protocol layer can add it's own */ + uint len; + char *ptr; +}; + +struct snic { + int iobase; /* NULL if uninitialized */ + int pstart, pstop, wordlength, current_page; + nic_stat stat; + void (*notify)(void *passback, packet_data *newpacket); + void *kore; /* Passback pointer */ + packet_buffer *tx_packet[MAX_TX], *last_tx; + int busy, send, sending; +}; + +#endif /* __NE2000_INTERFACE */ diff --git a/srv/ne2000/net.h b/srv/ne2000/net.h @@ -0,0 +1,180 @@ +/* $Id: //depot/blt/srv/ne2000/net.h#4 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#pragma pack(2) + +typedef struct +{ + uint8 dst[6]; + uint8 src[6]; + uint16 type; +} net_ether; + +typedef struct +{ + uint8 ip_hdr_len:4; + uint8 ip_version:4; + uint8 ip_tos; + uint16 ip_len; + + uint16 ip_id; + uint16 ip_off; + + uint8 ip_ttl; + uint8 ip_proto; + uint16 ip_chk; + + uint32 ip_src; + uint32 ip_dst; +} net_ip; + +typedef struct +{ + uint16 udp_src; + uint16 udp_dst; + + uint16 udp_len; + uint16 udp_chk; +} net_udp; + +typedef struct +{ + uint8 icmp_type; + uint8 icmp_code; + uint16 icmp_chk; + union { + struct { + uint16 id; + uint16 seq; + uint8 data[128]; + } ping; + } data; +} net_icmp; + +#define ICMP_PING_REQ 8 +#define ICMP_PING_REP 0 + +typedef struct +{ + uint16 arp_hard_type; + uint16 arp_prot_type; + uint8 arp_hard_size; + uint8 arp_prot_size; + uint16 arp_op; + uint8 arp_enet_sender[6]; + uint32 arp_ip_sender; + uint8 arp_enet_target[6]; + uint32 arp_ip_target; +} net_arp; + +typedef struct +{ + net_ether ether; + net_ip ip; + unsigned char data[0]; +} ip_packet; + +typedef struct { + net_ether ether; + net_ip ip; +/* stub for now */ +} tcp_packet; + +typedef struct { + net_ether ether; + net_ip ip; + net_udp udp; + unsigned char data[0]; +} udp_packet; + +typedef struct { + net_ether ether; + net_ip ip; + net_icmp icmp; + unsigned char data[0]; +} icmp_packet; + +#define ARP_OP_REQUEST 1 +#define ARP_OP_REPLY 2 + +/* yeah, ugly as shit */ +#define ntohs(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) ) +#define htons(n) ( (((n) & 0xFF00) >> 8) | (((n) & 0x00FF) << 8) ) +#define ntohl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) ) +#define htonl(n) ( (((n) & 0xFF000000) >> 24) | (((n) & 0x00FF0000) >> 8) | (((n) & 0x0000FF00) << 8) | (((n) & 0x000000FF) << 24) ) + +/* +typedef struct +{ + uint32 ip; + uint16 flags; + uint8 hw[6]; +} net_arp_table; + +typedef struct +{ + uint32 dest; + uint32 gw; + uint32 mask; + uint16 flags; + net_iface *iface; +} net_route_table; + + +typedef struct +{ + char name[8]; + uint32 addr; + uint32 bcast; + uint32 mask; + uint16 flags; + uint16 mtu; + uint32 metric; + + uint32 stat_rx_packets; + uint32 stat_rx_errors; + uint32 stat_rx_dropped; + uint32 stat_rx_overruns; + + uint32 stat_tx_packets; + uint32 stat_tx_errors; + uint32 stat_tx_dropped; + uint32 stat_tx_overruns; + + void (*send)(void); + void (*init)(void); + void (*add_proto)(net_proto *proto, uint16 id); + +} net_iface; + +#define IF_UP 0x0001 +#define IF_BROADCAST 0x0002 +#define IF_PROMISC 0x0004 +#define IF_LOOPBACK 0x0008 +#define IF_MULTICAST 0x0010 +#define IF_RUNNING 0x0020 +*/ diff --git a/srv/ne2000/pciglue.cpp b/srv/ne2000/pciglue.cpp @@ -0,0 +1,35 @@ +#define PCI_STUB + +#include <pci.h> + +extern "C" { + int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq); +} + +using namespace BLT; + +int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq) +{ + Message msg; + pci_cfg cfg; + int n; + int res = 0; + + PCI *pci = PCI::FindService(); + + if(pci){ + for(n=0;pci->get_nth_cfg(n,&cfg) == 0;n++){ + if((cfg.device_id == device) && + (cfg.vendor_id == vendor)){ + *iobase = cfg.base[0] & 0xfff8; + *irq = cfg.irq; + res = 1; + break; + } + } + delete pci; + } + + return res; +} + diff --git a/srv/network/Makefile b/srv/network/Makefile @@ -0,0 +1,10 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := network.c mbuf.c +LIBS := -lc -lblt -ldl +BINARY := network.bin +SUBDIRS := device protocol + +include $(BLTHOME)/make.actions + diff --git a/srv/network/device/Makefile b/srv/network/device/Makefile @@ -0,0 +1,6 @@ +BLTHOME := ../../../ +include $(BLTHOME)make.conf + +SUBDIRS := ne + +include $(BLTHOME)make.actions diff --git a/srv/network/device/ne/Makefile b/srv/network/device/ne/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../../../ +include $(BLTHOME)make.conf + +CFLAGS = $(CF) -I../../../../include -D_NETWORK + +OBJS := wrap.o support.o ne2000.o +SHLIB := ne.so + +include $(BLTHOME)make.actions diff --git a/srv/network/device/ne/defs.h b/srv/network/device/ne/defs.h @@ -0,0 +1,187 @@ +/* $Id: //depot/blt/srv/network/device/ne/defs.h#1 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __NE2000_SHARED_CODE_BASE +#define __NE2000_SHARED_CODE_BASE +typedef unsigned int uint; +typedef struct snic snic; +typedef struct nic_stat nic_stat; +typedef struct buffer_header buffer_header; +typedef struct packet_data packet_data; +typedef struct packet_buffer packet_buffer; +typedef struct nic_error_stat nic_error_stat; + +/* internal implementation procedures */ +int nic_probe(int addr); +int nic_dump_prom(snic *nic, unsigned char *prom); +void nic_overrun(snic *nic); +void nic_tx(snic *nic); +void nic_tx_err(snic *nic); +void nic_rx(snic *nic); +void nic_counters(snic *nic); +void nic_get_header(snic *nic, uint page, buffer_header *header); +int nic_send(snic *nic, uint buf); +void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset); +void nic_block_output(snic *nic, packet_buffer *pkt); + +#define PSTART 0x20 /* if NE2000 is byte length */ +#define PSTOP 0x40 +#define PSTARTW 0x40 /* if NE2000 is wordlength */ +#define PSTOPW 0x80 +#define MAX_LOAD 12 /* maximum services per IRQ request*/ +#define MAX_RX 10 /* maximum packets recieve per call*/ +#define MIN_LENGTH 60 /* minimum length for packet data */ +#define MAX_LENGTH 1500 /* maximum length for packet data area */ +#define TIMEOUT_DMAMATCH 40 /* for nic_block_input() */ +#define TIMEOUT_TX 40 + +/* DP8390 NIC Registers*/ +#define COMMAND 0x00 +#define STATUS COMMAND+0 +#define PHYSICAL COMMAND+1 /* page 1 */ +#define MULTICAST COMMAND+8 /* page 1 */ +#define PAGESTART COMMAND+1 /* page 0 */ +#define PAGESTOP COMMAND+2 +#define BOUNDARY COMMAND+3 +#define TRANSMITSTATUS COMMAND+4 +#define TRANSMITPAGE COMMAND+4 +#define TRANSMITBYTECOUNT0 COMMAND+5 +#define NCR COMMAND+5 +#define TRANSMITBYTECOUNT1 COMMAND+6 +#define INTERRUPTSTATUS COMMAND+7 +#define CURRENT COMMAND+7 /* page 1 */ +#define REMOTESTARTADDRESS0 COMMAND+8 +#define CRDMA0 COMMAND+8 +#define REMOTESTARTADDRESS1 COMMAND+9 +#define CRDMA1 COMMAND+9 +#define REMOTEBYTECOUNT0 COMMAND+10 /* how many bytes we will */ +#define REMOTEBYTECOUNT1 COMMAND+11 /* read through remote DMA->IO */ +#define RECEIVESTATUS COMMAND+12 +#define RECEIVECONFIGURATION COMMAND+12 +#define TRANSMITCONFIGURATION COMMAND+13 +#define FAE_TALLY COMMAND+13 /* page 0 */ +#define DATACONFIGURATION COMMAND+14 +#define CRC_TALLY COMMAND+14 +#define INTERRUPTMASK COMMAND+15 +#define MISS_PKT_TALLY COMMAND+15 + +/* NE2000 specific implementation registers */ +#define NE_RESET 0x1f /* Reset */ +#define NE_DATA 0x10 /* Data port (use for PROM) */ + +#define PAR0 COMMAND+1 +#define PAR1 COMMAND+2 +#define PAR2 COMMAND+3 +#define PAR3 COMMAND+4 +#define PAR4 COMMAND+5 +#define PAR5 COMMAND+6 + +/* NIC Commands */ +#define NIC_STOP 0x01 /* STOP */ +#define NIC_START 0x02 /* START */ +#define NIC_PAGE0 0x00 +#define NIC_PAGE1 0x40 +#define NIC_PAGE2 0x80 +#define NIC_TRANSMIT 0x04 /* Transmit a frame */ +#define NIC_REM_READ 0x08 /* Remote Read */ +#define NIC_REM_WRITE 0x10 /* Remote Write */ +#define NIC_DMA_DISABLE 0x20 /* Disable DMA */ + +/* Data Configuration Register */ +#define DCR_WTS 0x01 /* Word Transfer Select (0=byte, 1=word) */ +#define DCR_BOS 0x02 /* Byte Order Select (0=big-endian) */ +#define DCR_LAS 0x04 /* Long Address Select (0=dual 16-bit DMA) */ +#define DCR_LS 0x08 /* Loopback Select (0=loopback) */ +#define DCR_AR 0x10 /* Auto Initialize Remote */ +#define DCR_FT 0x60 /* (FT0 & FT1) FIFO Threshhold (see datasheet) */ +/*#define DCR_DEFAULT 0x58 Standard value for the DCR register */ +#define DCR_DEFAULT 0x48 /* don't use Automatic send packet */ +#define DCR_DEFAULT_WORD 0x49 /* defuault with wold length transfer */ + +/* Recieve Configure Register */ +#define RCR_SEP 0x01 /* Save Errored Packets */ +#define RCR_AR 0x02 /* Accept Runt Packets */ +#define RCR_AB 0x04 /* Accept Broadcast */ +#define RCR_AM 0x08 /* Accept Multicast */ +#define RCR_PRO 0x10 /* Promiscuous Physical */ +#define RCR_MON 0x20 /* Monitor Mode */ +/*#define RCR_DEFAULT 0x00 Standard value for the RCR register */ +#define RCR_DEFAULT 0x0c /* Accept Broadcast/Multicast Packets */ + +/* Recieve Status Register */ +/* note, this is also stored in the status byte in the buffer header. */ +/* That's the 4 byte entry in the local buffer, not the packet header. */ +#define RSR_PRX 0x01 /* Pakcet Received Intact */ +#define RSR_CRC 0x02 /* CRC Error */ +#define RSR_FAE 0x04 /* Frame Alignment Error */ +#define RSR_FO 0x08 /* FIFO Overrun */ +#define RSR_MPA 0x10 /* Missed Packet */ +#define RSR_PHY 0x20 /* Physical/Multicast Address (0=physical) */ +#define RSR_DIS 0x40 /* Receiver Disabled */ +#define RSR_DFR 0x80 /* Deferring */ + +/* Transmit Configure Register */ +#define TCR_CRC 0x01 /* Inhibit CRC (0=CRC active) */ +#define TCR_LB 0x06 /* (LB0 & LB1) Encoded Loopback Control */ +#define TCR_ATD 0x08 /* Auto Transmit Disable (0=normal) */ +#define TCR_OFST 0x10 /* Collision Offset Enable (1=low priority) */ +#define TCR_DEFAULT 0x00 /* Standard value for the TCR register */ +#define TCR_INTERNAL_LOOPBACK 0x02 /* Internal loopback configuration */ + +/* Transmit Status Register */ +#define TSR_PTX 0x01 /* Packet Transmitted */ +#define TSR_ND 0x02 /* Non-Deferral (Documented???) */ +#define TSR_COL 0x04 /* Transmit Collided */ +#define TSR_ABT 0x08 /* Transmit Aborted */ +#define TSR_CRS 0x10 /* Carrier Sense Lost */ +#define TSR_FU 0x20 /* FIFO Underrun */ +#define TSR_CDH 0x40 /* CD Heartbeat */ +#define TSR_OWC 0x80 /* Oout of Window Collision */ + +/* Interrupt Status Register */ +#define ISR_PRX 0x01 /* Packet Received */ +#define ISR_PTX 0x02 /* Packet Transmitted */ +#define ISR_RXE 0x04 /* Receive Error */ +#define ISR_TXE 0x08 /* Transmit Error */ +#define ISR_OVW 0x10 /* Overwrite Warning */ +#define ISR_CNT 0x20 /* Counter Overflow */ +#define ISR_RDC 0x40 /* Remote DMA Complete */ +#define ISR_RST 0x80 /* Reset Status */ +#define ISR_DEFAULT 0x00 /* Standard value for the ISR register */ +#define ISR_ALL 0x3f /* The services that we handle in the isr */ + +/* Interrupt Mask Register */ +#define IMR_PRXE 0x01 /* Packet Received Interrupt Enable */ +#define IMR_PTXE 0x02 /* Packet Transmitted Interrupt Enable */ +#define IMR_RXEE 0x04 /* Receive Error Interrupt Enable */ +#define IMR_TXEE 0x08 /* Transmit Error Interrupt Enable */ +#define IMR_OVWE 0x10 /* Overwrite Warning Interrupt Enable */ +#define IMR_CNTE 0x20 /* Counter Overflow Interrupt Enable */ +#define IMR_RDCE 0x40 /* DMA Complete Interrupt Enable */ +#define IMR_DEFAULT 0x3f /* CNTE | OVWE | TXEE | RXEE | PTXE | PRXE */ + +#endif diff --git a/srv/network/device/ne/err.h b/srv/network/device/ne/err.h @@ -0,0 +1,109 @@ +/* $Id: //depot/blt/srv/network/device/ne/err.h#1 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __ERR +#define __ERR + +/* NOTE If ret is negative then it is an error otherwise it returns a +// success code. */ + +///// +// Error codes +///// + +#define NUM_ERR 22 +#define NOERR 0 +#define ERR -1 +#define ERRNOMEM -2 +#define ERRRESOURCE -3 +#define ERRMEMCORRUPT -4 +#define ERRFORMAT -5 +#define ERRNOTFOUND -6 +#define ERRTYPE -7 +#define ERRTIMEOUT -8 +#define ERRNOTSUPPORTED -9 +#define ERROUTOFRANGE -10 +#define ERRPRIV -11 +#define ERRNOTREADY -12 +#define ERRNONEFREE -13 +#define ERRARG -14 +#define ERRINVALID -15 +#define ERRNOTOPEN -16 +#define ERRALREADYDONE -17 +#define ERRVER -18 +#define ERROVERFLOW -19 +#define ERRINUSE -20 +#define ERRTOOBIG -21 + +///// +// Success codes +///// + +#define SFOUND 1 +#define SNOTFOUND 2 +#define SALT 3 + +///// +// Facility codes +///// + +/* Bits 16-31 are reserved for the facility code. */ +#define OWNOS 0x70 +#define OWNNOMAD 0x70 + +///// +// Error Messages +///// + +#define MAX_ERR_MSG 32 +static const char err_msg[NUM_ERR][MAX_ERR_MSG] = { "success", + "error", + "out of memory", + "resource allocation", + "memory corrupt!!!", + "format", + "not found", + "type", + "timeout", + "not supported", + "out of range", + "access denied", + "not ready", + "none free", + "bad argument", + "invalid", + "not open", + "already done", + "incorrect version", + "overflow", + "in use", + "too big" }; + +typedef int ret; + +#endif /* __ERR */ + diff --git a/srv/network/device/ne/ne2000.c b/srv/network/device/ne/ne2000.c @@ -0,0 +1,860 @@ +/* $Id: //depot/blt/srv/network/device/ne/ne2000.c#1 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* This file contains a network driver core for the NE2000 card. +// Use at your own risk! (C) Copyright 1997, +// Douglas Armstrong site@xnet.com drarmstr@uiuc.edu 10/11/97 +// ... +// derived from National Semiconductor datasheets and application notes +// as well as the Linux driver by Donald Becker */ + +/* History Log: +10-25-97 Setup under CVS drarmstr +10-27-97 Added alloc_buffer() and free_buffer() drarmstr +12-08-97 Finished scatter gather drarmstr +03-03-98 Minor bug / Output cleanup drarmstr +03-04-98 snic->tx_buf[] packet_buf -> packet_buf* drarmstr +03-04-98 added passback pointer to notify and snic drarmstr +*/ + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ +#include <i386/io.h> +#include "defs.h" +#include "ne2000.h" +#include "err.h" +//extern void kprintf(char *, ...); /* Make sure your OS has these...*/ +#define kprintf(f, a...) +//#define kprintf printf +extern void idle(); +extern unsigned long ticks; + /* replace with a better timeout method, like wait() */ + +#ifdef XXX +static char *BLARGH = 0xB8000 + 160*23 + 152; +#define t(a) { BLARGH[0] = #a[0]; } +#define T(a) { BLARGH[2] = #a[0]; } +#else +#define t(a) {} +#define T(a) {} +#endif + +/* we may have to change inb and outb to inb_p and outb_p. +// Note, none of this code is gauranteed to be reentrant. + +// Note, don't create two nics to the same card and then try to use both +// of them. The results will be unpredictable. + +// This violates IO resource manegment if your OS handles that, but it +// works for now. Make sure that the driver has privlige access to the +// mapped I/O space and the IRQ.*/ +static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 }; + +/* internal procedure, don't call this directly.*/ +int nic_probe(int addr) { + uint regd; + uint state=inb(addr); /* save command state */ + + if(inb(addr==0xff)) return ERRNOTFOUND; + + outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); + regd=inb(addr + 0x0d); + outb(0xff, addr + 0x0d); + outb(NIC_DMA_DISABLE | NIC_PAGE0, addr); + inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/ + if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/ + outb(state,addr); /* restore command state*/ + outb(regd,addr + 0x0d); + return ERRNOTFOUND; } + + return addr; /* network card detected at io addr;*/ +} + +/* Detects for presence of NE2000 card. Will check given io addr that +// is passed to it as well as the default_ports array. Returns ERRNOTFOUND +// if no card is found, i/o address otherwise. This does conduct an ISA +// probe, so it's not always a good idea to run it. If you already have +// the information, then you can just use that with nic_init().*/ +int nic_detect(int given) { + int found; int f; + kprintf("NE2000: detecting card..."); + if(given) if((found=nic_probe(given))!=ERRNOTFOUND) { + kprintf("found at given:0x%x\n",given); + return found; } + + /* probe for PCI clones here.... or not...*/ + + for(f=0;default_ports[f]!='\0';f++) { + // perform resource manegment here + if((found=nic_probe(default_ports[f]))!=ERRNOTFOUND) { + kprintf("found at default:0x%x\n",default_ports[f]); + return found; } + } + kprintf("none found.\n"); + return ERRNOTFOUND; +} + +/* This initializes the NE2000 card. If it turns out the card is not +// really a NE2000 after all then it will return ERRNOTFOUND, else NOERR +// It also dumps the prom into buffer prom for the upper layers.. +// Pass it a nic with a null iobase and it will initialize the structure for +// you, otherwise it will just reinitialize it. */ +int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) { + uint f; + kprintf("NE2000: reseting NIC card..."); + if(!nic->iobase) { + nic->iobase=addr; + nic_stat_clear(&nic->stat); + nic->pstart=0; nic->pstop=0; nic->wordlength=0; + nic->current_page=0; + nic->notify=NULL; + for(f=0;f<MAX_TX;f++) { + nic->tx_packet[f]= NULL; +/* nic->tx_packet[f].count=0; + nic->tx_packet[f].buf=NULL; + nic->tx_packet[f].page=0; */ + } + nic->last_tx=NULL; + nic->busy=0; + nic->sending=0; + } else { + if(!nic->iobase || nic->iobase!=addr) return ERR; + } + + + outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/ + while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) { + /* TODO insert timeout code here.*/ + } + kprintf("done.\n"); + outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/ + + // Initialize registers + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/ + outb_p(DCR_DEFAULT, addr + DATACONFIGURATION); + outb_p(0x00, addr + REMOTEBYTECOUNT0); + outb_p(0x00, addr + REMOTEBYTECOUNT1); + outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ + outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ + outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/ + outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/ + + nic->wordlength=nic_dump_prom(nic,prom); + if(prom[14]!=0x57 || prom[15]!=0x57) { + kprintf("NE2000: PROM signature does not match NE2000 0x57.\n"); + return ERRNOTFOUND; + } + kprintf("NE2000: PROM signature matches NE2000 0x57.\n"); + + /* if the wordlength for the NE2000 card is 2 bytes, then + // we have to setup the DP8390 chipset to be the same or + // else all hell will break loose.*/ + if(nic->wordlength==2) { + outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION); + } + nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART; + nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP; + + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); + outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/ + outb_p(nic->pstart + TXPAGES, addr + PAGESTART); + outb_p(nic->pstop - 1, addr + BOUNDARY); + outb_p(nic->pstop, addr + PAGESTOP); + outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ + outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ + nic->current_page=nic->pstart + TXPAGES; + + /* put physical address in the registers */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */ + if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f); + else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f); + kprintf("NE2000: Physical Address- "); + kprintf("%X:%X:%X:%X:%X:%X\n", + inb(addr+PAR0),inb(addr+PAR1),inb(addr+PAR2), + inb(addr+PAR3),inb(addr+PAR4),inb(addr+PAR5)); + + /* setup multicast filter to accept all packets*/ + for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f); + + outb_p(nic->pstart+TXPAGES, addr + CURRENT); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */ + + return NOERR; +} + +/* This registers the function that will be called when a new packet +// comes in. */ +void nic_register_notify(snic *nic, + void (*newnotify)(void*,packet_data*), void *passback){ + nic->kore= passback; + nic->notify= newnotify; +} + +/* start the NIC so it can actually recieve or transmit packets */ +void nic_start(snic *nic, int promiscuous) { + int iobase; + kprintf("NE2000: Starting NIC.\n"); + if(!nic || !nic->iobase) { + kprintf("NE2000: can't start a non-initialized card.\n"); + return; } + iobase=nic->iobase; + outb(0xff, iobase + INTERRUPTSTATUS); + outb(IMR_DEFAULT, iobase + INTERRUPTMASK); + outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); + if(promiscuous) + outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION); + else + outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION); + + /* The following is debugging code! */ +#ifdef SHIT + kprintf("NE2000: Trying to fire off an IRQ.\n"); + outb_p(0x50,iobase+INTERRUPTMASK); + outb_p(0x00,iobase+REMOTEBYTECOUNT0); + outb_p(0x00,iobase+REMOTEBYTECOUNT1); + outb_p(NIC_REM_READ | NIC_START,iobase); /* this should fire off */ + outb_p(IMR_DEFAULT,iobase+INTERRUPTMASK); /* an interrupt... */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(0xff,iobase+INTERRUPTSTATUS); +#endif + /* End debugging code */ +} + +/* stops the NIC */ +void nic_stop(snic *nic) { + unsigned char tmp_buffer[16]; + if(!nic || !nic->iobase) return; /* make sure card was initialized */ + nic_init(nic,nic->iobase,tmp_buffer,NULL); +} + +void nic_isr(snic *nic) { + uint isr; /* Illinois Sreet Residence Hall */ + uint overload; + if(!nic || !nic->iobase) return; /* make sure card was initialized */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); + overload=MAX_LOAD+1; + while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) { + if((--overload)<=0) break; + if(isr & ISR_OVW) nic_overrun(nic); + else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic); + if(isr & ISR_PTX) nic_tx(nic); + else if(isr & ISR_TXE) nic_tx_err(nic); + if(isr & ISR_CNT) nic_counters(nic); + if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); + } + if(isr) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); + if(!overload) { + kprintf("NE2000: Too many requests in ISR. ISR:%X MaxLoad:%X\n", + isr, MAX_LOAD); + outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear + } else { + kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr); + outb_p(0xff, nic->iobase + INTERRUPTSTATUS); + // Ack it anyway + } + } +} + +/* You should call this before you just read the stats directlly from the +// snic struct. This procedure updates the counters */ +nic_stat nic_get_stats(snic *nic) { + nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY); + nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY); + nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY); + return nic->stat; +} + +void nic_stat_clear(nic_stat *that) { + that->rx_packets=0; + that->tx_buffered=0; that->tx_packets=0; + that->errors.frame_alignment=0; that->errors.crc=0; + that->errors.missed_packets=0; that->errors.rx=0; + that->errors.rx_size=0; that->errors.rx_dropped=0; + that->errors.rx_fifo=0; that->errors.rx_overruns=0; + that->errors.tx_collisions=0; +} + +/* Since this could be called by more than one other device, it should +// be properly protected for reentrancy. We should put in a proper +// semaphore or something, look into this. +// NOTE: It is your responsibility to clean up the packet_buffer when you +// are done calling this. */ +/* TODO- Have it check how lonk a transmission is taking and attempt to + restart the card if it's too long. */ +int nic_send_packet(snic *nic, packet_buffer *buffer) { + uint timeout; uint f; int iobase; +/* kprintf("nic_send_packet()\n"); */ + if(!buffer) return ERRARG; + if(!buffer->count || !buffer->buf) return ERRARG; + if(!nic || !nic->iobase) return ERR; + iobase=nic->iobase; + + t(A); + + buffer->len=0; + for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len; + if(buffer->len>MAX_LENGTH) return ERRTOOBIG; + + t(B); + + /* the following wait for anyother tasks that are calling + // nic_send_packet() right now. Note that this doesn't use + // an atomic semaphore, so something MAY leak through. */ +/* timeout=ticks+10; wait 10 ticks */ + timeout=ticks+100; + while(nic->busy && ticks<=timeout) idle(); + /* Replace this with a proper timeout thing that doesn't use the + // ticks method which will be diffrent on each OS. */ + t(C); + if(nic->busy) { + kprintf("NE2000: ERROR: Card stalled, timeout.\n"); + return ERRTIMEOUT; + } + nic->busy=1; /* mark as busy, replace with semaphore */ + + t(D); + + outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */ + t(E); + + timeout=ticks+TIMEOUT_TX; + while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) { + if(!nic->tx_packet[f]) { + t(F); + +/* nic->tx_packet[f]=*buffer;*/ + nic->tx_packet[f]=buffer; + nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET); + /*output page */ + +/* kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n", + buffer->count,buffer->page,buffer->buf); */ + t(>); + + nic_block_output(nic,nic->tx_packet[f]); + + t(<); + + if(!nic->sending) { + nic->send=f; nic->sending=1; + /* now let's actually trigger the transmitter */ + t(I); + + if(nic_send(nic,f)<0) { + nic->sending=0; + break; } + + /* note, the nic_tx() interrupt will mark this + // tx_packet buffer as free again once it + // confirms that the packet was sent. */ + } + t(J); + + nic->stat.tx_buffered++; + outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ + nic->busy=0; /* V() */ + t(K); + + return NOERR; + } + } + + t(L); + + outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ + nic->busy=0; /* V() */ + kprintf("NE2000: ERROR: Transmitter stalled, card timeout.\n"); + if(f==MAX_TX) { + kprintf("NE2000: ERROR: There are no transmit buffers available. TX stalled.\n"); + return ERRTIMEOUT; + } + return ERR; +} + +/* dumps the prom into a 16 byte buffer and returns the wordlength of +// the card. +// You should be able to make this procedure a wrapper of nic_block_input(). */ +int nic_dump_prom(snic *nic, unsigned char *prom) { + uint f; + int iobase=nic->iobase; + char wordlength=2; /* default wordlength of 2 */ + unsigned char dump[32]; + outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */ + outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */ + outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */ + outb_p(0x00, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + for(f=0;f<32;f+=2) { + dump[f]=inb_p(iobase + NE_DATA); + dump[f+1]=inb_p(iobase + NE_DATA); + if(dump[f]!=dump[f+1]) wordlength=1; + } + /* if wordlength is 2 bytes, then collapse prom to 16 bytes */ + for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)]; +/* kprintf("NE2000: prom dump - "); + for(f=0;f<LEN_PROM;f++) kprintf("%X",prom[f]); + kprintf("\n"); */ + + return wordlength; +} + +void nic_overrun(snic *nic) { + uint tx_status; int iobase=nic->iobase; + long starttime; uint resend=0; + kprintf("NE2000: Receive packet ring overrun!\n"); + if(!nic || !nic->iobase) return; + tx_status=inb_p(iobase) & NIC_TRANSMIT; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase); + nic->stat.errors.rx_overruns++; + + starttime=ticks; +kprintf("BEFORE\n"); + while(ticks-starttime<=10/*ticks to wait*/) idle(); + /* Arrgh! TODO: Replace this whole crappy code with a decent + // wait method. We need to wait at least 1.6ms as per National + // Semiconductor datasheets, but we should probablly wait a + // little more to be safe. */ +kprintf("AFTER\n"); + + outb_p(0x00, iobase + REMOTEBYTECOUNT0); + outb_p(0x00, iobase + REMOTEBYTECOUNT1); + if(tx_status) { + uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) & + (ISR_PTX | ISR_TXE); + if(!tx_completed) resend=1; + } + + outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION); + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + nic_rx(nic); /* cleanup RX ring */ + outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */ + + outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); + if(resend) + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT, + iobase); +} + +/* This is the procedure that markst the transmit buffer as available again */ +void nic_tx(snic *nic) { + uint f; int iobase=nic->iobase; + uint status; +/* kprintf("nic_tx()\n"); */ + if(!nic || !nic->iobase) return; + status=inb(iobase + TRANSMITSTATUS); + + if(!nic->tx_packet[nic->send]) { + kprintf("NE2000: ERROR: Invalid transmison packet buffer.\n"); + return; + } + if(!nic->sending) kprintf("NE2000: ERROR: Invalid nic->sending value.\n"); + + free_buffer(nic->tx_packet[nic->send]); + nic->tx_packet[nic->send]= NULL; +/* nic->tx_packet[nic->send].count=0; mark buffer as available */ +/* nic->tx_packet[nic->send].len=0; + nic->tx_packet[nic->send].page=0; */ + + for(f=0;f<MAX_TX;f++) { + if(nic->tx_packet[f]) { + kprintf("NE2000: DEBUG: transmitting secondary buffer:%X\n",f); + nic->stat.tx_buffered++; + nic->send=f; nic->sending=1; + nic_send(nic,f); /* send a back-to-back buffer */ + break; + } + } + if(f==MAX_TX) nic->sending=0; + + if(status & TSR_COL) nic->stat.errors.tx_collisions++; + if(status & TSR_PTX) nic->stat.tx_packets++; + else { + if(status & TSR_ABT) { + nic->stat.errors.tx_aborts++; + nic->stat.errors.tx_collisions+=16; } + if(status & TSR_CRS) nic->stat.errors.tx_carrier++; + if(status & TSR_FU) nic->stat.errors.tx_fifo++; + if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++; + if(status & TSR_OWC) nic->stat.errors.tx_window++; + } + + outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */ +} + +void nic_tx_err(snic *nic) { + unsigned char tsr; int iobase=nic->iobase; + if(!nic || !nic->iobase) return; + tsr=inb_p(nic->iobase); + kprintf("NE2000: ERROR: TX error: "); + if(tsr & TSR_ABT) kprintf("Too many collisions.\n"); + if(tsr & TSR_ND) kprintf("Not deffered.\n"); + if(tsr & TSR_CRS) kprintf("Carrier lost.\n"); + if(tsr & TSR_FU) kprintf("FIFO underrun.\n"); + if(tsr & TSR_CDH) kprintf("Heart attack!\n"); + + outb_p(ISR_TXE, iobase + INTERRUPTSTATUS); + if(tsr & (TSR_ABT | TSR_FU)) { + kprintf("NE2000: DEBUG: Attempting to retransmit packet.\n"); + nic_tx(nic); + } +} + +void nic_rx(snic *nic) { + uint packets=0; uint frame; uint rx_page; uint rx_offset; + uint len; uint next_pkt; uint numpages; + int iobase=nic->iobase; + buffer_header header; + if(!nic || !nic->iobase) return; + while(packets<MAX_RX) { + outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */ + rx_page=inb_p(iobase + CURRENT); /* get current page */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase); + frame=inb(iobase + BOUNDARY)+1; + /* we add one becuase boundary is a page behind + // as pre NS notes to help in overflow problems */ + if(frame>=nic->pstop) frame=nic->pstart+TXPAGES; + /* circual buffer */ + + if(frame != nic->current_page) { + kprintf("NE2000: ERROR: mismatched read page pointers!\n"); + kprintf("NE2000: NIC-Boundary:%x dev-current_page:%x\n", + frame, nic->current_page); } + +/* kprintf("Boundary-%x Current-%x\n",frame-1,rx_page); */ + if(frame==rx_page) break; /* all frames read */ + + rx_offset=frame << 8; /* current ptr in bytes(not pages) */ + + nic_get_header(nic,frame,&header); + len=header.count - sizeof(buffer_header); + /* length of packet */ + next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */ + + numpages=nic->pstop-(nic->pstart+TXPAGES); + if( (header.next!=next_pkt) + && (header.next!=next_pkt + 1) + && (header.next!=next_pkt - numpages) + && (header.next != next_pkt +1 - numpages)){ + kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n", + header.next,next_pkt,frame); + nic->current_page=frame; + outb(nic->current_page-1, iobase + BOUNDARY); + nic->stat.errors.rx++; + continue; + } + + if(len<60 || len>1518) { + kprintf("NE2000: invalid packet size:%d\n",len); + nic->stat.errors.rx_size++; + } else if((header.status & 0x0f) == RSR_PRX) { + /* We have a good packet, so let's recieve it! */ + + packet_data *newpacket=alloc_buffer_data(len); + if(!newpacket) { + kprintf("NE2000: ERROR: out of memory!\n"); + nic->stat.errors.rx_dropped++; + nic_block_input(nic,NULL,len,rx_offset+ + sizeof(buffer_header)); + } else { + nic_block_input(nic,newpacket->ptr,newpacket->len, + rx_offset+sizeof(buffer_header)); + /* read it */ + + if(nic->notify) nic->notify(nic->kore,newpacket); + else free_buffer_data(newpacket); + /* NOTE: you are responsible for deleting this buffer. */ + + nic->stat.rx_packets++; + } + } else { + kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n", + header.status,header.next,header.count); + if(header.status & RSR_FO) nic->stat.errors.rx_fifo++; + } +/* kprintf("frame:%x header.next:%x next_pkt:%x\n", + frame,header.next,next_pkt); */ + next_pkt=header.next; + + if(next_pkt >= nic->pstop) { + kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n", + next_pkt); + next_pkt=nic->pstart+TXPAGES; + } + + nic->current_page=next_pkt; + outb_p(next_pkt-1, iobase + BOUNDARY); + } + outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */ +} + +void nic_counters(snic *nic) { + nic->stat.errors.frame_alignment+=inb_p(nic->iobase+FAE_TALLY); + nic->stat.errors.crc+=inb_p(nic->iobase+CRC_TALLY); + nic->stat.errors.missed_packets+=inb_p(nic->iobase+MISS_PKT_TALLY); + /* reading the counters on the DC8390 clears them. */ + outb_p(ISR_CNT, nic->iobase + INTERRUPTSTATUS); /* ackkowledge int */ +} + +/* You should be able to make this procedure a wrapper of nic_block_input */ +void nic_get_header(snic *nic, uint page, buffer_header *header) { + int iobase=nic->iobase; uint f; + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0); + outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */ + outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */ + outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */ + outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */ + + if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++) + ((unsigned short *)header)[f]=inw(iobase+NE_DATA); + else for(f=0;f<sizeof(buffer_header);f++) + ((unsigned char *)header)[f]=inb(iobase+NE_DATA); + /* Do these need to be *_p variants??? */ + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} + +int nic_send(snic *nic, uint buf) { + uint len= (nic->tx_packet[buf]->len<MIN_LENGTH) ? + MIN_LENGTH : nic->tx_packet[buf]->len; +/* kprintf("nic_send()\n"); */ + if(!nic->tx_packet[buf]) return ERR; /* this is bad */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); + if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) { + kprintf("NE2000: ERROR: Transmitor busy.\n"); + free_buffer(nic->tx_packet[buf]); + nic->tx_packet[buf]= NULL; +/* nic->tx_packet[buf].count=0; mark as free again */ + return ERRTIMEOUT; } + outb_p(len & 0xff,nic->iobase+TRANSMITBYTECOUNT0); + outb_p(len >> 8,nic->iobase+TRANSMITBYTECOUNT1); + outb_p(nic->tx_packet[buf]->page,nic->iobase+TRANSMITPAGE); + outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase); + return NOERR; +} + +void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) { + int iobase=nic->iobase; uint f; + uint xfers=len; + uint timeout=TIMEOUT_DMAMATCH; uint addr; +/* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset); */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); + outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); + outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0); + outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + + /* allow for no buffer */ + if(buf){ + if(nic->wordlength==2) { + for(f=0;f<(len>>1);f++) + ((unsigned short *)buf)[f]=inw(iobase+NE_DATA); + if(len&0x01) { + ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA); + xfers++; + } + } else { + for(f=0;f<len;f++) + ((unsigned char *)buf)[f]=inb(iobase+NE_DATA); + } + } else { + if(nic->wordlength==2) { + for(f=0;f<(len>>1);f++) + inw(iobase+NE_DATA); + if(len&0x01) { + inb(iobase+NE_DATA); + xfers++; + } + } else { + for(f=0;f<len;f++) + inb(iobase+NE_DATA); + } + } + /* Do these need to be *_p variants??? */ + +/* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n"); */ + /* TODO: make this timeout a constant */ + for(f=0;f<timeout;f++) { + uint high=inb_p(iobase + REMOTESTARTADDRESS1); + uint low=inb_p(iobase + REMOTESTARTADDRESS0); + addr=(high<<8)+low; + if(((offset+xfers)&0xff)==low) break; + } + /* + if(f>=timeout) + kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", + offset+xfers, addr); HUH WHAT? BJS*/ + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} + +/* Now supports scatter gather */ +void nic_block_output(snic *nic, packet_buffer *pkt) { + int iobase=nic->iobase; + int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int tmplen; + int bufidx, buflen; /* current packet_data in packet_buffer */ + void *bufptr; + char skip=0; /* Ask me about this if you have questions */ + uint deleteme=0; /* delete when done debugging */ + outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); + + T(A); + + for(f=0;f<pkt->count;f++) deleteme+=pkt->buf[f].len; + T(B); + + if(pkt->len != deleteme) return; + + if(pkt->len > MAX_LENGTH) return; + /* we should not have gotten this far... Paranoia check */ + + /* this next part is to supposedly fix a "read-before-write" bug... */ + outb_p(0x42, iobase + REMOTEBYTECOUNT0); + outb_p(0x00, iobase + REMOTEBYTECOUNT1); + outb_p(0x42, iobase + REMOTESTARTADDRESS0); + outb_p(0x00, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_READ | NIC_START, iobase); + SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */ + T(C); + + tmplen=(pkt->len < MIN_LENGTH) ? MIN_LENGTH : pkt->len; + outb_p(tmplen & 0xff, iobase + REMOTEBYTECOUNT0); + outb_p(tmplen >> 8, iobase + REMOTEBYTECOUNT1); + outb_p(0x00, iobase + REMOTESTARTADDRESS0); + outb_p(pkt->page, iobase + REMOTESTARTADDRESS1); + outb_p(NIC_REM_WRITE | NIC_START, iobase); + + T(D); + + /* go through each buffer and transfer it's contents */ + for(bufidx=pkt->count-1; bufidx >= 0; bufidx--) { + char odd; + buflen=pkt->buf[bufidx].len; /* only do derefrence once */ + bufptr=pkt->buf[bufidx].ptr; /* for performance :) */ + + if(nic->wordlength==2) { + + odd=(buflen & 0x01); + buflen>>=1; /* half the transfers */ + + if(skip) ((uint)bufptr)--; /* korewa baka desu */ + + for(f=skip;f<buflen;f++) { /* do we skip? */ + outw(((unsigned short *)bufptr)[f],iobase+NE_DATA); + tmplen -= 2; + } + + /* output 16-bits of the last odd byte */ + skip=0; /* assume we don't skip */ + + if(odd) { + short tmp=((unsigned char *)bufptr)[buflen<<1]; + /* get the byte from the next segment */ + if((bufidx-1)>=0) { + tmp |= ((unsigned char *) pkt->buf[bufidx-1].ptr)[0] << 8; + } + outw(tmp,iobase + NE_DATA); + tmplen -= 2; + skip=1; + } + } else + for(f=0;f<buflen;f++) { + outb(((unsigned char *)bufptr)[f],iobase+NE_DATA); + tmplen--; + } + } + T(E); + + /* If it's too short, pad with 0s */ + if(tmplen > 0) { + T(F); +/* kprintf("Padding runt\n"); */ + if(nic->wordlength==2) { + for(f=0;f<tmplen/2;f++){ + outw(0x00,iobase + NE_DATA); + tmplen -= 2; + } + } + } + if (tmplen > 0) { + for(f=0;f<tmplen;f++) { + outb(0x00,iobase + NE_DATA); + tmplen--; + } + } + + + T(G); +#ifdef SHIT + if(nic->wordlength==2) { + for(w=0;w<(len>>1);w++) + outw(((unsigned short *)buf)[w],iobase+NE_DATA); + if(len & 0x01) { + short tmp=buf[len-1]; //so we can output a whole 16-bits + // if buf were on the end of something, we would die. + outw(tmp,iobase+NE_DATA); + } + } else for(f=0;f<len;f++) + outb(((unsigned char *)buf)[f],iobase+NE_DATA); + +#endif + for(f=0;f<timeout;f++) { + uint high=inb_p(iobase + REMOTESTARTADDRESS1); + uint low=inb_p(iobase + REMOTESTARTADDRESS0); + addr=(high<<8)+low; + if(( (((pkt->page<<8)+(nic->wordlength==2 && (pkt->len&0x01))? +/* pkt->len+1:pkt->len+2))&0xff)==low)*/ + pkt->len+0:pkt->len+1))&0xff)==low) + break; + if( (pkt->len < MIN_LENGTH) && ( (((pkt->page<<8)+MIN_LENGTH) + & 0xff) == low) ) + break; + } + T(H); +#ifdef SHIT + if(f>=timeout) + kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", + ( (pkt->len >= MIN_LENGTH) ? + ((pkt->page<<8)+ + (nic->wordlength==2&&(pkt->len&0x01))? + pkt->len+0:pkt->len+1) +/* pkt->len+1:pkt->len+2)*/ + : ((pkt->page<<8)+MIN_LENGTH) ), + addr); +#endif +/* TODO Check ISR_RDC */ + + T(I); + + outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ +} diff --git a/srv/network/device/ne/ne2000.h b/srv/network/device/ne/ne2000.h @@ -0,0 +1,116 @@ +/* $Id: //depot/blt/srv/network/device/ne/ne2000.h#1 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __NE2000_INTERFACE +#define __NE2000_INTERFACE +#ifndef __NE2000_SHARED_CODE_BASE +typedef unsigned int uint; +typedef struct snic snic; +typedef struct nic_stat nic_stat; +typedef struct buffer_header buffer_header; +typedef struct packet_data packet_data; +typedef struct packet_buffer packet_buffer; +typedef struct nic_error_stat nic_error_stat; +#endif /* NE2000_SHARED_CODE_BASE */ + +#define LEN_ADDR 6 +#define MAX_TX 2 /* be careful with this (dual buffers) */ +#define MAX_PAGESPERPACKET 6 +#define TXPAGES (MAX_TX*MAX_PAGESPERPACKET) +#define LEN_PROM 16 +#define LEN_HEADER 14 +#define MIN_LENGTH 60 /* minimum length for packet data */ +#define MAX_LENGTH 1500 /* maximum length for packet data area */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* external interface */ +int nic_detect(int given); +int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual); +void nic_register_notify(snic *nic, void(*newnotify)(void*,packet_data*),void*); +void nic_start(snic *nic, int promiscuous); +void nic_stop(snic *nic); +void nic_isr(snic *nic); +nic_stat nic_get_stats(snic *nic); +void nic_stat_clear(nic_stat *that); +int nic_send_packet(snic *nic, packet_buffer *buffer); + +/* Your implementation */ +/*packet_buffer *alloc_buffer(uint count); */ /* Optional */ +packet_data *alloc_buffer_data(uint size); +void free_buffer(packet_buffer *ptr); +void cleanup_buffer(packet_buffer *ptr); +void free_buffer_data(packet_data *ptr); /* Optional */ +/* I reserve the right to use the "Option" procedures in the future */ + +#ifdef __cplusplus +}; +#endif + +struct buffer_header { + unsigned char status; + unsigned char next; + unsigned short count; /* length of header and packet */ +}; + +struct nic_error_stat { + long frame_alignment, crc, missed_packets; + long rx, rx_size, rx_dropped, rx_fifo, rx_overruns; + long tx_collisions; + long tx_aborts, tx_carrier, tx_fifo, tx_heartbeat, tx_window; +}; + +struct nic_stat { + long rx_packets; + long tx_buffered, tx_packets; + nic_error_stat errors; +}; + +struct packet_buffer { + uint page; + uint count, len; + packet_data *buf; /* An array of data segments */ +}; + +struct packet_data { /* each protocol layer can add it's own */ + uint len; + char *ptr; +}; + +struct snic { + int iobase; /* NULL if uninitialized */ + int pstart, pstop, wordlength, current_page; + nic_stat stat; + void (*notify)(void *passback, packet_data *newpacket); + void *kore; /* Passback pointer */ + packet_buffer *tx_packet[MAX_TX], *last_tx; + int busy, send, sending; +}; + +#endif /* __NE2000_INTERFACE */ diff --git a/srv/network/device/ne/support.c b/srv/network/device/ne/support.c @@ -0,0 +1,62 @@ +/* $Id: //depot/blt/srv/network/device/ne/support.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include "ne2000.h" + +unsigned int ticks; + +void idle (void) +{ + int i; + + for (i = 0; i < 1000; i++) + ticks++; +} + +packet_data *alloc_buffer_data (uint size) +{ + packet_data *data; + + data = malloc (sizeof (packet_data)); + data->len = size; + data->ptr = malloc (size); + return data; +} + +void free_buffer (packet_buffer *buf) +{ + free (buf); +} + +void free_buffer_data (packet_data *pd) +{ + free (pd->ptr); + free (pd); +} + diff --git a/srv/network/device/ne/wrap.c b/srv/network/device/ne/wrap.c @@ -0,0 +1,180 @@ +/* $Id: //depot/blt/srv/network/device/ne/wrap.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * limitations: can only support one card for now. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <blt/qsem.h> +#include <blt/network/eth.h> +#include <blt/network/mbuf.h> +#include "ne2000.h" +#include "wrap.h" + +#define NE_IRQ 3 + +void probe (void); +static void isr (void); +static void receive (void *cb, packet_data *data); +static void send (int num, struct mbuf *data); + +static eth_drv_t driver = { "ne", send, NULL }; + +static int maxdev = 0; +static int __irq; +static qsem_t *__mutex; +static ne_card_t *__card; +static eth_dev_t *__dev; + +int _init (void) +{ + register_eth_driver (&driver); + return 0; +} + +void _fini (void) +{ +} + +void probe (void) +{ + int iobase; + ne_card_t *card; + eth_dev_t *dev; + + if (iobase = nic_detect (0)) + { + card = malloc (sizeof (ne_card_t)); + card->nic.iobase = 0; + card->irq = NE_IRQ; + card->mutex = qsem_create (1); + nic_init (&card->nic, iobase, card->prom, NULL); + printf ("network: ne0 at port 0x%x, irq %d, mac = %X:%X:%X:%X:%X:%X\n", + card->nic.iobase, card->irq, card->prom[0], card->prom[1], + card->prom[2], card->prom[3], card->prom[4], card->prom[5]); + dev = malloc (sizeof (eth_dev_t)); + dev->dev_driver = &driver; + dev->dev_num = maxdev++; + memcpy (dev->dev_addr, card->prom, sizeof (dev->dev_addr)); + dev->dev_data = card; + + register_eth_device (dev); + nic_register_notify (&card->nic, receive, NULL); + nic_start (&card->nic, 0); + + __card = card; + __irq = card->irq; + __mutex = card->mutex; + __dev = dev; + + thr_create (isr, 0, "network:ne:isr"); + } + else + printf ("network: ne: probe failed.\n"); +} + +int config (int num, const char *prot, int state, const char *data) +{ + eth_config (__dev, prot, state, data); + return 0; +} + +static void isr (void) +{ + os_handle_irq (__irq); + for (;;) + { + os_sleep_irq (); + qsem_acquire (__mutex); + nic_isr (&__card->nic); + qsem_release (__mutex); + } +} + +static void receive (void *cb, packet_data *data) +{ + struct mbuf *mbuf, *header; + + mbuf = mget (); + mbuf->m_type = MT_DATA; + mbuf->m_len = data->len; + if (data->len < MLEN) + { + mbuf->m_data = mbuf->m_databuf; + memcpy (mbuf->m_data, data->ptr, data->len); + } + free_buffer_data (data); + + header = mget (); + header->m_type = MT_IFADDR; + header->m_len = 3; + *((eth_dev_t **) header->m_data) = __dev; + header->m_next = mbuf; + + eth_input (header); +} + +struct _pbuf { + packet_buffer pb; /* 16 */ + packet_data pd; /* 8 */ + int n; +} pbuf; + +static void send (int num, struct mbuf *data) +{ + int res; + packet_buffer *pb; + + printf ("send! %d\n", data->m_next->m_len); +#if 0 + pb = malloc (sizeof (packet_buffer)); + pb->count = 1; + pb->len = data->m_next->m_len; + pb->buf = alloc_buffer_data (pb->len); + pb->buf->len = data->m_next->m_len; + memcpy (pb->buf->ptr, data->m_next->m_data, pb->len); + qsem_acquire (__mutex); + res = nic_send_packet (&__card->nic, pb); + qsem_release (__mutex); +#else + pbuf.pb.count = 1; + pbuf.pb.buf = &pbuf.pd; + pbuf.pd.ptr = malloc (1000); + memcpy (pbuf.pd.ptr, data->m_next->m_data, data->m_next->m_len); + pbuf.pb.len = pbuf.pd.len = data->m_next->m_len + 100; + qsem_acquire (__mutex); + res = nic_send_packet (&__card->nic, &pbuf.pb); + qsem_release (__mutex); +#endif + printf ("sent %d\n", res); + mput (data->m_next); + mput (data); +} + diff --git a/srv/network/device/ne/wrap.h b/srv/network/device/ne/wrap.h @@ -0,0 +1,43 @@ +/* $Id: //depot/blt/srv/network/device/ne/wrap.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef WRAP_H +#define WRAP_H + +#include <blt/qsem.h> + +typedef struct +{ + snic nic; + char prom[32]; + int irq; + qsem_t *mutex; +} ne_card_t; + +#endif + diff --git a/srv/network/mbuf.c b/srv/network/mbuf.c @@ -0,0 +1,106 @@ +/* $Id: //depot/blt/srv/network/mbuf.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <unistd.h> +#include <blt/qsem.h> +#include <blt/network/mbuf.h> + +#define MBUF_INIT_MEM 0x1000 /* start with one page of mbufs */ +#define MCL_INIT_MEM 0x4000 /* start with eight clusters */ + +static struct mbuf *free_mbuf = NULL; +static unsigned int **free_cluster = NULL; + +static qsem_t *free_mbuf_sem, *free_cluster_sem; + +void mbinit (void) +{ + unsigned int i, **cl; + struct mbuf *m; + + m = sbrk (MBUF_INIT_MEM); + for (i = 0; i < MBUF_INIT_MEM / sizeof (struct mbuf); i++) + { + m[i].m_next = free_mbuf; + m[i].m_nextpkt = NULL; + m[i].m_len = MLEN; + m[i].m_data = (char *) &m[i] + sizeof (struct mbuf); + m[i].m_type = MT_FREE; + m[i].m_flags = 0; + free_mbuf = &m[i]; + } + + cl = sbrk (MCL_INIT_MEM); + for (i = 0; i < MCL_INIT_MEM / 0x800; i++, cl += 0x800 / sizeof (int)) + { + *cl = (unsigned int *) free_cluster; + free_cluster = cl; + } + + free_mbuf_sem = qsem_create (1); + free_cluster_sem = qsem_create (1); +} + +struct mbuf *mget (void) +{ + struct mbuf *mbuf; + + qsem_acquire (free_mbuf_sem); + if ((mbuf = free_mbuf) == NULL) + { + /* allocate more memory */ + } + else + free_mbuf = free_mbuf->m_next; + qsem_release (free_mbuf_sem); + mbuf->m_next = NULL; + return mbuf; +} + +char *mgetcl (struct mbuf *mbuf) +{ +} + +void mput (struct mbuf *mbuf) +{ + mbuf->m_nextpkt = NULL; + mbuf->m_len = MLEN; + mbuf->m_data = (char *) mbuf + sizeof (struct mbuf); + mbuf->m_type = MT_FREE; + mbuf->m_flags = 0; + mputcl (mbuf); + qsem_acquire (free_mbuf_sem); + mbuf->m_next = free_mbuf; + free_mbuf = mbuf->m_next; + qsem_release (free_mbuf_sem); +} + +void mputcl (struct mbuf *mbuf) +{ +} + diff --git a/srv/network/network.c b/srv/network/network.c @@ -0,0 +1,257 @@ +/* $Id: //depot/blt/srv/network/network.c#5 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <blt/tell.h> +#include <blt/os.h> +#include <blt/network/module.h> +#include <blt/network/mbuf.h> + +static int ctl_port, tell_port; +module_t *modlist = NULL; + +void network_cmd (const char *cmd, const char *arg) +{ + char c[] = { 0, 0 }, *name, *num, *prot; + int i, len, ifnum, state; + void *handle; + void (*probe)(void); + void (*config)(int, const char *, int, const char *); + module_t *m; + + if (!strcmp (cmd, "load")) + { + printf (" %s", arg); + name = malloc (len = BLT_MAX_NAME_LENGTH); + strlcpy (name, "/boot/", len); + strlcat (name, arg, len); + strlcat (name, ".so", len); + handle = dlopen (name, 0); + if (handle == NULL) + { + printf ("(error)", arg); + return; + } + free (name); + m = malloc (sizeof (module_t)); + m->name = malloc (strlen (arg) + 1); + strcpy (m->name, arg); + m->handle = handle; + m->next = modlist; + modlist = m; + } + else if (!strcmp (cmd, "probe")) + { + m = modlist; + while (m != NULL) + { + if (!strcmp (m->name, arg)) + { + probe = dlsym (m->handle, "probe"); + if (probe != NULL) + { + (*probe) (); + return; + } + } + else + m = m->next; + } + } + else if (!strcmp (cmd, "config")) + { + name = malloc (len = BLT_MAX_NAME_LENGTH); + for (i = 0; (i < len) && arg[i]; i++) + if ((arg[i] >= '0') && (arg[i] <= '9')) + { + name[i] = 0; + break; + } + else + name[i] = arg[i]; + + num = malloc (BLT_MAX_NAME_LENGTH); + *num = 0; + i++; + while ((arg[i] != ' ') && arg[i]) + { + *c = arg[i]; + strlcat (num, c, len); + } + ifnum = atoi (num); + + prot = malloc (BLT_MAX_NAME_LENGTH); + *prot = 0; + i++; + while ((arg[i] != ' ') && arg[i]) + { + *c = arg[i++]; + strlcat (prot, c, len); + } + + *num = 0; + i++; + while ((arg[i] != ' ') && arg[i]) + { + *c = arg[i++]; + strlcat (num, c, len); + } + if (!strcmp (num, "up")) + state = 1; + else if (!strcmp (num, "down")) + state = 0; + else + ; + + m = modlist; + while (m != NULL) + { + if (!strcmp (m->name, name)) + { + config = dlsym (m->handle, "config"); + if (config != NULL) + { + (*config) (ifnum, prot, state, arg + i + 1); + return; + } + } + else + m = m->next; + } + free (name); + free (num); + free (prot); + } +} + +void network_tell (const char *msg) +{ + const char *c, *cmd; + char *full; + char *d; + int i, whole, len; + + c = msg; + cmd = NULL; + whole = 0; + while (*c) + { + i = 0; + while ((c[i] != ' ') && c[i]) + i++; + d = malloc (i + 1); + strlcpy (d, c, i + 1); + if (cmd == NULL) + { + cmd = d; + if (!strcmp (cmd, "load")) + printf ("network: loading drivers. ["); + else if (!strcmp (cmd, "config")) + { + whole = 1; + full = malloc (len = strlen (msg + 1)); + *full = 0; + } + } + else if (!whole) + network_cmd (cmd, d); + else + { + strlcat (full, d, len); + strlcat (full, " ", len); + } + if (i != strlen (c)) + c += i + 1; + else + break; + } + if (!strcmp (cmd, "load")) + printf (" ]\n"); + else if (!strcmp (cmd, "config")) + { + network_cmd (cmd, full); + free (full); + } +} + +int network_main (volatile int *ready) +{ + char *buffer; + int len; + msg_hdr_t mh; + + ctl_port = port_create (0, "network_ctl_port"); + tell_port = port_create (0, "network_tell_port"); + port_slave (ctl_port, tell_port); + namer_register (ctl_port, "network"); + namer_register (tell_port, "network:tell"); + + printf ("network: ready.\n"); + buffer = malloc (len = 256); + mbinit (); + *ready = 1; + + for (;;) + { + mh.src = 0; + mh.dst = ctl_port; + mh.data = buffer; + mh.size = len; + old_port_recv (&mh); + + if (mh.dst == tell_port) + { + network_tell (buffer); + mh.dst = mh.src; + mh.src = tell_port; + mh.data = &tell_port; + mh.size = 1; + old_port_send (&mh); + } + else if (mh.dst == ctl_port) + { + } + } + + return 0; +} + +int main (int argc, char **argv) +{ + volatile int ready = 0; + + thr_create (network_main, (int *) &ready, "network"); + while (!ready) ; + return 0; +} + diff --git a/srv/network/protocol/Makefile b/srv/network/protocol/Makefile @@ -0,0 +1,6 @@ +BLTHOME := ../../../ +include $(BLTHOME)make.conf + +SUBDIRS := eth arp ipv4 + +include $(BLTHOME)make.actions diff --git a/srv/network/protocol/arp/Makefile b/srv/network/protocol/arp/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../../../ +include $(BLTHOME)make.conf + +CFLAGS += -D_NETWORK +OBJS := arp.o +SHLIB := arp.so + +include $(BLTHOME)make.actions diff --git a/srv/network/protocol/arp/arp.c b/srv/network/protocol/arp/arp.c @@ -0,0 +1,108 @@ +/* $Id: //depot/blt/srv/network/protocol/arp/arp.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <blt/network/mbuf.h> +#include <blt/network/eth.h> +#include <blt/network/ipv4.h> + +void arp_input (struct mbuf *mbuf); +static eth_prot_t protocol = { "arp", 0, arp_input, NULL }; + +int _init (void) +{ + protocol.num = htons (ETH_PROT_ARP); + register_eth_protocol (&protocol); + return 0; +} + +void arp_print_addrs (arp_packet *arp) +{ + printf ("%X:%X:%X:%X:%X:%X %X:%X:%X:%X:%X:%X\n", arp->header.src[0], + arp->header.src[1], arp->header.src[2], arp->header.src[3], + arp->header.src[4], arp->header.src[5], arp->header.dst[0], + arp->header.dst[1], arp->header.dst[2], arp->header.dst[3], + arp->header.dst[4], arp->header.dst[5]); +} + +/* + * this doesn't take too long, so we do it synchronously. + */ +void arp_input (struct mbuf *mbuf) +{ + arp_packet *arp_request, *arp_reply; + ipv4_iface_t *iface; + eth_dev_t *dev; + struct mbuf *reply_header, *reply; + + arp_request = (arp_packet *) mbuf->m_next->m_data; + iface = iflist; + while (iface != NULL) + if (!memcmp (iface->addr, arp_request->targ_ip_addr, 4)) + { + printf ("ARP: who-has %d.%d.%d.%d tell %d.%d.%d.%d\n", + arp_request->targ_ip_addr[0], arp_request->targ_ip_addr[1], + arp_request->targ_ip_addr[2], arp_request->targ_ip_addr[3], + arp_request->send_ip_addr[0], arp_request->send_ip_addr[1], + arp_request->send_ip_addr[2], arp_request->send_ip_addr[3]); + + dev = *((eth_dev_t **) mbuf->m_data); + reply_header = mget (); + reply_header->m_next = reply = mget (); + arp_reply = (arp_packet *) (reply->m_data = reply->m_databuf); + memcpy (arp_reply->header.dst, arp_request->header.src, 6); + memcpy (arp_reply->header.src, dev->dev_addr, 6); + arp_reply->header.frame_type = htons (ETH_PROT_ARP); + arp_reply->hard_type = htons (1); + arp_reply->prot_type = htons (ETH_PROT_IP); + arp_reply->hard_size = 6; + arp_reply->prot_size = 4; + arp_reply->op = htons (ETH_ARP_OP_REPLY); + memcpy (arp_reply->send_eth_addr, dev->dev_addr, 6); + memcpy (arp_reply->send_ip_addr, iface->addr, 4); + memcpy (arp_reply->targ_eth_addr, arp_request->header.src, 6); + memcpy (arp_reply->targ_ip_addr, arp_request->send_ip_addr, 4); + + printf ("ARP: reply %d.%d.%d.%d is-at %X:%X:%X:%X:%X:%X\n", + arp_reply->send_ip_addr[0], arp_reply->send_ip_addr[1], + arp_reply->send_ip_addr[2], arp_reply->send_ip_addr[3], + arp_reply->send_eth_addr[0], arp_reply->send_eth_addr[1], + arp_reply->send_eth_addr[2], arp_reply->send_eth_addr[3], + arp_reply->send_eth_addr[4], arp_reply->send_eth_addr[5]); + + arp_print_addrs (arp_request); + arp_print_addrs (arp_reply); + reply->m_len = sizeof (arp_packet); + dev->dev_driver->output (dev->dev_num, reply_header); + mput (mbuf->m_next); + mput (mbuf); + return; + } + else + iface = iface->next; +} + diff --git a/srv/network/protocol/eth/Makefile b/srv/network/protocol/eth/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../../../ +include $(BLTHOME)make.conf + +CFLAGS += -D_NETWORK +OBJS := eth.o +SHLIB := eth.so + +include $(BLTHOME)make.actions diff --git a/srv/network/protocol/eth/eth.c b/srv/network/protocol/eth/eth.c @@ -0,0 +1,210 @@ +/* $Id: //depot/blt/srv/network/protocol/eth/eth.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +e* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <blt/qsem.h> +#include <blt/network/eth.h> +#include <blt/network/mbuf.h> +#include <blt/network/module.h> + +eth_drv_t *drvlist = NULL; +eth_dev_t *devlist = NULL; +eth_prot_t *protlist = NULL; + +static qsem_t *eth_input_lock_sem, *eth_input_length_sem; +static qsem_t *eth_output_lock_sem, *eth_output_length_sem; +static struct mbuf *eth_input_queue = NULL, *eth_output_queue = NULL; +static void eth_input_thread (void); +static void eth_output_thread (void); + +int _init (void) +{ + eth_input_lock_sem = qsem_create (1); + eth_input_length_sem = qsem_create (0); + thr_create (eth_input_thread, 0, "network:eth:input"); + eth_output_lock_sem = qsem_create (1); + eth_output_length_sem = qsem_create (0); + thr_create (eth_output_thread, 0, "network:eth:output"); + return 1; +} + +void _fini (void) +{ +} + +void register_eth_driver (eth_drv_t *drv) +{ + drv->next = drvlist; + drvlist = drv; +} + +void unregister_eth_driver (eth_drv_t *drv) +{ +} + +void register_eth_device (eth_dev_t *dev) +{ + dev->next = devlist; + devlist = dev; +} + +void unregister_eth_device (eth_dev_t *dev) +{ +} + +void register_eth_protocol (eth_prot_t *prot) +{ + prot->next = protlist; + protlist = prot; +} + +void unregister_eth_protocol (eth_prot_t *prot) +{ +} + +void eth_input (struct mbuf *mbuf) +{ + struct mbuf *m; + + qsem_acquire (eth_input_lock_sem); + if (eth_input_queue == NULL) + { + eth_input_queue = mbuf; + mbuf->m_nextpkt = NULL; + } + else + { + m = eth_input_queue; + while (m->m_nextpkt != NULL) + m = m->m_nextpkt; + m->m_nextpkt = mbuf; + } + qsem_release (eth_input_lock_sem); + qsem_release (eth_input_length_sem); +} + +static void eth_input_thread (void) +{ + struct mbuf *mbuf, *mbuf_header; + eth_prot_t *prot; + ether_header *header; + + for (;;) + { + qsem_acquire (eth_input_length_sem); + qsem_acquire (eth_input_lock_sem); + mbuf_header = eth_input_queue; + eth_input_queue = eth_input_queue->m_nextpkt; + qsem_release (eth_input_lock_sem); + + mbuf = mbuf_header->m_next; + header = (ether_header *) mbuf->m_data; +#if 0 + printf ("eth_input_thread prot: %x src: %X:%X:%X:%X:%X:%X dst: " + "%X:%X:%X:%X:%X:%X\n", header->frame_type, header->src[0], + header->src[1], header->src[2], header->src[3], header->src[4], + header->src[5], header->dst[0], header->dst[1], header->dst[2], + header->dst[3], header->dst[4], header->dst[5]); +#endif + prot = protlist; + while (prot != NULL) + if (prot->num == header->frame_type) + { + prot->input (mbuf_header); + break; + } + else + prot = prot->next; + } +} + +void eth_output (struct mbuf *mbuf) +{ + struct mbuf *m; + + qsem_acquire (eth_output_lock_sem); + if (eth_output_queue == NULL) + { + eth_output_queue = mbuf; + mbuf->m_nextpkt = NULL; + } + else + { + m = eth_output_queue; + while (m->m_nextpkt != NULL) + m = m->m_nextpkt; + m->m_nextpkt = mbuf; + } + qsem_release (eth_output_lock_sem); + qsem_release (eth_output_length_sem); +} + +static void eth_output_thread (void) +{ + struct mbuf *mbuf; + + for (;;) + { + qsem_acquire (eth_output_length_sem); + qsem_acquire (eth_output_lock_sem); + mbuf = eth_output_queue; + eth_output_queue = eth_input_queue->m_nextpkt; + qsem_release (eth_output_lock_sem); + printf ("eth_output_thread\n"); + } +} + +void eth_config (eth_dev_t *dev, const char *prot, int state, const char *data) +{ + char *devname; + int len; + int (*config_up)(const char *, void (*)(struct mbuf *), const char *); + module_t *mod; + + mod = modlist; + while (mod != NULL) + if (!strcmp (mod->name, prot)) + { + printf ("network: %s%d: interface %s, ", dev->dev_driver->name, + dev->dev_num, state ? "up" : "down"); + devname = malloc (len = 16); + snprintf (devname, len, "%s%d", dev->dev_driver->name, + dev->dev_num); + config_up = dlsym (mod->handle, "ipv4_config_up"); /* XXX */ + if (config_up != NULL) + (*config_up) (devname, eth_output, data); + return; + } + else + mod = mod->next; + printf ("network: %s%d: unknown protocol %s\n", dev->dev_driver->name, + dev->dev_num, prot); +} + diff --git a/srv/network/protocol/ipv4/Makefile b/srv/network/protocol/ipv4/Makefile @@ -0,0 +1,8 @@ +BLTHOME := ../../../../ +include $(BLTHOME)make.conf + +CFLAGS += -D_NETWORK +OBJS := iface.o +SHLIB := ipv4.so + +include $(BLTHOME)make.actions diff --git a/srv/network/protocol/ipv4/iface.c b/srv/network/protocol/ipv4/iface.c @@ -0,0 +1,84 @@ +/* $Id: //depot/blt/srv/network/protocol/ipv4/iface.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <blt/network/ipv4.h> + +ipv4_iface_t *iflist = NULL; + +int _init (void) +{ + return 1; +} + +int ipv4_config_up (const char *name, void (*output)(struct mbuf *), + const char *data) +{ + char c[] = { 0, 0 }, temp[16]; + unsigned char num[8]; + int i, j, k, len, space; + ipv4_iface_t *iface; + + for (i = j = k = space = *temp = 0; i < strlen (data); i++) + if (data[i] == '.') + { + num[k++] = atoi (temp); + j++; + *temp = 0; + } + else if (data[i] == ' ') + { + num[k++] = atoi (temp); + j++; + *temp = 0; + space = 1; + } + else + { + *c = data[j++]; + strlcat (temp, c, sizeof (temp)); + } + iface = malloc (sizeof (ipv4_iface_t)); + iface->name = name; + iface->addr[0] = num[0]; iface->addr[1] = num[1]; + iface->addr[2] = num[2]; iface->addr[3] = num[3]; + iface->netmask[0] = num[4]; iface->netmask[1] = num[5]; + iface->netmask[2] = num[6]; iface->netmask[3] = num[7]; + iface->output = output; + iface->next = iflist; + iflist = iface; + printf ("address %d.%d.%d.%d netmask %d.%d.%d.%d\n", + iface->addr[0], iface->addr[1], iface->addr[2], iface->addr[3], + iface->netmask[0], iface->netmask[1], iface->netmask[2], + iface->netmask[3]); +} + +int ipv4_config_down (void) +{ +} + diff --git a/srv/pci/Makefile b/srv/pci/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +SRCS := pci.c server.cpp +CRT0 := $(BLTHOME)lib/crt0.o +BINARY := pci.bin +LIBS := -lposix -lblt -lc + +include $(BLTHOME)make.actions diff --git a/srv/pci/pci.c b/srv/pci/pci.c @@ -0,0 +1,138 @@ +/* Copyright 1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> + +#include <i386/io.h> + +#include "pci.h" + +typedef struct confadd +{ + uchar reg:8; + uchar func:3; + uchar dev:5; + uchar bus:8; + uchar rsvd:7; + uchar enable:1; +} confadd; + +uint32 pci_read(int bus, int dev, int func, int reg, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + outl(u.n,0xCF8); + + base = 0xCFC + (reg & 0x03); + + switch(bytes){ + case 1: return inb(base); + case 2: return inw(base); + case 4: return inl(base); + default: return 0; + } +} + +void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes) +{ + uint32 base; + + union { + confadd c; + uint32 n; + } u; + + u.c.enable = 1; + u.c.rsvd = 0; + u.c.bus = bus; + u.c.dev = dev; + u.c.func = func; + u.c.reg = reg & 0xFC; + + base = 0xCFC + (reg & 0x03); + outl(u.n,0xCF8); + switch(bytes){ + case 1: outb(v,base); break; + case 2: outw(v,base); break; + case 4: outl(v,base); break; + } + +} + +int pci_probe(int bus, int dev, int func, pci_cfg *cfg) +{ + uint32 *word = (uint32 *) cfg; + uint32 v; + int i; + for(i=0;i<4;i++){ + word[i] = pci_read(bus,dev,func,4*i,4); + } + if(cfg->vendor_id == 0xffff) return 1; + + cfg->bus = bus; + cfg->dev = dev; + cfg->func = func; +#if 0 + printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func); + printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n", + cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface); + printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n", + cfg->status, cfg->command, cfg->bist, cfg->header_type, + cfg->latency_timer, cfg->cache_line_size); +#endif + + switch(cfg->header_type & 0x7F){ + case 0: /* normal device */ + for(i=0;i<6;i++){ + v = pci_read(bus,dev,func,i*4 + 0x10, 4); + if(v) { + int v2; + pci_write(bus,dev,func,i*4 + 0x10, 0xffffffff, 4); + v2 = pci_read(bus,dev,func,i*4+0x10, 4) & 0xfffffff0; + pci_write(bus,dev,func,i*4 + 0x10, v, 4); + v2 = 1 + ~v2; + if(v & 1) { +// printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff); + cfg->base[i] = v & 0xffff; + cfg->size[i] = v2 & 0xffff; + } else { +// printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2); + cfg->base[i] = v; + cfg->size[i] = v2; + } + } else { + cfg->base[i] = 0; + cfg->size[i] = 0; + } + + } + v = pci_read(bus,dev,func,0x3c,1); + cfg->irq = (v == 0xff ? 0 : v); + +// printf(" * Interrupt Line: %X\n",cfg->irq); + break; + case 1: +// printf(" * PCI <-> PCI Bridge\n"); + break; + default: +// printf(" * Unknown Header Type\n"); + } + return 0; +} + + diff --git a/srv/pci/pci.h b/srv/pci/pci.h @@ -0,0 +1,151 @@ +/* Copyright 1999, Brian J. Swetland. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#ifndef _PCI_H +#define _PCI_H + +#include <blt/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + /* normal header stuff */ + uint16 vendor_id; + uint16 device_id; + + uint16 command; + uint16 status; + + uint8 revision_id; + uint8 interface; + uint8 sub_class; + uint8 base_class; + + uint8 cache_line_size; + uint8 latency_timer; + uint8 header_type; + uint8 bist; + + /* device info */ + uint8 bus; + uint8 dev; + uint8 func; + uint8 irq; + + /* base registers */ + uint32 base[6]; + uint32 size[6]; + +} pci_cfg; + +uint32 pci_read(int bus, int dev, int func, int reg, int bytes); +void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes); +int pci_probe(int bus, int dev, int func, pci_cfg *cfg); + +#ifdef __cplusplus +} +#endif + +#ifdef PCI_STUB + +#include <blt/Connection.h> +#include <blt/Message.h> + +namespace BLT { + +class PCI +{ +public: + int read(int bus, int dev, int func, int reg, uint32 *v, int bytes); + int write(int bus, int dev, int func, int reg, uint32 v, int bytes); + int get_nth_cfg(int n, pci_cfg *cfg); + + static PCI *FindService(); + ~PCI(); + +private: + PCI(Connection *pci); + Connection *pci; +}; + +inline int +PCI::read(int bus, int dev, int func, int reg, uint32 *v, int bytes) +{ + int32 res; + Message msg; + msg.PutInt32('code',2); + msg.PutInt32('arg0',bus); + msg.PutInt32('arg1',dev); + msg.PutInt32('arg2',func); + msg.PutInt32('arg3',reg); + msg.PutInt32('arg4',bytes); + + if((res = pci->Call(&msg,&msg))) return res; + msg.GetInt32('ret0',(int32*) v); + msg.GetInt32('resp',&res); + + return res; +} + +inline int +PCI::write(int bus, int dev, int func, int reg, uint32 v, int bytes) +{ + int32 res; + Message msg; + msg.PutInt32('code',3); + msg.PutInt32('arg0',bus); + msg.PutInt32('arg1',dev); + msg.PutInt32('arg2',func); + msg.PutInt32('arg3',reg); + msg.PutInt32('arg4',(int32)v); + msg.PutInt32('arg5',bytes); + + if((res = pci->Call(&msg,&msg))) return res; + msg.GetInt32('resp',&res); + + return res; +} + +inline int +PCI::get_nth_cfg(int n, pci_cfg *cfg) +{ + int32 res; + Message msg; + msg.PutInt32('code',1); + msg.PutInt32('arg0',n); + + if((res = pci->Call(&msg,&msg))) return res; + if((res = msg.GetData('ret0','pcic',cfg,sizeof(pci_cfg)))) return res; + msg.GetInt32('resp',&res); + + return res; +} + +inline PCI * +PCI::FindService() +{ + Connection *cnxn = Connection::FindService("pci"); + if(cnxn) { + return new PCI(cnxn); + } else { + return 0; + } +} + +PCI::PCI(Connection *cnxn){ + pci = cnxn; +} + +PCI::~PCI(){ + delete pci; +} + +} + +#endif + +#endif diff --git a/srv/pci/server.cpp b/srv/pci/server.cpp @@ -0,0 +1,132 @@ +#include <blt/Message.h> +#include <blt/Connection.h> +#include <blt/namer.h> +#include <blt/syscall.h> + +using namespace BLT; + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pci.h" + +static pci_cfg *pci_dev[128]; +static int pci_count = 0; + +void server(void *data) +{ + Connection *cnxn = (Connection *) data; + Message msg,reply; + int res; + + while(cnxn->Recv(&msg) == 0){ + int32 op = -1; + msg.GetInt32('code',&op); + + reply.Empty(); + + switch(op){ + case 1: { // get_nth_pci_cfg + int32 n = -1; + msg.GetInt32('arg0', &n); + if((n >= 0) && (n < pci_count)){ + reply.PutData('ret0','pcic',pci_dev[n],sizeof(pci_cfg)); + res = 0; + } else { + res = -1; + } + break; + } + + case 2: { // pci_read + int32 bus = 0; + int32 dev = 0; + int32 func = 0; + int32 reg = 0; + int32 size = 0; + msg.GetInt32('arg0',&bus); + msg.GetInt32('arg1',&dev); + msg.GetInt32('arg2',&func); + msg.GetInt32('arg3',&reg); + msg.GetInt32('arg4',&size); + + printf("pci: read(%d,%d,%d,%d,%d)\n",bus,dev,func,reg,size); + size = (int32) pci_read(bus,dev,func,reg,size); + + reply.PutInt32('ret0',size); + res = 0; + break; + } + + case 3: { // pci_write + int32 bus = 0; + int32 dev = 0; + int32 func = 0; + int32 reg = 0; + int32 size = 0; + int32 val = 0; + + msg.GetInt32('arg0',&bus); + msg.GetInt32('arg1',&dev); + msg.GetInt32('arg2',&func); + msg.GetInt32('arg3',&reg); + msg.GetInt32('arg4',&val); + msg.GetInt32('arg5',&size); + pci_write(bus,dev,func,reg,(uint32)val,size); + res = 0; + break; + } + + default: + res = -1; + } + + reply.PutInt32('resp',res); + res = msg.Reply(&reply); + } +} + +int pci_scan() +{ + pci_cfg cfg; + int bus,dev,func; + + for(bus=0;bus<255;bus++){ + for(dev=0;dev<32;dev++) { + if(pci_probe(bus,dev,0,&cfg)) continue; + pci_dev[pci_count] = (pci_cfg*) malloc(sizeof(pci_cfg)); + memcpy(pci_dev[pci_count],&cfg,sizeof(pci_cfg)); + pci_count++; + if(cfg.header_type & 0x80){ + for(func=1;func<8;func++){ + if(!pci_probe(bus,dev,func,&cfg)){ + pci_dev[pci_count] = (pci_cfg*) malloc(sizeof(pci_cfg)); + memcpy(pci_dev[pci_count],&cfg,sizeof(pci_cfg)); + pci_count++; + } + } + } + } + } +} + +int main(int argc, char **argv[]) +{ + Connection *cnxn; + + if(namer_find("pci",0) > 0) { +// printf("pci: server is already running\n"); + return 0; + } + + cnxn = Connection::CreateService("pci"); + + pci_scan(); + + if(cnxn){ +// printf("pci: server started\n",cnxn); + thr_resume(thr_create(server,cnxn,"pci server")); + } + return 0; +} diff --git a/srv/vfs/Makefile b/srv/vfs/Makefile @@ -0,0 +1,14 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +BINARY := vfs.bin +OBJS := vfs.o fs.o super.o vnode.o shm.o path.o rootfs.o bootfs.o +CRT0 := $(BLTHOME)lib/crtb.o +LIBS := -lposix -lblt -ldl -lc +SUBDIRS := drivers + +#CFLAGS += -DVFS_SANDBOX -Isandbox -Wall + +sandbox: fs.o super.o vnode.o + +include $(BLTHOME)make.actions diff --git a/srv/vfs/bootfs.c b/srv/vfs/bootfs.c @@ -0,0 +1,317 @@ +/* $Id: //depot/blt/srv/vfs/bootfs.c#9 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/stat.h> +#include <blt/syscall.h> +#include "vfs-int.h" +#include "bootfs.h" + +static int inode_max = 0; + +static struct vnode_ops bootfs_vnode_ops = +{ + bootfs_read_vnode, bootfs_drop_vnode, NULL, NULL, bootfs_walk, NULL, + bootfs_mount, bootfs_unmount, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + bootfs_opendir, bootfs_closedir, NULL, bootfs_rewinddir, bootfs_readdir, + bootfs_open, bootfs_close, bootfs_free_cookie, bootfs_read, NULL, + NULL, NULL, bootfs_rstat, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +struct fs_type bootfs = { "bootfs", &bootfs_vnode_ops, NULL }; + +static struct bootfs_inode *bootfs_inew (const char *name, int offset, + int size) +{ + struct bootfs_inode *inode; + + inode = malloc (sizeof (struct bootfs_inode)); + inode->i_ino = inode_max++; + inode->i_offset = offset; + inode->i_size = size; + strlcpy (inode->i_name, name, sizeof (inode->i_name)); + inode->i_next = NULL; + return inode; +} + +int bootfs_mount (struct superblock *super, const char *data, int silent) +{ + int i; + struct bootfs_sb_data *sb_data; + struct bootfs_inode *inode; + boot_entry *be; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_mount\n"); +#endif + sb_data = (struct bootfs_sb_data *) malloc (sizeof (struct bootfs_sb_data)); + sb_data->d_bootdir_area = area_clone (3, 0, (void **) &sb_data->d_bootdir, + 0); + sb_data->inode_list = NULL; + + /* create inode list */ + sb_data->inode_list = bootfs_inew (".", 0, 0); + sb_data->inode_list->i_next = bootfs_inew ("..", 0, 0); + for (i = 0; i < BOOTDIR_MAX_ENTRIES; i++) + if ((sb_data->d_bootdir->bd_entry[i].be_type != BE_TYPE_NONE) && + strcmp (sb_data->d_bootdir->bd_entry[i].be_name, + BOOTDIR_DIRECTORY)) + { + be = &sb_data->d_bootdir->bd_entry[i]; + inode = bootfs_inew (be->be_name, be->be_offset, be->be_vsize); + inode->i_next = sb_data->inode_list; + sb_data->inode_list = inode; + } + + super->sb_data = sb_data; + super->sb_root = vget (super, 0); + return 0; +} + +void bootfs_unmount (struct superblock *sb) +{ +#ifdef BOOTFS_DEBUG + printf ("bootfs_unmount\n"); +#endif +} + +int bootfs_read_vnode (struct vnode *vnode) +{ + struct bootfs_sb_data *sb_data; + struct bootfs_inode *inode; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_read_vnode %llx\n", vnode->v_vnid); +#endif + sb_data = vnode->v_sb->sb_data; + inode = sb_data->inode_list; + while (inode != NULL) + if (inode->i_ino == vnode->v_vnid) + { + vnode->v_data = inode; + return 0; + } + else + inode = inode->i_next; + + return 0; +} + +void bootfs_drop_vnode (struct vnode *vnode) +{ +#ifdef BOOTFS_DEBUG + vnode->v_data = NULL; +#endif +} + +struct vnode *bootfs_walk (struct vnode *parent, const char *path) +{ + struct bootfs_sb_data *data; + struct bootfs_inode *inode; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_walk %s\n", path); +#endif + if (parent->v_vnid) + return NULL; + else + { + data = parent->v_sb->sb_data; + inode = data->inode_list; + while (inode != NULL) + //if (!strncmp (inode->i_name, path, BOOTDIR_NAMELEN)) + if (!strcmp (inode->i_name, path)) + return vget (parent->v_sb, inode->i_ino); + else + inode = inode->i_next; + return NULL; + } +} + +int bootfs_opendir (struct vnode *dir, void **cookie) +{ + struct bootfs_sb_data *data; + struct vfs_dirent_node *head, *p; + struct bootfs_inode *inode; + union bootfs_cookie *bc; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_opendir\n"); +#endif + if (dir->v_vnid) + return ENOTDIR; /* paranoia */ + + head = NULL; + data = dir->v_sb->sb_data; + inode = data->inode_list; + while (inode != NULL) + { + p = malloc (sizeof (struct vfs_dirent_node)); + p->dirent = malloc (sizeof (struct dirent)); + p->dirent->d_fileno = inode->i_ino; + p->dirent->d_reclen = sizeof (struct dirent); + strncpy (p->dirent->d_name, inode->i_name, sizeof (p->dirent->d_name)); + + p->next = head; + head = p; + inode = inode->i_next; + } + + bc = malloc (sizeof (union bootfs_cookie)); + bc->u_dir.head = bc->u_dir.current = head; + *cookie = bc; + return 0; +} + +void bootfs_closedir (struct vnode *dir, void *cookie) +{ +#ifdef BOOTFS_DEBUG + printf ("bootfs_closedir\n"); +#endif +} + +int bootfs_rewinddir (struct vnode *dir, void *cookie) +{ + union bootfs_cookie *bc; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_rewinddir\n"); +#endif + + bc = cookie; + bc->u_dir.current = bc->u_dir.head; + return 0; +} + +int bootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie) +{ + struct dirent *orig; + union bootfs_cookie *bc; + + bc = cookie; + if (bc->u_dir.current == NULL) + return 1; + orig = bc->u_dir.current->dirent; + dirent->d_fileno = orig->d_fileno; + dirent->d_reclen = orig->d_reclen; + strncpy (dirent->d_name, orig->d_name, BLT_MAX_NAME_LENGTH); + bc->u_dir.current = bc->u_dir.current->next; +#ifdef BOOTFS_DEBUG + printf ("bootfs_readdir %s\n", dirent->d_name); +#endif + return 0; +} + +int bootfs_open (struct vnode *vnode, void **cookie) +{ + struct bootfs_sb_data *data; + struct bootfs_inode *inode; + union bootfs_cookie *bc; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_open %llx\n", vnode->v_vnid); +#endif + data = vnode->v_sb->sb_data; + inode = vnode->v_data; + bc = malloc (sizeof (union bootfs_cookie)); + bc->u_file.begin = (char *) data->d_bootdir + inode->i_offset * 0x1000; + bc->u_file.pos = 0; + *cookie = bc; + return 0; +} + +int bootfs_close (struct vnode *vnode, void *cookie) +{ +#ifdef BOOTFS_DEBUG + printf ("bootfs_close %llx\n", vnode->v_vnid); +#endif + return 0; +} + +void bootfs_free_cookie (void *cookie) +{ +#ifdef BOOTFS_DEBUG + printf ("bootfs_free_cookie\n"); +#endif + free (cookie); +} + +int bootfs_read (struct vnode *vnode, char *buf, size_t count, off_t offset, + size_t *numread, void *cookie) +{ + char *src; + struct bootfs_sb_data *data; + struct bootfs_inode *inode; + union bootfs_cookie *bc; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_read %llx\n", vnode->v_vnid); +#endif + data = vnode->v_sb->sb_data; + inode = vnode->v_data; + bc = cookie; + if (offset >= inode->i_size) + { + *numread = 0; + return 0; + } + src = (char *) data->d_bootdir + inode->i_offset * 0x1000 + offset; + *numread = (count <= inode->i_size - offset) ? count : (inode->i_size - + offset); + memcpy (buf, src, *numread); + return 0; +} + +int bootfs_rstat (struct vnode *vnode, struct stat *buf) +{ + struct bootfs_inode *inode; + +#ifdef BOOTFS_DEBUG + printf ("bootfs_rstat %llx\n", vnode->v_vnid); +#endif + inode = vnode->v_data; + + buf->st_ino = inode->i_ino; + buf->st_nlink = 0; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_blksize = 512; + buf->st_size = inode->i_size; + buf->st_blocks = (inode->i_size & 0xfff) ? (inode->i_size >> 12) + 1 : + inode->i_size >> 12; + return 0; +} + diff --git a/srv/vfs/bootfs.h b/srv/vfs/bootfs.h @@ -0,0 +1,81 @@ +/* $Id: //depot/blt/srv/vfs/bootfs.h#6 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BOOTFS_H_ +#define _BOOTFS_H_ + +#include <boot.h> +#include "vfs-int.h" + +struct bootfs_inode +{ + int i_ino, i_offset, i_size; + char i_name[BOOTDIR_NAMELEN]; + struct bootfs_inode *i_next; +}; + +struct bootfs_sb_data +{ + int d_bootdir_area; + boot_dir *d_bootdir; + struct bootfs_inode *inode_list; +}; + +union bootfs_cookie +{ + struct + { + struct vfs_dirent_node *head, *current; + } u_dir; + struct + { + char *begin; + int pos; + } u_file; +}; + +int bootfs_mount (struct superblock *sb, const char *data, int silent); +void bootfs_unmount (struct superblock *sb); +int bootfs_read_vnode (struct vnode *vnode); +void bootfs_drop_vnode (struct vnode *vnode); +struct vnode *bootfs_walk (struct vnode *parent, const char *path); +int bootfs_opendir (struct vnode *dir, void **cookie); +void bootfs_closedir (struct vnode *dir, void *cookie); +int bootfs_rewinddir (struct vnode *dir, void *cookie); +int bootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie); +int bootfs_open (struct vnode *dir, void **cookie); +int bootfs_close (struct vnode *dir, void *cookie); +void bootfs_free_cookie (void *cookie); +int bootfs_read (struct vnode *dir, char *buf, size_t count, off_t offset, + size_t *res, void *cookie); +int bootfs_rstat (struct vnode *vnode, struct stat *buf); + +#endif + diff --git a/srv/vfs/drivers/Makefile b/srv/vfs/drivers/Makefile @@ -0,0 +1,6 @@ +BLTHOME := ../../../ +include $(BLTHOME)make.conf + +SUBDIRS := ffs + +include $(BLTHOME)make.actions diff --git a/srv/vfs/drivers/ffs/Makefile b/srv/vfs/drivers/ffs/Makefile @@ -0,0 +1,9 @@ +BLTHOME := ../../../../ +include $(BLTHOME)make.conf + +SHLIB := ffs.so +OBJS := super.o inode.o file.o dir.o +CFLAGS += -I. -I../.. +#CFLAGS += -DVFS_SANDBOX -I. -I../.. + +include $(BLTHOME)make.actions diff --git a/srv/vfs/drivers/ffs/dinode.h b/srv/vfs/drivers/ffs/dinode.h @@ -0,0 +1,132 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/dinode.h#2 $ */ +/* OpenBSD: dinode.h,v 1.3 1997/02/24 14:27:16 niklas Exp */ +/* NetBSD: dinode.h,v 1.7 1995/06/15 23:22:48 cgd Exp */ + +/* + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dinode.h 8.6 (Berkeley) 9/13/94 + */ + +#ifndef DINODE_H +#define DINODE_H + +/* + * The root inode is the root of the file system. Inode 0 can't be used for + * normal purposes and historically bad blocks were linked to inode 1, thus + * the root inode is 2. (Inode 1 is no longer used for this purpose, however + * numerous dump tapes make this assumption, so we are stuck with it). + */ +#define ROOTINO ((ino_t)2) + +/* + * The Whiteout inode# is a dummy non-zero inode number which will + * never be allocated to a real file. It is used as a place holder + * in the directory entry which has been tagged as a DT_W entry. + * See the comments about ROOTINO above. + */ +#define WINO ((ino_t)1) + +/* + * A dinode contains all the meta-data associated with a UFS file. + * This structure defines the on-disk format of a dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ + +#define NDADDR 12 /* Direct addresses in inode. */ +#define NIADDR 3 /* Indirect addresses in inode. */ + +struct ffs_dinode { + uint16 di_mode; /* 0: IFMT, permissions; see below. */ + int16 di_nlink; /* 2: File link count. */ + union { + uint16 oldids[2]; /* 4: Ffs: old user and group ids. */ + ino_t inumber; /* 4: Lfs: inode number. */ + } di_u; + uint64 di_size; /* 8: File byte count. */ + int32 di_atime; /* 16: Last access time. */ + int32 di_atimensec; /* 20: Last access time. */ + int32 di_mtime; /* 24: Last modified time. */ + int32 di_mtimensec; /* 28: Last modified time. */ + int32 di_ctime; /* 32: Last inode change time. */ + int32 di_ctimensec; /* 36: Last inode change time. */ + int32 di_db[NDADDR]; /* 40: Direct disk blocks. */ + int32 di_ib[NIADDR]; /* 88: Indirect disk blocks. */ + uint32 di_flags; /* 100: Status flags (chflags). */ + int32 di_blocks; /* 104: Blocks actually held. */ + int32 di_gen; /* 108: Generation number. */ + uint32 di_uid; /* 112: File owner. */ + uint32 di_gid; /* 116: File group. */ + int32 di_spare[2]; /* 120: Reserved; currently unused */ +}; + +/* + * The di_db fields may be overlaid with other information for + * file types that do not have associated disk storage. Block + * and character devices overlay the first data block with their + * dev_t value. Short symbolic links place their path in the + * di_db area. + */ +#define di_inumber di_u.inumber +#define di_ogid di_u.oldids[1] +#define di_ouid di_u.oldids[0] +#define di_rdev di_db[0] +#define di_shortlink di_db +#define MAXSYMLINKLEN ((NDADDR + NIADDR) * sizeof(uint32)) + +/* File permissions. */ +#define IEXEC 0000100 /* Executable. */ +#define IWRITE 0000200 /* Writeable. */ +#define IREAD 0000400 /* Readable. */ +#define ISVTX 0001000 /* Sticky bit. */ +#define ISGID 0002000 /* Set-gid. */ +#define ISUID 0004000 /* Set-uid. */ + +/* File types. */ +#define IFMT 0170000 /* Mask of file type. */ +#define IFIFO 0010000 /* Named pipe (fifo). */ +#define IFCHR 0020000 /* Character device. */ +#define IFDIR 0040000 /* Directory file. */ +#define IFBLK 0060000 /* Block device. */ +#define IFREG 0100000 /* Regular file. */ +#define IFLNK 0120000 /* Symbolic link. */ +#define IFSOCK 0140000 /* UNIX domain socket. */ +#define IFWHT 0160000 /* Whiteout. */ + +#endif + diff --git a/srv/vfs/drivers/ffs/dir.c b/srv/vfs/drivers/ffs/dir.c @@ -0,0 +1,153 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/dir.c#3 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include "vfs-int.h" + +#ifndef VFS_SANDBOX +#include <blt/blkdev.h> +#else +#include "../../sandbox/blkdev.h" +#endif + +#include "ffs.h" +#include "ffs-blt.h" +#include "dinode.h" +#include "dir.h" + +int ffs_opendir (struct vnode *dir, void **cookie) +{ + char *buf; + int i, j, offset; + struct vfs_dirent_node *head, *p; + struct ffs_super *fs; + struct ffs_super_data *data; + struct ffs_dinode *di; + struct ffs_dircookie *fc; + struct ffs_direct *direct; + +#ifdef FFS_DEBUG + printf ("ffs_opendir %lld\n", dir->v_vnid); +#endif + + head = NULL; + data = dir->v_sb->sb_data; + fs = data->sbbuf; + di = dir->v_data; + buf = malloc (BLKSIZE); + for (i = 0; i < NDADDR; i++) + if (di->di_db[i]) + { + blk_read (data->dev, buf, fsbtodb (fs, di->di_db[i]), + BLKSIZE / data->dev->blksize); + for (j = offset = 0; offset < BLKSIZE; offset += direct->d_reclen) + { + direct = (struct ffs_direct *) (buf + offset); + if (!direct->d_ino) + break; + //printf ("opendir %s %d %d\n", direct->d_name, offset, j++); + //if (j > 10) for (;;) ; + p = malloc (sizeof (struct vfs_dirent_node)); + p->dirent = malloc (sizeof (struct dirent)); + p->dirent->d_fileno = direct->d_ino; + p->dirent->d_reclen = sizeof (struct dirent); + strncpy (p->dirent->d_name, direct->d_name, + sizeof (p->dirent->d_name)); + p->next = head; + head = p; + } + } + for (i = 0; i < NIADDR; i++) + if (di->di_ib[i]) + { + } + free (buf); + fc = malloc (sizeof (struct ffs_dircookie)); + fc->head = fc->current = head; + *cookie = fc; + return 0; +} + +void ffs_closedir (struct vnode *dir, void *cookie) +{ +#ifdef FFS_DEBUG + printf ("ffs_closedir %lld\n", dir->v_vnid); +#endif +} + +void ffs_free_dircookie (void *cookie) +{ + struct ffs_dircookie *fc; + +#ifdef FFS_DEBUG + printf ("ffs_freedircookie\n"); +#endif + fc = cookie; + while (fc->head != NULL) + { + fc->current = fc->head->next; + free (fc->head); + fc->head = fc->current; + } + free (fc); +} + +int ffs_rewinddir (struct vnode *dir, void *cookie) +{ + struct ffs_dircookie *fc; + +#ifdef FFS_DEBUG + printf ("ffs_rewinddir %lld\n", dir->v_vnid); +#endif + fc = cookie; + fc->current = fc->head; + return 0; +} + +int ffs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie) +{ + struct dirent *orig; + struct ffs_dircookie *fc; + +#ifdef FFS_DEBUG + //printf ("ffs_readdir %lld\n", dir->v_vnid); +#endif + fc = cookie; + if (fc->current == NULL) + return 1; + orig = fc->current->dirent; + dirent->d_fileno = orig->d_fileno; + dirent->d_reclen = orig->d_reclen; + strncpy (dirent->d_name, orig->d_name, MAXNAMLEN); + fc->current = fc->current->next; + return 0; +} + diff --git a/srv/vfs/drivers/ffs/dir.h b/srv/vfs/drivers/ffs/dir.h @@ -0,0 +1,149 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/dir.h#1 $ */ +/* OpenBSD: dir.h,v 1.6 1997/05/30 08:34:56 downsj Exp */ +/* NetBSD: dir.h,v 1.8 1996/03/09 19:42:41 scottr Exp */ + +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dir.h 8.4 (Berkeley) 8/10/94 + */ + +#ifndef DIR_H +#define DIR_H + +/* + * Theoretically, directories can be more than 2Gb in length, however, in + * practice this seems unlikely. So, we define the type doff_t as a 32-bit + * quantity to keep down the cost of doing lookup on a 32-bit machine. +*/ +#define doff_t int32 +#define MAXDIRSIZE (0x7fffffff) + +/* + * A directory consists of some number of blocks of DIRBLKSIZE + * bytes, where DIRBLKSIZE is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZE byte block contains some number of directory entry + * structures, which are of variable length. Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry. These are followed by the name padded to a 4 byte boundary + * with null bytes. All names are guaranteed null terminated. + * The maximum length of a name in a directory is MAXNAMLEN. + * + * The macro DIRSIZ(fmt, dp) gives the amount of space required to represent + * a directory entry. Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZE bytes + * in a directory block are claimed by the directory entries. This + * usually results in the last entry in a directory having a large + * dp->d_reclen. When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen. If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ +#ifndef DIRBLKSIZE +#define DIRBLKSIZE DEV_BSIZE +#endif +#define MAXNAMLEN 255 + +struct ffs_direct { + uint32 d_ino; /* inode number of entry */ + uint16 d_reclen; /* length of this record */ + uint8 d_type; /* file type, see below */ + uint8 d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN + 1];/* name with length <= MAXNAMLEN */ +}; + +/* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +/* + * Convert between stat structure types and directory types. + */ +#define IFTODT(mode) (((mode) & 0170000) >> 12) +#define DTTOIF(dirtype) ((dirtype) << 12) + +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry. This requires the amount of space in struct direct + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + */ +#if (BYTE_ORDER == LITTLE_ENDIAN) +#define DIRSIZ(oldfmt, dp) \ + ((oldfmt) ? \ + ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_type+1 + 3) &~ 3)) : \ + ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))) +#else +#define DIRSIZ(oldfmt, dp) \ + ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) +#endif +#define OLDDIRFMT 1 +#define NEWDIRFMT 0 + +/* + * Template for manipulating directories. Should use struct direct's, + * but the name field is MAXNAMLEN - 1, and this just won't do. + */ +struct dirtemplate { + uint32 dot_ino; + int16 dot_reclen; + uint8 dot_type; + uint8 dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + uint32 dotdot_ino; + int16 dotdot_reclen; + uint8 dotdot_type; + uint8 dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; + +#endif + diff --git a/srv/vfs/drivers/ffs/ffs-blt.h b/srv/vfs/drivers/ffs/ffs-blt.h @@ -0,0 +1,69 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/ffs-blt.h#2 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FFS_BLT_H +#define FFS_BLT_H + +#include <dirent.h> + +struct ffs_super_data +{ + blkdev_t *dev; + struct ffs_super *sbbuf; +}; + +struct ffs_cookie +{ + char *buf1, *buf2; + int block1, block2; +}; + +struct ffs_dircookie +{ + struct vfs_dirent_node *head, *current; +}; + +int ffs_mount (struct superblock *super, const char *data, int silent); +void ffs_unmount (struct superblock *super); +int ffs_read_vnode (struct vnode *vnode); +void ffs_drop_vnode (struct vnode *vnode); +struct vnode *ffs_walk (struct vnode *parent, const char *path); +int ffs_opendir (struct vnode *dir, void **cookie); +void ffs_closedir (struct vnode *dir, void *cookie); +void ffs_free_dircookie (void *cookie); +int ffs_rewinddir (struct vnode *dir, void *cookie); +int ffs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie); +int ffs_open (struct vnode *dir, void **cookie); +int ffs_close (struct vnode *dir, void *cookie); +void ffs_free_cookie (void *cookie); +int ffs_read (struct vnode *vnode, char *buf, size_t count, off_t offset, + size_t *numbytes, void *cookie); +int ffs_rstat (struct vnode *vnode, struct stat *buf); + +#endif + diff --git a/srv/vfs/drivers/ffs/ffs.h b/srv/vfs/drivers/ffs/ffs.h @@ -0,0 +1,520 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/ffs.h#1 $ */ +/* OpenBSD: fs.h,v 1.8 1998/11/29 00:45:30 art Exp */ +/* NetBSD: fs.h,v 1.6 1995/04/12 21:21:02 mycroft Exp */ + +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fs.h 8.10 (Berkeley) 10/27/94 + */ + +#ifndef FFS_H +#define FFS_H + +#ifndef VFS_SANDBOX +#include <blt/types.h> +#else +#include "types.h" +#endif + +/* + * Each disk drive contains some number of file systems. + * A file system consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A file system is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For file system fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * The first boot and super blocks are given in absolute disk addresses. + * The byte-offset forms are preferred, as they don't imply a sector size. + */ +#define DEV_BSIZE 512 +#define BBSIZE 8192 +#define SBSIZE 8192 +#define BLKSIZE 8192 +#define BBOFF ((off_t)(0)) +#define SBOFF ((off_t)(BBOFF + BBSIZE)) +#define BBLOCK ((uint32)(0)) +#define SBLOCK ((uint32)(BBLOCK + BBSIZE / DEV_BSIZE)) + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressible; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks. To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary. The file system format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided. The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The file system records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBSIZE, + * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE 4096 + +/* + * The path name on which the file system is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + */ +#define MAXMNTLEN 512 + +/* + * The limit on the amount of summary information per file system + * is defined by MAXCSBUFS. It is currently parameterized for a + * size of 128 bytes (2 million cylinder groups on machines with + * 32-bit pointers, and 1 million on 64-bit machines). One pointer + * is taken away to point to an array of cluster sizes that is + * computed as cylinder groups are inspected. + */ +#define MAXCSBUFS ((128 / sizeof(void *)) - 1) + +/* + * A summary of contiguous blocks of various sizes is maintained + * in each cylinder group. Normally this is set by the initial + * value of fs_maxcontig. To conserve space, a maximum summary size + * is set by FS_MAXCONTIG. + */ +#define FS_MAXCONTIG 16 + +/* + * MINFREE gives the minimum acceptable percentage of file system + * blocks which may be free. If the freelist drops below this level + * only the superuser may continue to allocate blocks. This may + * be set to 0 if no reserve of free blocks is deemed necessary, + * however throughput drops by fifty percent if the file system + * is run at between 95% and 100% full; thus the minimum default + * value of fs_minfree is 5%. However, to get good clustering + * performance, 10% is a better choice. hence we use 10% as our + * default value. With 10% free space, fragmentation is not a + * problem, so we choose to optimize for time. + */ +#define MINFREE 5 +#define DEFAULTOPT FS_OPTTIME + +/* + * The file system is made out of blocks of at most MAXBSIZE units, with + * smaller units (fragments) only in the last direct block. MAXBSIZE + * primarily determines the size of buffers in the buffer pool. It may be + * made larger without any effect on existing file systems; however making + * it smaller makes some file systems unmountable. + */ +#define MAXFRAG 8 + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks. These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + * + * N.B. sizeof(struct csum) must be a power of two in order for + * the ``fs_cs'' macro to work (see below). + */ +struct csum { + int32 cs_ndir; /* number of directories */ + int32 cs_nbfree; /* number of free blocks */ + int32 cs_nifree; /* number of free inodes */ + int32 cs_nffree; /* number of free frags */ +}; + +/* + * Super block for an FFS file system. + */ +struct ffs_super { + int32 fs_firstfield; /* historic file system linked list, */ + int32 fs_unused_1; /* used for incore super blocks */ + uint32 fs_sblkno; /* addr of super-block in filesys */ + uint32 fs_cblkno; /* offset of cyl-block in filesys */ + uint32 fs_iblkno; /* offset of inode-blocks in filesys */ + uint32 fs_dblkno; /* offset of first data after cg */ + int32 fs_cgoffset; /* cylinder group offset in cylinder */ + int32 fs_cgmask; /* used to calc mod fs_ntrak */ + time_t fs_time; /* last time written */ + int32 fs_size; /* number of blocks in fs */ + int32 fs_dsize; /* number of data blocks in fs */ + int32 fs_ncg; /* number of cylinder groups */ + int32 fs_bsize; /* size of basic blocks in fs */ + int32 fs_fsize; /* size of frag blocks in fs */ + int32 fs_frag; /* number of frags in a block in fs */ +/* these are configuration parameters */ + int32 fs_minfree; /* minimum percentage of free blocks */ + int32 fs_rotdelay; /* num of ms for optimal next block */ + int32 fs_rps; /* disk revolutions per second */ +/* these fields can be computed from the others */ + int32 fs_bmask; /* ``blkoff'' calc of blk offsets */ + int32 fs_fmask; /* ``fragoff'' calc of frag offsets */ + int32 fs_bshift; /* ``lblkno'' calc of logical blkno */ + int32 fs_fshift; /* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ + int32 fs_maxcontig; /* max number of contiguous blks */ + int32 fs_maxbpg; /* max number of blks per cyl group */ +/* these fields can be computed from the others */ + int32 fs_fragshift; /* block to frag shift */ + int32 fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int32 fs_sbsize; /* actual size of super block */ + int32 fs_csmask; /* csum block offset */ + int32 fs_csshift; /* csum block number */ + int32 fs_nindir; /* value of NINDIR */ + int32 fs_inopb; /* value of INOPB */ + int32 fs_nspf; /* value of NSPF */ +/* yet another configuration parameter */ + int32 fs_optim; /* optimization preference, see below */ +/* these fields are derived from the hardware */ + int32 fs_npsect; /* # sectors/track including spares */ + int32 fs_interleave; /* hardware sector interleave */ + int32 fs_trackskew; /* sector 0 skew, per track */ +/* fs_id takes the space of the unused fs_headswitch and fs_trkseek fields */ + int32 fs_id[2]; /* unique filesystem id */ +/* sizes determined by number of cylinder groups and their sizes */ + uint32 fs_csaddr; /* blk addr of cyl grp summary area */ + int32 fs_cssize; /* size of cyl grp summary area */ + int32 fs_cgsize; /* cylinder group size */ +/* these fields are derived from the hardware */ + int32 fs_ntrak; /* tracks per cylinder */ + int32 fs_nsect; /* sectors per track */ + int32 fs_spc; /* sectors per cylinder */ +/* this comes from the disk driver partitioning */ + int32 fs_ncyl; /* cylinders in file system */ +/* these fields can be computed from the others */ + int32 fs_cpg; /* cylinders per group */ + int32 fs_ipg; /* inodes per group */ + int32 fs_fpg; /* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ + struct csum fs_cstotal; /* cylinder summary information */ +/* these fields are cleared at mount time */ + int8 fs_fmod; /* super block modified flag */ + int8 fs_clean; /* file system is clean flag */ + int8 fs_ronly; /* mounted read-only flag */ + int8 fs_flags; /* see FS_ below */ + uint8 fs_fsmnt[MAXMNTLEN]; /* name mounted on */ +/* these fields retain the current block allocation info */ + int32 fs_cgrotor; /* last cg searched */ + struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */ + int32 *fs_maxcluster; /* max cluster in each cyl group */ + int32 fs_cpc; /* cyl per cycle in postbl */ + int16 fs_opostbl[16][8]; /* old rotation block list head */ + int32 fs_sparecon[49]; /* reserved for future constants */ + time_t fs_fscktime; /* last time fsck(8)ed */ + int32 fs_contigsumsize; /* size of cluster summary array */ + int32 fs_maxsymlinklen; /* max length of an internal symlink */ + int32 fs_inodefmt; /* format of on-disk inodes */ + uint64 fs_maxfilesize; /* maximum representable file size */ + int64 fs_qbmask; /* ~fs_bmask - for use with quad size */ + int64 fs_qfmask; /* ~fs_fmask - for use with quad size */ + int32 fs_state; /* validate fs_clean field */ + int32 fs_postblformat; /* format of positional layout tables */ + int32 fs_nrpos; /* number of rotational positions */ + int32 fs_postbloff; /* (u_int16) rotation block list head */ + int32 fs_rotbloff; /* (u_int8) blocks for each rotation */ + int32 fs_magic; /* magic number */ + uint8 fs_space[1]; /* list of blocks for each rotation */ +/* actually longer */ +}; + +/* + * Filesystem identification + */ +#define FS_MAGIC 0x011954 /* the fast filesystem magic number */ +#define FS_OKAY 0x7c269d38 /* superblock checksum */ +#define FS_42INODEFMT -1 /* 4.2BSD inode format */ +#define FS_44INODEFMT 2 /* 4.4BSD inode format */ + +/* + * Filesystem clean flags + */ +#define FS_ISCLEAN 0x01 +#define FS_WASCLEAN 0x02 + +/* + * Preference for optimization. + */ +#define FS_OPTTIME 0 /* minimize allocation time */ +#define FS_OPTSPACE 1 /* minimize disk fragmentation */ + +/* + * Filesystem flags. + */ +#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ +#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ + +/* + * Rotational layout table format types + */ +#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ +#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ +/* + * Macros for access to superblock array structures + */ +#define fs_postbl(fs, cylno) \ + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ + ? ((fs)->fs_opostbl[cylno]) \ + : ((int16 *)((uint8 *)(fs) + \ + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) +#define fs_rotbl(fs) \ + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ + ? ((fs)->fs_space) \ + : ((uint8 *)((uint8 *)(fs) + (fs)->fs_rotbloff))) + +/* + * The size of a cylinder group is calculated by CGSIZE. The maximum size + * is limited by the fact that cylinder groups are at most one block. + * Its size is derived from the size of the maps maintained in the + * cylinder group and the (struct cg) size. + */ +#define CGSIZE(fs) \ + /* base cg */ (sizeof(struct cg) + sizeof(int32) + \ + /* blktot size */ (fs)->fs_cpg * sizeof(int32) + \ + /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(int16) + \ + /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ + /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY) +\ + /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ + /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32) + \ + /* cluster map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPB(fs), NBBY))) + +/* + * Convert cylinder group to base address of its global summary info. + * + * N.B. This macro assumes that sizeof(struct csum) is a power of two. + */ +#define fs_cs(fs, indx) \ + fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask] + +/* + * Cylinder group block for a file system. + */ +#define CG_MAGIC 0x090255 +struct cg { + int32 cg_firstfield; /* historic cyl groups linked list */ + int32 cg_magic; /* magic number */ + time_t cg_time; /* time last written */ + int32 cg_cgx; /* we are the cgx'th cylinder group */ + int16 cg_ncyl; /* number of cyl's this cg */ + int16 cg_niblk; /* number of inode blocks this cg */ + int32 cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + int32 cg_rotor; /* position of last used block */ + int32 cg_frotor; /* position of last used frag */ + int32 cg_irotor; /* position of last used inode */ + int32 cg_frsum[MAXFRAG]; /* counts of available frags */ + int32 cg_btotoff; /* (int32) block totals per cylinder */ + int32 cg_boff; /* (u_int16) free block positions */ + int32 cg_iusedoff; /* (u_int8) used inode map */ + int32 cg_freeoff; /* (u_int8) free block map */ + int32 cg_nextfreeoff; /* (u_int8) next available space */ + int32 cg_clustersumoff; /* (u_int32) counts of avail clusters */ + int32 cg_clusteroff; /* (u_int8) free cluster map */ + int32 cg_nclusterblks; /* number of clusters this cg */ + int32 cg_sparecon[13]; /* reserved for future use */ + uint8 cg_space[1]; /* space for cylinder group maps */ +/* actually longer */ +}; + +/* + * Macros for access to cylinder group array structures + */ +#define cg_blktot(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_btot) \ + : ((int32 *)((uint8 *)(cgp) + (cgp)->cg_btotoff))) +#define cg_blks(fs, cgp, cylno) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_b[cylno]) \ + : ((int16 *)((uint8 *)(cgp) + \ + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) +#define cg_inosused(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_iused) \ + : ((uint8 *)((uint8 *)(cgp) + (cgp)->cg_iusedoff))) +#define cg_blksfree(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_free) \ + : ((uint8 *)((uint8 *)(cgp) + (cgp)->cg_freeoff))) +#define cg_chkmagic(cgp) \ + ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) +#define cg_clustersfree(cgp) \ + ((uint8 *)((uint8 *)(cgp) + (cgp)->cg_clusteroff)) +#define cg_clustersum(cgp) \ + ((int32 *)((uint8 *)(cgp) + (cgp)->cg_clustersumoff)) + +/* + * Turn file system block numbers into disk block addresses. + * This maps file system blocks to device size blocks. + */ +#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb) +#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc file system addresses of cylinder group data structures. + */ +#define cgbase(fs, c) ((uint32)((fs)->fs_fpg * (c))) +#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ +#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ +#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ +#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ +#define cgstart(fs, c) \ + (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) + +/* + * Macros for handling inode numbers: + * inode number to file system block offset. + * inode number to cylinder group number. + * inode number to file system block address. + */ +#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) +#define ino_to_fsba(fs, x) \ + ((uint32)(cgimin((fs), ino_to_cg((fs), x)) + \ + (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) +#define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) + +/* + * Give cylinder group number for a file system block. + * Give cylinder group block number for a file system block. + */ +#define dtog(fs, d) ((d) / (fs)->fs_fpg) +#define dtogd(fs, d) ((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ + (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) +#define cbtocylno(fs, bno) \ + ((bno) * NSPF(fs) / (fs)->fs_spc) +#define cbtorpos(fs, bno) \ + (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \ + (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \ + (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & (fs)->fs_qbmask) +#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ + ((loc) & (fs)->fs_qfmask) +#define lblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \ + ((blk) << (fs)->fs_bshift) +#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ + ((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ + ((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ + (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ + (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) +#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ + ((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ + ((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ + ((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ + ((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve. + */ +#define freespace(fs, percentreserved) \ + (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ + (fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the file system. + */ +#define blksize(fs, ip, lbn) \ + (((lbn) >= NDADDR || (ip)->i_ffs_size >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (ip)->i_ffs_size)))) +#define dblksize(fs, dip, lbn) \ + (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) + +#define sblksize(fs, size, lbn) \ + (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (size))))) + + +/* + * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte + * sector size. + */ +#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) +#define NSPF(fs) ((fs)->fs_nspf) + +/* + * Number of inodes in a secondary storage block/fragment. + */ +#define INOPB(fs) ((fs)->fs_inopb) +#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * Number of indirects in a file system block. + */ +#define NINDIR(fs) ((fs)->fs_nindir) + +#endif + diff --git a/srv/vfs/drivers/ffs/file.c b/srv/vfs/drivers/ffs/file.c @@ -0,0 +1,201 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/file.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vfs-int.h" + +#ifndef VFS_SANDBOX +#include <blt/blkdev.h> +#else +#include "../../sandbox/blkdev.h" +#endif + +#include "ffs.h" +#include "ffs-blt.h" +#include "dinode.h" + +int ffs_open (struct vnode *vnode, void **cookie) +{ + struct ffs_super_data *data; + struct ffs_dinode *inode; + struct ffs_cookie *fc; + +#ifdef FFS_DEBUG + printf ("ffs_open %lld\n", vnode->v_vnid); +#endif + data = vnode->v_sb->sb_data; + inode = vnode->v_data; + fc = malloc (sizeof (struct ffs_cookie)); + *cookie = fc; + return 0; +} + +int ffs_close (struct vnode *vnode, void *cookie) +{ +#ifdef FFS_DEBUG + printf ("ffs_close %lld\n", vnode->v_vnid); +#endif + return 0; +} + +void ffs_free_cookie (void *cookie) +{ +#ifdef FFS_DEBUG + printf ("ffs_free_cookie\n"); +#endif + free (cookie); +} + +static inline int32 ffs_fbtofsb (struct ffs_super *fs, blkdev_t *dev, + struct ffs_dinode *di, uint32 fb) +{ + int32 *buf, res; + + if (fb < NDADDR) + return di->di_db[fb]; + else if ((fb -= NDADDR) < NINDIR (fs)) + { + buf = malloc (BLKSIZE); + blk_read (dev, buf, fsbtodb (fs, di->di_ib[0]), BLKSIZE / dev->blksize); + res = buf[fb]; + free (buf); + return res; + } + else if ((fb -= NINDIR (fs)) < NINDIR (fs) * NINDIR (fs)) + { + printf ("ffs: doubly indirect blocks unsupported.\n"); + return 0; + } + else if ((fb -= NINDIR (fs) * NINDIR (fs)) < NINDIR (fs) * NINDIR (fs) * + NINDIR (fs)) + { + printf ("ffs: trebly indirect blocks unsupported.\n"); + return 0; + } + else + return -1; +} + +int ffs_read (struct vnode *vnode, char *buf, size_t count, off_t pos, + size_t *numbytes, void *cookie) +{ + char *temp; + int i, block; + off_t offset, len; + struct ffs_super *fs; + struct ffs_super_data *data; + struct ffs_dinode *di; + +#ifdef FFS_DEBUG + printf ("ffs_read %lld %d\n", pos, count); +#endif + *numbytes = 0; + if (!count) + return 0; + data = vnode->v_sb->sb_data; + fs = data->sbbuf; + di = vnode->v_data; + if (pos >= di->di_size) + return 0; + if (pos + count > di->di_size) + count = di->di_size - pos; + temp = malloc (BLKSIZE); + + /* + * if we are not starting at a block boundary, first read up to the + * next block boundary. + */ + if ((offset = pos % BLKSIZE)) + { + block = ffs_fbtofsb (fs, data->dev, di, pos / BLKSIZE); + len = (count < (BLKSIZE - offset)) ? count : (BLKSIZE - offset); + blk_read (data->dev, temp, fsbtodb (fs, block), BLKSIZE / + data->dev->blksize); + memcpy (buf, temp + offset, len); + *numbytes += len, pos += len; +#ifdef FFS_DEBUG + printf ("ffs_read: (1) %lld\n", len); +#endif + } + if (*numbytes == count) + goto done; + + /* + * now we are block-aligned; read whole blocks at a time until we have + * less than a full block to go. + */ + for (i = 0; i < ((count - *numbytes) / BLKSIZE); i++, *numbytes += BLKSIZE, + pos += BLKSIZE) + { + block = ffs_fbtofsb (fs, data->dev, di, pos / BLKSIZE); + blk_read (data->dev, temp, fsbtodb (fs, block), BLKSIZE / + data->dev->blksize); + memcpy (buf + *numbytes, temp, BLKSIZE); +#ifdef FFS_DEBUG + printf ("ffs_read: (2) #%d\n", i); +#endif + } + if (*numbytes == count) + goto done; + + /* + * read in the next block and copy as much as we need. + */ + block = ffs_fbtofsb (fs, data->dev, di, pos / BLKSIZE); + blk_read (data->dev, temp, fsbtodb (fs, block), BLKSIZE / + data->dev->blksize); + memcpy (buf + *numbytes, temp, len = count - *numbytes); + *numbytes += len, pos += len; +#ifdef FFS_DEBUG + printf ("ffs_read: (3) %lld\n", len); +#endif + +done: + free (temp); + return 0; +} + +int ffs_rstat (struct vnode *vnode, struct stat *buf) +{ + struct ffs_dinode *di; +#ifdef FFS_DEBUG + printf ("ffs_rstat %lld\n", vnode->v_vnid); +#endif + + di = vnode->v_data; + buf->st_ino = vnode->v_vnid; + buf->st_nlink = di->di_nlink; + buf->st_uid = di->di_uid; + buf->st_gid = di->di_gid; + buf->st_size = di->di_size; + buf->st_blocks = di->di_blocks; + return 0; +} + diff --git a/srv/vfs/drivers/ffs/inode.c b/srv/vfs/drivers/ffs/inode.c @@ -0,0 +1,141 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/inode.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vfs-int.h" + +#ifndef VFS_SANDBOX +#include <blt/blkdev.h> +#else +#include "../../sandbox/blkdev.h" +#endif + +#include "ffs.h" +#include "ffs-blt.h" +#include "dinode.h" +#include "dir.h" + +int ffs_read_vnode (struct vnode *vnode) +{ + char *buf; + int block, offset; + struct ffs_super *fs; + struct ffs_super_data *data; + struct ffs_dinode *di; + +#ifdef FFS_DEBUG + printf ("ffs_read_vnode %lld\n", vnode->v_vnid); +#endif + data = vnode->v_sb->sb_data; + fs = data->sbbuf; + vnode->v_data = di = malloc (sizeof (struct ffs_dinode)); + buf = malloc (BLKSIZE); + block = fsbtodb (fs, ino_to_fsba (fs, (int) vnode->v_vnid)); + offset = ino_to_fsbo (fs, (int) vnode->v_vnid); + blk_read (data->dev, buf, block, BLKSIZE / data->dev->blksize); + memcpy (di, (struct ffs_dinode *) buf + offset, sizeof (struct ffs_dinode)); + free (buf); + return 0; +} + +void ffs_drop_vnode (struct vnode *vnode) +{ +#ifdef FFS_DEBUG + printf ("ffs_drop_vnode %lld\n", vnode->v_vnid); +#endif + free (vnode->v_data); +} + +static struct vnode *ffs_walk_one (struct vnode *parent, const char *path) +{ + char *buf; + int i, offset; + struct ffs_super *fs; + struct ffs_super_data *data; + struct ffs_dinode *di; + struct ffs_direct *direct; + +#ifdef FFS_DEBUG + printf ("ffs_walk_one %s\n", path); +#endif + data = parent->v_sb->sb_data; + fs = data->sbbuf; + di = parent->v_data; + buf = malloc (BLKSIZE); + + for (i = 0; i < NDADDR; i++) + if (di->di_db[i]) + { + blk_read (data->dev, buf, fsbtodb (fs, di->di_db[i]), + BLKSIZE / data->dev->blksize); + for (offset = 0; offset < BLKSIZE; offset += direct->d_reclen) + { + direct = (struct ffs_direct *) (buf + offset); + if (!strcmp (direct->d_name, path)) + return vget (parent->v_sb, direct->d_ino); + } + } + printf ("ffs_walk_one: failage 1!\n"); + + for (i = 0; i < NIADDR; i++) + if (di->di_ib[i]) + { + printf ("ffs_walk_one: indirect %d\n", di->di_ib[i]); + } + + free (buf); + printf ("ffs_walk_one: failage 2!\n"); + return NULL; +} + +struct vnode *ffs_walk (struct vnode *parent, const char *path) +{ + char *name; + int i, j, len; + struct vnode *vn, *vnnext; + +#ifdef FFS_DEBUG + printf ("ffs_walk %s\n", path); +#endif + vn = parent; + name = malloc ((len = strlen (path)) + 1); + strcpy (name, path); + + for (i = 0; i < strlen (path); i = j + 1, vn = vnnext) + { + for (j = i; (name[j] != '/') && (j < len); j++) ; + name[j] = 0; + vnnext = ffs_walk_one (vn, name + i); + if (vn != parent) + vput (vn); + } + return vn; +} + diff --git a/srv/vfs/drivers/ffs/super.c b/srv/vfs/drivers/ffs/super.c @@ -0,0 +1,101 @@ +/* $Id: //depot/blt/srv/vfs/drivers/ffs/super.c#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vfs-int.h" + +#ifndef VFS_SANDBOX +#include <blt/blkdev.h> +#else +#include "../../sandbox/blkdev.h" +#endif + +#include "ffs.h" +#include "ffs-blt.h" +#include "dinode.h" + +static struct vnode_ops ffs_vnode_ops = +{ + ffs_read_vnode, ffs_drop_vnode, NULL, NULL, ffs_walk, NULL, + ffs_mount, ffs_unmount, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + ffs_opendir, ffs_closedir, ffs_free_dircookie, ffs_rewinddir, ffs_readdir, + ffs_open, ffs_close, ffs_free_cookie, ffs_read, NULL, NULL, NULL, + ffs_rstat, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +static struct fs_type ffs = { "ffs", &ffs_vnode_ops, NULL }; + +int _init (void) +{ +#ifdef FFS_DEBUG + printf ("ffs: registering driver\n"); +#endif + fs_register (&ffs); + return 0; +} + +int ffs_mount (struct superblock *super, const char *data, int silent) +{ + struct ffs_super_data *sbdata; + struct ffs_super *ds; + +#ifdef FFS_DEBUG + printf ("ffs_mount, data `%s'\n", data); +#endif + sbdata = malloc (sizeof (struct ffs_super_data)); + blk_open (data, 0, &sbdata->dev); + super->sb_data = sbdata; + sbdata->sbbuf = ds = malloc (SBSIZE); + blk_read (sbdata->dev, ds, SBOFF / sbdata->dev->blksize, + SBSIZE / sbdata->dev->blksize); + super->sb_root = vget (super, ROOTINO); + super->sb_dev = malloc (strlen (data) + 1); + strcpy (super->sb_dev, data); + return 0; +} + +void ffs_unmount (struct superblock *super) +{ + struct ffs_super_data *sbdata; + +#ifdef FFS_DEBUG + printf ("ffs_unmount\n"); +#endif + vput (super->sb_root); + sbdata = super->sb_data; + blk_close (sbdata->dev); + free (sbdata->sbbuf); + free (sbdata); +} + diff --git a/srv/vfs/fs.c b/srv/vfs/fs.c @@ -0,0 +1,77 @@ +/* $Id: //depot/blt/srv/vfs/fs.c#1 $ +** +** Copyright 1998 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <string.h> +#include "vfs-int.h" + +int fs_register (struct fs_type *driver) +{ + struct fs_type *p; + + if (fs_drivers == NULL) + { + fs_drivers = driver; + fs_drivers->next = NULL; + return 0; + } + else + { + p = fs_drivers; + while (p->next != NULL) + { + if (!strcmp (p->name, driver->name)) + return 1; + p = p->next; + } + p->next = driver; + driver->next = NULL; + return 0; + } +} + +struct superblock *fs_find (const char *node) +{ + int len, bestlen; + struct superblock *super, *best; + + super = mount_list; + len = bestlen = 0; + best = NULL; + while (super != NULL) + { + if (!strncmp (super->sb_dir, node, len = strlen (super->sb_dir))) + if (len > bestlen) + { + best = super; + bestlen = len; + } + super = super->sb_next; + } + return best; +} + diff --git a/srv/vfs/path.c b/srv/vfs/path.c @@ -0,0 +1,97 @@ +/* $Id: //depot/blt/srv/vfs/path.c#2 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include "path.h" + +char *path_concat (char *s, const char *t) +{ + char *c; + + c = s; + while (*c++) ; + c--; + + while (*t) /* for each component */ + if (*t == '/') + *c++ = *t++; + else if (*t != '.') /* normal component */ + while (*t && (*t != '/')) + *c++ = *t++; + else /* doesn't begin with . or / */ + { + t++; + if ((*t == '/') || !*t) /* ./ component */ + t++; + else if (*t == '.') /* ../ component */ + { + if (c != s + 1) /* can't .. from the root dir */ + { + c -= 2; + while ((c != s) && (*c != '/')) + c--; + c++; + t++; + if (*t == '/') + t++; + } + } + else /* component beginning with a period */ + { + *c++ = '.'; + while (*t && (*t != '/')) + *c++ = *t++; + } + } + + *c = 0; + if (((c - 1) != s) && (c[-1] == '/')) + c[-1] = 0; + + return s; +} + +char *path_combine (const char *s, const char *t, char *d) +{ + const char *c; + char *node; + + *d = 0; + node = d; + if (*t == '/') + return path_concat (node, t); + + c = s; + while (*c) + *d++ = *c++; + if (*d != '/') + *d++ = '/'; + + return path_concat (node, t); +} + diff --git a/srv/vfs/path.h b/srv/vfs/path.h @@ -0,0 +1,36 @@ +/* $Id: //depot/blt/srv/vfs/path.h#2 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _PATH_H_ +#define _PATH_H_ + +char *path_concat (char *s, const char *t); +char *path_combine (const char *s, const char *t, char *d); + +#endif + diff --git a/srv/vfs/rootfs.c b/srv/vfs/rootfs.c @@ -0,0 +1,218 @@ +/* $Id: //depot/blt/srv/vfs/rootfs.c#3 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "vfs-int.h" +#include "rootfs.h" + +static int inode_max = 0; + +static struct vnode_ops rootfs_vnode_ops = +{ + rootfs_read_vnode, rootfs_drop_vnode, NULL, NULL, rootfs_walk, NULL, + rootfs_mount, rootfs_unmount, NULL, NULL, NULL, NULL, + NULL, rootfs_mkdir, NULL, NULL, NULL, NULL, NULL, NULL, + rootfs_opendir, rootfs_closedir, NULL, rootfs_rewinddir, rootfs_readdir, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +}; + +struct fs_type rootfs = { "rootfs", &rootfs_vnode_ops, NULL }; + +static struct rootfs_inode *rootfs_inew (const char *name) +{ + struct rootfs_inode *i; + + i = malloc (sizeof (struct rootfs_inode)); + i->i_ino = inode_max++; + i->i_name = malloc (strlen (name) + 1); + strcpy (i->i_name, name); + i->i_next = NULL; + return i; +} + +int rootfs_mount (struct superblock *super, const char *data, int silent) +{ + struct rootfs_inode *ri; + +#ifdef ROOTFS_DEBUG + printf ("rootfs_mount\n"); +#endif + super->sb_data = ri = rootfs_inew ("."); + ri->i_next = rootfs_inew (".."); + super->sb_root = vget (super, 0); + return 0; +} + +void rootfs_unmount (struct superblock *super) +{ +#ifdef ROOTFS_DEBUG + printf ("rootfs_unmount\n"); +#endif +} + +int rootfs_read_vnode (struct vnode *vnode) +{ + struct rootfs_inode *inode; + +#ifdef ROOTFS_DEBUG + printf ("rootfs_read_vnode %llx\n", vnode->v_vnid); +#endif + inode = vnode->v_sb->sb_data; + while (inode != NULL) + if (inode->i_ino == vnode->v_vnid) + { + vnode->v_data = inode; + return 0; + } + else + inode = inode->i_next; + return -1; +} + +void rootfs_drop_vnode (struct vnode *vnode) +{ + vnode->v_data = NULL; +} + +struct vnode *rootfs_walk (struct vnode *parent, const char *path) +{ + struct rootfs_inode *inode; + +#ifdef ROOTFS_DEBUG + printf ("rootfs_walk %llx %s\n", parent->v_vnid, path); +#endif + inode = parent->v_data; + while (inode != NULL) + if (strcmp (inode->i_name, path)) + inode = inode->i_next; + else + return vget (parent->v_sb, inode->i_ino); + return NULL; +} + +int rootfs_mkdir (struct vnode *parent, const char *name, mode_t mode) +{ + struct rootfs_inode *inode, *p; + +#ifdef ROOTFS_DEBUG + printf ("rootfs_mkdir %llx %s\n", parent->v_vnid, name); +#endif + if (parent->v_vnid) + return -1; /* paranoia */ + + inode = malloc (sizeof (struct rootfs_inode)); + inode->i_ino = inode_max++; + inode->i_name = malloc (strlen (name) + 1); + strcpy (inode->i_name, name); + inode->i_next = NULL; + + p = parent->v_sb->sb_data; + while (p->i_next != NULL) + p = p->i_next; + p->i_next = inode; + return 0; +} + +int rootfs_opendir (struct vnode *dir, void **cookie) +{ + struct vfs_dirent_node *head, *p; + struct rootfs_inode *inode; + union rootfs_cookie *rc; + +#ifdef ROOTFS_DEBUG + printf ("rootfs_opendir\n"); +#endif + if (dir->v_vnid) + return ENOTDIR; /* paranoia */ + + head = NULL; + inode = dir->v_sb->sb_data; + while (inode != NULL) + { + p = malloc (sizeof (struct vfs_dirent_node)); + p->dirent = malloc (sizeof (struct dirent)); + p->dirent->d_fileno = inode->i_ino; + p->dirent->d_reclen = sizeof (struct dirent); + strncpy (p->dirent->d_name, inode->i_name, sizeof (p->dirent->d_name)); + + p->next = head; + head = p; + inode = inode->i_next; + } + + rc = malloc (sizeof (union rootfs_cookie)); + rc->u_dir.head = rc->u_dir.current = head; + *cookie = rc; + return 0; +} + +void rootfs_closedir (struct vnode *dir, void *cookie) +{ +#ifdef ROOTFS_DEBUG + printf ("rootfs_closedir\n"); +#endif +} + +int rootfs_rewinddir (struct vnode *dir, void *cookie) +{ + union rootfs_cookie *rc; + +#ifdef ROOTFS_DEBUG + printf ("rootfs_rewinddir\n"); +#endif + + rc = cookie; + rc->u_dir.current = rc->u_dir.head; + return 0; +} + +int rootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie) +{ + struct dirent *orig; + union rootfs_cookie *rc; + + rc = cookie; + if (rc->u_dir.current == NULL) + return 1; + orig = rc->u_dir.current->dirent; + dirent->d_fileno = orig->d_fileno; + dirent->d_reclen = orig->d_reclen; + strncpy (dirent->d_name, orig->d_name, BLT_MAX_NAME_LENGTH); + rc->u_dir.current = rc->u_dir.current->next; +#ifdef ROOTFS_DEBUG + printf ("rootfs_readdir %s\n", dirent->d_name); +#endif + return 0; +} + diff --git a/srv/vfs/rootfs.h b/srv/vfs/rootfs.h @@ -0,0 +1,67 @@ +/* $Id: //depot/blt/srv/vfs/rootfs.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _ROOTFS_H_ +#define _ROOTFS_H_ + +#include "vfs-int.h" + +struct rootfs_inode +{ + int i_ino; + char *i_name; + struct rootfs_inode *i_next; +}; + +union rootfs_cookie +{ + struct + { + struct vfs_dirent_node *head, *current; + } u_dir; + struct + { + int pos; + } u_file; +}; + +static struct rootfs_inode *rootfs_inew (const char *name); + +int rootfs_mount (struct superblock *sb, const char *data, int silent); +void rootfs_unmount (struct superblock *super); +int rootfs_read_vnode (struct vnode *vnode); +void rootfs_drop_vnode (struct vnode *vnode); +struct vnode *rootfs_walk (struct vnode *vnode, const char *path); +int rootfs_mkdir (struct vnode *vnode, const char *name, mode_t mode); +int rootfs_opendir (struct vnode *dir, void **cookie); +void rootfs_closedir (struct vnode *dir, void *cookie); +int rootfs_readdir (struct vnode *dir, struct dirent *dirent, void *cookie); +int rootfs_rewinddir (struct vnode *dir, void *cookie); + +#endif + diff --git a/srv/vfs/sandbox/Makefile b/srv/vfs/sandbox/Makefile @@ -0,0 +1,14 @@ +# $Id: //depot/blt/srv/vfs/sandbox/Makefile#2 $ + +CFLAGS = $(CF) -I. -Wall -g -DVFS_SANDBOX +LIBS = +OBJS = vfs.o blkdev.o ../fs.o ../super.o ../vnode.o ../../../lib/libblt/hash.o +EXEC = vfs + +all: $(EXEC) + +$(EXEC): $(OBJS) + $(CC) -o $(EXEC) $(OBJS) $(LIBS) + +clean: + rm -f *.o *~ core *.core $(EXEC) diff --git a/srv/vfs/sandbox/README b/srv/vfs/sandbox/README @@ -0,0 +1,17 @@ +This is a test harness for developing filesystem drivers under UNIX to +be used on OpenBLT. Its design was inspired by a similar system written +by Dominic Giampaolo for designing BFS as described in *Practical +Filesystem Design with the Be File System*. + +This code is guaranteed to build on OpenBSD/sparc, but should build on +other UNIX systems. It will probably also build on UNIX-like systems +such as Linux. I will eventually make it work on BeOS. To build, type +`make' as this is not built during a normal build. + + +Some caveats: + + - add -DVFS_SANDBOX to $(CF) in make.conf + - if you're using this on an architecture other than Intel, remember + to rebuild the driver you're testing, fs.o, super.o, and hash.o + diff --git a/srv/vfs/sandbox/blkdev.c b/srv/vfs/sandbox/blkdev.c @@ -0,0 +1,78 @@ +/* $Id: //depot/blt/srv/vfs/sandbox/blkdev.c#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include "blkdev.h" + +int blk_open (const char *name, int flags, blkdev_t **retdev) +{ + int fd; + struct stat statbuf; + + if (stat (name, &statbuf)) + { + *retdev = NULL; + return -1; + } + if ((fd = open (name, O_RDONLY, 0)) < 0) + { + *retdev = NULL; + return -1; + } + *retdev = malloc (sizeof (blkdev_t)); + (*retdev)->blksize = 512; + (*retdev)->devno = fd; + return 0; +} + +int blk_close (blkdev_t *dev) +{ + close (dev->devno); + free (dev); + return 0; +} + +int blk_read (blkdev_t *dev, void *buf, int block, int count) +{ + int i; + + lseek (dev->devno, block * dev->blksize, SEEK_SET); + for (i = 0; i < count; i++) + read (dev->devno, buf + dev->blksize * i, dev->blksize); + return 0; +} + +int blk_write (blkdev_t dev, const void *buf, int block, int count) +{ + return 0; +} + diff --git a/srv/vfs/sandbox/blkdev.h b/srv/vfs/sandbox/blkdev.h @@ -0,0 +1,48 @@ +/* $Id: //depot/blt/srv/vfs/sandbox/blkdev.h#1 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef SANDBOX_BLKDEV_H +#define SANDBOX_BLKDEV_H + +#ifdef _BLT_BLKDEV_H_ +#error using both blt/blkdev.h and sandbox/blkdev.h is bad +#endif + +typedef struct +{ + int blksize; + dev_t devno; +} blkdev_t; + +int blk_open (const char *name, int flags, blkdev_t **retdev); +int blk_close (blkdev_t *dev); +int blk_read (blkdev_t *dev, void *buf, int block, int count); +int blk_write (blkdev_t dev, const void *buf, int block, int count); + +#endif + diff --git a/srv/vfs/sandbox/hash.h b/srv/vfs/sandbox/hash.h @@ -0,0 +1,56 @@ +/* $Id: //depot/blt/srv/vfs/sandbox/hash.h#1 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED +** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HASH_H +#define HASH_H + +typedef struct +{ + int valid, dirty, key, dsize; + void *data; +} hashnode_t; + +typedef struct +{ + hashnode_t *table; + int size_index, used, dirty; + float max_load; +} hashtable_t; + +hashtable_t *hashtable_new (float max_load); +void hashtable_del (hashtable_t *t); +void hashtable_insert (hashtable_t *t, int key, void *data, int dsize); +void *hashtable_lookup (hashtable_t *t, int key, int *dsize); +void *hashtable_remove (hashtable_t *t, int key, int *dsize); +void hashtable_print (hashtable_t *t); + +#endif + diff --git a/srv/vfs/sandbox/types.h b/srv/vfs/sandbox/types.h @@ -0,0 +1,50 @@ +/* $Id: //depot/blt/srv/vfs/sandbox/types.h#1 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef TYPES_H +#define TYPES_H + +typedef unsigned long long uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; +typedef long long int64; +typedef int int32; +typedef short int16; +typedef char int8; + +/* +typedef unsigned int off_t; +typedef unsigned int mode_t; +typedef unsigned int dev_t; +typedef unsigned int ino_t; +typedef unsigned int nlink_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; +*/ + +#endif diff --git a/srv/vfs/sandbox/vfs.c b/srv/vfs/sandbox/vfs.c @@ -0,0 +1,157 @@ +/* $Id: //depot/blt/srv/vfs/sandbox/vfs.c#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <dlfcn.h> +#include "../vfs-int.h" + +#define NAME_PREFIX "../drivers/" +#define NAME_SUFFIX ".so" + +struct fs_type *fs_drivers; +struct superblock *mount_list = NULL; + +void usage (void) +{ + printf ("usage: vfs driver file\n"); + exit (1); +} + +int main (int argc, char **argv) +{ + char *buf, c; + int i, len, num, pos, res; + void *fs, *cookie; + struct stat statbuf; + struct dirent dirent; + struct vnode *vn; + + if (argc < 3) + usage (); + + buf = malloc (strlen (NAME_PREFIX) + strlen (NAME_SUFFIX) + + strlen (argv[1]) * 2 + 2); + strcpy (buf, NAME_PREFIX); + strcat (buf, argv[1]); + strcat (buf, "/"); + strcat (buf, argv[1]); + strcat (buf, NAME_SUFFIX); + + if (stat (buf, &statbuf)) + { + printf ("driver `%s' not found\n", argv[1]); + exit (1); + } + if ((fs = dlopen (buf, 0)) == NULL) + { + printf ("error loading driver `%s'\n", argv[1]); + exit (1); + } + + vfs_mount ("/", argv[1], 0, argv[2]); + free (buf); + +/* + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/afs/ThisCell"); + vput (vn); + vn = fs_drivers->t_vops->walk (mount_list->sb_root, + "etc/kerberosIV/krb.conf"); + vput (vn); + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "bin/df"); + vput (vn); +*/ +/* + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc"); + fs_drivers->t_vops->opendir (vn, &cookie); + vput (vn); +*/ +/* + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "bin"); + printf ("vnid is %lld\n", vn->v_vnid); + fs_drivers->t_vops->opendir (vn, &cookie); + while (!fs_drivers->t_vops->readdir (vn, &dirent, cookie)) + printf ("name %s\n", dirent.d_name); + fs_drivers->t_vops->rewinddir (vn, cookie); + fs_drivers->t_vops->closedir (vn, cookie); + fs_drivers->t_vops->free_dircookie (cookie); + vput (vn); +*/ +/* + buf = malloc (len = 13062); + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/rc"); + fs_drivers->t_vops->open (vn, &cookie); + res = fs_drivers->t_vops->read (vn, buf, len, pos = 0, &num, cookie); + printf ("read %d %d bytes\n", res, num); + for (i = 0; i < len; i++) + printf ("%c", buf[i]); + vput (vn); +*/ +/* + pos = 0; + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/rc"); + fs_drivers->t_vops->open (vn, &cookie); + do + { + res = fs_drivers->t_vops->read (vn, &c, 1, pos++, &num, cookie); + printf ("%c", c); + } + while (!res && num); + vput (vn); +*/ +/* + //pos = 12 * 8192; + pos = 0; + buf = malloc (len = 8192); + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/magic"); + fs_drivers->t_vops->open (vn, &cookie); + do + { + res = fs_drivers->t_vops->read (vn, buf, len, pos, &num, cookie); + pos += num; + for (i = 0; i < num; i++) + printf ("%c", buf[i]); + } + while (!res && num); + vput (vn); + free (buf); +*/ + + vn = fs_drivers->t_vops->walk (mount_list->sb_root, "etc/magic"); + fs_drivers->t_vops->rstat (vn, &statbuf); + printf ("inode is %lld, nlink is %d, uid is %d, gid is %d, size is %d\n", + statbuf.st_ino, statbuf.st_nlink, statbuf.st_uid, statbuf.st_gid, + statbuf.st_size); + vput (vn); + + return 0; +} + diff --git a/srv/vfs/shm.c b/srv/vfs/shm.c @@ -0,0 +1,86 @@ +/* $Id: //depot/blt/srv/vfs/shm.c#6 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <string.h> +#include <dirent.h> +#include "bootfs.h" +#include "shm.h" + +void shm_write_dir (struct ofile *ofile, int skip, int doff, int len, + int *numents, int *more) +{ + int i, res; + struct dirent dirent; + struct vnode *vnode; + register struct vnode_ops *ops; + + vnode = ofile->o_vnode; + ops = vnode->v_sb->sb_vops; + ops->rewinddir (vnode, ofile->o_cookie); + for (i = 0; i < skip; i++) + ops->readdir (vnode, &dirent, ofile->o_cookie); + for (i = res = 0; (i < (len / sizeof (struct dirent))) && !res; i++) + { + res = ops->readdir (vnode, &dirent, ofile->o_cookie); + if (!res) + memcpy (ofile->dataptr + doff + i * sizeof (struct dirent), + &dirent, sizeof (struct dirent)); + } + *numents = (i == 0) ? 0 : i - 1; + *more = 0; +} + +void shm_write (struct ofile *ofile, int skip, int doff, int len, + int *numbytes, int *more) +{ +#if 0 + char buf[256]; + int i, res; + struct vnode *vnode; + register struct vnode_ops *ops; + + vnode = ofile->o_vnode; + ops = vnode->v_sb->sb_vops; +/* + FIXME - this works without this code for now, but won't when we get lseek + for (i = 0; i < skip; i++) + ops->read (vnode, buf, 1, ofile->o_cookie); +*/ + for (i = 0, res = 1; (i < len) && res; i += res) + if ((res = ops->read (vnode, buf, sizeof (buf), ofile->o_cookie)) > 0) + memcpy (ofile->dataptr + doff + i, buf, res); + *numbytes = i; + *more = (i == len); +#ifdef SHM_DEBUG + printf ("shm_write: %x / %x %x %x %x %x\n", ofile->dataptr + doff, + *numbytes, i, *more, len, skip); +#endif +#endif +} + diff --git a/srv/vfs/shm.h b/srv/vfs/shm.h @@ -0,0 +1,40 @@ +/* $Id: //depot/blt/srv/vfs/shm.h#2 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _SHM_H_ +#define _SHM_H_ + +#include "vfs-int.h" + +void shm_write_dir (struct ofile *ofile, int skip, int doff, int len, + int *numents, int *more); +void shm_write (struct ofile *ofile, int skip, int doff, int len, + int *numbytes, int *more); + +#endif + diff --git a/srv/vfs/super.c b/srv/vfs/super.c @@ -0,0 +1,90 @@ +/* $Id: //depot/blt/srv/vfs/super.c#5 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vfs-int.h" + +int vfs_mount (const char *dir, const char *type, int flags, const void *data) +{ + int res; + static int rootmounted = 0; + struct fs_type *driver; + struct superblock *super; + +#ifdef VFS_DEBUG + printf ("vfs_mount %s %s\n", dir, type); +#endif + + /* find filesystem driver */ + driver = fs_drivers; + while (driver != NULL) + { + if (!strcmp (driver->name, type)) + break; + else + driver = driver->next; + } + if (driver == NULL) + { + printf ("vfs: no driver\n"); + return 1; + } + super = malloc (sizeof (struct superblock)); + super->sb_vops = driver->t_vops; + + super->sb_dir = malloc (strlen (dir) + 1); + strcpy (super->sb_dir, dir); + + /* verify mount point existence */ + if (!rootmounted) + { + rootmounted = 1; + super->sb_dev = "none"; + } + else + { + super->sb_dev = "none"; + } + + super->sb_vnode_cache = hashtable_new (0.75); + super->sb_next = NULL; + res = driver->t_vops->mount (super, data, 1); + if (!res) + { + if (mount_list != NULL) + super->sb_next = mount_list; + mount_list = super; + if (strcmp (type, "rootfs") && strcmp (type, "bootfs")) + printf ("vfs: mounted type %s on %s from %s\n", type, + super->sb_dir, super->sb_dev); + } + return res; +} + diff --git a/srv/vfs/vfs-int.h b/srv/vfs/vfs-int.h @@ -0,0 +1,211 @@ +/* $Id: //depot/blt/srv/vfs/vfs-int.h#11 $ +** +** Copyright 1999 Sidney Cammeresi. +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VFS_INT_H_ +#define _VFS_INT_H_ + + +#include <dirent.h> +#include <sys/stat.h> + +#ifndef VFS_SANDBOX +#include <blt/types.h> +#include <blt/hash.h> +#include <blt/qsem.h> +#include <blt/vfs.h> +#include <blt/syscall.h> +#else +#include "hash.h" +#define MAX_FDS 256 +#endif + +struct fs_type +{ + char *name; + struct vnode_ops *t_vops; + struct fs_type *next; +}; + +struct superblock +{ + char *sb_dev, *sb_dir; + struct vnode *sb_root; + struct vnode_ops *sb_vops; + void *sb_data; + hashtable_t *sb_vnode_cache; + struct superblock *sb_next; +}; + +/* + * This stuff was mercilessly stolen from *Practical File System Design + * With the Be File System* by Dominic Giampaolo. According to rumours, + * it is a lot like the way BeOS handles stuff internally. + */ + +/* + * don't be alarmed by all of the voids; i've just not yet come to the + * semantics of all of these yet. patience, please. + */ +struct vnode_ops +{ + int (*read_vnode) (struct vnode *vnode); + void (*drop_vnode) (struct vnode *vnode); + void (*remove_vnode) (void); + void (*secure_vnode) (void); + struct vnode *(*walk) (struct vnode *parent, const char *path); + void (*access) (void); + + int (*mount) (struct superblock *sb, const char *data, int silent); + void (*unmount) (struct superblock *sb); + void (*initialise) (void); + void (*sync) (void); + void (*rfstat) (void); + void (*wfstat) (void); + + void (*create) (void); + int (*mkdir) (struct vnode *parent, const char *name, mode_t mode); + void (*symlink) (void); + void (*link) (void); + void (*rename) (void); + void (*unlink) (void); + void (*rmdir) (void); + void (*readlink) (void); + + int (*opendir) (struct vnode *dir, void **cookie); + void (*closedir) (struct vnode *dir, void *cookie); + void (*free_dircookie) (void *cookie); + int (*rewinddir) (struct vnode *dir, void *cookie); + int (*readdir) (struct vnode *vnode, struct dirent *dirent, void *cookie); + + int (*open) (struct vnode *vnode, void **cookie); + int (*close) (struct vnode *vnode, void *cookie); + void (*free_cookie) (void *cookie); + int (*read) (struct vnode *vnode, char *buf, size_t count, off_t offset, + size_t *res, void *cookie); + void (*write) (struct vnode *vnode, const char *buf, size_t count, + void *cookie); + void (*ioctl) (void); + void (*setflags) (void); + int (*rstat) (struct vnode *vnode, struct stat *buf); + int (*wstat) (struct vnode *vnode, struct stat *buf); + void (*fsync) (void); + + void (*open_attrdir) (void); + void (*close_attrdir) (void); + void (*free_attrdircookie) (void); + void (*rewind_attrdir) (void); + void (*read_attrdir) (void); + void (*read_attr) (void); + void (*write_attr) (void); + void (*remove_attr) (void); + void (*rename_attr) (void); + void (*stat_attr) (void); + + void (*open_indexdir) (void); + void (*close_indexdir) (void); + void (*free_indexdircookie) (void); + void (*rewind_indexdir) (void); + void (*read_indexdir) (void); + void (*create_index) (void); + void (*remove_index) (void); + void (*rename_index) (void); + void (*stat_index) (void); + + void (*open_query) (void); + void (*close_query) (void); + void (*free_query_cookie) (void); + void (*read_query) (void); +}; + +struct vnode +{ + unsigned long long v_vnid; + unsigned int v_refcount; + struct superblock *v_sb; + void *v_data; +#ifndef VFS_SANDBOX + qsem_t *v_lock; +#endif +}; + +struct ofile +{ + struct vnode *o_vnode; + void *o_cookie; + int area, offset, length, flags; + int o_pos; + void *dataptr; +}; + +struct fdarray +{ + struct ofile *ofile[MAX_FDS]; +}; + +struct ioctx +{ + char *cwd; + struct fdarray fdarray; +}; + +struct client +{ + int in, out, filename_area; + struct ioctx ioctx; + char *nameptr; +}; + +/* functions for use by modules */ +int fs_register (struct fs_type *type); +void fs_unregister (struct fs_type *type); + +/* utility functions */ +struct superblock *fs_find (const char *name); +struct vnode *vget (struct superblock *super, int num); +void vput (struct vnode *vnode); + +#ifndef VFS_SANDBOX +vfs_res_t *vfs_openconn (int rport, int area); +vfs_res_t *vfs_scroll_area (struct client *client, vfs_cmd_t *vc); +vfs_res_t *vfs_opendir (struct client *client, vfs_cmd_t *vc); +vfs_res_t *vfs_closedir (struct client *client, vfs_cmd_t *vc); +#endif + +struct vfs_dirent_node +{ + struct dirent *dirent; + struct vfs_dirent_node *next; +}; + +extern struct fs_type *fs_drivers; +extern struct superblock *mount_list; + +int vfs_mount (const char *dir, const char *type, int flags, const void *data); + +#endif + diff --git a/srv/vfs/vfs.c b/srv/vfs/vfs.c @@ -0,0 +1,671 @@ +/* Copyright 1998-1999, Sidney Cammeresi. All rights reserved. +** Distributed under the terms of the OpenBLT License +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <boot.h> +#include <dlfcn.h> +#include <sys/stat.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <blt/error.h> +#include <blt/hash.h> +#include <blt/libsyms.h> +#include <blt/vfs.h> +#include "vfs-int.h" +#include "path.h" +#include "shm.h" + +#define FG_GREEN "\033[32m" +#define FG_RED "\033[34m" +#define FG_WHITE "\033[37m" + +int vfs_port; +struct fs_type *fs_drivers; +struct superblock *mount_list = NULL; +hashtable_t *conn_table; + +void __libc_init_vfs (void), __dlinit (void); + +extern struct fs_type rootfs, bootfs; +extern void __libc_init_console (); +extern int __blk_ref; + +vfs_res_t *vfs_openconn (int rport, int area) +{ + int i, private_port; + vfs_res_t *res; + struct client *client; + + res = malloc (sizeof (vfs_res_t)); + res->status = VFS_OK; + res->errno = 0; + private_port = port_create (rport, "vfs_private_port"); + port_slave (vfs_port, private_port); + res->data[0] = private_port; + + client = malloc (sizeof (struct client)); + client->in = rport; + client->out = private_port; + client->filename_area = area; + area_clone (area, 0, (void **) &client->nameptr, 0); + client->ioctx.cwd = malloc (BLT_MAX_NAME_LENGTH); + strcpy (client->ioctx.cwd, "/"); + for (i = 0; i < MAX_FDS; i++) + client->ioctx.fdarray.ofile[i] = NULL; + hashtable_insert (conn_table, client->in, client, sizeof (struct client)); + +#ifdef VFS_DEBUG + printf ("vfs_openconn: from port %d, assigned port %d, area %d " + "mapped to %p\n", rport, private_port, area, client->nameptr); +#endif + return res; +} + +vfs_res_t *vfs_scroll_area (struct client *client, vfs_cmd_t *vc) +{ + struct ofile *ofile; + vfs_res_t *res; + + res = malloc (sizeof (vfs_res_t)); + ofile = client->ioctx.fdarray.ofile[vc->data[0]]; + shm_write (ofile, vc->data[1], 0, ofile->length, &res->data[0], + &res->data[1]); + res->status = VFS_OK; + res->errno = 0; + return res; +} + +int vfs_mkdir (const char *dir, mode_t mode) +{ + const char *s; + int res; + struct superblock *super; + struct vnode *vnode; + +#ifdef VFS_DEBUG + printf ("vfs_mkdir %s %d\n", dir, mode); +#endif + + /* find superblock and check if mkdir supported */ + super = fs_find (dir); + if (super->sb_vops->mkdir == NULL) + return ENOSYS; + + /* XXX dispatch to root vnode for now */ + vnode = super->sb_root; + s = dir + strlen (super->sb_dir); + res = super->sb_vops->mkdir (vnode, s, mode); + return res; +} + +vfs_res_t *vfs_opendir (struct client *client, vfs_cmd_t *vc) +{ + char *reldir, *dir; + int i; + vfs_res_t *res; + struct ofile *ofile; + struct superblock *super; + struct vnode *vnode; + + reldir = client->nameptr + vc->data[0]; + res = malloc (sizeof (vfs_res_t)); +#ifdef VFS_DEBUG + printf ("vfs_opendir %s\n", reldir); +#endif + + /* get a file descriptor */ + for (i = 0; i < MAX_FDS; i++) + if (client->ioctx.fdarray.ofile[i] == NULL) + break; + if (i == MAX_FDS) + { + res->status = VFS_ERROR; + res->errno = EMFILE; + return res; + } + + /* is opendir supported? */ + dir = malloc (BLT_MAX_NAME_LENGTH); + strlcpy (dir, client->ioctx.cwd, BLT_MAX_NAME_LENGTH); + path_combine (client->ioctx.cwd, reldir, dir); + super = fs_find (dir); + if (super == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOENT; + free (dir); + return res; + } + if (super->sb_vops->opendir == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOSYS; + free (dir); + return res; + } + + /* find directory's vnode */ + if (!strcmp (dir, super->sb_dir)) + vnode = super->sb_root; + else + vnode = super->sb_vops->walk (super->sb_root, dir + + strlen (super->sb_dir) + 1); + if (vnode == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOENT; + free (dir); + return res; + } + + /* stat here to check for directory */ + + /* call filesystem's opendir and read the directory */ + ofile = client->ioctx.fdarray.ofile[i] = malloc (sizeof (struct ofile)); + ofile->o_vnode = vnode; + ofile->area = area_clone (vc->data[1], 0, &ofile->dataptr, 0); + ofile->offset = vc->data[2]; + ofile->length = vc->data[3]; + res->errno = super->sb_vops->opendir (vnode, &ofile->o_cookie); + res->status = res->errno ? VFS_ERROR : VFS_OK; + res->data[0] = i; + free (dir); + return res; +} + +vfs_res_t *vfs_closedir (struct client *client, vfs_cmd_t *vc) +{ + vfs_res_t *res; + struct ofile *ofile; + struct vnode *vnode; + +#ifdef VFS_DEBUG + printf ("vfs_closedir %d\n", vc->data[0]); +#endif + res = malloc (sizeof (vfs_res_t)); + + /* is file descriptor valid? */ + if ((ofile = client->ioctx.fdarray.ofile[vc->data[0]]) == NULL) + { + res->errno = EBADF; + res->status = VFS_ERROR; + return res; + } + + /* is closedir supported? */ + vnode = ofile->o_vnode; + if (vnode->v_sb->sb_vops->closedir == NULL) + { + res->errno = ENOSYS; + res->status = VFS_ERROR; + return res; + } + + /* call filesystem */ + vnode->v_sb->sb_vops->closedir (vnode, ofile->o_cookie); + if (!res->errno && (vnode->v_sb->sb_vops->free_dircookie != NULL)) + vnode->v_sb->sb_vops->free_dircookie (ofile->o_cookie); + free (ofile); + client->ioctx.fdarray.ofile[vc->data[0]] = NULL; + + res->status = VFS_OK; + res->errno = 0; + return res; +} + +vfs_res_t *vfs_open (struct client *client, vfs_cmd_t *vc) +{ + int i; + char *path; + vfs_res_t *res; + struct ofile *ofile; + struct superblock *super; + struct vnode *vnode; + + res = malloc (sizeof (vfs_res_t)); + path = client->nameptr + vc->data[0]; +#ifdef VFS_DEBUG + printf ("vfs_open %s\n", path); +#endif + + /* get a file descriptor */ + for (i = 0; i < MAX_FDS; i++) + if (client->ioctx.fdarray.ofile[i] == NULL) + break; + if (i == MAX_FDS) + { + res->status = VFS_ERROR; + res->errno = EMFILE; + return res; + } + + /* is open supported? */ + super = fs_find (path); + if (super == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOENT; + return res; + } + if (super->sb_vops->open == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOSYS; + return res; + } + + /* find file's vnode */ + vnode = super->sb_vops->walk (super->sb_root, path + + strlen (super->sb_dir) + 1); + if (vnode == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOENT; + return res; + } + + /* call filesystem */ + ofile = client->ioctx.fdarray.ofile[i] = malloc (sizeof (struct ofile)); + ofile->o_vnode = vnode; + ofile->o_pos = 0; + ofile->area = area_clone (vc->data[1], 0, &ofile->dataptr, 0); + ofile->offset = vc->data[2]; + ofile->length = vc->data[3]; + res->errno = super->sb_vops->open (vnode, &ofile->o_cookie); + res->status = res->errno ? VFS_ERROR : VFS_OK; + res->data[0] = i; + return res; +} + +vfs_res_t *vfs_close (struct client *client, vfs_cmd_t *vc) +{ + vfs_res_t *res; + struct ofile *ofile; + struct superblock *super; + + res = malloc (sizeof (vfs_res_t)); +#ifdef VFS_DEBUG + printf ("vfs_close\n"); +#endif + + ofile = client->ioctx.fdarray.ofile[vc->data[0]]; + if (ofile == NULL) + { + res->status = VFS_ERROR; + res->errno = EBADF; + return res; + } + super = ofile->o_vnode->v_sb; + if (super->sb_vops->close == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOSYS; + return res; + } + res->errno = super->sb_vops->close (ofile->o_vnode, + ofile->o_cookie); + + if (super->sb_vops->free_cookie != NULL) + super->sb_vops->free_cookie (ofile->o_cookie); + + res->status = res->errno ? VFS_ERROR : VFS_OK; + return res; +} + +vfs_res_t *vfs_read (struct client *client, vfs_cmd_t *vc, void **data, + int *len) +{ + size_t numread; + void *buf; + vfs_res_t *res; + struct ofile *ofile; + struct superblock *super; + +#ifdef VFS_DEBUG + printf ("vfs_read\n"); +#endif + res = malloc (sizeof (vfs_res_t)); + buf = malloc (vc->data[1]); + + ofile = client->ioctx.fdarray.ofile[vc->data[0]]; + if (ofile == NULL) + { + res->status = VFS_ERROR; + res->errno = EBADF; + return res; + } + super = ofile->o_vnode->v_sb; + if (super->sb_vops->read == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOSYS; + return res; + } + + res->errno = super->sb_vops->read (ofile->o_vnode, buf, vc->data[1], + ofile->o_pos, &numread, ofile->o_cookie); + res->status = res->errno ? VFS_ERROR : VFS_OK; + res->data[0] = numread; + ofile->o_pos += *len = numread; + *data = buf; + return res; +} + +vfs_res_t *vfs_rstat (struct client *client, vfs_cmd_t *vc) +{ + char *path; + vfs_res_t *res; + struct superblock *super; + struct vnode *vnode; + struct stat *buf; + +#ifdef VFS_DEBUG + printf ("vfs_rstat\n"); +#endif + res = malloc (sizeof (vfs_res_t) + sizeof (struct stat)); + buf = (void *) res + sizeof (vfs_res_t); + path = client->nameptr + vc->data[0]; + + /* is stat supported? */ + super = fs_find (path); + if (super == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOENT; + return res; + } + if (super->sb_vops->rstat == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOSYS; + return res; + } + + /* find file's vnode */ + vnode = super->sb_vops->walk (super->sb_root, path + + strlen (super->sb_dir) + 1); + if (vnode == NULL) + { + res->status = VFS_ERROR; + res->errno = ENOENT; + return res; + } + + /* call filesystem */ + res->errno = super->sb_vops->rstat (vnode, buf); + res->status = res->errno ? VFS_ERROR : VFS_OK; + return res; +} + +void vfs_tell_cmd (const char *cmd, char *arg) +{ + char *name; + const char *type, *dir, *data; + int i, len; + void *handle; + + if (!strcmp (cmd, "load")) + { + printf (" %s", arg); + name = malloc (len = BLT_MAX_NAME_LENGTH); + strlcpy (name, "/boot/", len); + strlcat (name, arg, len); + strlcat (name, ".so", len); + handle = dlopen (name, 0); + if (handle == NULL) + { + printf ("(error)"); + return; + } + free (name); + } + else if (!strcmp (cmd, "mount")) + { + type = arg; + for (i = 0; arg[i] != ' '; i++) ; + arg[i] = 0; + dir = arg + i + 1; + for (arg++; arg[i] != ' '; i++) ; + arg[i] = 0; + data = arg + i + 1; + vfs_mount (dir, type, 0, data); + } +} + +void vfs_tell_parse (const char *msg) +{ + const char *c, *cmd; + char *full; + char *d; + int i, whole, len; + + c = msg; + cmd = full = NULL; + whole = len = 0; + while (*c) + { + i = 0; + while ((c[i] != ' ') && c[i]) + i++; + d = malloc (i + 1); + strlcpy (d, c, i + 1); + if (cmd == NULL) + { + cmd = d; + if (!strcmp (cmd, "load")) + printf ("vfs: loading drivers. ["); + else if (!strcmp (cmd, "mount")) + { + whole = 1; + full = malloc (len = strlen (msg + 1)); + *full = 0; + } + } + else if (!whole) + vfs_tell_cmd (cmd, d); + else + { + strlcat (full, d, len); + strlcat (full, " ", len); + } + if (i != strlen (c)) + c += i + 1; + else + break; + } + if (whole) + full[strlen (full) - 1] = 0; + if (!strcmp (cmd, "load")) + printf (" ]\n"); + else if (!strcmp (cmd, "mount")) + vfs_tell_cmd (cmd, full); +} + +void vfs_tell (void) +{ + char buf[64]; + int port; + msg_hdr_t mh; + + __libc_init_fdl (); + __libc_init_vfs (); + __dlinit (); + __blk_ref++; + + port = port_create (0, "vfs:tell"); + namer_register (port, "vfs:tell"); + + for (;;) + { + mh.src = 0; + mh.dst = port; + mh.data = buf; + mh.size = sizeof (buf); + old_port_recv (&mh); + vfs_tell_parse (mh.data); + + mh.dst = mh.src; + mh.src = port; + mh.data = &port; + mh.size = 1; + old_port_send (&mh); + } +} + +int vfs_main (volatile int *ready) +{ + int i, size, len; + void *data; + msg_hdr_t msg, reply; + vfs_cmd_t vc; + vfs_res_t *res; + struct client *client; + + /* open a connection to the console */ + __libc_init_console (); + + /* get a public port and register ourself with the namer */ + vfs_port = port_create (0, "vfs_listen_port"); + namer_register (vfs_port, "vfs"); + + /* say hello */ +#ifdef VFS_DEBUG + printf ("vfs: " FG_GREEN "listener ready" FG_WHITE " (port %d)\n", + vfs_port); +#endif + + /* initialise structures */ + fs_drivers = NULL; + conn_table = hashtable_new (0.75); + res = NULL; + client = NULL; + + /* mount the root and boot filesystems */ + fs_register (&rootfs); + fs_register (&bootfs); + vfs_mount ("/", "rootfs", 0, NULL); + vfs_mkdir ("/boot", 755); + vfs_mount ("/boot", "bootfs", 0, NULL); + thr_create (vfs_tell, 0, "vfs:tell"); + *ready = 1; + + for (;;) + { + /* + * listen for commands. all ports will be slaved to the one + * we just created, so we only need to listen on one port. + */ + msg.src = 0; + msg.dst = vfs_port; + msg.data = &vc; + msg.size = sizeof (vc); + old_port_recv (&msg); + + if (vc.cmd != VFS_OPENCONN) + client = hashtable_lookup (conn_table, msg.src, NULL); + size = sizeof (vfs_res_t); + data = NULL; + + switch (vc.cmd) + { + case VFS_OPENCONN: + res = vfs_openconn (msg.src, vc.data[0]); + break; + + case VFS_SCROLL_AREA: + res = vfs_scroll_area (client, &vc); + break; + + case VFS_OPENDIR: + res = vfs_opendir (client, &vc); + if (res->status == VFS_OK) + shm_write_dir (client->ioctx.fdarray.ofile[res->data[0]], + 0, 0, vc.data[3], &res->data[1], &res->data[2]); + break; + + case VFS_CLOSEDIR: + res = vfs_closedir (client, &vc); + break; + + case VFS_OPEN: + res = vfs_open (client, &vc); + if (res->status == VFS_OK) + shm_write (client->ioctx.fdarray.ofile[res->data[0]], + 0, 0, vc.data[3], &res->data[1], &res->data[2]); + break; + + case VFS_CLOSE: + res = vfs_close (client, &vc); + break; + + case VFS_READ: + res = vfs_read (client, &vc, &data, &len); + break; + + case VFS_RSTAT: + res = vfs_rstat (client, &vc); + size = sizeof (vfs_res_t) + sizeof (struct stat); + break; + + case VFS_MKDIR: + res = malloc (sizeof (vfs_res_t)); + res->status = vfs_mkdir (client->nameptr + vc.data[0], + vc.data[1]); + res->errno = 0; + break; + } + + if (res != NULL) + { + reply.src = (vc.cmd == VFS_OPENCONN) ? vfs_port : client->out; + reply.dst = msg.src; + reply.data = res; + reply.size = size; + old_port_send (&reply); + free (res); + + if (data != NULL) + { + reply.src = client->out; + reply.dst = msg.src; + if (len < 0x1000) + { + reply.data = data; + reply.size = len; + old_port_send (&reply); + } + else + { + for (i = 0; len > 0x1000; i += 0x1000, len -= 0x1000) + { + reply.data = (char *) data + i; + reply.size = 0x1000; + old_port_send (&reply); + } + reply.data = (char *) data + i; + reply.size = len; + old_port_send (&reply); + } + free (data); + } + } + } + + /* not reached */ + return 0; +} + +int main (void) +{ + volatile int ready = 0; + + thr_create (vfs_main, (int *) &ready, "vfs"); + while (!ready) ; + return 0; +} + diff --git a/srv/vfs/vnode.c b/srv/vfs/vnode.c @@ -0,0 +1,61 @@ +/* $Id: //depot/blt/srv/vfs/vnode.c#4 $ +** +** Copyright 1999 Sidney Cammeresi +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include "vfs-int.h" + +struct vnode *vget (struct superblock *super, int vnid) +{ + struct vnode *v; + +#ifdef VNODE_DEBUG + printf ("vfs: vget %d\n", vnid); +#endif + v = malloc (sizeof (struct vnode)); + v->v_vnid = vnid; + v->v_refcount = 1; + v->v_sb = super; +#ifndef VFS_SANDBOX + v->v_lock = qsem_create (1); +#endif + super->sb_vops->read_vnode (v); + return v; +} + +void vput (struct vnode *vnode) +{ + vnode->v_sb->sb_vops->drop_vnode (vnode); +#ifndef VFS_SANDBOX + qsem_destroy (vnode->v_lock); +#endif + vnode->v_refcount--; + if (!vnode->v_refcount) + free (vnode); +} + diff --git a/srv/window/GraphicsContext.cpp b/srv/window/GraphicsContext.cpp @@ -0,0 +1,228 @@ +#include "Renderer.h" +#include "Rect.h" +#include "Region.h" +#include "GraphicsContext.h" +#include "util.h" +#include "font.h" +#include "Window.h" + +#define swap(a, b) { int temp = a; a = b; b = temp; } + + +GraphicsContext::GraphicsContext() + : fRenderer(0) +{ +} + +void GraphicsContext::SetColor(char color) +{ + fCurrentColor = color; +} + +const unsigned kBottom = 1; +const unsigned kTop = 2; +const unsigned kLeft = 4; +const unsigned kRight = 8; + +inline unsigned clipmask(int x, int y, const Rect &rect) +{ + unsigned mask = 0; + if (x < rect.left) + mask |= kLeft; + else if (x > rect.right) + mask |= kRight; + + if (y < rect.top) + mask |= kTop; + else if (y > rect.bottom) + mask |= kBottom; + + return mask; +} + +inline int vert_intersection(int x1, int y1, int x2, int y2, int x) +{ + return y1 + (y2 - y1) * (x - x1) / (x2 - x1); +} + +inline int horz_intersection(int x1, int y1, int x2, int y2, int y) +{ + return x1 + (x2 - x1) * (y - y1) / (y2 - y1); +} + +void GraphicsContext::DrawLine(int x1, int y1, int x2, int y2) +{ + x1 += fXOrigin; + x2 += fXOrigin; + y1 += fYOrigin; + y2 += fYOrigin; + + for (int rect = 0; rect < fClipRegion.CountRects(); rect++) { + const Rect &clipRect = fClipRegion.RectAt(rect); + int clippedX1 = x1; + int clippedY1 = y1; + int clippedX2 = x2; + int clippedY2 = y2; + unsigned point1mask = clipmask(clippedX1, clippedY1, clipRect); + unsigned point2mask = clipmask(clippedX2, clippedY2, clipRect); + + bool rejected = false; + while (point1mask != 0 || point2mask != 0) { + if ((point1mask & point2mask) != 0) { + rejected = true; + break; + } + + unsigned mask = point1mask ? point1mask : point2mask; + int x = 0; + int y = 0; + if (mask & kBottom) { + y = clipRect.bottom; + x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y); + } else if (mask & kTop) { + y = clipRect.top; + x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y); + } else if (mask & kRight) { + x = clipRect.right; + y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x); + } else if (mask & kLeft) { + x = clipRect.left; + y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x); + } + + if (point1mask) { + // Clip point 1 + point1mask = clipmask(x, y, clipRect); + clippedX1 = x; + clippedY1 = y; + } else { + // Clip point 2 + point2mask = clipmask(x, y, clipRect); + clippedX2 = x; + clippedY2 = y; + } + } + + if (!rejected) + fRenderer->DrawLine(clippedX1, clippedY1, clippedX2, clippedY2, fCurrentColor); + } +} + + + +void GraphicsContext::FillRect(int x1, int y1, int x2, int y2) +{ + x1 += fXOrigin; + x2 += fXOrigin; + y1 += fYOrigin; + y2 += fYOrigin; + + if (x1 > x2) swap(x1, x2); + if (y1 > y2) swap(y1, y2); + + for (int rect = 0; rect < fClipRegion.CountRects(); rect++) { + const Rect &clipRect = fClipRegion.RectAt(rect); + int clipleft = max(x1, clipRect.left); + int cliptop = max(y1, clipRect.top); + int clipright = min(x2, clipRect.right); + int clipbottom = min(y2, clipRect.bottom); + + if (clipright >= clipleft && clipbottom >= cliptop) + fRenderer->FillRect(clipleft, cliptop, clipright, clipbottom, + fCurrentColor); + } +} + +void GraphicsContext::Blit(int x, int y, char image[], int image_width, + int image_height, int img_bytes_per_row) +{ + x += fXOrigin; + y += fYOrigin; + + for (int rect = 0; rect < fClipRegion.CountRects(); rect++) { + const Rect &clipRect = fClipRegion.RectAt(rect); + int clipleft = max(x, clipRect.left); + int cliptop = max(y, clipRect.top); + int clipright = min(x + image_width - 1, clipRect.right); + int clipbottom = min(y + image_height - 1, clipRect.bottom); + + if (clipright >= clipleft && clipbottom >= cliptop) { + fRenderer->Blit(clipleft, cliptop, image + (clipleft - x) + + (cliptop - y) * img_bytes_per_row, clipright - clipleft + 1, + clipbottom - cliptop + 1, img_bytes_per_row); + } + } +} + +void GraphicsContext::StretchBlit(Rect imageRect, Rect screenRect, char image[], int img_bytes_per_row) +{ + screenRect.left += fXOrigin; + screenRect.top += fYOrigin; + screenRect.right += fXOrigin; + screenRect.bottom += fYOrigin; + + for (int rect = 0; rect < fClipRegion.CountRects(); rect++) { + const Rect &clipRect = fClipRegion.RectAt(rect); + Rect clippedScreenRect; + clippedScreenRect.left = max(screenRect.left, clipRect.left); + clippedScreenRect.top = max(screenRect.top, clipRect.top); + clippedScreenRect.right = min(screenRect.right, clipRect.right); + clippedScreenRect.bottom = min(screenRect.bottom, clipRect.bottom); + + if (clippedScreenRect.Width() > 0 && clippedScreenRect.Height() > 0) { + Rect clippedImageRect; + clippedImageRect.left = (clippedScreenRect.left - screenRect.left) + * imageRect.Width() / screenRect.Width(); + clippedImageRect.right = (clippedScreenRect.right - screenRect.left) + * imageRect.Width() / screenRect.Width(); + clippedImageRect.top = (clippedScreenRect.top - screenRect.top) + * imageRect.Height() / screenRect.Height(); + clippedImageRect.bottom = (clippedScreenRect.bottom - screenRect.top) + * imageRect.Height() / screenRect.Height(); + + fRenderer->StretchBlit(clippedImageRect, clippedScreenRect, image, img_bytes_per_row); + } + } +} + +void GraphicsContext::CopyRect(Rect src, Rect dest, const Region &inCleanRegion, + Region &outNotCopied) +{ + src.OffsetBy(fXOrigin, fYOrigin); + dest.OffsetBy(fXOrigin, fYOrigin); + + int dX = dest.left - src.left; + int dY = dest.top - src.top; + Region copyRegion = inCleanRegion; + copyRegion.ConstrainTo(dest); + copyRegion.Translate(-dX, -dY); + copyRegion.Intersect(inCleanRegion); + for (int rect = 0; rect < copyRegion.CountRects(); rect++) { + const Rect &srcRect = copyRegion.RectAt(rect); + Rect destRect(srcRect); + destRect.OffsetBy(dX, dY); + fRenderer->CopyRect(srcRect, destRect); + } + + copyRegion.Invert(); + copyRegion.Intersect(fClipRegion); + outNotCopied = copyRegion; +} + +void GraphicsContext::DrawString(int x, int y, const char *string) +{ + while (*string) { + Blit(x, y, (char*) &font5x8[*string++ * 40], 5, 8, 5); + x += 5; + } +} + +Rect GraphicsContext::Bounds() +{ + Rect rect = fClipRegion.Bounds(); + rect.OffsetBy(-fXOrigin, -fYOrigin); + return rect; +} + + + diff --git a/srv/window/GraphicsContext.h b/srv/window/GraphicsContext.h @@ -0,0 +1,71 @@ +#ifndef _GRAPHICS_CONTEXT_H +#define _GRAPHICS_CONTEXT_H + +#include "Renderer.h" +#include "Region.h" + +class Window; + +class GraphicsContext { +public: + + GraphicsContext(); + Rect Bounds(); + + inline const Region& ClipRegion(); + inline void SetClipRegion(const Region&); + inline void SetRenderer(Renderer*); + inline Renderer* GetRenderer(); + inline void SetOrigin(int x, int y); + + void DrawLine(int, int, int, int); + void FillRect(int, int, int, int); + void Blit(int x, int y, char image[], int image_width, + int image_height, int img_bytes_per_row); + void StretchBlit(Rect imageRect, Rect screenRect, char image[], + int img_bytes_per_row); + void CopyRect(Rect src, Rect dest, const Region &inCleanRegion, + Region &outNotCopied); + + void SetColor(char color); + void DrawString(int x, int y, const char *string); + +private: + + Region fClipRegion; + Renderer *fRenderer; + char fCurrentColor; + int fXOrigin; + int fYOrigin; +}; + + +inline const Region& GraphicsContext::ClipRegion() +{ + return fClipRegion; +} + +inline void GraphicsContext::SetClipRegion(const Region &region) +{ + fClipRegion = region; + fClipRegion.ConstrainTo(fRenderer->Bounds()); +} + +inline void GraphicsContext::SetRenderer(Renderer *renderer) +{ + fRenderer = renderer; +} + +inline Renderer* GraphicsContext::GetRenderer() +{ + return fRenderer; +} + +inline void GraphicsContext::SetOrigin(int x, int y) +{ + fXOrigin = x; + fYOrigin = y; +} + + +#endif diff --git a/srv/window/Makefile b/srv/window/Makefile @@ -0,0 +1,13 @@ +BLTHOME := ../../ +include $(BLTHOME)make.conf + +CFLAGS += -fno-rtti -fno-exceptions -fno-pic -O2 +LIBS := -lposix -lblt -lc +BINARY := window_server.bin + +OBJS := main.o GraphicsContext.o Region.o \ + Window.o WindowManager.o Renderer_8bpp.o \ + vga.o Renderer_vga.o SerialMouse.o + +include $(BLTHOME)make.actions + diff --git a/srv/window/Rect.h b/srv/window/Rect.h @@ -0,0 +1,131 @@ +#ifndef RECT_H +#define RECT_H + +#include <stdio.h> +#include "util.h" + +class Rect { +public: + inline Rect(); + inline Rect(int left, int top, int right, int bottom); + inline void SetTo(int l, int t, int r, int b); + inline Rect& InsetBy(int, int); + inline Rect& OffsetBy(int, int); + inline Rect& OffsetTo(int, int); + inline bool Contains(int, int) const; + inline bool Contains(const Rect&) const; + inline bool Intersects(const Rect&) const; + inline Rect& Intersect(const Rect&); + inline bool Valid() const; + inline int Width() const; + inline int Height() const; + inline void Dump() const; + + int left; + int top; + int right; + int bottom; +}; + +inline Rect::Rect() + : left(0), + top(0), + right(0), + bottom(0) +{ +} + +inline Rect::Rect(int l, int t, int r, int b) + : left(l), + top(t), + right(r), + bottom(b) +{ +} + +inline void Rect::SetTo(int l, int t, int r, int b) +{ + left = l; + top = t; + right = r; + bottom = b; +} + + + +inline Rect& Rect::InsetBy(int h, int v) +{ + left += h; + right -= h; + top += v; + bottom -= v; + return *this; +} + +inline Rect& Rect::OffsetBy(int h, int v) +{ + left += h; + right += h; + top += v; + bottom += v; + return *this; +} + + +inline Rect& Rect::OffsetTo(int h, int v) +{ + right += (h - left); + bottom += (v - top); + left = h; + top = v; + return *this; +} + +inline bool Rect::Intersects(const Rect &rect) const +{ + return max(left, rect.left) <= min(right, rect.right) + && max(top, rect.top) <= min(bottom, rect.bottom); +} + +inline bool Rect::Valid() const +{ + return right >= left && bottom >= top; +} + +inline void Rect::Dump() const +{ + printf("Rect (%d, %d, %d, %d)\n", left, top, right, bottom); +} + + +inline int Rect::Width() const +{ + return right - left; +} + +inline int Rect::Height() const +{ + return bottom - top; +} + +inline bool Rect::Contains(int x, int y) const +{ + return (x >= left && x <= right && y >= top && y <= bottom); +} + +inline bool Rect::Contains(const Rect &rect) const +{ + return rect.left >= left && rect.right <= right + && rect.top >= top && rect.bottom <= bottom; +} + +inline Rect& Rect::Intersect(const Rect &rect) +{ + left = max(left, rect.left); + right = min(right, rect.right); + top = max(top, rect.top); + bottom = min(bottom, rect.bottom); + return *this; +} + +#endif diff --git a/srv/window/Region.cpp b/srv/window/Region.cpp @@ -0,0 +1,341 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "Region.h" +#include "util.h" + +const int kRectAllocSize = 16; + +Region::Region() + : fRects(0), + fNumRects(0), + fOpLevel(0) +{ +} + +Region::Region(const Region &copyRegion) + : fRects(0), + fNumRects(0), + fOpLevel(0) +{ + SetTo(copyRegion); +} + +Region::~Region() +{ + free(fRects); +} + +Region& Region::SetTo(const Region &copyRegion) +{ + AllocSpace(copyRegion.fNumRects); + fNumRects = copyRegion.fNumRects; + memcpy(fRects, copyRegion.fRects, fNumRects * sizeof(Rect)); + return *this; +} + +Region& Region::operator=(const Region &copyRegion) +{ + return SetTo(copyRegion); +} + +Rect Region::Bounds() const +{ + Rect bounds(COORD_MAX, COORD_MAX, -COORD_MAX, -COORD_MAX); + for (int i = 0; i < fNumRects; i++) { + const Rect &rect = RectAt(i); + bounds.left = min(bounds.left, rect.left); + bounds.right = max(bounds.right, rect.right); + bounds.top = min(bounds.top, rect.top); + bounds.bottom = max(bounds.bottom, rect.bottom); + } + + return bounds; +} + +Region& Region::Include(const Rect &rect) +{ + Region temp; + + BeginOperation(); + // Make sure that there are no overlaps + temp.AddRect(rect); + for (int i = 0; i < fNumRects; i++) + temp.Exclude(RectAt(i)); + + AddRegionRects(temp); + EndOperation(); + return *this; +} + +Region& Region::Include(const Region &region) +{ + BeginOperation(); + for (int i = 0; i < region.CountRects(); i++) + Include(region.RectAt(i)); + EndOperation(); + + return *this; +} + +#define SPLIT_TEST(rect1, rect2) \ + (max(rect1.left, rect2.left) < min(rect1.right, rect2.right) \ + && max(rect1.top, rect2.top) < min(rect1.bottom, rect2.bottom)) + +Region& Region::Exclude(const Rect &excludeRect) +{ + BeginOperation(); + int index = 0; + int rectsToCheck = fNumRects; + while (index < rectsToCheck) { + Rect &clipRect = fRects[index]; + + if (!excludeRect.Intersects(clipRect)) { + index++; + continue; + } + + // This clip rect intersects the excluded rect, and could be divided into + // as many as eight pieces. Test for each case. Note that none of these + // rectangles overlap!!!! + Rect quad1(clipRect.left, clipRect.top, excludeRect.left - 1, excludeRect.top - 1); + if (SPLIT_TEST(clipRect, quad1)) { + quad1.Intersect(clipRect); + AddRect(quad1); + } + + Rect quad2(excludeRect.left, clipRect.top, excludeRect.right, excludeRect.top - 1); + if (SPLIT_TEST(clipRect, quad2)) { + quad2.Intersect(clipRect); + AddRect(quad2); + } + + Rect quad3(excludeRect.right + 1, clipRect.top, clipRect.right, excludeRect.top - 1); + if (SPLIT_TEST(clipRect, quad3)) { + quad3.Intersect(clipRect); + AddRect(quad3); + } + + Rect quad4(clipRect.left, excludeRect.top, excludeRect.left - 1, excludeRect.bottom); + if (SPLIT_TEST(clipRect, quad4)) { + quad4.Intersect(clipRect); + AddRect(quad4); + } + + Rect quad5(excludeRect.right + 1, excludeRect.top, clipRect.right, excludeRect.bottom); + if (SPLIT_TEST(clipRect, quad5)) { + quad5.Intersect(clipRect); + AddRect(quad5); + } + + Rect quad6(clipRect.left, excludeRect.bottom + 1, excludeRect.left - 1, clipRect.bottom); + if (SPLIT_TEST(clipRect, quad6)) { + quad6.Intersect(clipRect); + AddRect(quad6); + } + + Rect quad7(excludeRect.left, excludeRect.bottom + 1, excludeRect.right, clipRect.bottom); + if (SPLIT_TEST(clipRect, quad7)) { + quad7.Intersect(clipRect); + AddRect(quad7); + } + + Rect quad8(excludeRect.right + 1, excludeRect.bottom + 1, clipRect.right, clipRect.bottom); + if (SPLIT_TEST(clipRect, quad8)) { + quad8.Intersect(clipRect); + AddRect(quad8); + } + + // This rect has been split, remove it. Note we don't + // change the index + RemoveRect(index); + rectsToCheck--; + } + EndOperation(); + return *this; +} + +Region& Region::Exclude(const Region &ex) +{ + BeginOperation(); + Region temp(ex); + temp.Invert(); + Intersect(temp); + EndOperation(); + return *this; +} + + + +Region& Region::Clear() +{ + fNumRects = 0; + AllocSpace(0); + return *this; +} + +Region& Region::ConstrainTo(const Rect &rect) +{ + BeginOperation(); + for (int i = fNumRects - 1; i >= 0; i--) { + fRects[i].left = max(rect.left, fRects[i].left); + fRects[i].right = min(rect.right, fRects[i].right); + fRects[i].top = max(rect.top, fRects[i].top); + fRects[i].bottom = min(rect.bottom, fRects[i].bottom); + if (!fRects[i].Valid()) + RemoveRect(i); + } + + EndOperation(); + return *this; +} + +Region& Region::Translate(int x, int y) +{ + for (int i = 0; i < fNumRects; i++) { + fRects[i].left += x; + fRects[i].right += x; + fRects[i].top += y; + fRects[i].bottom += y; + } + + return *this; +} + +Region& Region::Intersect(const Region &intersectRegion) +{ + BeginOperation(); + Region newRegion; + for (int i = 0; i < fNumRects; i++) { + for (int j = 0; j < intersectRegion.fNumRects; j++) { + if (RectAt(i).Intersects(intersectRegion.RectAt(j))) { + Rect temp(RectAt(i)); + temp.Intersect(intersectRegion.RectAt(j)); + newRegion.AddRect(temp); + } + } + } + + SetTo(newRegion); + EndOperation(); + return *this; +} + +Region& Region::Invert() +{ + BeginOperation(); + Region temp; + temp.Include(Rect(-COORD_MAX, -COORD_MAX, COORD_MAX, COORD_MAX)); + for (int i = 0; i < fNumRects; i++) + temp.Exclude(fRects[i]); + + SetTo(temp); + EndOperation(); + return *this; +} + +const bool Region::FindRect(int x, int y, Rect &outRect) const +{ + for (int i = 0; i < CountRects(); i++) { + if (RectAt(i).Contains(x, y)) { + outRect = RectAt(i); + return true; + } + } + + return false; +} + +void Region::AddRect(const Rect &rect) +{ + AllocSpace(fNumRects + 1); + fRects[fNumRects++] = rect; +} + +void Region::RemoveRect(int index) +{ + fNumRects--; + memcpy(fRects + index, fRects + index + 1, (fNumRects - index) * sizeof(Rect)); + AllocSpace(fNumRects); +} + +void Region::AddRegionRects(const Region &region) +{ + for (int i = 0; i < region.fNumRects; i++) + AddRect(region.RectAt(i)); +} + +void Region::Consolidate() +{ + // Optimize region by consolidating adjacent rectangles. + for (int i = 0; i < fNumRects; i++) { + for (int j = fNumRects - 1; j > i; j--) { + Rect &rect1 = fRects[i]; + Rect &rect2 = fRects[j]; + if (rect1.top == rect2.top && rect1.bottom == rect2.bottom) { + if (rect1.right + 1 == rect2.left) { + rect1.right = rect2.right; + RemoveRect(j); + } else if (rect2.right + 1 == rect1.left) { + rect1.left = rect2.left; + RemoveRect(j); + } + } else if (rect1.left == rect2.left && rect1.right == rect2.right) { + if (rect1.top == rect2.bottom + 1) { + rect1.top = rect2.top; + RemoveRect(j); + } else if (rect1.bottom + 1 == rect2.top) { + rect1.bottom = rect2.bottom; + RemoveRect(j); + } + } + } + } +} + +void Region::AllocSpace(int numRects) +{ + int currentAlloc = ((fNumRects + kRectAllocSize - 1) / kRectAllocSize) + * kRectAllocSize; + int sizeWanted = ((numRects + kRectAllocSize - 1) / kRectAllocSize) + * kRectAllocSize; + + if (sizeWanted != currentAlloc) { + if (fRects == 0 && sizeWanted > 0) + fRects = (Rect*) malloc(sizeWanted * sizeof(Rect)); + else if (sizeWanted == 0 && fRects != 0) { + free(fRects); + fRects = 0; + } else + fRects = (Rect*) realloc(fRects, sizeWanted * sizeof(Rect)); + } +} + + +void Region::BeginOperation() +{ + fOpLevel++; +} + +void Region::EndOperation() +{ + if (--fOpLevel == 0) + Consolidate(); + + ASSERT(fOpLevel >= 0); +} + + + +void Region::Dump() const +{ + printf("Region: "); + for (int i = 0; i < fNumRects; i++) { + if ((i % 6) == 5) + printf("\n"); + printf("(%d %d %d %d) ", fRects[i].left, fRects[i].top, fRects[i].right, + fRects[i].bottom); + } + + printf("\n"); +} diff --git a/srv/window/Region.h b/srv/window/Region.h @@ -0,0 +1,73 @@ +#ifndef _REGION_H +#define _REGION_H + +#include "Rect.h" +#include "assert.h" + +const int COORD_MAX = 0x7ffffff0; + +class Region { +public: + + Region(); + ~Region(); + Region(const Region&); + Region& Clear(); + Region& Include(const Rect&); + Region& Include(const Region&); + Region& Exclude(const Rect&); + Region& Exclude(const Region&); + Region& Invert(); + Region& Intersect(const Region&); + Region& Translate(int x, int y); + Region& ConstrainTo(const Rect&); + Region& SetTo(const Region&); + Region& operator=(const Region&); + + const bool FindRect(int x, int y, Rect &outRect) const; + + Rect Bounds() const; + inline bool Valid() const; + inline int CountRects() const; + const Rect& RectAt(int index) const; + + void Dump() const; + +private: + + void AddRect(const Rect&); + void RemoveRect(int index); + void Consolidate(); + + // Assumes there are no overlaps + void AddRegionRects(const Region&); + + void AllocSpace(int numRects); + + void BeginOperation(); + void EndOperation(); + + Rect *fRects; + int fNumRects; + int fOpLevel; +}; + +inline int Region::CountRects() const +{ + return fNumRects; +} + +inline const Rect& Region::RectAt(int index) const +{ + ASSERT(index < fNumRects); + return fRects[index]; +} + + +inline bool Region::Valid() const +{ + return fNumRects > 0; +} + + +#endif diff --git a/srv/window/Renderer.h b/srv/window/Renderer.h @@ -0,0 +1,67 @@ +#ifndef _RENDERER_H +#define _RENDERER_H + +#include "Rect.h" + +class Renderer { +public: + + inline Renderer(char *baseAddress, int width, int height, int bytesPerRow); + virtual void DrawLine(int x1, int y1, int x2, int y2, char color) = 0; + virtual void FillRect(int x1, int y1, int x2, int y2, char color) = 0; + virtual void Blit(int x, int y, char image[], int image_width, + int image_height, int img_bytes_per_row) = 0; + virtual void StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[], + int imageBytesPerRow) = 0; + virtual void CopyRect(const Rect &source, const Rect &dest) = 0; + + inline Rect Bounds() const; + + inline char *BufferBaseAddress() const; + inline int BufferWidth() const; + inline int BufferHeight() const; + inline int BufferBytesPerRow() const; + +private: + char *fBufferBaseAddress; + int fBufferWidth; + int fBufferHeight; + int fBufferBytesPerRow; +}; + +inline Renderer::Renderer(char *baseAddress, int width, int height, int bytesPerRow) + : fBufferBaseAddress(baseAddress), + fBufferWidth(width), + fBufferHeight(height), + fBufferBytesPerRow(bytesPerRow) +{ +} + +inline char* Renderer::BufferBaseAddress() const +{ + return fBufferBaseAddress; +} + +inline int Renderer::BufferWidth() const +{ + return fBufferWidth; +} + +inline int Renderer::BufferHeight() const +{ + return fBufferHeight; +} + +inline int Renderer::BufferBytesPerRow() const +{ + return fBufferBytesPerRow; +} + +inline Rect Renderer::Bounds() const +{ + return Rect(0, 0, fBufferWidth - 1, fBufferHeight - 1); +} + + + +#endif diff --git a/srv/window/Renderer_8bpp.cpp b/srv/window/Renderer_8bpp.cpp @@ -0,0 +1,233 @@ +#include "Renderer_8bpp.h" +#include "assert.h" + +Renderer_8bpp::Renderer_8bpp(char *baseAddress, int width, int height, int bytesPerRow) + : Renderer(baseAddress, width, height, bytesPerRow) +{ +} + +const unsigned kBottom = 1; +const unsigned kTop = 2; +const unsigned kLeft = 4; +const unsigned kRight = 8; + +#define clipmask(x, y, rect) \ + ({ unsigned mask = 0; \ + if (x < rect.left) mask |= kLeft; \ + else if (x > rect.right) mask |= kRight; \ + if (y < rect.top) mask |= kTop; \ + else if (y > rect.bottom) mask |= kBottom; \ + mask;}) + +void Renderer_8bpp::DrawLine(int x1, int y1, int x2, int y2, char color) +{ + ASSERT(x1 >= 0 && x1 < BufferWidth()); + ASSERT(x2 >= 0 && x2 < BufferWidth()); + ASSERT(y1 >= 0 && y1 < BufferWidth()); + ASSERT(y2 >= 0 && y2 < BufferWidth()); + + // Swap if necessary so we always draw top to bottom + if (y1 > y2) { + int temp = y1; + y1 = y2; + y2 = temp; + + temp = x1; + x1 = x2; + x2 = temp; + } + + int deltaY = y2 - y1; + int deltaX = x2 > x1 ? x2 - x1 : x1 - x2; + int xDir = x2 > x1 ? 1 : -1; + int error = 0; + char *ptr = BufferBaseAddress() + x1 + y1 * BufferBytesPerRow(); + + if (deltaX == 0) { + // Vertical line + for (int y = deltaY; y >= 0; y--) { + *ptr = color; + ptr += BufferBytesPerRow(); + } + } else if (deltaY == 0) { + // Horizontal line + for (int x = deltaX; x >= 0; x--) { + *ptr = color; + ptr += xDir; + } + } else if (deltaX > deltaY) { + // Diagonal with horizontal major axis + x2 += xDir; // Want to quit on pixel past last. Ugly, I know. + for (int x = x1; x != x2; x += xDir) { + *ptr = color; + + error += deltaY; + if (error > deltaX) { + ptr += BufferBytesPerRow(); + error -= deltaX; + } + + ptr += xDir; + } + } else { + // Diagonal with vertical major axis + for (int y = y1; y <= y2; y++) { + *ptr = color; + + error += deltaX; + if (error > deltaY) { + ptr += xDir; + error -= deltaY; + } + + ptr += BufferBytesPerRow(); + } + } +} + +void Renderer_8bpp::FillRect(int x1, int y1, int x2, int y2, char color) +{ + ASSERT(x1 >= 0 && x1 <= BufferWidth()); + ASSERT(x2 >= 0 && x2 <= BufferWidth()); + ASSERT(y1 >= 0 && y1 <= BufferWidth()); + ASSERT(y2 >= 0 && y2 <= BufferWidth()); + ASSERT(x2 >= x1); + ASSERT(y2 >= y1); + + char *ptr = BufferBaseAddress() + x1 + y1 * BufferBytesPerRow(); + unsigned int longcolor = (unsigned int)(unsigned char)color | ((unsigned int)(unsigned char)color << 8) | + ((unsigned int)(unsigned char)color << 16) | ((unsigned int)(unsigned char)color << 24); + + int wrap = BufferBytesPerRow() - (x2 - x1) - 1; + for (int y = y1; y <= y2; y++) { + int x = x1; + while (x <= x2 && (x & 3) != 0) { + *ptr++ = color; + x++; + } + + while (x + 4 <= x2) { + *((long*) ptr) = longcolor; + ptr += 4; + x += 4; + } + + while (x <= x2) { + *ptr++ = color; + x++; + } + + ptr += wrap; + } +} + +void Renderer_8bpp::Blit(int x, int y, char image[], int imageWidth, + int imageHeight, int imageBytesPerRow) +{ + ASSERT(x >= 0 && x + imageWidth <= BufferWidth()); + ASSERT(y >= 0 && y + imageHeight <= BufferWidth()); + + char *screen_ptr = BufferBaseAddress() + x + y * BufferBytesPerRow(); + char *image_ptr = image; + int imageOffs = imageBytesPerRow - imageWidth; + int screenOffs = BufferBytesPerRow() - imageWidth; + + for (int i = 0; i < imageHeight; i++) { + for (int j = 0; j < imageWidth; j++) { + if ((unsigned char) *image_ptr != 0xff) + *screen_ptr = *image_ptr; + + screen_ptr++; + image_ptr++; + } + + image_ptr += imageOffs; + screen_ptr += screenOffs; + } +} + +void Renderer_8bpp::StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[], + int imageBytesPerRow) +{ + ASSERT(imageRect.Valid()); + ASSERT(displayRect.Valid()); + ASSERT(imageRect.left >= 0); + ASSERT(imageRect.top >= 0); + ASSERT(imageRect.right < imageBytesPerRow); + + int verror = 0; + char *screen_ptr = BufferBaseAddress() + displayRect.left + displayRect.top + * BufferBytesPerRow(); + char *current_image_line = image + imageRect.left + imageRect.top * + imageBytesPerRow; + int screenOffs = BufferBytesPerRow() - displayRect.Width() - 1; + + for (int y = displayRect.top; y <= displayRect.bottom; y++) { + char *image_ptr = current_image_line; + int herror = 0; + for (int x = displayRect.left; x <= displayRect.right; x++) { + if ((unsigned char) *image_ptr != 0xff) + *screen_ptr = *image_ptr; + + herror += imageRect.Width(); + while (herror >= displayRect.Width()) { + herror -= displayRect.Width(); + image_ptr++; + } + + screen_ptr++; + } + + verror += imageRect.Height(); + while (verror > displayRect.Height()) { + verror -= displayRect.Height(); + current_image_line += imageBytesPerRow; + } + + screen_ptr += screenOffs; + } +} + +void Renderer_8bpp::CopyRect(const Rect &source, const Rect &dest) +{ + ASSERT(source.Width() == dest.Width()); + ASSERT(source.Height() == dest.Height()); + + int dX; + int dY; + int startX; + int startY; + if (dest.left > source.left && dest.left < source.right) { + // overlap left side, copy backward + dX = -1; + startX = source.right; + } else { + dX = 1; + startX = source.left; + } + + if (dest.top > source.top && dest.top < source.bottom) { + // overlap bottom, copy top up + dY = -(BufferBytesPerRow() + dX * (source.Width() + 1)); + startY = source.bottom; + } else { + dY = (BufferBytesPerRow() - dX * (source.Width() - 1)); + startY = source.top; + } + + char *srcptr = BufferBaseAddress() + startX + startY * BufferBytesPerRow(); + int offset = (dest.left - source.left) + (dest.top - source.top) + * BufferBytesPerRow(); + + for (int y = source.top; y <= source.bottom; y++) { + for (int x = source.left; x <= source.right; x++) { + *((char*) srcptr + offset) = *srcptr; + srcptr += dX; + } + + srcptr += dY; + } +} + + + diff --git a/srv/window/Renderer_8bpp.h b/srv/window/Renderer_8bpp.h @@ -0,0 +1,20 @@ +#ifndef _RENDERER_8BPP_H +#define _RENDERER_8BPP_H + +#include "Renderer.h" +#include "Rect.h" + +class Renderer_8bpp : public Renderer { +public: + Renderer_8bpp(char *baseAddress, int width, int height, int bytesPerRow); + void DrawLine(int x1, int y1, int x2, int y2, char color); + void FillRect(int x1, int y1, int x2, int y2, char color); + void Blit(int x, int y, char image[], int image_width, + int image_height, int img_bytes_per_row); + void StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[], + int imageBytesPerRow); + void CopyRect(const Rect &source, const Rect &dest); +}; + + +#endif diff --git a/srv/window/Renderer_vga.cpp b/srv/window/Renderer_vga.cpp @@ -0,0 +1,230 @@ +#include "Renderer_vga.h" +#include "assert.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +const unsigned char kCursorBits [] = { + 0x3f,0x3f,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x3f,0x3f,0x3f,0x3f,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x3f,0x3f,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x3f,0x3f,0x3f,0xff,0x3f,0x00,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x00,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +}; + +Renderer_vga::Renderer_vga(char *baseAddress, int width, int height, int bytesPerRow) + : Renderer_8bpp(baseAddress, width, height, bytesPerRow) +{ + fCursorX = width / 2; + fCursorY = height / 2; + DrawCursor(); +} + +const unsigned kBottom = 1; +const unsigned kTop = 2; +const unsigned kLeft = 4; +const unsigned kRight = 8; + +#define clipmask(x, y, rect) \ + ({ unsigned mask = 0; \ + if (x < rect.left) mask |= kLeft; \ + else if (x > rect.right) mask |= kRight; \ + if (y < rect.top) mask |= kTop; \ + else if (y > rect.bottom) mask |= kBottom; \ + mask;}) + +inline int vert_intersection(int x1, int y1, int x2, int y2, int x) +{ + return y1 + (y2 - y1) * (x - x1) / (x2 - x1); +} + +inline int horz_intersection(int x1, int y1, int x2, int y2, int y) +{ + return x1 + (x2 - x1) * (y - y1) / (y2 - y1); +} + +void Renderer_vga::DrawLine(int x1, int y1, int x2, int y2, char color) +{ + Rect cursorRect(fCursorX, fCursorY, fCursorX + 16, fCursorY + 16); + bool invalidateCursor = true; + + int clippedX1 = x1; + int clippedY1 = y1; + int clippedX2 = x2; + int clippedY2 = y2; + unsigned point1mask = clipmask(clippedX1, clippedY1, cursorRect); + unsigned point2mask = clipmask(clippedX2, clippedY2, cursorRect); + while (point1mask != 0 || point2mask != 0) { + if ((point1mask & point2mask) != 0) { + invalidateCursor = false; + break; + } + + unsigned mask = point1mask ? point1mask : point2mask; + int x = 0; + int y = 0; + if (mask & kBottom) { + y = cursorRect.bottom; + x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y); + } else if (mask & kTop) { + y = cursorRect.top; + x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y); + } else if (mask & kRight) { + x = cursorRect.right; + y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x); + } else if (mask & kLeft) { + x = cursorRect.left; + y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x); + } + + if (point1mask) { + // Clip point 1 + point1mask = clipmask(x, y, cursorRect); + clippedX1 = x; + clippedY1 = y; + } else { + // Clip point 2 + point2mask = clipmask(x, y, cursorRect); + clippedX2 = x; + clippedY2 = y; + } + } + + if (invalidateCursor) + EraseCursor(); + + Renderer_8bpp::DrawLine(x1, y1, x2, y2, color); + + if (invalidateCursor) + DrawCursor(); +} + +void Renderer_vga::FillRect(int x1, int y1, int x2, int y2, char color) +{ + + bool invalidateCursor = false; + if (Rect(x1, y1, x2, y2).Intersects(Rect(fCursorX, fCursorY, fCursorX + 16, + fCursorY + 16))) { + invalidateCursor = true; + EraseCursor(); + } + + Renderer_8bpp::FillRect(x1, y1, x2, y2, color); + if (invalidateCursor) + DrawCursor(); +} + +void Renderer_vga::Blit(int x, int y, char image[], int imageWidth, + int imageHeight, int imageBytesPerRow) +{ + + bool invalidateCursor = false; + if (Rect(x, y, x + imageWidth, y + imageHeight).Intersects(Rect(fCursorX, + fCursorY, fCursorX + 16, fCursorY + 16))) { + invalidateCursor = true; + EraseCursor(); + } + + Renderer_8bpp::Blit(x, y, image, imageWidth, imageHeight, imageBytesPerRow); + if (invalidateCursor) + DrawCursor(); +} + +void Renderer_vga::StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[], + int imageBytesPerRow) +{ + + bool invalidateCursor = false; + if (displayRect.Intersects(Rect(fCursorX, fCursorY, fCursorX + 16, + fCursorY + 16))) { + invalidateCursor = true; + EraseCursor(); + } + + Renderer_8bpp::StretchBlit(imageRect, displayRect, image, imageBytesPerRow); + + if (invalidateCursor) + DrawCursor(); +} + +void Renderer_vga::CopyRect(const Rect &source, const Rect &dest) +{ + bool invalidateCursor = false; + Rect cursorRect(fCursorX, fCursorY, fCursorX + 16, fCursorY + 16); + if (cursorRect.Intersects(source) || cursorRect.Intersects(dest)) { + invalidateCursor = true; + EraseCursor(); + } + + Renderer_8bpp::CopyRect(source, dest); + if (invalidateCursor) + DrawCursor(); +} + +void Renderer_vga::SetCursorPosition(int x, int y) +{ + EraseCursor(); + fCursorX = x; + fCursorY = y; + DrawCursor(); +} + +void Renderer_vga::EraseCursor() +{ + char *screen_ptr = BufferBaseAddress() + fCursorX + fCursorY * BufferBytesPerRow(); + char *saveBackground = fSavedBackground; + int cursorDisplayWidth = MIN(16, BufferBytesPerRow() - fCursorX); + int cursorDisplayHeight = MIN(16, BufferHeight() - fCursorY); + int stride = BufferBytesPerRow() - cursorDisplayWidth; + + for (int y = 0; y < cursorDisplayHeight; y++) { + for (int x = 0; x < cursorDisplayWidth; x++) { + if ((unsigned char) *saveBackground != 0xff) + *screen_ptr = *saveBackground; + + screen_ptr++; + saveBackground++; + } + + screen_ptr += stride; + saveBackground += 16 - cursorDisplayWidth; + } +} + +void Renderer_vga::DrawCursor() +{ + char *screen_ptr = BufferBaseAddress() + fCursorX + fCursorY * BufferBytesPerRow(); + char *cursorImage = (char *) kCursorBits; + char *saveBackground = fSavedBackground; + int cursorDisplayWidth = MIN(16, BufferBytesPerRow() - fCursorX); + int cursorDisplayHeight = MIN(16, BufferHeight() - fCursorY); + int stride = BufferBytesPerRow() - cursorDisplayWidth; + + for (int y = 0; y < cursorDisplayHeight; y++) { + for (int x = 0; x < cursorDisplayWidth; x++) { + if ((unsigned char) *cursorImage != 0xff) { + *saveBackground = *screen_ptr; + *screen_ptr = *cursorImage; + } else + *saveBackground = 0xff; + + screen_ptr++; + cursorImage++; + saveBackground++; + } + + screen_ptr += stride; + cursorImage += 16 - cursorDisplayWidth; + saveBackground += 16 - cursorDisplayWidth; + } +} diff --git a/srv/window/Renderer_vga.h b/srv/window/Renderer_vga.h @@ -0,0 +1,30 @@ +#ifndef _RENDERER_VGA_H +#define _RENDERER_VGA_H + +#include <blt/qsem.h> +#include "Renderer_8bpp.h" +#include "Rect.h" + +class Renderer_vga : public Renderer_8bpp { +public: + Renderer_vga(char *baseAddress, int width, int height, int bytesPerRow); + void DrawLine(int x1, int y1, int x2, int y2, char color); + void FillRect(int x1, int y1, int x2, int y2, char color); + void Blit(int x, int y, char image[], int image_width, + int image_height, int img_bytes_per_row); + void StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[], + int imageBytesPerRow); + void CopyRect(const Rect &source, const Rect &dest); + + void SetCursorPosition(int x, int y); + +private: + void EraseCursor(); + void DrawCursor(); + + char fSavedBackground[256]; + int fCursorX, fCursorY; +}; + + +#endif diff --git a/srv/window/SerialMouse.cpp b/srv/window/SerialMouse.cpp @@ -0,0 +1,86 @@ +#include <i386/io.h> +#include <blt/syscall.h> +#include <stdio.h> +#include "SerialMouse.h" +#include "util.h" + +#define POLL 1 + +const int kBaudRate = 1200; +const int kPortBase = 0x3f8; + +SerialMouse::SerialMouse(int xmax, int ymax) + : fXPos(xmax / 2), + fYPos(ymax / 2), + fXMax(xmax), + fYMax(ymax) +{ + unsigned short divisor = 115200 / kBaudRate; + + outb(0, kPortBase + 1); // No interrupts for now + outb(0, kPortBase + 4); // clear DTR and RTS + + outb(0x80, kPortBase + 3); // load divisor latch + outb((divisor & 0xff), kPortBase); // divisor LSB + outb((divisor >> 8), kPortBase + 1); // divisor MSB + outb(2, kPortBase + 3); // clear DLAB, set up for 7N1 + + outb(3, kPortBase + 4); // Say hello. Raise DTR and RTS + if (SerialRead() == 'M') + printf("Detected MS serial mouse\n"); +} + + +// The data is sent in 3 byte packets in following format: +// D7 D6 D5 D4 D3 D2 D1 D0 +// 1. X 1 LB RB Y7 Y6 X7 X6 +// 2. X 0 X5 X4 X3 X2 X1 X0 +// 3. X 0 Y5 Y4 Y3 Y2 Y1 Y0 +void SerialMouse::GetPos(int *out_x, int *out_y, int *out_buttons) +{ + char b1; + + // loop until we get to the beginning of a packet + while (true) { + b1 = SerialRead(); + if ((b1 & (1 << 6)) != 0) + break; // beginning of packet + } + + char b2 = SerialRead(); + char b3 = SerialRead(); + + fXPos += (int)(char)((b1 << 6) | (b2 & 0x3f)); + fYPos += (int)(char)(((b1 << 4) & 0xc0) | (b3 & 0x3f)); + + fXPos = min(fXPos, fXMax); + fXPos = max(fXPos, 0); + fYPos = min(fYPos, fYMax); + fYPos = max(fYPos, 0); + + *out_buttons = (b1 >> 4) & 3; + *out_x = fXPos; + *out_y = fYPos; +} + +unsigned char SerialMouse::SerialRead() +{ + while (true) { +#if POLL + while ((inb(kPortBase + 5) & 1) == 0) + ; +#else + os_handle_irq(4); + outb(1, kPortBase + 1); // Interrupt on recieve ready + os_sleep_irq(); + int id = inb(kPortBase + 2); + if ((id & 1) == 0 || (id >> 1) != 2) + continue; // Not for me +#endif + + break; + } + + return inb(kPortBase); +} + diff --git a/srv/window/SerialMouse.h b/srv/window/SerialMouse.h @@ -0,0 +1,24 @@ +#ifndef _SERIAL_MOUSE_H +#define _SERIAL_MOUSE_H + +struct mouse_data_packet; + +const int MAIN_BUTTON = 1; +const int SECONDARY_BUTTON = 2; + +class SerialMouse { +public: + + SerialMouse(int xmax, int ymax); + void GetPos(int *out_x, int *out_y, int *out_buttons); + +private: + + unsigned char SerialRead(); + + int fXPos, fYPos; + int fXMax, fYMax; +}; + + +#endif diff --git a/srv/window/Window.cpp b/srv/window/Window.cpp @@ -0,0 +1,303 @@ +#include <blt/syscall.h> +#include <blt/os.h> +#include <stdio.h> +#include <win/Event.h> +#include "assert.h" +#include "Window.h" + +Window::Window(int id, int eventPort, Renderer *renderer) + : fID(id), + fNextSibling(0), + fPreviousSibling(0), + fChildList(0), + fParent(0), + fIsVisible(false), + fEventPort(eventPort), + fPaintMsgSent(false), + fColor(0) +{ + if (renderer) { + // I am being attached directly to a renderer. My clip + // region is the bounds of the renderer. + fGC.SetRenderer(renderer); + fFrame = renderer->Bounds(); + fVisibleRegion.Clear(); + fVisibleRegion.Include(fFrame); + fClipRegion = fVisibleRegion; + fGC.SetClipRegion(fClipRegion); + } +} + +Window::~Window() +{ + if (fParent) + fParent->RemoveChild(this); +} + +Window* Window::ChildAtPoint(int x, int y) +{ + // See what child is covering me at this point + for (Window *child = fChildList; child; child = child->fNextSibling) { + if (child->Frame().Contains(x, y)) + return child->ChildAtPoint(x - child->Frame().left, y - child->Frame().top); + } + + return this; // I guess that's me! +} + +void Window::UpdateClipRegion() +{ + Region newClipRegion = fVisibleRegion; + Rect myScreenFrame = LocalToScreen(Bounds()); + + // Walk the child list. It is ordered from front to back. + for (Window *child = fChildList; child; child = child->fNextSibling) { + // Ship hidden children (and effectively all their descendents). + if (!child->IsVisible()) { + Region empty; + child->SetVisibleRegion(empty); + continue; + } + + // My children are obscured both by my siblings and theirs. + // Create a new region. Note that fClipRegion is initialized as + // my visible region (that is, parts of me that aren't clipped by + // my siblings). With iteration, each child window is excluded + // from it, so this clips my children against each other. + Region childClipRegion = newClipRegion; + Rect childScreenFrame = LocalToScreen(child->Frame()); + childClipRegion.ConstrainTo(childScreenFrame); + child->SetVisibleRegion(childClipRegion); + + // I am obscured by my child windows, remove them from my clip + // region. + newClipRegion.Exclude(childScreenFrame); + } + + // Handle exposures. + // 1. Invert the old clipping region to find + // which parts of the window were previously hidden. + // 2. Intersect that with the new clipping region to find areas + // that have become visible. + Region exposedRegion = fClipRegion; + exposedRegion.Invert(); + exposedRegion.Intersect(newClipRegion); + + if (exposedRegion.Valid()) + Invalidate(exposedRegion); + + // Now set the new clip region for this window. + fClipRegion = newClipRegion; + fGC.SetClipRegion(fClipRegion); + fGC.SetOrigin(myScreenFrame.left, myScreenFrame.top); +} + +void Window::AddChild(const Rect &frame, Window *child) +{ + child->fFrame = frame; + child->fGC.SetRenderer(fGC.GetRenderer()); + + child->fNextSibling = fChildList; + child->fPreviousSibling = &fChildList; + if (fChildList) + fChildList->fPreviousSibling = &child->fNextSibling; + + fChildList = child; + child->fParent = this; + if (child->IsVisible()) + UpdateClipRegion(); +} + +void Window::RemoveChild(Window *window) +{ + ASSERT(window->parent == this); + ASSERT(window->fPreviousSibling); + + *window->fPreviousSibling = window->fNextSibling; + fParent = 0; + + // Should remove all of its children + + UpdateClipRegion(); +} + +void Window::MoveToFront() +{ + fParent->RemoveChild(this); + fParent->AddChild(fFrame, this); + UpdateClipRegion(); +} + +void Window::SetVisibleRegion(const Region &region) +{ + fVisibleRegion = region; + UpdateClipRegion(); + + if (fInRedraw) { + Region drawRegion = fCurrentRedrawRegion; + drawRegion.Intersect(fClipRegion); + fGC.SetClipRegion(drawRegion); + } else + fGC.SetClipRegion(fClipRegion); +} + +const Region& Window::ClipRegion() const +{ + return fClipRegion; +} + +void Window::MoveTo(long x, long y) +{ + fFrame.OffsetTo(x, y); + UpdateClipRegion(); +} + +void Window::ResizeTo(long width, long height) +{ + fFrame.right = fFrame.left + width; + fFrame.bottom = fFrame.top + height; + UpdateClipRegion(); +} + +void Window::Invalidate(const Region &region) +{ + // Erase background + for (int rect = 0; rect < region.CountRects(); rect++) { + const Rect &clipRect = region.RectAt(rect); + fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right, + clipRect.bottom, Color()); + } + + fInvalidRegion.Include(region); + if (!fPaintMsgSent) { + Event paintEvent; + paintEvent.what = EVT_PAINT; + PostEvent(&paintEvent); + fPaintMsgSent = true; + } +} + +void Window::Invalidate(const Rect &rect) +{ + Rect screenRect(LocalToScreen(rect)); + + // Erase background + Region eraseRegion(fVisibleRegion); + Region invalRegion; + invalRegion.Include(screenRect); + eraseRegion.Intersect(invalRegion); + for (int index = 0; index < eraseRegion.CountRects(); index++) { + const Rect &clipRect = eraseRegion.RectAt(index); + fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right, + clipRect.bottom, Color()); + } + + // The rect is assumed to be in window coordinates + fInvalidRegion.Include(screenRect); + if (!fPaintMsgSent) { + Event paintEvent; + paintEvent.what = EVT_PAINT; + PostEvent(&paintEvent); + fPaintMsgSent = true; + } +} + +GraphicsContext& Window::GC() +{ + return fGC; +} + +void Window::BeginPaint(Rect &out_invalidRect) +{ + fPaintMsgSent = false; + fInRedraw = true; + fCurrentRedrawRegion = fInvalidRegion; + fInvalidRegion.Clear(); + + Region drawRegion = fCurrentRedrawRegion; + drawRegion.Intersect(fClipRegion); + out_invalidRect = ScreenToLocal(drawRegion.Bounds()); + fGC.SetClipRegion(drawRegion); +} + +void Window::EndPaint() +{ + fInRedraw = false; +} + +bool Window::IsVisible() const +{ + return fIsVisible; +} + +char Window::Color() const +{ + return fColor; +} + +void Window::SetColor(char c) +{ + fColor = c; +} + +void Window::Show() +{ + if (!fIsVisible) { + fIsVisible = true; + if (fParent) + fParent->UpdateClipRegion(); + } +} + +void Window::Hide() +{ + if (fIsVisible) { + fIsVisible = false; + if (fParent) + fParent->UpdateClipRegion(); + } +} + +void Window::PostEvent(Event *event) +{ + event->target = fID; + + msg_hdr_t header; + header.src = fEventPort; // May break someday + header.dst = fEventPort; + header.data = event; + header.size = sizeof(Event); + old_port_send(&header); +} + +Rect Window::LocalToScreen(const Rect &inRect) const +{ + Rect outRect = inRect; + for (const Window *window = this; window; window = window->fParent) + outRect.OffsetBy(window->fFrame.left, window->fFrame.top); + + return outRect; +} + +Rect Window::ScreenToLocal(const Rect &inRect) const +{ + Rect outRect = inRect; + for (const Window *window = this; window; window = window->fParent) + outRect.OffsetBy(-window->fFrame.left, -window->fFrame.top); + + return outRect; +} + +void Window::DumpChildList(int level) +{ + for (int i = 0; i < level; i++) + printf(" | "); + + Rect frame = Frame(); + printf(" + %d %d %d %d\n", frame.left, frame.top, frame.right, frame.bottom); + for (Window *child = fChildList; child; child = child->fNextSibling) + child->DumpChildList(level + 1); +} + + + diff --git a/srv/window/Window.h b/srv/window/Window.h @@ -0,0 +1,103 @@ +#ifndef _WINDOW_H +#define _WINDOW_H + +#include "Region.h" +#include "GraphicsContext.h" + +class Event; + +class Window { +public: + + Window(int id, int eventPort, Renderer *renderer = 0); + ~Window(); + void AddChild(const Rect& frame, Window *window); + void RemoveChild(Window *window); + void MoveToFront(); + inline int ID() const; + + Window *ChildAtPoint(int x, int y); + + Rect LocalToScreen(const Rect&) const; + Rect ScreenToLocal(const Rect&) const; + + void SetVisibleRegion(const Region&); + inline const Rect& Frame() const; + inline Rect Bounds() const; + + const Region& InvalidRegion() const; + const Region& ClipRegion() const; + void Invalidate(const Region&); + void Invalidate(const Rect&); + void BeginPaint(Rect &out_invalidRect); + void EndPaint(); + GraphicsContext& GC(); + void ResetGC(); + bool IsVisible() const; + char Color() const; + void SetColor(char); + void Show(); + void Hide(); + void PostEvent(Event*); + + void DumpChildList(int level = 0); + +private: + void UpdateClipRegion(); + void MoveTo(long, long); + void ResizeTo(long, long); + + int fID; + Window *fNextSibling; + Window **fPreviousSibling; + Window *fChildList; + Window *fParent; + + Region fInvalidRegion; + Region fCurrentRedrawRegion; + + // The visible region represents what part of this window is not + // obscured by siblings of my parent. I maintain this + // when recomputing clipping for my children. + Region fVisibleRegion; + + // The clip region is the visible region, minus parts of my window + // that are obscured by my children. + Region fClipRegion; + + Rect fFrame; + GraphicsContext fGC; + bool fIsVisible; + bool fInRedraw; + int fEventPort; + bool fPaintMsgSent; + char fColor; +}; + +inline int Window::ID() const +{ + return fID; +} + +inline const Rect& Window::Frame() const +{ + return fFrame; +} + +inline Rect Window::Bounds() const +{ + Rect rect(fFrame); + rect.OffsetTo(0, 0); + return rect; +} + +inline const Region& Window::InvalidRegion() const +{ + return fInvalidRegion; +} + + + + +#endif + diff --git a/srv/window/WindowManager.cpp b/srv/window/WindowManager.cpp @@ -0,0 +1,524 @@ +#include <blt/os.h> +#include <blt/syscall.h> +#include <blt/namer.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <win/Event.h> + +#include "WindowManager.h" +#include "Renderer.h" +#include "Window.h" +#include "protocol.h" +#include "SerialMouse.h" +#include "Renderer_vga.h" + +const int kReceiveBufferSize = 16384; +const int kMaxStrLen = 256; + +WindowManager::WindowManager(Renderer *screenRenderer) + : fNextWindowID(1), + fReceiveBufferSize(0), + fReceiveBufferPos(0), + fCurrentMouseFocus(0), + fMouseFocusLocked(false), + fInFocusLockedWindow(false), + fScreenRenderer(screenRenderer) +{ + fReceiveBuffer = (char*) malloc(kReceiveBufferSize); + for (int i = 0; i < kMaxWindows; i++) + fWindowArray[i] = 0; + + // Create the root window, which has an id of 0. + fWindowArray[0] = new Window(0, -1, screenRenderer); + Region screen; + screen.Include(screenRenderer->Bounds()); + fWindowArray[0]->SetVisibleRegion(screen); + + fCursorLock = qsem_create(1); + + thr_create((void*) StartDispatchThread, this, "draw_thread"); + thr_create((void*) StartMouseThread, this, "mouse_thread"); +} + +WindowManager::~WindowManager() +{ + qsem_destroy(fCursorLock); +} + +Window* WindowManager::CreateWindow(Window *parent, const Rect &rect, int eventPort) +{ + while (fWindowArray[fNextWindowID % kMaxWindows] != 0) + fNextWindowID++; + + Window *window = new Window(fNextWindowID, eventPort); + fWindowArray[fNextWindowID % kMaxWindows] = window; + fNextWindowID++; + + parent->AddChild(rect, window); + return window; +} + +void WindowManager::InvalidateMouseBoundries() +{ + fMouseBoundries.SetTo(-1, -1, -1, -1); +} + + +void WindowManager::DestroyWindow(Window *window) +{ + fWindowArray[window->ID() % kMaxWindows] = 0; + delete window; +} + +Window* WindowManager::LookupWindow(int id) +{ + Window *window = fWindowArray[id % kMaxWindows]; + if (window && window->ID() == id) + return window; + + return 0; +} + +Window* WindowManager::WindowAtPoint(int x, int y) +{ + Window *root = LookupWindow(0); + return root->ChildAtPoint(x, y); +} + +int WindowManager::StartDispatchThread(void *windowManager) +{ + ((WindowManager*) windowManager)->DispatchThread(); + return 0; +} + +void WindowManager::ReadServicePort(void *data, int size) +{ + int sizeRead = 0; + while (sizeRead < size) { + int sizeToRead = size - sizeRead; + + if (fReceiveBufferSize - fReceiveBufferPos < sizeToRead) + sizeToRead = fReceiveBufferSize - fReceiveBufferPos; + + if (sizeToRead == 0) { + msg_hdr_t header; + header.src = 0; + header.dst = fServicePort; + header.data = fReceiveBuffer; + header.size = kReceiveBufferSize; + + fReceiveBufferSize = old_port_recv(&header); + fReceiveBufferPos = 0; + fRequestorPort = header.src; + continue; + } + + memcpy((void*) ((char*) data + sizeRead), + (void*) (fReceiveBuffer + fReceiveBufferPos), sizeToRead); + fReceiveBufferPos += sizeToRead; + sizeRead += sizeToRead; + } +} + +void WindowManager::Respond(void *data, int size) +{ + msg_hdr_t header; + header.src = fServicePort; + header.dst = RequestorPort(); + header.data = data; + header.size = size; + old_port_send(&header); +} + +int WindowManager::ReadInt32() +{ + int outval; + ReadServicePort(&outval, 4); + return outval; +} + +short WindowManager::ReadInt16() +{ + short outval; + ReadServicePort(&outval, 2); + return outval; +} + +char WindowManager::ReadInt8() +{ + char outval; + ReadServicePort(&outval, 1); + return outval; +} + +int WindowManager::RequestorPort() const +{ + return fRequestorPort; +} + +void WindowManager::LockCursor() +{ + qsem_acquire(fCursorLock); +} + +void WindowManager::UnlockCursor() +{ + qsem_release(fCursorLock); +} + +void WindowManager::DispatchThread() +{ + fServicePort = port_create(0, "window_server"); + + namer_register(fServicePort, "window_server"); + + while (true) { + int opcode = ReadInt8(); + switch (opcode) { + case OP_DRAW_LINE: { + long windowID = ReadInt32(); + long x1 = ReadInt32(); + long y1 = ReadInt32(); + long x2 = ReadInt32(); + long y2 = ReadInt32(); + + Window *targetWindow = LookupWindow(windowID); + LockCursor(); + if (targetWindow) + targetWindow->GC().DrawLine(x1, y1, x2, y2); + UnlockCursor(); + + break; + } + + case OP_FILL_RECT: { + long windowID = ReadInt32(); + long x1 = ReadInt32(); + long y1 = ReadInt32(); + long x2 = ReadInt32(); + long y2 = ReadInt32(); + Window *targetWindow = LookupWindow(windowID); + LockCursor(); + if (targetWindow) + targetWindow->GC().FillRect(x1, y1, x2, y2); + UnlockCursor(); + + break; + } + + case OP_SET_PEN_COLOR: { + long windowID = ReadInt32(); + char color = ReadInt8(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + targetWindow->GC().SetColor(color); + + break; + } + + case OP_SET_BG_COLOR: { + long windowID = ReadInt32(); + char color = ReadInt8(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) { + targetWindow->SetColor(color); + targetWindow->Invalidate(targetWindow->Bounds()); + } + + break; + } + + case OP_DRAW_STRING: { + // Draw string + long windowID = ReadInt32(); + long x = ReadInt32(); + long y = ReadInt32(); + + char buf[kMaxStrLen + 1]; + char c; + int index = 0; + while (true) { + c = ReadInt8(); + if (c == 0) + break; + + if (index < kMaxStrLen) + buf[index++] = c; + } + + buf[index] = 0; + Window *targetWindow = LookupWindow(windowID); + LockCursor(); + if (targetWindow) + targetWindow->GC().DrawString(x, y, buf); + + UnlockCursor(); + } + + case OP_DESTROY_WINDOW: { + long windowID = ReadInt32(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + DestroyWindow(targetWindow); + + InvalidateMouseBoundries(); + break; + } + + case OP_SHOW_WINDOW: { + long windowID = ReadInt32(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + targetWindow->Show(); + + InvalidateMouseBoundries(); + break; + } + + case OP_HIDE_WINDOW: { + long windowID = ReadInt32(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + targetWindow->Hide(); + + InvalidateMouseBoundries(); + break; + } + + case OP_MAKE_FOCUS: { + long windowID = ReadInt32(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + targetWindow->MoveToFront(); + + InvalidateMouseBoundries(); + break; + } + + case OP_BEGIN_PAINT: { + long windowID = ReadInt32(); + Rect rect; + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + targetWindow->BeginPaint(rect); + + Respond(&rect, sizeof(rect)); + break; + } + + case OP_END_PAINT: { + long windowID = ReadInt32(); + Window *targetWindow = LookupWindow(windowID); + if (targetWindow) + targetWindow->EndPaint(); + + break; + } + + case OP_CREATE_WINDOW: { + long parentWindow = ReadInt32(); + Rect rect; + rect.left = ReadInt32(); + rect.top = ReadInt32(); + rect.right = ReadInt32(); + rect.bottom = ReadInt32(); + long eventPort = ReadInt32(); + + Window *parent = LookupWindow(parentWindow); + int id = -1; + LockCursor(); + if (parent) + id = CreateWindow(parent, rect, eventPort)->ID(); + UnlockCursor(); + + Respond(&id, sizeof(id)); + InvalidateMouseBoundries(); + break; + } + + case OP_COPY_RECT: { + long windowID = ReadInt32(); + Rect sourceRect; + sourceRect.left = ReadInt32(); + sourceRect.top = ReadInt32(); + sourceRect.right = ReadInt32(); + sourceRect.bottom = ReadInt32(); + + long destX = ReadInt32(); + long destY = ReadInt32(); + Rect destRect(sourceRect); + destRect.OffsetTo(destX, destY); + + Window *targetWindow = LookupWindow(windowID); + LockCursor(); + if (targetWindow) { + Region invalidateRegion; + if (targetWindow->InvalidRegion().Valid()) { + // Parts of the window are damaged and can't be copied. + Region copyRegion = targetWindow->ClipRegion(); + copyRegion.Exclude(targetWindow->InvalidRegion()); + targetWindow->GC().CopyRect(sourceRect, destRect, + copyRegion, invalidateRegion); + } else { + targetWindow->GC().CopyRect(sourceRect, destRect, + targetWindow->ClipRegion(), invalidateRegion); + } + + // Draw parts of the window which have been "copied" + // out from under another window. + targetWindow->Invalidate(invalidateRegion); + } + UnlockCursor(); + + break; + } + + case OP_INVALIDATE: { + long windowID = ReadInt32(); + Rect rect; + rect.left = ReadInt32(); + rect.top = ReadInt32(); + rect.right = ReadInt32(); + rect.bottom = ReadInt32(); + + Window *targetWindow = LookupWindow(windowID); + LockCursor(); + if (targetWindow) + targetWindow->Invalidate(rect); + UnlockCursor(); + + break; + } + + case OP_LOCK_MOUSE_FOCUS: + fMouseFocusLocked = true; + break; + + default: + printf("unrecognized drawing command %d\n", opcode); + } + } +} + +void WindowManager::SetCursorPos(int x, int y) +{ + LockCursor(); + // a bit of a hack for now + ((Renderer_vga*)fScreenRenderer)->SetCursorPosition(x, y); + UnlockCursor(); +} + +int WindowManager::StartMouseThread(void *_wm) +{ + ((WindowManager*) _wm)->MouseThread(); + return 0; +} + +void WindowManager::MouseThread() +{ + SerialMouse *mouse = new SerialMouse(fScreenRenderer->BufferWidth() - 1, fScreenRenderer->BufferHeight() + - 1); + int cx = 160, cy = 100, buttons = 0; + int last_cx = cx; + int last_cy = cy; + int last_buttons = buttons; + while (true) { + mouse->GetPos(&cx, &cy, &buttons); + + if (last_cx != cx || last_cy != cy) { + SetCursorPos(cx, cy); + last_cx = cx; + last_cy = cy; + + Window *oldMouseFocus = fCurrentMouseFocus; + if (fCurrentMouseFocus == 0 || !fMouseBoundries.Contains(cx, cy)) { + // Either there is no focus window, or we have moved out + // of the current rectangle that is known to be in this window. + // Check to see what window we are over. + Window *focusWindow = WindowAtPoint(cx, cy); + if (fMouseFocusLocked) { + // Mouse focus is locked, don't actually switch focus windows + if (focusWindow == fCurrentMouseFocus && !fInFocusLockedWindow) { + // Inform the window with locked focus that the mouse has entered + Rect screenFrame = fCurrentMouseFocus->LocalToScreen( + fCurrentMouseFocus->Bounds()); + Event evt; + evt.what = EVT_MOUSE_ENTER; + evt.target = fCurrentMouseFocus->ID(); + evt.x = cx - screenFrame.left; + evt.y = cy - screenFrame.top; + fCurrentMouseFocus->PostEvent(&evt); + fInFocusLockedWindow = true; + } else if (focusWindow != fCurrentMouseFocus && fInFocusLockedWindow) { + // Inform the window with the locked focus that the mouse has left. + Event evt; + evt.what = EVT_MOUSE_LEAVE; + evt.target = oldMouseFocus->ID(); + fCurrentMouseFocus->PostEvent(&evt); + fInFocusLockedWindow = false; + } + + focusWindow->ClipRegion().FindRect(cx, cy, fMouseBoundries); + } else { + fCurrentMouseFocus = focusWindow; + fCurrentMouseFocus->ClipRegion().FindRect(cx, cy, fMouseBoundries); + } + } + + if (oldMouseFocus == fCurrentMouseFocus) { + // Post a mouse moved message to the current focus window + Rect screenFrame = fCurrentMouseFocus->LocalToScreen( + fCurrentMouseFocus->Bounds()); + + Event evt; + evt.what = EVT_MOUSE_MOVED; + evt.target = fCurrentMouseFocus->ID(); + evt.x = cx - screenFrame.left; + evt.y = cy - screenFrame.top; + fCurrentMouseFocus->PostEvent(&evt); + } else { + // Inform the old window (if there is one), that the mouse is leaving + if (oldMouseFocus) { + Event evt; + evt.what = EVT_MOUSE_LEAVE; + evt.target = oldMouseFocus->ID(); + oldMouseFocus->PostEvent(&evt); + } + + // Inform the new window that the mouse has entered + Rect screenFrame = fCurrentMouseFocus->LocalToScreen( + fCurrentMouseFocus->Bounds()); + + Event evt; + evt.what = EVT_MOUSE_ENTER; + evt.target = fCurrentMouseFocus->ID(); + evt.x = cx - screenFrame.left; + evt.y = cy - screenFrame.top; + fCurrentMouseFocus->PostEvent(&evt); + } + } + + if (buttons != last_buttons && fCurrentMouseFocus) { + // If the user has released the buttons, unlock the mouse focus + if (buttons == 0 && fMouseFocusLocked) { + InvalidateMouseBoundries(); + fMouseFocusLocked = false; + } + + // Send a button message to the window + Rect screenFrame = fCurrentMouseFocus->LocalToScreen( + fCurrentMouseFocus->Bounds()); + + Event evt; + evt.what = buttons != 0 ? EVT_MOUSE_DOWN : EVT_MOUSE_UP; + evt.target = fCurrentMouseFocus->ID(); + evt.x = cx - screenFrame.left; + evt.y = cy - screenFrame.top; + fCurrentMouseFocus->PostEvent(&evt); + last_buttons = buttons; + } + + os_sleep(1); + } +} diff --git a/srv/window/WindowManager.h b/srv/window/WindowManager.h @@ -0,0 +1,62 @@ +#ifndef _WINDOW_MANAGER_H +#define _WINDOW_MANAGER_H + +#include <blt/qsem.h> +#include "Rect.h" + +class Renderer; +class Window; + +const int kMaxWindows = 255; + +class WindowManager { +public: + + WindowManager(Renderer *screenRenderer); + ~WindowManager(); + +private: + + Window* CreateWindow(Window *parent, const Rect &rect, int eventPort); + void DestroyWindow(Window *window); + Window* LookupWindow(int id); + Window* WindowAtPoint(int x, int y); + + int RequestorPort() const; + static int StartDispatchThread(void *windowManager); + void DispatchThread(); + void ReadServicePort(void*, int); + int ReadInt32(); + short ReadInt16(); + char ReadInt8(); + void Respond(void *, int); + + void SetCursorPos(int x, int y); + static int StartMouseThread(void *_wm); + void MouseThread(); + void LockCursor(); + void UnlockCursor(); + + void InvalidateMouseBoundries(); + + + Window *fWindowArray[kMaxWindows]; + int fNextWindowID; + + int fServicePort; + char *fReceiveBuffer; + int fReceiveBufferSize; + int fReceiveBufferPos; + int fRequestorPort; + qsem_t *fCursorLock; + + Rect fMouseBoundries; + Window *fCurrentMouseFocus; + bool fMouseFocusLocked; + bool fInFocusLockedWindow; + + Renderer *fScreenRenderer; +}; + + +#endif diff --git a/srv/window/assert.h b/srv/window/assert.h @@ -0,0 +1,7 @@ +#ifndef ASSERT_H +#define ASSERT_H + +#define ASSERT(x) +#define trespass(x) + +#endif diff --git a/srv/window/font.h b/srv/window/font.h @@ -0,0 +1,130 @@ +const unsigned char font5x8[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xff, 0xce, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/srv/window/main.cpp b/srv/window/main.cpp @@ -0,0 +1,290 @@ +#include <blt/namer.h> +#include <blt/syscall.h> +#include <blt/conio.h> +#include <blt/os.h> +#include <blt/qsem.h> +#include <string.h> +#include "Renderer_vga.h" +#include "GraphicsContext.h" +#include "Window.h" +#include "WindowManager.h" +#include "vga.h" + + +struct ColorMapEntry { + int red; + int green; + int blue; +} colorTable[255] = { + {0, 0, 0}, + {112, 219, 147}, + {112, 219, 147}, + {50, 204, 153}, + {50, 204, 153}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 255}, + {0, 0, 255}, + {95, 159, 159}, + {95, 159, 159}, + {66, 66, 111}, + {66, 66, 111}, + {107, 35, 142}, + {107, 35, 142}, + {191, 216, 216}, + {191, 216, 216}, + {143, 143, 188}, + {143, 143, 188}, + {50, 50, 204}, + {50, 50, 204}, + {127, 0, 255}, + {127, 0, 255}, + {47, 47, 79}, + {47, 47, 79}, + {35, 35, 142}, + {35, 35, 142}, + {35, 35, 142}, + {35, 35, 142}, + {50, 153, 204}, + {50, 153, 204}, + {0, 127, 255}, + {0, 127, 255}, + {35, 107, 142}, + {35, 107, 142}, + {255, 127, 0}, + {255, 127, 0}, + {0, 255, 255}, + {0, 255, 255}, + {142, 35, 35}, + {142, 35, 35}, + {204, 127, 50}, + {204, 127, 50}, + {219, 219, 112}, + {219, 219, 112}, + {234, 234, 173}, + {234, 234, 173}, + {0, 255, 0}, + {0, 255, 0}, + {47, 79, 47}, + {47, 79, 47}, + {79, 79, 47}, + {79, 79, 47}, + {35, 142, 35}, + {35, 142, 35}, + {50, 204, 50}, + {50, 204, 50}, + {107, 142, 35}, + {107, 142, 35}, + {66, 111, 66}, + {66, 111, 66}, + {127, 255, 0}, + {127, 255, 0}, + {143, 188, 143}, + {143, 188, 143}, + {35, 142, 107}, + {35, 142, 107}, + {0, 255, 127}, + {0, 255, 127}, + {153, 204, 50}, + {153, 204, 50}, + {47, 79, 79}, + {47, 79, 79}, + {47, 79, 79}, + {47, 79, 79}, + {84, 84, 84}, + {84, 84, 84}, + {84, 84, 84}, + {84, 84, 84}, + {168, 168, 168}, + {168, 168, 168}, + {168, 168, 168}, + {168, 168, 168}, + {159, 159, 95}, + {159, 159, 95}, + {255, 0, 255}, + {255, 0, 255}, + {142, 35, 107}, + {142, 35, 107}, + {204, 50, 50}, + {204, 50, 50}, + {219, 112, 219}, + {219, 112, 219}, + {153, 50, 204}, + {153, 50, 204}, + {147, 112, 219}, + {147, 112, 219}, + {188, 143, 143}, + {188, 143, 143}, + {234, 173, 234}, + {234, 173, 234}, + {255, 0, 0}, + {255, 0, 0}, + {79, 47, 47}, + {79, 47, 47}, + {219, 112, 147}, + {219, 112, 147}, + {255, 0, 127}, + {255, 0, 127}, + {204, 50, 153}, + {204, 50, 153}, + {111, 66, 66}, + {111, 66, 66}, + {142, 107, 35}, + {142, 107, 35}, + {219, 147, 112}, + {219, 147, 112}, + {216, 191, 216}, + {216, 191, 216}, + {173, 234, 234}, + {173, 234, 234}, + {112, 147, 219}, + {112, 147, 219}, + {112, 219, 219}, + {112, 219, 219}, + {79, 47, 79}, + {79, 47, 79}, + {159, 95, 159}, + {159, 95, 159}, + {216, 216, 191}, + {216, 216, 191}, + {252, 252, 252}, + {252, 252, 252}, + {255, 255, 0}, + {255, 255, 0}, + {147, 219, 112}, + {147, 219, 112}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255}, + {255, 255, 255} // Transparent color +}; + + +int main() +{ + InitVGA(); + char *vmem = (char*) 0xa0000; + area_create(64*1024, 0, (void**) &vmem, AREA_PHYSMAP); + memset((void*) vmem, 0, 320 * 200); + + Renderer *screen = new Renderer_vga((char*) vmem, 320, 200, 320); + for (int i = 0; i < 256; i++) + SetPalette(i, colorTable[i].red, colorTable[i].green, colorTable[i].blue); + + new WindowManager(screen); + return 0; +} diff --git a/srv/window/protocol.h b/srv/window/protocol.h @@ -0,0 +1,20 @@ +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + +const char OP_DRAW_LINE = 1; +const char OP_FILL_RECT = 2; +const char OP_SET_PEN_COLOR = 3; +const char OP_DRAW_STRING = 4; +const char OP_DESTROY_WINDOW = 5; +const char OP_HIDE_WINDOW = 6; +const char OP_SHOW_WINDOW = 7; +const char OP_MAKE_FOCUS = 8; +const char OP_BEGIN_PAINT = 9; +const char OP_END_PAINT = 10; +const char OP_SET_BG_COLOR = 11; +const char OP_CREATE_WINDOW = 12; +const char OP_COPY_RECT = 13; +const char OP_INVALIDATE = 14; +const char OP_LOCK_MOUSE_FOCUS = 15; + +#endif diff --git a/srv/window/util.h b/srv/window/util.h @@ -0,0 +1,7 @@ +#ifndef UTIL_H +#define UTIL_H + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#endif diff --git a/srv/window/vga.cpp b/srv/window/vga.cpp @@ -0,0 +1,104 @@ +/* $Id: $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "vga.h" + +#include <i386/io.h> + +const int MiscOutputReg = 0x3c2; +const int DataReg = 0x3c0; +const int AddressReg = 0x3c0; + +const char mode13[][32] = { + { 0x03, 0x01, 0x0f, 0x00, 0x0e }, /* 0x3c4, index 0-4*/ + { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x0e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff }, /* 0x3d4, index 0-0x18*/ + { 0, 0, 0, 0, 0, 0x40, 0x05, 0x0f, 0xff }, /* 0x3ce, index 0-8*/ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 0x41, 0, 0x0f, 0, 0 } /* 0x3c0, index 0-0x14*/ +}; + +#define Vga256 0x13 // 320x200x256 +#define TextMode 0x03 // 80x25 text mode +#define PaletteMask 0x3C6 // bit mask register +#define PaletteRegisterRead 0x3C7 // read index +#define PaletteRegisterWrite 0x3C8 // write index +#define PaletteData 0x3C9 // send/receive data here +#define RomCharSegment 0xF000 +#define RomCharOffset 0xFA6E +#define CharWidth 8 +#define CharHeight 8 + +void SetPalette(int color, int red, int green, int blue) +{ + + outb(0xFF, PaletteMask); + outb(color, PaletteRegisterWrite); + outb(red, PaletteData); + outb(green, PaletteData); + outb(blue, PaletteData); +} + +int InitVGA() +{ + int i; + + outb_p(0x63, MiscOutputReg); + outb_p(0x00, 0x3da); + + for (i=0; i < 5; i++) { + outb_p(i, 0x3c4); + outb_p(mode13[0][i], 0x3c4+1); + } + + outw_p(0x0e11, 0x3d4); + + for (i=0; i < 0x19; i++) { + outb_p(i, 0x3d4); + outb_p(mode13[1][i], (0x3d4 + 1)); + } + + for (i=0; i < 0x9; i++) { + outb_p(i, 0x3ce); + outb_p(mode13[2][i], (0x3ce + 1)); + } + + inb_p(0x3da); + + for (i=0; i < 0x15; i++) { + inw(DataReg); + outb_p(i, AddressReg); + outb_p(mode13[3][i], DataReg); + } + + outb_p(0x20, 0x3c0); + + return 1; +} + diff --git a/srv/window/vga.h b/srv/window/vga.h @@ -0,0 +1,34 @@ +/* $Id: $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _vga_h +#define _vga_h + +void SetPalette(int color, int red, int green, int blue); +int InitVGA(); + +#endif diff --git a/util/Makefile b/util/Makefile @@ -0,0 +1,26 @@ +# $Id: //depot/blt/util/Makefile#3 $ + +CC=cc +CFLAGS=-O2 +#-DxBIG_ENDIAN +#NETSTUFF=-lsocket -lnsl + +all: netboot bootmaker dumphex + +netboot: netboot.o + $(CC) -o netboot netboot.o $(NETSTUFF) + +bootmaker: bootmaker.o + $(CC) -o bootmaker bootmaker.o + +dumphex: dumphex.o + $(CC) -o dumphex dumphex.o + +dumph: dumph.o + $(CC) -o dumph dumph.o + +bootblock.h: dumph bootsect.bin + ./dumph bootsect.bin > bootblock.h + +clean: + rm -f netboot bootmaker dumphex *.o *~ diff --git a/util/blt-link b/util/blt-link @@ -0,0 +1,13 @@ +#!/bin/sh + +# $Id: //depot/blt/util/link#1 $ +# +# Copyright 1998 Sidney Cammeresi +# All rights reserved. +# +# You may use this file in accordance with the license of this distribution. +# +# Script to generate dynamically linked executables + +gcc -nostdlib -nostartfiles $BLTSRCDIR/lib/crt0.o -L$BLTHOME/lib/obj -e _start -Wl,-dynamic-linker,/system/lib/rtld,-T,$BLTSRCDIR/util/blt_i386.x $@ + diff --git a/util/blt_i386.x b/util/blt_i386.x @@ -0,0 +1,80 @@ +/* $Id: //depot/blt/util/blt_i386.x#2 $ */ +/* Modified by Sidney Cammeresi */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x1000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x9090 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x9090 + .rodata : { *(.rodata) } + .rodata1 : { *(.rodata1) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (ALIGN(8) & (0x1000 - 1)); + .data : + { + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/util/bootblock.h b/util/bootblock.h @@ -0,0 +1,93 @@ +/* $Id: //depot/blt/util/bootblock.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +unsigned char bootblock[] = { + 0xeb, 0x03, 0x00, 0x00, 0x00, 0xfa, 0x33, 0xc0, + 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0xe8, 0xc4, 0x01, + 0x36, 0x0f, 0x01, 0x16, 0x4f, 0x7d, 0x0f, 0x20, + 0xc0, 0x0c, 0x01, 0x0f, 0x22, 0xc0, 0x66, 0xea, + 0x26, 0x7c, 0x00, 0x00, 0x08, 0x00, 0xbb, 0x10, + 0x00, 0x8e, 0xdb, 0x8e, 0xc3, 0x8e, 0xd3, 0x24, + 0xfe, 0x0f, 0x22, 0xc0, 0xea, 0x39, 0x00, 0xc0, + 0x07, 0x33, 0xc0, 0x8e, 0xc0, 0x8e, 0xd8, 0x8e, + 0xd0, 0x66, 0xbf, 0x00, 0x00, 0x10, 0x00, 0xbb, + 0x02, 0x00, 0x2e, 0x8b, 0x0e, 0x02, 0x00, 0x33, + 0xd2, 0xfb, 0xe8, 0x12, 0x01, 0xfa, 0xe8, 0x4b, + 0x01, 0x66, 0xa3, 0x00, 0x40, 0x66, 0xc7, 0x06, + 0x04, 0x40, 0x00, 0x00, 0x01, 0x00, 0x66, 0x89, + 0xc1, 0x66, 0xc1, 0xe9, 0x0c, 0x66, 0x8b, 0x3e, + 0x04, 0x40, 0x66, 0x81, 0xc1, 0x00, 0x04, 0x00, + 0x00, 0x66, 0x33, 0xc0, 0xf3, 0x67, 0x66, 0xab, + 0x66, 0x8b, 0x1e, 0x04, 0x40, 0x66, 0x8b, 0x0e, + 0x00, 0x40, 0x66, 0xc1, 0xe9, 0x0c, 0x66, 0xb8, + 0x03, 0x00, 0x00, 0x00, 0x66, 0xbf, 0x00, 0x10, + 0x00, 0x00, 0x66, 0x67, 0x89, 0x04, 0x3b, 0x66, + 0x05, 0x00, 0x10, 0x00, 0x00, 0x66, 0x83, 0xc7, + 0x04, 0xe2, 0xef, 0x66, 0x8b, 0x0e, 0x00, 0x40, + 0x66, 0xc1, 0xe9, 0x16, 0x66, 0x41, 0x66, 0xa1, + 0x04, 0x40, 0x66, 0x05, 0x03, 0x10, 0x00, 0x00, + 0x66, 0x33, 0xff, 0x66, 0x67, 0x89, 0x04, 0x3b, + 0x66, 0x67, 0x89, 0x84, 0x3b, 0x00, 0x0f, 0x00, + 0x00, 0x66, 0x05, 0x00, 0x10, 0x00, 0x00, 0x66, + 0x83, 0xc7, 0x04, 0xe2, 0xe6, 0x66, 0xa1, 0x04, + 0x40, 0x66, 0x89, 0xc1, 0x0c, 0x03, 0x66, 0x67, + 0x89, 0x83, 0xfc, 0x0f, 0x00, 0x00, 0x66, 0x67, + 0x8b, 0x1d, 0x74, 0x00, 0x10, 0x00, 0x66, 0x81, + 0xc3, 0x00, 0x10, 0x10, 0x00, 0x66, 0xbd, 0x00, + 0x00, 0x10, 0x00, 0xb0, 0xcf, 0x2e, 0xa2, 0x5d, + 0x01, 0x2e, 0xa2, 0x65, 0x01, 0x2e, 0x0f, 0x01, + 0x16, 0x4f, 0x01, 0x0f, 0x22, 0xd9, 0x66, 0xb8, + 0x01, 0x00, 0x00, 0x80, 0x0f, 0x22, 0xc0, 0x66, + 0xea, 0x27, 0x7d, 0x00, 0x00, 0x08, 0x00, 0x66, + 0xb8, 0x10, 0x00, 0x66, 0x8e, 0xd8, 0x66, 0x8e, + 0xc0, 0x66, 0x8e, 0xe0, 0x66, 0x8e, 0xe8, 0x66, + 0x8e, 0xd0, 0x89, 0xcc, 0x83, 0xec, 0x04, 0xba, + 0x04, 0x7c, 0x00, 0x00, 0x55, 0x52, 0x67, 0xff, + 0x36, 0x00, 0x40, 0xff, 0xd3, 0xeb, 0xfe, 0xff, + 0xff, 0x4f, 0x7d, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x9a, 0x8f, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x92, 0x8f, 0x00, 0x53, + 0x51, 0xb0, 0x13, 0x28, 0xd8, 0x8b, 0xcb, 0xbb, + 0x00, 0x80, 0xb4, 0x02, 0xcd, 0x13, 0x72, 0x2a, + 0x66, 0xbe, 0x00, 0x80, 0x00, 0x00, 0x66, 0x33, + 0xc9, 0x88, 0xc1, 0xc1, 0xe1, 0x07, 0xf3, 0x67, + 0x66, 0xa5, 0x59, 0x5b, 0x80, 0xf6, 0x01, 0x75, + 0x02, 0xfe, 0xc7, 0xb3, 0x01, 0x32, 0xe4, 0x2b, + 0xc8, 0x7f, 0xcc, 0xb0, 0x0c, 0xba, 0xf2, 0x03, + 0xee, 0xc3, 0xeb, 0xfe, 0xb8, 0x32, 0x31, 0x66, + 0xbb, 0xf0, 0x0f, 0x10, 0x00, 0x67, 0x8b, 0x13, + 0x67, 0x89, 0x03, 0x67, 0x8b, 0x3b, 0x67, 0x89, + 0x13, 0x39, 0xc7, 0x75, 0x09, 0x66, 0x81, 0xc3, + 0x00, 0x10, 0x00, 0x00, 0xeb, 0xe7, 0x66, 0x8b, + 0xc3, 0x66, 0x2d, 0x00, 0x10, 0x00, 0x00, 0x66, + 0x83, 0xc0, 0x10, 0xc3, 0xe8, 0x0f, 0x00, 0x75, + 0x1b, 0xb0, 0xd1, 0xe6, 0x64, 0xe8, 0x06, 0x00, + 0x75, 0x12, 0xb0, 0xdf, 0xe6, 0x60, 0x66, 0xb9, + 0x00, 0x00, 0x02, 0x00, 0xeb, 0x00, 0xe4, 0x64, + 0xa8, 0x02, 0xe0, 0xf8, 0xc3, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x55, 0xaa, +}; diff --git a/util/bootmaker.c b/util/bootmaker.c @@ -0,0 +1,414 @@ +/* $Id: //depot/blt/util/bootmaker.c#4 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "../include/boot.h" + +#include "bootblock.h" + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int make_floppy = 0; + +void die(char *s, char *a) +{ + fprintf(stderr,"error: "); + fprintf(stderr,s,a); + fprintf(stderr,"\n"); + exit(1); +} + +void *loadfile(char *file, int *size) +{ + int fd; + char *data; + struct stat info; + + if((fd = open(file,O_RDONLY)) != -1){ + if(fstat(fd,&info)){ + close(fd); + *size = 0; + return NULL; + } + data = (char *) malloc(info.st_size); + if(read(fd, data, info.st_size) != info.st_size) { + close(fd); + *size = 0; + return NULL; + } + close(fd); + *size = info.st_size; + return data; + } + *size = 0; + return NULL; +} + +/* at location 2 is a uint16, set to blocks * 8 */ +int writebootblock(FILE *fp, unsigned int blocks) +{ + unsigned char bb[512]; + + blocks *= 8; + + memcpy(bb,bootblock,512); + + bb[2] = (blocks & 0x00FF); + bb[3] = (blocks & 0xFF00) >> 8; + + fwrite(bb,512,1,fp); +} + +typedef struct _nvpair +{ + struct _nvpair *next; + char *name; + char *value; +} nvpair; + + +typedef struct _section +{ + struct _section *next; + char *name; + struct _nvpair *firstnv; +} section; + +void print_sections(section *first) +{ + nvpair *p; + + while(first){ + printf("\n[%s]\n",first->name); + for(p = first->firstnv; p; p = p->next){ + printf("%s=%s\n",p->name,p->value); + } + first = first->next; + } +} + +#ifdef xBIG_ENDIAN +unsigned int fix(unsigned int x) +{ + int r; + unsigned char *a = (unsigned char *) &x; + unsigned char b[4]; + + b[0] = a[3]; + b[1] = a[2]; + b[2] = a[1]; + b[3] = a[0]; + + r = *((unsigned int *)b); + return r; + +} +#else +#define fix(x) (x) +#endif + +#define stNEWLINE 0 +#define stSKIPLINE 1 +#define stHEADER 2 +#define stLHS 3 +#define stRHS 4 + +section *first = NULL; +section *last = NULL; + +section *load_ini(char *file) +{ + char *data,*end; + int size; + int state = stNEWLINE; + section *cur; + + char *lhs,*rhs; + + if(!(data = loadfile(file,&size))){ + return NULL; + } + end = data+size; + + while(data < end){ + switch(state){ + case stSKIPLINE: + if(*data == '\n'){ + state = stNEWLINE; + } + data++; + break; + + case stNEWLINE: + if(*data == '\n'){ + data++; + break; + } + if(*data == '['){ + lhs = data+1; + state = stHEADER; + data++; + break; + } + if(*data == '#' || *data <= ' '){ + state = stSKIPLINE; + data++; + break; + } + lhs = data; + data++; + state = stLHS; + break; + case stHEADER: + if(*data == ']'){ + cur = (section *) malloc(sizeof(section)); + cur->name = lhs; + cur->firstnv = NULL; + cur->next = NULL; + if(last){ + last->next = cur; + last = cur; + } else { + last = first = cur; + } + *data = 0; + state = stSKIPLINE; + } + data++; + break; + case stLHS: + if(*data == '\n'){ + state = stNEWLINE; + } + if(*data == '='){ + *data = 0; + rhs = data+1; + state = stRHS; + } + data++; + continue; + case stRHS: + if(*data == '\n'){ + nvpair *p = (nvpair *) malloc(sizeof(nvpair)); + p->name = lhs; + p->value = rhs; + *data = 0; + p->next = cur->firstnv; + cur->firstnv = p; + state = stNEWLINE; + } + data++; + break; + } + } + return first; + +} + + +char *getval(section *s, char *name) +{ + nvpair *p; + for(p = s->firstnv; p; p = p->next){ + if(!strcmp(p->name,name)) return p->value; + } + return NULL; +} + +char *getvaldef(section *s, char *name, char *def) +{ + nvpair *p; + for(p = s->firstnv; p; p = p->next){ + if(!strcmp(p->name,name)) return p->value; + } + return def; +} + +#define centry bdir.bd_entry[c] +void makeboot(section *s, char *outfile) +{ + FILE *fp; + void *rawdata[64]; + int rawsize[64]; + char fill[4096]; + boot_dir bdir; + int i,c; + int nextpage = 1; /* page rel offset of next loaded object */ + + memset(fill,0,4096); + + memset(&bdir, 0, 4096); + for(i=0;i<64;i++){ + rawdata[i] = NULL; + rawsize[i] = 0; + } + + c = 1; + + bdir.bd_entry[0].be_type = fix(BE_TYPE_DIRECTORY); + bdir.bd_entry[0].be_size = fix(1); + bdir.bd_entry[0].be_vsize = fix(1); + rawdata[0] = (void *) &bdir; + rawsize[0] = 4096; + + strcpy(bdir.bd_entry[0].be_name,"SBBB/Directory"); + + while(s){ + char *type = getvaldef(s,"type","NONE"); + char *file = getval(s,"file"); + int vsize; + int size; + struct stat statbuf; + + if(!type) die("section %s has no type",s->name); + + strncpy(centry.be_name,s->name,32); + centry.be_name[31] = 0; + + if(!file) die("section %s has no file",s->name); + if(!(rawdata[c] = loadfile(file,&rawsize[c]))) + die("cannot load \"%s\"",file); + + if(stat(file,&statbuf)) + die("cannot stat \"%s\"",file); + vsize = statbuf.st_size; + + centry.be_size = rawsize[c] / 4096 + (rawsize[c] % 4096 ? 1 : 0); + centry.be_vsize = + (vsize < centry.be_size) ? centry.be_size : vsize; + + centry.be_offset = nextpage; + nextpage += centry.be_size; + + centry.be_size = fix(centry.be_size); + centry.be_vsize = fix(centry.be_vsize); + centry.be_offset = fix(centry.be_offset); + + if(!strcmp(type,"boot")){ + centry.be_type = fix(BE_TYPE_BOOTSTRAP); + centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0"))); + centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0"))); + } + if(!strcmp(type,"code")){ + centry.be_type = fix(BE_TYPE_CODE); + centry.be_code_vaddr = fix(atoi(getvaldef(s,"vaddr","0"))); + centry.be_code_ventr = fix(atoi(getvaldef(s,"ventry","0"))); + } + if(!strcmp(type,"data")){ + centry.be_type = fix(BE_TYPE_DATA); + } + if(!strcmp(type,"elf32")){ + centry.be_type = fix(BE_TYPE_ELF32); + } + + if(centry.be_type == BE_TYPE_NONE){ + die("unrecognized section type \"%s\"",type); + } + + c++; + s = s->next; + + if(c==64) die("too many sections (>63)",NULL); + } + + if(!(fp = fopen(outfile,"w"))){ + die("cannot write to \"%s\"",outfile); + } + + if(make_floppy) { + fprintf(stderr,"whoohah!"); + + writebootblock(fp, nextpage+1); + } + + for(i=0;i<c;i++){ + fwrite(rawdata[i],rawsize[i],1,fp); + if(rawsize[i]%4096) fwrite(fill,4096 - (rawsize[i]%4096),1,fp); + } + fclose(fp); + + +} + +int main(int argc, char **argv) +{ + char *file = NULL; + section *s; + + if(argc < 2){ +usage: + fprintf(stderr,"usage: %s [ --floppy | -f ] [ <inifile> ... ] -o <bootfile>\n",argv[0]); + return 1; + } + + argc--; + argv++; + + while(argc){ + if(!strcmp(*argv,"--floppy")){ + make_floppy = 1; + } else if(!strcmp(*argv,"-o")){ + argc--; + argv++; + if(argc){ + file = *argv; + } else { + goto usage; + } + } else { + if(load_ini(*argv) == NULL){ + fprintf(stderr,"warning: cannot load '%s'\n",*argv); + } + } + argc--; + argv++; + } + + + if((argc > 3) && !strcmp(argv[3],"-floppy")){ + make_floppy = 1; + } + + if(!file){ + fprintf(stderr,"error: no output specified\n"); + goto usage; + } + + if(!first){ + fprintf(stderr,"error: no data to write?!\n"); + goto usage; + } + + makeboot(first,file); + + return 0; +} diff --git a/util/dfp.h b/util/dfp.h @@ -0,0 +1,126 @@ +/* $Id: //depot/blt/util/dfp.h#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* +** Distributed Fish Protocol +** Version 1.0 +** +** Special Interest Group for Operating Systems +** Association for Computing Machinery +** University of Illinios at Urbana-Champaign +*/ + +#ifndef _DFP_H +#define _DFP_H + +#ifdef _WIN32 +#include <sys/types.h> +#include <winsock.h> +#endif + +#ifdef NEED_TYPES +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef char sint8; +#endif + +#define DFP_VERSION 0x0201 + +#define DEFAULT_DFP_PORT 5049 + +#define DFP_MIN_SUBTANK_X 0 +#define DFP_MAX_SUBTANK_X 3 +#define DFP_MIN_SUBTANK_Y 0 +#define DFP_MAX_SUBTANK_Y 3 + +#define DFP_PKT_PING 0 +#define DFP_PKT_PONG 1 +#define DFP_PKT_SEND_FISH 2 +#define DFP_PKT_ACK_FISH 3 +#define DFP_PKT_NACK_FISH 4 +#define DFP_PKT_SYNC_FISH 5 + +/* pack everything along byte boundaries */ +#pragma pack( 1 ) + +typedef struct +{ + uint16 version; + uint8 src_tank_x; + uint8 src_tank_y; + uint8 dst_tank_x; + uint8 dst_tank_y; + uint8 type; /* one of DFP_PKT_* */ + uint8 pad; /* should be 0 */ + uint16 size; /* size of entire packet */ +} dfp_base; + +typedef struct +{ + uint8 creator_tank_x; + uint8 creator_tank_y; + uint8 timestamp[4]; +} dfp_uid; + +typedef struct +{ + uint8 x; + uint8 y; + sint8 dx; + sint8 dy; + uint16 ttl; + uint8 name[16]; +} dfp_fish; + + +#define DFP_SIZE_LOCATE 10 +#define DFP_SIZE_CONFIRM 16 +#define DFP_SIZE_TRANSFER 38 + + +typedef struct +{ + dfp_base base; +} dfp_pkt_locate; + +typedef struct +{ + dfp_base base; + dfp_uid uid; +} dfp_pkt_confirm; + +typedef struct +{ + dfp_base base; + dfp_uid uid; + dfp_fish fish; +} dfp_pkt_transfer; + +/* restore default packing */ +#pragma pack() + +#endif /* __DFP_H */ diff --git a/util/dumph.c b/util/dumph.c @@ -0,0 +1,59 @@ +/* $Id: //depot/blt/util/dumph.c#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include <stdio.h> + +static void dump(unsigned char *x, int sections) +{ + int i; + + printf("unsigned char bootblock[] = {\n"); + + for(i=0;i<sections;i++){ + printf("\t0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n\t0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", + x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7], + x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15]); + x += 16; + + } + + printf("};\n"); + +} + +int main(int argc, char *argv[]) +{ + FILE *fp; + unsigned char buf[4096*3]; + if(fp = fopen(argv[1],"r")){ + fread(buf,1,512,fp); + dump(buf,512/16); + fclose(fp); + } + return 0; + +} diff --git a/util/dumphex.c b/util/dumphex.c @@ -0,0 +1,51 @@ +/* $Id: //depot/blt/util/dumphex.c#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include <stdio.h> + +static void dump(unsigned char *x, int sections) +{ + int i; + + for(i=0;i<sections;i++){ + printf("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + 16*i,x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7], + x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15]); + x += 16; + } +} + +int main(int argc, char *argv[]) +{ + FILE *fp; + unsigned char buf[4096*3]; + if(fp = fopen(argv[1],"r")){ + fread(buf,1,4096*3,fp); + dump(buf,4096*3/16); + fclose(fp); + } +} diff --git a/util/fishfinder.c b/util/fishfinder.c @@ -0,0 +1,108 @@ +/* $Id: //depot/blt/util/fishfinder.c#2 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include <stdio.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <netinet/in.h> + +#undef uint32 + +#define NEED_TYPES +#include "dfp.h" + +char *types[] = { "PING", "PONG", "SEND", "ACK ", "NAK ", "SYNC" }; + +int main(int argc, char *argv[]) +{ + struct sockaddr_in dst,src; + dfp_pkt_transfer dfp,dfp2; + char n2[17]; + int s; + + + src.sin_family = AF_INET; + src.sin_addr.s_addr = htonl(INADDR_ANY); + src.sin_port = htons(DEFAULT_DFP_PORT); + + if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + perror("socket"); + + if(bind(s, (struct sockaddr *) &src, sizeof(src)) == -1) + perror("bind"); + + for(;;){ + if(recvfrom(s,(void *)&dfp,sizeof(dfp),0,NULL,NULL) < 0) { + perror("recvfrom"); + } + dfp.base.size = ntohs(dfp.base.size); + dfp.base.version = ntohs(dfp.base.version); + + if(dfp.base.version != DFP_VERSION){ + printf("version mismatch!\n"); + continue; + } + + if(dfp.base.type > 5) continue; + + printf("%s: (%d,%d) -> (%d,%d) ", types[dfp.base.type], + dfp.base.src_tank_x, dfp.base.src_tank_y, + dfp.base.dst_tank_x, dfp.base.dst_tank_y, + dfp.base.size); + + switch(dfp.base.type){ + case DFP_PKT_PING: + case DFP_PKT_PONG: + printf("\n"); + break; + case DFP_PKT_SYNC_FISH: + case DFP_PKT_SEND_FISH: + printf("[%02x%02x%02x%02x%02x%02x] ", + dfp.uid.creator_tank_x, dfp.uid.creator_tank_y, + dfp.uid.timestamp[0], dfp.uid.timestamp[1], + dfp.uid.timestamp[2], dfp.uid.timestamp[3]); + strncpy(n2,dfp.fish.name,16); + n2[16]=0; + printf("@(%3d,%3d) d(%3d,%3d) \"%s\"\n", + dfp.fish.x, dfp.fish.y, dfp.fish.dx, dfp.fish.dy, n2); + break; + case DFP_PKT_NACK_FISH: + case DFP_PKT_ACK_FISH: + printf("[%02x%02x%02x%02x%02x%02x]\n", + dfp.uid.creator_tank_x, dfp.uid.creator_tank_y, + dfp.uid.timestamp[0], dfp.uid.timestamp[1], + dfp.uid.timestamp[2], dfp.uid.timestamp[3]); + break; + } + } + + close(s); + return 0; +} diff --git a/util/ic.c b/util/ic.c @@ -0,0 +1,367 @@ +// RPC Interface Compiler (ic) +// + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <string.h> + +typedef struct ic_type ic_type; +typedef struct ic_param ic_param; +typedef struct ic_func ic_func; +typedef struct ic_ifc ic_ifc; + +struct ic_type +{ + ic_type *next; + + char *name; + enum { + BASIC, + ARRAY, + STRING, + STRUCT + } type; + int size; + ic_type *parts; +}; + +struct ic_param +{ + ic_param *next; + + char *name; + ic_type *type; + enum { + IN = 1, + OUT = 2 + } flags; +}; + +struct ic_func +{ + ic_func *next; + + char *name; + ic_param *params; +}; + +struct ic_ifc +{ + char *name; + char *key; + ic_func *funcs; +}; + +ic_type *types = NULL; + +ic_type builtins[] = { + { NULL, "int32", BASIC, 4, NULL }, + { NULL, "uint32", BASIC, 4, NULL }, + { NULL, "int16", BASIC, 2, NULL }, + { NULL, "uint16", BASIC, 2, NULL }, + { NULL, NULL, BASIC, 0, NULL } +}; + +int line = 1; +char token[256]; +char *data; +char *file; + +void die(const char *fmt, ...) +{ + va_list ap; + va_start(ap,fmt); + fprintf(stderr,"%s:%d - ",file,line); + vfprintf(stderr,fmt,ap); + fprintf(stderr,"\n"); + va_end(ap); + exit(1); +} + + +void next(void) +{ + char *x = token; + + if(*data == 0) { + token[0] = 0; + return; + } + +eat_space: + while(*data <= ' ') { + if(*data == '\n') line++; + data++; + } + + if(*data == '#') { + while(*data != '\n') data++; + goto eat_space; + } + + if(*data == '"') { + data++; + while(*data != '"') { + *x++ = *data++; + } + *x = 0; + data++; + return; + } + + for(;;){ + switch(*data){ + case '{': + case '}': + case '(': + case ')': + case ',': + case '#': + case '"': + case ':': + if(x == token){ + *x++ = *data++; + } + *x = 0; + return; + default: + if(*data <= ' '){ + *x = 0; + return; + } else { + *x++ = *data++; + if((x - token) > 255) die("token too long"); + } + } + } +} + +int match(const char *tok) +{ + if(!strcmp(token,tok)){ + next(); + return 1; + } else { + return 0; + } +} + +void force(const char *tok) +{ + if(strcmp(token,tok)){ + die("expecting '%s', found '%s'",tok,token); + } + next(); +} + +ic_type *type(void) +{ + ic_type *t; + + if(match("string")){ + t = (ic_type *) malloc(sizeof(ic_type)); + if(!t) die("out of memory"); + + force(":"); + t->size = atoi(token); next(); + t->name = "string"; + t->type = STRING; + t->next = NULL; + t->parts = NULL; + + return t; + } + + for(t = types; t; t = t->next){ + if(match(t->name)) return t; + } + + die("unknown type '%s'",token); + return NULL; +} + +ic_param *param(void) +{ + ic_param *p = (ic_param*) malloc(sizeof(ic_param)); + if(!p) die("out of memory"); + + if(match("in")){ + p->flags = IN; + } else if(match("out")) { + p->flags = OUT; + } else { + die("expecting 'in' or 'out', found '%s'",token); + } + + p->type = type(); + p->name = strdup(token); next(); + p->next = NULL; + + return p; +} + +ic_func *function(void) +{ + ic_param *p,*last = NULL; + ic_func *func = (ic_func*) malloc(sizeof(ic_func)); + if(!func) die("out of memory"); + + func->name = strdup(token); next(); + func->next = NULL; + func->params = NULL; + + force("("); + + for(;;){ + if(match(")")) { + match(";"); /* optional semi */ + return func; + } + p = param(); + if(last) { + last->next = p; + } else { + func->params = p; + } + last = p; + match(","); + } +} + + + +ic_ifc *interface(void) +{ + ic_func *func,*last = NULL; + ic_ifc *ifc = (ic_ifc*) malloc(sizeof(ic_ifc)); + + if(!ifc) die("out of memory"); + + ifc->name = strdup(token); next(); + ifc->key = strdup(token); next(); + ifc->funcs = NULL; + + force("{"); + + for(;;){ + if(match("}")) { + match(";"); /* optional semi */ + return ifc; + } + func = function(); + if(last){ + last->next = func; + } else { + ifc->funcs = func; + } + last = func; + } +} + +void mkheader(FILE *f, ic_ifc *ifc) +{ + ic_func *func; + ic_param *p; + char *upname,*x; + + x = upname = strdup(ifc->name); + while(*x) { + *x = toupper(*x); + x++; + } + fprintf(f,"/* Generated File - DO NOT EDIT */\n\n"); + fprintf(f,"#define IFC_%s \"%s\"\n\n",upname,ifc->key); + fprintf(f,"typedef struct {\n"); + for(func = ifc->funcs; func; func = func->next){ + fprintf(f,"\tstatus_t (*%s)(\n",func->name); + fprintf(f,"\t\tconst ifc_handle *handle%s\n",func->params?",":""); + + for(p = func->params; p; p = p->next){ + fprintf(f,"\t\t%s %s%s\n",p->type->name,p->name, + p->next ? "," : ""); + } + fprintf(f,"\t\t);\n"); + } + fprintf(f,"} ifc_%s;\n",ifc->name); +} + +void mkstub(FILE *f, ic_ifc *ifc) +{ + ic_func *func; + ic_param *p; + + fprintf(f,"/* Generated File - DO NOT EDIT */\n\n"); + + /* eject the stubs */ + for(func = ifc->funcs; func; func = func->next){ + fprintf(f,"static status_t\n"); + fprintf(f,"stub_%s(\n",func->name); + fprintf(f,"\t)\n"); + fprintf(f,"{\n"); + fprintf(f,"\treturn -1;\n"); + fprintf(f,"}\n\n"); + } + + /* eject the decl */ + fprintf(f,"ifc_%s ifc_%s_impl = {\n",ifc->name,ifc->name); + for(func = ifc->funcs; func; func = func->next){ + fprintf(f,"\t&stub_%s%s\n",func->name,func->next?",":""); + } + fprintf(f,"};\n"); +} + +void parse(void) +{ + ic_ifc *ifc; + next(); + + for(;;){ + if(match("interface")) { + ifc = interface(); + mkheader(stdout,ifc); + mkstub(stdout,ifc); + } + if(match("")) return; + die("unexpected token '%s'",token); + } +} + +int main(int argc, char *argv[]) +{ + int i,fd; + struct stat s; + + /* install built-in types */ + for(i=0;builtins[i].name;i++){ + builtins[i].next = types; + types = builtins + i; + } + + if(argc != 2) { + fprintf(stderr,"error: no input file\n"); + return 1; + } + + file = argv[1]; + + if(((fd = open(file,O_RDONLY)) < 0) || fstat(fd,&s)){ + fprintf(stderr,"error: cannot open \"%s\"\n",file); + return 1; + } + + data = (char*) malloc(s.st_size + 1); + read(fd, data, s.st_size); + data[s.st_size] = 0; + close(fd); + + parse(); +} + + + + + + +\ No newline at end of file diff --git a/util/namer.ifc b/util/namer.ifc @@ -0,0 +1,14 @@ +# +# BLT Naming Service +# + +interface namer "/blt/system/namer" { + lookup( + in string:256 name, + out int32 port + ) + register( + in string:256 name, + in int32 port + ) +} +\ No newline at end of file diff --git a/util/netboot.c b/util/netboot.c @@ -0,0 +1,129 @@ +/* $Id: //depot/blt/util/netboot.c#3 $ +** +** Copyright 1998 Brian J. Swetland +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include <stdio.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <sys/time.h> +#include <unistd.h> + +#include "../netboot/netboot.h" + +int main(int argc, char *argv[]) +{ + struct sockaddr_in dst,src; + char buf[128]; + net_boot nb,nbr; + int fd; + struct timeval timeout; + int s,l,i; + fd_set read_fds; + + if(argc != 3) { + fprintf(stderr,"usage: test <filename> <addr>\n"); + exit(1); + + } + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = inet_addr(argv[2]); + dst.sin_port = htons(NETBOOT_PORT); + + src.sin_family = AF_INET; + src.sin_addr.s_addr = htonl(INADDR_ANY); + src.sin_port = htons(NETBOOT_PORT); + + if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + perror("socket"); + + if(bind(s, (struct sockaddr *) &src, sizeof(src)) == -1) + perror("bind"); + + fprintf(stderr,"loading ["); + + fd = open(argv[1],O_RDONLY); + + i = 0; + + while(read(fd,&(nb.data),1024) > 0){ + nb.cmd = htons(NETBOOT_CMD_LOAD); + nb.blk = htons(i); + + retry: + if(sendto(s, &nb, sizeof(nb), 0, (struct sockaddr *) &dst, sizeof(dst)) + == -1){ + perror("sendto"); + } + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + FD_ZERO(&read_fds); + FD_SET(s,&read_fds); + + if(select(s+1, &read_fds, NULL, NULL, &timeout) == 1){ + + if(recvfrom(s,&nbr,sizeof(nbr),0,NULL,NULL) < 0) { + fprintf(stderr,"e"); + goto retry; + } + if(nbr.cmd != htons(NETBOOT_CMD_ACK)) { + fprintf(stderr,"e"); + goto retry; + } + if(nbr.blk != nb.blk) { + fprintf(stderr,"e"); + goto retry; + } + fprintf(stderr,"."); + } else { + fprintf(stderr,"T"); + goto retry; + } + i++; + } + + nb.cmd = htons(NETBOOT_CMD_EXEC); + nb.blk = htons(0); + + if(sendto(s, &nb, 4, 0, (struct sockaddr *) &dst, sizeof(dst)) + == -1){ + perror("sendto"); + } + +/* if(recvfrom(s,&nb,sizeof(nb),0,NULL,NULL) < 0) perror("recvfrom"); + if(nb.cmd == htons(NETBOOT_CMD_ACK)) fprintf(stderr,"!");*/ + + fprintf(stderr,"] done\n"); + + close(s); + + return 0; + +}