Sorting source tree a bit
authorJohn Hodge <[email protected]>
Tue, 7 Feb 2012 09:25:05 +0000 (17:25 +0800)
committerJohn Hodge <[email protected]>
Tue, 7 Feb 2012 09:25:05 +0000 (17:25 +0800)
722 files changed:
Design Notes/AcessFS.txt [deleted file]
Design Notes/Spinlocks.txt [deleted file]
Design Notes/VFS - Select.txt [deleted file]
Design Notes/VTerm.txt [deleted file]
Kernel/.gitignore [deleted file]
Kernel/Doxyfile [deleted file]
Kernel/Doxyfile.api [deleted file]
Kernel/DoxygenLayout.xml [deleted file]
Kernel/GenSyscalls.php [deleted file]
Kernel/GenSyscalls.pl [deleted file]
Kernel/Makefile [deleted file]
Kernel/adt.c [deleted file]
Kernel/arch/archdoc.h [deleted file]
Kernel/arch/armv7/Makefile [deleted file]
Kernel/arch/armv7/debug.c [deleted file]
Kernel/arch/armv7/include/arch.h [deleted file]
Kernel/arch/armv7/include/assembly.h [deleted file]
Kernel/arch/armv7/include/lock.h [deleted file]
Kernel/arch/armv7/include/mm_virt.h [deleted file]
Kernel/arch/armv7/include/options.h [deleted file]
Kernel/arch/armv7/include/proc.h [deleted file]
Kernel/arch/armv7/lib.S [deleted file]
Kernel/arch/armv7/lib.c [deleted file]
Kernel/arch/armv7/link.ld [deleted file]
Kernel/arch/armv7/main.c [deleted file]
Kernel/arch/armv7/mm_phys.c [deleted file]
Kernel/arch/armv7/mm_virt.c [deleted file]
Kernel/arch/armv7/pci.c [deleted file]
Kernel/arch/armv7/proc.S [deleted file]
Kernel/arch/armv7/proc.c [deleted file]
Kernel/arch/armv7/start.S [deleted file]
Kernel/arch/armv7/time.c [deleted file]
Kernel/arch/helpers.h [deleted file]
Kernel/arch/m68k/Makefile [deleted file]
Kernel/arch/m68k/debug.c [deleted file]
Kernel/arch/m68k/include/arch.h [deleted file]
Kernel/arch/m68k/include/mm_virt.h [deleted file]
Kernel/arch/m68k/include/proc.h [deleted file]
Kernel/arch/m68k/lib.c [deleted file]
Kernel/arch/m68k/link.ld [deleted file]
Kernel/arch/m68k/main.c [deleted file]
Kernel/arch/m68k/mm_phys.c [deleted file]
Kernel/arch/m68k/mm_virt.c [deleted file]
Kernel/arch/m68k/proc.c [deleted file]
Kernel/arch/m68k/time.c [deleted file]
Kernel/arch/x86/Makefile [deleted file]
Kernel/arch/x86/desctab.asm [deleted file]
Kernel/arch/x86/errors.c [deleted file]
Kernel/arch/x86/include/arch.h [deleted file]
Kernel/arch/x86/include/arch_int.h [deleted file]
Kernel/arch/x86/include/desctab.h [deleted file]
Kernel/arch/x86/include/mm_phys.h [deleted file]
Kernel/arch/x86/include/mm_virt.h [deleted file]
Kernel/arch/x86/include/mp.h [deleted file]
Kernel/arch/x86/include/multiboot2.h [deleted file]
Kernel/arch/x86/include/proc.h [deleted file]
Kernel/arch/x86/include/vm8086.h [deleted file]
Kernel/arch/x86/irq.c [deleted file]
Kernel/arch/x86/kpanic.c [deleted file]
Kernel/arch/x86/lib.c [deleted file]
Kernel/arch/x86/link.ld [deleted file]
Kernel/arch/x86/main.c [deleted file]
Kernel/arch/x86/mm_phys.c [deleted file]
Kernel/arch/x86/mm_virt.c [deleted file]
Kernel/arch/x86/pci.c [deleted file]
Kernel/arch/x86/proc.asm [deleted file]
Kernel/arch/x86/proc.c [deleted file]
Kernel/arch/x86/start.asm [deleted file]
Kernel/arch/x86/time.c [deleted file]
Kernel/arch/x86/vm8086.c [deleted file]
Kernel/arch/x86_64/Makefile [deleted file]
Kernel/arch/x86_64/desctab.asm [deleted file]
Kernel/arch/x86_64/errors.c [deleted file]
Kernel/arch/x86_64/include/arch.h [deleted file]
Kernel/arch/x86_64/include/arch_config.h [deleted file]
Kernel/arch/x86_64/include/common.inc.asm [deleted file]
Kernel/arch/x86_64/include/desctab.h [deleted file]
Kernel/arch/x86_64/include/mm_virt.h [deleted file]
Kernel/arch/x86_64/include/proc.h [deleted file]
Kernel/arch/x86_64/include/vm8086.h [deleted file]
Kernel/arch/x86_64/kernelpanic.c [deleted file]
Kernel/arch/x86_64/lib.c [deleted file]
Kernel/arch/x86_64/link.ld [deleted file]
Kernel/arch/x86_64/main.c [deleted file]
Kernel/arch/x86_64/mm_phys.c [deleted file]
Kernel/arch/x86_64/mm_virt.c [deleted file]
Kernel/arch/x86_64/pci.c [deleted symlink]
Kernel/arch/x86_64/proc.asm [deleted file]
Kernel/arch/x86_64/proc.c [deleted file]
Kernel/arch/x86_64/rme.c [deleted symlink]
Kernel/arch/x86_64/rme.h [deleted symlink]
Kernel/arch/x86_64/start32.asm [deleted file]
Kernel/arch/x86_64/start64.asm [deleted file]
Kernel/arch/x86_64/time.c [deleted file]
Kernel/arch/x86_64/vm8086.c [deleted file]
Kernel/bin/README [deleted file]
Kernel/bin/elf.c [deleted file]
Kernel/bin/elf.h [deleted file]
Kernel/bin/pe.c [deleted file]
Kernel/bin/pe.h [deleted file]
Kernel/binary.c [deleted file]
Kernel/debug.c [deleted file]
Kernel/drv/Makefile [deleted file]
Kernel/drv/fifo.c [deleted file]
Kernel/drv/iocache.c [deleted file]
Kernel/drv/pci.c [deleted file]
Kernel/drv/proc.c [deleted file]
Kernel/drv/vterm.c [deleted file]
Kernel/drv/vterm.h [deleted file]
Kernel/drv/vterm_font.c [deleted file]
Kernel/drv/vterm_font_8x16.h [deleted file]
Kernel/drv/vterm_font_8x8.h [deleted file]
Kernel/drv/vterm_input.c [deleted file]
Kernel/drv/vterm_output.c [deleted file]
Kernel/drv/vterm_termbuf.c [deleted file]
Kernel/drv/vterm_vt100.c [deleted file]
Kernel/drvutil.c [deleted file]
Kernel/events.c [deleted file]
Kernel/heap.c [deleted file]
Kernel/include/acess.h [deleted file]
Kernel/include/adt.h [deleted file]
Kernel/include/api_drv_common.h [deleted file]
Kernel/include/api_drv_disk.h [deleted file]
Kernel/include/api_drv_joystick.h [deleted file]
Kernel/include/api_drv_keyboard.h [deleted file]
Kernel/include/api_drv_network.h [deleted file]
Kernel/include/api_drv_terminal.h [deleted file]
Kernel/include/api_drv_video.h [deleted file]
Kernel/include/apidoc/arch_x86.h [deleted file]
Kernel/include/apidoc_mainpage.h [deleted file]
Kernel/include/binary.h [deleted file]
Kernel/include/binary_ext.h [deleted file]
Kernel/include/drv_pci.h [deleted file]
Kernel/include/drv_pci_int.h [deleted file]
Kernel/include/errno.h [deleted file]
Kernel/include/events.h [deleted file]
Kernel/include/fs_devfs.h [deleted file]
Kernel/include/fs_sysfs.h [deleted file]
Kernel/include/hal_proc.h [deleted file]
Kernel/include/heap.h [deleted file]
Kernel/include/heap_int.h [deleted file]
Kernel/include/init.h [deleted file]
Kernel/include/iocache.h [deleted file]
Kernel/include/lib/keyvalue.h [deleted file]
Kernel/include/mboot.h [deleted file]
Kernel/include/modules.h [deleted file]
Kernel/include/mutex.h [deleted file]
Kernel/include/semaphore.h [deleted file]
Kernel/include/signal.h [deleted file]
Kernel/include/syscalls.h [deleted file]
Kernel/include/syscalls.inc.asm [deleted file]
Kernel/include/threads.h [deleted file]
Kernel/include/threads_int.h [deleted file]
Kernel/include/timers.h [deleted file]
Kernel/include/tpl_mm_phys_bitmap.h [deleted file]
Kernel/include/tpl_mm_phys_stack.h [deleted file]
Kernel/include/vfs.h [deleted file]
Kernel/include/vfs_ext.h [deleted file]
Kernel/include/vfs_int.h [deleted file]
Kernel/include/vfs_ramfs.h [deleted file]
Kernel/include/vfs_threads.h [deleted file]
Kernel/include/workqueue.h [deleted file]
Kernel/lib.c [deleted file]
Kernel/logging.c [deleted file]
Kernel/messages.c [deleted file]
Kernel/modules.c [deleted file]
Kernel/mutex.c [deleted file]
Kernel/semaphore.c [deleted file]
Kernel/syscalls.c [deleted file]
Kernel/syscalls.lst [deleted file]
Kernel/system.c [deleted file]
Kernel/threads.c [deleted file]
Kernel/time.c [deleted file]
Kernel/vfs/acls.c [deleted file]
Kernel/vfs/dir.c [deleted file]
Kernel/vfs/fs/devfs.c [deleted file]
Kernel/vfs/fs/root.c [deleted file]
Kernel/vfs/handle.c [deleted file]
Kernel/vfs/io.c [deleted file]
Kernel/vfs/main.c [deleted file]
Kernel/vfs/memfile.c [deleted file]
Kernel/vfs/mmap.c [deleted file]
Kernel/vfs/mount.c [deleted file]
Kernel/vfs/nodecache.c [deleted file]
Kernel/vfs/open.c [deleted file]
Kernel/vfs/select.c [deleted file]
Kernel/workqueue.c [deleted file]
KernelLand/Kernel/.gitignore [new file with mode: 0644]
KernelLand/Kernel/Doxyfile [new file with mode: 0644]
KernelLand/Kernel/Doxyfile.api [new file with mode: 0644]
KernelLand/Kernel/DoxygenLayout.xml [new file with mode: 0644]
KernelLand/Kernel/GenSyscalls.php [new file with mode: 0644]
KernelLand/Kernel/GenSyscalls.pl [new file with mode: 0755]
KernelLand/Kernel/Makefile [new file with mode: 0644]
KernelLand/Kernel/adt.c [new file with mode: 0644]
KernelLand/Kernel/arch/archdoc.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/Makefile [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/debug.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/include/arch.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/include/assembly.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/include/lock.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/include/mm_virt.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/include/options.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/include/proc.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/lib.S [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/lib.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/link.ld [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/main.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/mm_phys.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/mm_virt.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/pci.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/proc.S [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/proc.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/start.S [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/time.c [new file with mode: 0644]
KernelLand/Kernel/arch/helpers.h [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/Makefile [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/debug.c [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/include/arch.h [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/include/mm_virt.h [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/include/proc.h [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/lib.c [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/link.ld [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/main.c [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/mm_phys.c [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/mm_virt.c [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/proc.c [new file with mode: 0644]
KernelLand/Kernel/arch/m68k/time.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/Makefile [new file with mode: 0644]
KernelLand/Kernel/arch/x86/desctab.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86/errors.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/arch.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/arch_int.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/desctab.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/mm_phys.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/mm_virt.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/mp.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/multiboot2.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/proc.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/include/vm8086.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86/irq.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/kpanic.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/lib.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/link.ld [new file with mode: 0644]
KernelLand/Kernel/arch/x86/main.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/mm_phys.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/mm_virt.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/pci.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/proc.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86/proc.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/start.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86/time.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/vm8086.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/Makefile [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/desctab.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/errors.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/arch.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/arch_config.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/common.inc.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/desctab.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/mm_virt.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/proc.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/include/vm8086.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/kernelpanic.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/lib.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/link.ld [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/main.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/mm_phys.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/mm_virt.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/pci.c [new symlink]
KernelLand/Kernel/arch/x86_64/proc.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/proc.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/rme.c [new symlink]
KernelLand/Kernel/arch/x86_64/rme.h [new symlink]
KernelLand/Kernel/arch/x86_64/start32.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/start64.asm [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/time.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/vm8086.c [new file with mode: 0644]
KernelLand/Kernel/bin/README [new file with mode: 0644]
KernelLand/Kernel/bin/elf.c [new file with mode: 0644]
KernelLand/Kernel/bin/elf.h [new file with mode: 0644]
KernelLand/Kernel/bin/pe.c [new file with mode: 0644]
KernelLand/Kernel/bin/pe.h [new file with mode: 0644]
KernelLand/Kernel/binary.c [new file with mode: 0644]
KernelLand/Kernel/debug.c [new file with mode: 0644]
KernelLand/Kernel/drv/Makefile [new file with mode: 0644]
KernelLand/Kernel/drv/fifo.c [new file with mode: 0644]
KernelLand/Kernel/drv/iocache.c [new file with mode: 0644]
KernelLand/Kernel/drv/pci.c [new file with mode: 0644]
KernelLand/Kernel/drv/proc.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm.h [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_font.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_font_8x16.h [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_font_8x8.h [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_input.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_output.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_termbuf.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm_vt100.c [new file with mode: 0644]
KernelLand/Kernel/drvutil.c [new file with mode: 0644]
KernelLand/Kernel/events.c [new file with mode: 0644]
KernelLand/Kernel/heap.c [new file with mode: 0644]
KernelLand/Kernel/include/acess.h [new file with mode: 0644]
KernelLand/Kernel/include/adt.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_common.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_disk.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_joystick.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_keyboard.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_network.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_terminal.h [new file with mode: 0644]
KernelLand/Kernel/include/api_drv_video.h [new file with mode: 0644]
KernelLand/Kernel/include/apidoc/arch_x86.h [new file with mode: 0644]
KernelLand/Kernel/include/apidoc_mainpage.h [new file with mode: 0644]
KernelLand/Kernel/include/binary.h [new file with mode: 0644]
KernelLand/Kernel/include/binary_ext.h [new file with mode: 0644]
KernelLand/Kernel/include/drv_pci.h [new file with mode: 0644]
KernelLand/Kernel/include/drv_pci_int.h [new file with mode: 0644]
KernelLand/Kernel/include/errno.h [new file with mode: 0644]
KernelLand/Kernel/include/events.h [new file with mode: 0644]
KernelLand/Kernel/include/fs_devfs.h [new file with mode: 0644]
KernelLand/Kernel/include/fs_sysfs.h [new file with mode: 0644]
KernelLand/Kernel/include/hal_proc.h [new file with mode: 0644]
KernelLand/Kernel/include/heap.h [new file with mode: 0644]
KernelLand/Kernel/include/heap_int.h [new file with mode: 0644]
KernelLand/Kernel/include/init.h [new file with mode: 0644]
KernelLand/Kernel/include/iocache.h [new file with mode: 0644]
KernelLand/Kernel/include/lib/keyvalue.h [new file with mode: 0644]
KernelLand/Kernel/include/mboot.h [new file with mode: 0644]
KernelLand/Kernel/include/modules.h [new file with mode: 0644]
KernelLand/Kernel/include/mutex.h [new file with mode: 0644]
KernelLand/Kernel/include/semaphore.h [new file with mode: 0644]
KernelLand/Kernel/include/signal.h [new file with mode: 0644]
KernelLand/Kernel/include/syscalls.h [new file with mode: 0644]
KernelLand/Kernel/include/syscalls.inc.asm [new file with mode: 0644]
KernelLand/Kernel/include/threads.h [new file with mode: 0644]
KernelLand/Kernel/include/threads_int.h [new file with mode: 0644]
KernelLand/Kernel/include/timers.h [new file with mode: 0644]
KernelLand/Kernel/include/tpl_mm_phys_bitmap.h [new file with mode: 0644]
KernelLand/Kernel/include/tpl_mm_phys_stack.h [new file with mode: 0644]
KernelLand/Kernel/include/vfs.h [new file with mode: 0644]
KernelLand/Kernel/include/vfs_ext.h [new file with mode: 0644]
KernelLand/Kernel/include/vfs_int.h [new file with mode: 0644]
KernelLand/Kernel/include/vfs_ramfs.h [new file with mode: 0644]
KernelLand/Kernel/include/vfs_threads.h [new file with mode: 0644]
KernelLand/Kernel/include/workqueue.h [new file with mode: 0644]
KernelLand/Kernel/lib.c [new file with mode: 0644]
KernelLand/Kernel/logging.c [new file with mode: 0644]
KernelLand/Kernel/messages.c [new file with mode: 0644]
KernelLand/Kernel/modules.c [new file with mode: 0644]
KernelLand/Kernel/mutex.c [new file with mode: 0644]
KernelLand/Kernel/semaphore.c [new file with mode: 0644]
KernelLand/Kernel/syscalls.c [new file with mode: 0644]
KernelLand/Kernel/syscalls.lst [new file with mode: 0644]
KernelLand/Kernel/system.c [new file with mode: 0644]
KernelLand/Kernel/threads.c [new file with mode: 0644]
KernelLand/Kernel/time.c [new file with mode: 0644]
KernelLand/Kernel/vfs/acls.c [new file with mode: 0644]
KernelLand/Kernel/vfs/dir.c [new file with mode: 0644]
KernelLand/Kernel/vfs/fs/devfs.c [new file with mode: 0644]
KernelLand/Kernel/vfs/fs/root.c [new file with mode: 0644]
KernelLand/Kernel/vfs/handle.c [new file with mode: 0644]
KernelLand/Kernel/vfs/io.c [new file with mode: 0644]
KernelLand/Kernel/vfs/main.c [new file with mode: 0644]
KernelLand/Kernel/vfs/memfile.c [new file with mode: 0644]
KernelLand/Kernel/vfs/mmap.c [new file with mode: 0644]
KernelLand/Kernel/vfs/mount.c [new file with mode: 0644]
KernelLand/Kernel/vfs/nodecache.c [new file with mode: 0644]
KernelLand/Kernel/vfs/open.c [new file with mode: 0644]
KernelLand/Kernel/vfs/select.c [new file with mode: 0644]
KernelLand/Kernel/workqueue.c [new file with mode: 0644]
KernelLand/Modules/Display/BochsGA/Makefile [new file with mode: 0644]
KernelLand/Modules/Display/BochsGA/bochsvbe.c [new file with mode: 0644]
KernelLand/Modules/Display/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/Display/PL110/Makefile [new file with mode: 0644]
KernelLand/Modules/Display/PL110/main.c [new file with mode: 0644]
KernelLand/Modules/Display/Tegra2Vid/Makefile [new file with mode: 0644]
KernelLand/Modules/Display/Tegra2Vid/main.c [new file with mode: 0644]
KernelLand/Modules/Display/Tegra2Vid/tegra2.h [new file with mode: 0644]
KernelLand/Modules/Display/VESA/Makefile [new file with mode: 0644]
KernelLand/Modules/Display/VESA/common.h [new file with mode: 0644]
KernelLand/Modules/Display/VESA/main.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/Makefile [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/dir.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/ext2.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/ext2_common.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/ext2fs.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/read.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/Ext2/write.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/Makefile [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/fat.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/fs_fat.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/Makefile [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/files.lst [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/initrd.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/main.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/LEAN/common.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/LEAN/main.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/Filesystems/NFS/Makefile [new file with mode: 0644]
KernelLand/Modules/Filesystems/NFS/common.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/NFS/main.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/NTFS/Makefile [new file with mode: 0644]
KernelLand/Modules/Filesystems/NTFS/attributes.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/NTFS/common.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/NTFS/dir.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/NTFS/index.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/NTFS/main.c [new file with mode: 0644]
KernelLand/Modules/IPStack/Makefile [new file with mode: 0644]
KernelLand/Modules/IPStack/arp.c [new file with mode: 0644]
KernelLand/Modules/IPStack/arp.h [new file with mode: 0644]
KernelLand/Modules/IPStack/firewall.c [new file with mode: 0644]
KernelLand/Modules/IPStack/firewall.h [new file with mode: 0644]
KernelLand/Modules/IPStack/icmp.c [new file with mode: 0644]
KernelLand/Modules/IPStack/icmp.h [new file with mode: 0644]
KernelLand/Modules/IPStack/interface.c [new file with mode: 0644]
KernelLand/Modules/IPStack/ipstack.h [new file with mode: 0644]
KernelLand/Modules/IPStack/ipv4.c [new file with mode: 0644]
KernelLand/Modules/IPStack/ipv4.h [new file with mode: 0644]
KernelLand/Modules/IPStack/ipv6.c [new file with mode: 0644]
KernelLand/Modules/IPStack/ipv6.h [new file with mode: 0644]
KernelLand/Modules/IPStack/link.c [new file with mode: 0644]
KernelLand/Modules/IPStack/link.h [new file with mode: 0644]
KernelLand/Modules/IPStack/main.c [new file with mode: 0644]
KernelLand/Modules/IPStack/routing.c [new file with mode: 0644]
KernelLand/Modules/IPStack/sctp.c [new file with mode: 0644]
KernelLand/Modules/IPStack/tcp.c [new file with mode: 0644]
KernelLand/Modules/IPStack/tcp.h [new file with mode: 0644]
KernelLand/Modules/IPStack/udp.c [new file with mode: 0644]
KernelLand/Modules/IPStack/udp.h [new file with mode: 0644]
KernelLand/Modules/Input/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/8042.c [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/Makefile [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/common.h [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/kb.c [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/kb_kbdus.h [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/main.c [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/pl050.c [new file with mode: 0644]
KernelLand/Modules/Input/PS2KbMouse/ps2mouse.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/Makefile [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/acess-edi.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_devices.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_dma_streams.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_interrupts.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_memory_mapping.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_objects.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_port_io.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/edi_pthreads.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi/helpers.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi_int.inc.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/edi_io.inc.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/EDI/main.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/Makefile [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/Notes.txt [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/buf.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/cb.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/imc.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/physio/meta_bus.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/physio/meta_intr.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/physio/pio.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/arch/x86.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/attr.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/buf.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/cb.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/imc.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/init.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/log.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/mem.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/meta_gio.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/meta_mgmt.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi/strmem.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/include/udi_physio.h [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/logging.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/main.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/mem.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/meta_gio.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/meta_mgmt.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/physio.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/physio/meta_bus.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/physio/meta_intr.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/physio_main.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/strmem.c [new file with mode: 0644]
KernelLand/Modules/Libraries/SunRPC/proto.h [new file with mode: 0644]
KernelLand/Modules/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/Network/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/Network/NE2000/Makefile [new file with mode: 0644]
KernelLand/Modules/Network/NE2000/ne2000.c [new file with mode: 0644]
KernelLand/Modules/Network/PCnet-FASTIII/Makefile [new file with mode: 0644]
KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c [new file with mode: 0644]
KernelLand/Modules/Network/RTL8139/Makefile [new file with mode: 0644]
KernelLand/Modules/Network/RTL8139/rtl8139.c [new file with mode: 0644]
KernelLand/Modules/Sound/SoundBlaster16/Makefile [new file with mode: 0644]
KernelLand/Modules/Sound/SoundBlaster16/main.c [new file with mode: 0644]
KernelLand/Modules/Sound/SoundBlaster16/sbdsp.txt [new file with mode: 0644]
KernelLand/Modules/Storage/ATA/Makefile [new file with mode: 0644]
KernelLand/Modules/Storage/ATA/common.h [new file with mode: 0644]
KernelLand/Modules/Storage/ATA/io.c [new file with mode: 0644]
KernelLand/Modules/Storage/ATA/main.c [new file with mode: 0644]
KernelLand/Modules/Storage/ATA/mbr.c [new file with mode: 0644]
KernelLand/Modules/Storage/FDD/Makefile [new file with mode: 0644]
KernelLand/Modules/Storage/FDD/fdd.c [new file with mode: 0644]
KernelLand/Modules/Storage/FDDv2/Makefile [new file with mode: 0644]
KernelLand/Modules/Storage/FDDv2/common.h [new file with mode: 0644]
KernelLand/Modules/Storage/FDDv2/fdc.c [new file with mode: 0644]
KernelLand/Modules/Storage/FDDv2/main.c [new file with mode: 0644]
KernelLand/Modules/Storage/LVM/Makefile [new file with mode: 0644]
KernelLand/Modules/Storage/LVM/lvm.h [new file with mode: 0644]
KernelLand/Modules/Storage/LVM/lvm_int.h [new file with mode: 0644]
KernelLand/Modules/Storage/LVM/main.c [new file with mode: 0644]
KernelLand/Modules/Storage/LVM/mbr.c [new file with mode: 0644]
KernelLand/Modules/Storage/LVM/volumes.c [new file with mode: 0644]
KernelLand/Modules/Storage/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/USB/Core/Makefile [new file with mode: 0644]
KernelLand/Modules/USB/Core/hub.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/include/usb_core.h [new file with mode: 0644]
KernelLand/Modules/USB/Core/include/usb_host.h [new file with mode: 0644]
KernelLand/Modules/USB/Core/include/usb_hub.h [new file with mode: 0644]
KernelLand/Modules/USB/Core/main.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb.h [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_devinit.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_io.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_lowlevel.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_lowlevel.h [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_poll.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_proto.h [new file with mode: 0644]
KernelLand/Modules/USB/HID/hid.h [new file with mode: 0644]
KernelLand/Modules/USB/HID/keysyms.h [new file with mode: 0644]
KernelLand/Modules/USB/HID/main.c [new file with mode: 0644]
KernelLand/Modules/USB/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/USB/OHCI/ohci.h [new file with mode: 0644]
KernelLand/Modules/USB/UHCI/Makefile [new file with mode: 0644]
KernelLand/Modules/USB/UHCI/uhci.c [new file with mode: 0644]
KernelLand/Modules/USB/UHCI/uhci.h [new file with mode: 0644]
KernelLand/Modules/armv7/GIC/Makefile [new file with mode: 0644]
KernelLand/Modules/armv7/GIC/gic.c [new file with mode: 0644]
KernelLand/Modules/armv7/GIC/gic.h [new file with mode: 0644]
KernelLand/Modules/armv7/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/link.ld [new file with mode: 0644]
KernelLand/Modules/x86/ISADMA/Makefile [new file with mode: 0644]
KernelLand/Modules/x86/ISADMA/dma.c [new file with mode: 0644]
KernelLand/Modules/x86/ISADMA/include/dma.h [new file with mode: 0644]
KernelLand/Modules/x86/Makefile.tpl [new file with mode: 0644]
KernelLand/Modules/x86/VGAText/Makefile [new file with mode: 0644]
KernelLand/Modules/x86/VGAText/vga.c [new file with mode: 0644]
Modules/Display/BochsGA/Makefile [deleted file]
Modules/Display/BochsGA/bochsvbe.c [deleted file]
Modules/Display/Makefile.tpl [deleted file]
Modules/Display/PL110/Makefile [deleted file]
Modules/Display/PL110/main.c [deleted file]
Modules/Display/Tegra2Vid/Makefile [deleted file]
Modules/Display/Tegra2Vid/main.c [deleted file]
Modules/Display/Tegra2Vid/tegra2.h [deleted file]
Modules/Display/VESA/Makefile [deleted file]
Modules/Display/VESA/common.h [deleted file]
Modules/Display/VESA/main.c [deleted file]
Modules/Filesystems/Ext2/Makefile [deleted file]
Modules/Filesystems/Ext2/dir.c [deleted file]
Modules/Filesystems/Ext2/ext2.c [deleted file]
Modules/Filesystems/Ext2/ext2_common.h [deleted file]
Modules/Filesystems/Ext2/ext2fs.h [deleted file]
Modules/Filesystems/Ext2/read.c [deleted file]
Modules/Filesystems/Ext2/write.c [deleted file]
Modules/Filesystems/FAT/Makefile [deleted file]
Modules/Filesystems/FAT/fat.c [deleted file]
Modules/Filesystems/FAT/fs_fat.h [deleted file]
Modules/Filesystems/InitRD/.gitignore [deleted file]
Modules/Filesystems/InitRD/GenerateInitRD.php [deleted file]
Modules/Filesystems/InitRD/Makefile [deleted file]
Modules/Filesystems/InitRD/files.lst [deleted file]
Modules/Filesystems/InitRD/initrd.h [deleted file]
Modules/Filesystems/InitRD/main.c [deleted file]
Modules/Filesystems/Makefile.tpl [deleted file]
Modules/Filesystems/NFS/Makefile [deleted file]
Modules/Filesystems/NFS/common.h [deleted file]
Modules/Filesystems/NFS/main.c [deleted file]
Modules/Filesystems/NTFS/Makefile [deleted file]
Modules/Filesystems/NTFS/attributes.h [deleted file]
Modules/Filesystems/NTFS/common.h [deleted file]
Modules/Filesystems/NTFS/dir.c [deleted file]
Modules/Filesystems/NTFS/index.h [deleted file]
Modules/Filesystems/NTFS/main.c [deleted file]
Modules/IPStack/Makefile [deleted file]
Modules/IPStack/arp.c [deleted file]
Modules/IPStack/arp.h [deleted file]
Modules/IPStack/firewall.c [deleted file]
Modules/IPStack/firewall.h [deleted file]
Modules/IPStack/icmp.c [deleted file]
Modules/IPStack/icmp.h [deleted file]
Modules/IPStack/interface.c [deleted file]
Modules/IPStack/ipstack.h [deleted file]
Modules/IPStack/ipv4.c [deleted file]
Modules/IPStack/ipv4.h [deleted file]
Modules/IPStack/ipv6.c [deleted file]
Modules/IPStack/ipv6.h [deleted file]
Modules/IPStack/link.c [deleted file]
Modules/IPStack/link.h [deleted file]
Modules/IPStack/main.c [deleted file]
Modules/IPStack/routing.c [deleted file]
Modules/IPStack/sctp.c [deleted file]
Modules/IPStack/tcp.c [deleted file]
Modules/IPStack/tcp.h [deleted file]
Modules/IPStack/udp.c [deleted file]
Modules/IPStack/udp.h [deleted file]
Modules/Input/Makefile.tpl [deleted file]
Modules/Input/PS2KbMouse/8042.c [deleted file]
Modules/Input/PS2KbMouse/Makefile [deleted file]
Modules/Input/PS2KbMouse/common.h [deleted file]
Modules/Input/PS2KbMouse/kb.c [deleted file]
Modules/Input/PS2KbMouse/kb_kbdus.h [deleted file]
Modules/Input/PS2KbMouse/main.c [deleted file]
Modules/Input/PS2KbMouse/pl050.c [deleted file]
Modules/Input/PS2KbMouse/ps2mouse.c [deleted file]
Modules/Interfaces/EDI/Makefile [deleted file]
Modules/Interfaces/EDI/edi/acess-edi.h [deleted file]
Modules/Interfaces/EDI/edi/edi.h [deleted file]
Modules/Interfaces/EDI/edi/edi_devices.h [deleted file]
Modules/Interfaces/EDI/edi/edi_dma_streams.h [deleted file]
Modules/Interfaces/EDI/edi/edi_interrupts.h [deleted file]
Modules/Interfaces/EDI/edi/edi_memory_mapping.h [deleted file]
Modules/Interfaces/EDI/edi/edi_objects.h [deleted file]
Modules/Interfaces/EDI/edi/edi_port_io.h [deleted file]
Modules/Interfaces/EDI/edi/edi_pthreads.h [deleted file]
Modules/Interfaces/EDI/edi/helpers.h [deleted file]
Modules/Interfaces/EDI/edi_int.inc.c [deleted file]
Modules/Interfaces/EDI/edi_io.inc.c [deleted file]
Modules/Interfaces/EDI/main.c [deleted file]
Modules/Interfaces/Makefile.tpl [deleted file]
Modules/Interfaces/UDI/Makefile [deleted file]
Modules/Interfaces/UDI/Notes.txt [deleted file]
Modules/Interfaces/UDI/buf.c [deleted file]
Modules/Interfaces/UDI/cb.c [deleted file]
Modules/Interfaces/UDI/imc.c [deleted file]
Modules/Interfaces/UDI/include/physio/meta_bus.h [deleted file]
Modules/Interfaces/UDI/include/physio/meta_intr.h [deleted file]
Modules/Interfaces/UDI/include/physio/pio.h [deleted file]
Modules/Interfaces/UDI/include/udi.h [deleted file]
Modules/Interfaces/UDI/include/udi/arch/x86.h [deleted file]
Modules/Interfaces/UDI/include/udi/attr.h [deleted file]
Modules/Interfaces/UDI/include/udi/buf.h [deleted file]
Modules/Interfaces/UDI/include/udi/cb.h [deleted file]
Modules/Interfaces/UDI/include/udi/imc.h [deleted file]
Modules/Interfaces/UDI/include/udi/init.h [deleted file]
Modules/Interfaces/UDI/include/udi/log.h [deleted file]
Modules/Interfaces/UDI/include/udi/mem.h [deleted file]
Modules/Interfaces/UDI/include/udi/meta_gio.h [deleted file]
Modules/Interfaces/UDI/include/udi/meta_mgmt.h [deleted file]
Modules/Interfaces/UDI/include/udi/strmem.h [deleted file]
Modules/Interfaces/UDI/include/udi_physio.h [deleted file]
Modules/Interfaces/UDI/logging.c [deleted file]
Modules/Interfaces/UDI/main.c [deleted file]
Modules/Interfaces/UDI/mem.c [deleted file]
Modules/Interfaces/UDI/meta_gio.c [deleted file]
Modules/Interfaces/UDI/meta_mgmt.c [deleted file]
Modules/Interfaces/UDI/physio.c [deleted file]
Modules/Interfaces/UDI/physio/meta_bus.c [deleted file]
Modules/Interfaces/UDI/physio/meta_intr.c [deleted file]
Modules/Interfaces/UDI/physio_main.c [deleted file]
Modules/Interfaces/UDI/strmem.c [deleted file]
Modules/Libraries/SunRPC/proto.h [deleted file]
Modules/Makefile.tpl [deleted file]
Modules/Network/Makefile.tpl [deleted file]
Modules/Network/NE2000/Makefile [deleted file]
Modules/Network/NE2000/ne2000.c [deleted file]
Modules/Network/PCnet-FASTIII/Makefile [deleted file]
Modules/Network/PCnet-FASTIII/pcnet-fast3.c [deleted file]
Modules/Network/RTL8139/Makefile [deleted file]
Modules/Network/RTL8139/rtl8139.c [deleted file]
Modules/Sound/SoundBlaster16/Makefile [deleted file]
Modules/Sound/SoundBlaster16/main.c [deleted file]
Modules/Sound/SoundBlaster16/sbdsp.txt [deleted file]
Modules/Storage/ATA/Makefile [deleted file]
Modules/Storage/ATA/common.h [deleted file]
Modules/Storage/ATA/io.c [deleted file]
Modules/Storage/ATA/main.c [deleted file]
Modules/Storage/ATA/mbr.c [deleted file]
Modules/Storage/FDD/Makefile [deleted file]
Modules/Storage/FDD/fdd.c [deleted file]
Modules/Storage/FDDv2/Makefile [deleted file]
Modules/Storage/FDDv2/common.h [deleted file]
Modules/Storage/FDDv2/fdc.c [deleted file]
Modules/Storage/FDDv2/main.c [deleted file]
Modules/Storage/Makefile.tpl [deleted file]
Modules/USB/Core/Makefile [deleted file]
Modules/USB/Core/hub.c [deleted file]
Modules/USB/Core/include/usb_core.h [deleted file]
Modules/USB/Core/include/usb_host.h [deleted file]
Modules/USB/Core/include/usb_hub.h [deleted file]
Modules/USB/Core/main.c [deleted file]
Modules/USB/Core/usb.c [deleted file]
Modules/USB/Core/usb.h [deleted file]
Modules/USB/Core/usb_devinit.c [deleted file]
Modules/USB/Core/usb_io.c [deleted file]
Modules/USB/Core/usb_lowlevel.c [deleted file]
Modules/USB/Core/usb_lowlevel.h [deleted file]
Modules/USB/Core/usb_poll.c [deleted file]
Modules/USB/Core/usb_proto.h [deleted file]
Modules/USB/HID/hid.h [deleted file]
Modules/USB/HID/keysyms.h [deleted file]
Modules/USB/HID/main.c [deleted file]
Modules/USB/Makefile.tpl [deleted file]
Modules/USB/UHCI/Makefile [deleted file]
Modules/USB/UHCI/uhci.c [deleted file]
Modules/USB/UHCI/uhci.h [deleted file]
Modules/armv7/GIC/Makefile [deleted file]
Modules/armv7/GIC/gic.c [deleted file]
Modules/armv7/GIC/gic.h [deleted file]
Modules/armv7/Makefile.tpl [deleted file]
Modules/link.ld [deleted file]
Modules/x86/ISADMA/Makefile [deleted file]
Modules/x86/ISADMA/dma.c [deleted file]
Modules/x86/ISADMA/include/dma.h [deleted file]
Modules/x86/Makefile.tpl [deleted file]
Modules/x86/VGAText/Makefile [deleted file]
Modules/x86/VGAText/vga.c [deleted file]
Notes/AcessFS.txt [new file with mode: 0644]
Notes/Spinlocks.txt [new file with mode: 0644]
Notes/VFS - Select.txt [new file with mode: 0644]
Notes/VTerm.txt [new file with mode: 0644]

diff --git a/Design Notes/AcessFS.txt b/Design Notes/AcessFS.txt
deleted file mode 100644 (file)
index 7c74beb..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-Acess File System
-- Database Design
-
-== Data Strutures ==
-Blocks are of a size specified in the superblock
-- Superblock
- > Fixed offset: 1024 bytes
-- Field Table
- > Offset set in superblock
-- Index Table
-- Inode Table
-
-=== Superblock ===
-struct sSuperblock {
-       Uint8   Magic[4];       // == '\xACFS'+Version
-       Uint8   BlockSize;      // TrueSize = 2^(7+BlockSize)
-};
-
-=== Field Table ===
-struct sFieldTableEntry {
-       Uint16  Ident;
-       Uint8   Type;
-       Uint8   Length;
-       char    Text[];
-} FieldTable[SuperBlock.NFields];
-
-=== Index Table ==
-struct sIndexTableEntry {
-       Uint16  Field;
-       Uint16  CheckSum;
-       Uint32  Block;
-} IndexTable[SuperBlock.NFields];
-
-=== Index Table entry ==
-struct {
-       Uint32  NumEntries;
-       Uint32  Links[];
-};
-
-=== Inode Table ===
-struct sInodeTable {
-       
-};
-
-=== Inode ===
-struct sInodeEntry {
-       Uint16  Name;
-       Uint8   Size;
-       Uint8   Checksum;
-       Uint8   data[];
-};
-
-Each `sInodeEntry` defines an entry in a "database"
-
diff --git a/Design Notes/Spinlocks.txt b/Design Notes/Spinlocks.txt
deleted file mode 100644 (file)
index b4f6b84..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-SHORTLOCK()
-       cli; lock cmpxchg
-SHORTREL()
-       lock and ; sti
-
-
-LONGLOCK()
-       mov eax, 1
-       lock cmpxchg lock.lock, eax
-       if(eax) {
-               SHORTLOCK(lock.listLock)
-               // add to list (linked list, 4 static entries)
-               SHORTREL(lock.listLock)
-               for(;;)
-               {
-                       check owner
-                       mov eax, 1
-                       lock cmpxchg lock.lock, eax
-                       if(!eax)        break;  // got lock
-                       Threads_Sleep();
-               }
-       }
-
-LONGREL()
-       lock and lock.lock, 0
-       pop off front of list, free entry, wake thread
diff --git a/Design Notes/VFS - Select.txt b/Design Notes/VFS - Select.txt
deleted file mode 100644 (file)
index 70e1993..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-select()
-- Implemented using a wait queue for every file descriptor
-- That requires waiting on sockets to be centeralised
-
-All wait tasks (reads on VTerm, Pipes, PTYs, network sockets) use the kernel
-version of select with an inifinite timeout.
-They then signal the VFS using their VFS node pointer as a reference
-
-The VFS function select()
-- Maintains a list of processes on each node (if select has been called on that node)
-- Each process maybe has a semaphore on it (to use the semaphore code to maintain the process list)
- > Could maybe use a mutex instead
-
-
-VFS_Select(int, fd_set* read, fd_set* write, fd_set* except)
-
-read is the set of sockets that we are waiting to read from
-write         "           "           "           be able to write to
-except        "           "           "        for possible errors on
-
-
-Hence, each VFS_Node has three listener lists (or just pointers)
-- One for when data is avaliable
-- One for when space is avaliable for writing
-- One for when an error occurs (closed pipe, etc ...)
diff --git a/Design Notes/VTerm.txt b/Design Notes/VTerm.txt
deleted file mode 100644 (file)
index 6173108..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-
-== Read ==
-- UTF-8 / UCS-4 Character Stream
- > Selected with mode call
-
-== Write ==
-UTF-8 Emulation Text Mode:
-- Emuates a character device
- > VT-100/ANSI Control Codes
- > Characters/Symbols are sent as UTF-8
-
-/*
-Native Text Mode:
-- NxM 64-bit entries
- > UCS-32 Codepoint (if a diacritic is encountered, the previous character is modified)
- > 12-bit (16 encoded) Foreground
- > 12-bit (16 encoded) Background
-*/
-
-Framebuffer Graphics:
-- WxH 32-bit (3x 8-bit channels) framebuffer
-- Write to entire framebuffer
-
-Accellerated Graphics:
-- Command Stream
- > Each Node.Write call is a single command
- + NOP (-)
- + Direct (Uint16 X, Y, W, H, Uint32 Data[])
- + Blit (Uint16 W, H, SrcX, SrxY, DstX, DstY, Uint32 Data[])
- + Fill (Uint16 X, Y, W, H)
- + Rect (Uint16 X, Y, W, H)
- + Line (Uint16 X, Y, W, H)
- + Text (Uint16 X, Y, Size, Font)
- + ShowTile (Uint16 ID, Uint16 X, Y)
- + DelTile (Uint16 ID)
-- Extra IOCtls
- + int LoadFont(char *Path)
- + UnloadFont(int *ID)
- + int MakeTile(struct {Uint16 W, H, Uint32 Data[]} *Img)
- + DelTile(int *ID)
-- Allow fast switch between Accel/Framebuffer?
-- Min Reqd Tile Size 32x32
- > Tiles should be driver emulated if unavaliable by hardware
-3D Graphics: (Can be emulated if not avaliable, or just denied)
-- Command Stream
- >
- + NOP (-)
- + FlipBuffer (-)
- + LoadTexture(Uint16 ID, W, H, Uint32 Data[])
- + UnloadTexture(Uint16 ID)
- + SetTexture(Uint16 ID)
- + Triangle (Uint16 Texture, Uint32[3+3+2][3])
diff --git a/Kernel/.gitignore b/Kernel/.gitignore
deleted file mode 100644 (file)
index 439ce3e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*.BuildNum.*
diff --git a/Kernel/Doxyfile b/Kernel/Doxyfile
deleted file mode 100644 (file)
index a474dd5..0000000
+++ /dev/null
@@ -1,1510 +0,0 @@
-# Doxyfile 1.5.8
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file 
-# that follow. The default is UTF-8 which is also the encoding used for all 
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
-# iconv built into libc) for the transcoding. See 
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
-# by quotes) that should identify the project.
-
-PROJECT_NAME           = Acess2
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
-# This could be handy for archiving the generated documentation or 
-# if some version control system is used.
-
-PROJECT_NUMBER         = 
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
-# base path where the generated documentation will be put. 
-# If a relative path is entered, it will be relative to the location 
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = ../SrcDoc/Kernel
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
-# 4096 sub-directories (in 2 levels) under the output directory of each output 
-# format and will distribute the generated files over these directories. 
-# Enabling this option can be useful when feeding doxygen a huge amount of 
-# source files, where putting all generated files in the same directory would 
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS         = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
-# documentation generated by doxygen is written. Doxygen will use this 
-# information to generate all constant output in the proper language. 
-# The default language is English, other supported languages are: 
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
-# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
-# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
-# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
-# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, 
-# Spanish, Swedish, and Ukrainian.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
-# include brief member descriptions after the members that are listed in 
-# the file and class documentation (similar to JavaDoc). 
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
-# the brief description of a member or function before the detailed description. 
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator 
-# that is used to form the text in various listings. Each string 
-# in this list, if found as the leading text of the brief description, will be 
-# stripped from the text and the result after processing the whole list, is 
-# used as the annotated text. Otherwise, the brief description is used as-is. 
-# If left blank, the following values are used ("$name" is automatically 
-# replaced with the name of the entity): "The $name class" "The $name widget" 
-# "The $name file" "is" "provides" "specifies" "contains" 
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF       = 
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
-# Doxygen will generate a detailed section even if there is only a brief 
-# description.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
-# inherited members of a class in the documentation of that class as if those 
-# members were ordinary class members. Constructors, destructors and assignment 
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
-# path before files name in the file list and in the header files. If set 
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES        = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
-# can be used to strip a user-defined part of the path. Stripping is 
-# only done if one of the specified strings matches the left-hand part of 
-# the path. The tag can be used to show relative paths in the file list. 
-# If left blank the directory from which doxygen is run is used as the 
-# path to strip.
-
-STRIP_FROM_PATH        = 
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
-# the path mentioned in the documentation of a class, which tells 
-# the reader which header file to include in order to use a class. 
-# If left blank only the name of the header file containing the class 
-# definition is used. Otherwise one should specify the include paths that 
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH    = 
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
-# (but less readable) file names. This can be useful is your file systems 
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
-# will interpret the first line (until the first dot) of a JavaDoc-style 
-# comment as the brief description. If set to NO, the JavaDoc 
-# comments will behave just like regular Qt-style comments 
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF      = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
-# interpret the first line (until the first dot) of a Qt-style 
-# comment as the brief description. If set to NO, the comments 
-# will behave just like regular Qt-style comments (thus requiring 
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
-# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
-# comments) as a brief description. This used to be the default behaviour. 
-# The new default is to treat a multi-line C++ comment block as a detailed 
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
-# member inherits the documentation from any documented member that it 
-# re-implements.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
-# a new page for each member. If set to NO, the documentation of a member will 
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that acts 
-# as commands in the documentation. An alias has the form "name=value". 
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
-# put the command \sideeffect (or @sideeffect) in the documentation, which 
-# will result in a user-defined paragraph with heading "Side Effects:". 
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES                = 
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
-# sources only. Doxygen will then generate output that is more tailored for C. 
-# For instance, some of the names that are used will be different. The list 
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
-# sources only. Doxygen will then generate output that is more tailored for 
-# Java. For instance, namespaces will be presented as packages, qualified 
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
-# sources only. Doxygen will then generate output that is more tailored for 
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
-# sources. Doxygen will then generate output that is tailored for 
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it parses. 
-# With this tag you can assign which parser to use for a given extension. 
-# Doxygen has a built-in mapping, but you can override or extend it using this tag. 
-# The format is ext=language, where ext is a file extension, and language is one of 
-# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, 
-# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat 
-# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), 
-# use: inc=Fortran f=C
-
-EXTENSION_MAPPING      = 
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
-# to include (a tag file for) the STL sources as input, then you should 
-# set this tag to YES in order to let doxygen match functions declarations and 
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
-# func(std::string) {}). This also make the inheritance and collaboration 
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to 
-# enable parsing support.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
-# Doxygen will parse them like normal C++ but will assume all classes use public 
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter 
-# and setter methods for a property. Setting this option to YES (the default) 
-# will make doxygen to replace the get and set methods by a property in the 
-# documentation. This will only work if the methods are indeed getting or 
-# setting a simple type. If this is not the case, or you want to show the 
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
-# tag is set to YES, then doxygen will reuse the documentation of the first 
-# member in the group (if any) for the other members of the group. By default 
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
-# the same type (for instance a group of public functions) to be put as a 
-# subgroup of that type (e.g. under the Public Functions section). Set it to 
-# NO to prevent subgrouping. Alternatively, this can be done per class using 
-# the \nosubgrouping command.
-
-SUBGROUPING            = YES
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
-# is documented as struct, union, or enum with the name of the typedef. So 
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
-# with name TypeT. When disabled the typedef will appear as a member of a file, 
-# namespace, or class. And the struct will be named TypeS. This can typically 
-# be useful for C code in case the coding convention dictates that all compound 
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT   = YES
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
-# determine which symbols to keep in memory and which to flush to disk. 
-# When the cache is full, less often used symbols will be written to disk. 
-# For small to medium size projects (<1000 input files) the default value is 
-# probably good enough. For larger projects a too small cache size can cause 
-# doxygen to be busy swapping symbols to and from disk most of the time 
-# causing a significant performance penality. 
-# If the system has enough physical memory increasing the cache will improve the 
-# performance by keeping more symbols in memory. Note that the value works on 
-# a logarithmic scale so increasing the size by one will rougly double the 
-# memory usage. The cache size is given by this formula: 
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
-# documentation are documented, even if no documentation was available. 
-# Private class members and static file members will be hidden unless 
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL            = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
-# will be included in the documentation.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file 
-# will be included in the documentation.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
-# defined locally in source files will be included in the documentation. 
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. When set to YES local 
-# methods, which are defined in the implementation section but not in 
-# the interface are included in the documentation. 
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be 
-# extracted and appear in the documentation as a namespace called 
-# 'anonymous_namespace{file}', where file will be replaced with the base 
-# name of the file that contains the anonymous namespace. By default 
-# anonymous namespace are hidden.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
-# undocumented members of documented classes, files or namespaces. 
-# If set to NO (the default) these members will be included in the 
-# various overviews, but no documentation section is generated. 
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
-# undocumented classes that are normally visible in the class hierarchy. 
-# If set to NO (the default) these classes will be included in the various 
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
-# friend (class|struct|union) declarations. 
-# If set to NO (the default) these declarations will be included in the 
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
-# documentation blocks found inside the body of a function. 
-# If set to NO (the default) these blocks will be appended to the 
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation 
-# that is typed after a \internal command is included. If the tag is set 
-# to NO (the default) then the documentation will be excluded. 
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
-# file names in lower-case letters. If set to YES upper-case letters are also 
-# allowed. This is useful if you have classes or files whose names only differ 
-# in case and if your file system supports case sensitive file names. Windows 
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
-# will show members with their full class and namespace scopes in the 
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
-# will put a list of the files that are included by a file in the documentation 
-# of that file.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
-# is inserted in the documentation for inline members.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
-# will sort the (detailed) documentation of file and class members 
-# alphabetically by member name. If set to NO the members will appear in 
-# declaration order.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
-# brief documentation of file, namespace and class members alphabetically 
-# by member name. If set to NO (the default) the members will appear in 
-# declaration order.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
-# hierarchy of group names into alphabetical order. If set to NO (the default) 
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
-# sorted by fully-qualified names, including namespaces. If set to 
-# NO (the default), the class list will be sorted only by class name, 
-# not including the namespace part. 
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
-# Note: This option applies only to the class list, not to the 
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or 
-# disable (NO) the todo list. This list is created by putting \todo 
-# commands in the documentation.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or 
-# disable (NO) the test list. This list is created by putting \test 
-# commands in the documentation.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or 
-# disable (NO) the bug list. This list is created by putting \bug 
-# commands in the documentation.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
-# disable (NO) the deprecated list. This list is created by putting 
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional 
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS       = 
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
-# the initial value of a variable or define consists of for it to appear in 
-# the documentation. If the initializer consists of more lines than specified 
-# here it will be hidden. Use a value of 0 to hide initializers completely. 
-# The appearance of the initializer of individual variables and defines in the 
-# documentation can be controlled using \showinitializer or \hideinitializer 
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
-# at the bottom of the documentation of classes and structs. If set to YES the 
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES        = YES
-
-# If the sources in your project are distributed over multiple directories 
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
-# This will remove the Files entry from the Quick Index and from the 
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
-# Namespaces page. 
-# This will remove the Namespaces entry from the Quick Index 
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
-# doxygen should invoke to get the current version for each file (typically from 
-# the version control system). Doxygen will invoke the program by executing (via 
-# popen()) the command <command> <input-file>, where <command> is the value of 
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
-# provided by doxygen. Whatever the program writes to standard output 
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER    = 
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by 
-# doxygen. The layout file controls the global structure of the generated output files 
-# in an output format independent way. The create the layout file that represents 
-# doxygen's defaults, run doxygen with the -l option. You can optionally specify a 
-# file name after the option, if omitted DoxygenLayout.xml will be used as the name 
-# of the layout file.
-
-LAYOUT_FILE            = 
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated 
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are 
-# generated by doxygen. Possible values are YES and NO. If left blank 
-# NO is used.
-
-WARNINGS               = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
-# potential errors in the documentation, such as not documenting some 
-# parameters in a documented function, or documenting parameters that 
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be abled to get warnings for 
-# functions that are documented, but have no documentation for their parameters 
-# or return value. If set to NO (the default) doxygen will only warn about 
-# wrong or incomplete parameter documentation, but not about the absence of 
-# documentation.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that 
-# doxygen can produce. The string should contain the $file, $line, and $text 
-# tags, which will be replaced by the file and line number from which the 
-# warning originated and the warning text. Optionally the format may contain 
-# $version, which will be replaced by the version of the file (if it could 
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning 
-# and error messages should be written. If left blank the output is written 
-# to stderr.
-
-WARN_LOGFILE           = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain 
-# documented source files. You may enter file names like "myfile.cpp" or 
-# directories like "/usr/src/myproject". Separate the files or directories 
-# with spaces.
-
-INPUT                  = .
-
-# This tag can be used to specify the character encoding of the source files 
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
-# also the default input encoding. Doxygen uses libiconv (or the iconv built 
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
-# the list of possible encodings.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the 
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank the following patterns are tested: 
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
-
-FILE_PATTERNS          = *.c *.h
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
-# should be searched for input files as well. Possible values are YES and NO. 
-# If left blank NO is used.
-
-RECURSIVE              = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should 
-# excluded from the INPUT source files. This way you can easily exclude a 
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE                = arch/archdoc.h
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
-# directories that are symbolic links (a Unix filesystem feature) are excluded 
-# from the input.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the 
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
-# certain files from those directories. Note that the wildcards are matched 
-# against the file with absolute path, so to exclude all test directories 
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       = 
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
-# (namespaces, classes, functions, etc.) that should be excluded from the 
-# output. The symbol name can be a fully qualified name, a word, or if the 
-# wildcard * is used, a substring. Examples: ANamespace, AClass, 
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS        = 
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or 
-# directories that contain example code fragments that are included (see 
-# the \include command).
-
-EXAMPLE_PATH           = 
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank all files are included.
-
-EXAMPLE_PATTERNS       = 
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
-# searched for input files to be used with the \include or \dontinclude 
-# commands irrespective of the value of the RECURSIVE tag. 
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or 
-# directories that contain image that are included in the documentation (see 
-# the \image command).
-
-IMAGE_PATH             = 
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should 
-# invoke to filter for each input file. Doxygen will invoke the filter program 
-# by executing (via popen()) the command <filter> <input-file>, where <filter> 
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
-# input file. Doxygen will then use the output that the filter program writes 
-# to standard output. 
-# If FILTER_PATTERNS is specified, this tag will be 
-# ignored.
-
-INPUT_FILTER           = 
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
-# basis. 
-# Doxygen will compare the file name with each pattern and apply the 
-# filter if there is a match. 
-# The filters are a list of the form: 
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
-# is applied to all files.
-
-FILTER_PATTERNS        = 
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
-# INPUT_FILTER) will be used to filter the input files when producing source 
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES    = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
-# be generated. Documented entities will be cross-referenced with these sources. 
-# Note: To get rid of all source code in the generated output, make sure also 
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body 
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
-# doxygen to hide any special comment blocks from generated source code 
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES 
-# then for each documented function all documented 
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES 
-# then for each documented function all documented entities 
-# called/used by that function will be listed.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
-# link to the source code. 
-# Otherwise they will link to the documentation.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code 
-# will point to the HTML generated by the htags(1) tool instead of doxygen 
-# built-in source browser. The htags tool is part of GNU's global source 
-# tagging system (see http://www.gnu.org/software/global/global.html). You 
-# will need version 4.8.6 or higher.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
-# will generate a verbatim copy of the header file for each class for 
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
-# of all compounds will be generated. Enable this if the project 
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX     = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all 
-# classes will be put under the same header in the alphabetical index. 
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX          = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
-# generate HTML output.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard header.
-
-HTML_HEADER            = 
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard footer.
-
-HTML_FOOTER            = 
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
-# style sheet that is used by each HTML page. It can be used to 
-# fine-tune the look of the HTML output. If the tag is left blank doxygen 
-# will generate a default style sheet. Note that doxygen will try to copy 
-# the style sheet file to the HTML output directory, so don't put your own 
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET        = 
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
-# files or namespaces will be aligned in HTML using tables. If set to 
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
-# documentation will contain sections that can be hidden and shown after the 
-# page has loaded. For this to work a browser that supports 
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files 
-# will be generated that can be used as input for Apple's Xcode 3 
-# integrated development environment, introduced with OSX 10.5 (Leopard). 
-# To create a documentation set, doxygen will generate a Makefile in the 
-# HTML output directory. Running make will produce the docset in that 
-# directory and running "make install" will install the docset in 
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
-# it at startup. 
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
-
-GENERATE_DOCSET        = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
-# feed. A documentation feed provides an umbrella under which multiple 
-# documentation sets from a single provider (such as a company or product suite) 
-# can be grouped.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
-# should uniquely identify the documentation set bundle. This should be a 
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
-# will be generated that can be used as input for tools like the 
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP      = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
-# be used to specify the file name of the resulting .chm file. You 
-# can add a path in front of the file if the result should not be 
-# written to the html output directory.
-
-CHM_FILE               = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
-# be used to specify the location (absolute path including file name) of 
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION           = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
-# controls if a separate .chi index file is generated (YES) or that 
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI           = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
-# content.
-
-CHM_INDEX_ENCODING     = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
-# controls whether a binary table of contents is generated (YES) or a 
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members 
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND             = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER 
-# are set, an additional index file will be generated that can be used as input for 
-# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated 
-# HTML documentation.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
-# be used to specify the file name of the resulting .qch file. 
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE               = 
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating 
-# Qt Help Project output. For more information please see 
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE          = 
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
-# Qt Help Project output. For more information please see 
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. 
-# For more information please see 
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME   = 
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see 
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS  = 
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's 
-# filter section matches. 
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS  = 
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
-# be used to specify the location of Qt's qhelpgenerator. 
-# If non-empty doxygen will try to run qhelpgenerator on the generated 
-# .qhp file.
-
-QHG_LOCATION           = 
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
-# top of each HTML page. The value NO (the default) enables the index and 
-# the value YES disables it.
-
-DISABLE_INDEX          = NO
-
-# This tag can be used to set the number of enum values (range [1..20]) 
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
-# structure should be generated to display hierarchical information. 
-# If the tag value is set to FRAME, a side panel will be generated 
-# containing a tree-like index structure (just like the one that 
-# is generated for HTML Help). For this to work a browser that supports 
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
-# probably better off using the HTML help feature. Other possible values 
-# for this tag are: HIERARCHIES, which will generate the Groups, Directories, 
-# and Class Hierarchy pages using a tree view instead of an ordered list; 
-# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which 
-# disables this behavior completely. For backwards compatibility with previous 
-# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE 
-# respectively.
-
-GENERATE_TREEVIEW      = NONE
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
-# used to set the initial width (in pixels) of the frame in which the tree 
-# is shown.
-
-TREEVIEW_WIDTH         = 250
-
-# Use this tag to change the font size of Latex formulas included 
-# as images in the HTML documentation. The default is 10. Note that 
-# when you change the font size after a successful doxygen run you need 
-# to manually remove any form_*.png images from the HTML output directory 
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE       = 10
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
-# generate Latex output.
-
-GENERATE_LATEX         = YES
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
-# invoked. If left blank `latex' will be used as the default command name.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
-# generate index for LaTeX. If left blank `makeindex' will be used as the 
-# default command name.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
-# LaTeX documents. This may be useful for small projects and may help to 
-# save some trees in general.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used 
-# by the printer. Possible values are: a4, a4wide, letter, legal and 
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE             = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES         = 
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
-# the generated latex document. The header should contain everything until 
-# the first chapter. If it is left blank doxygen will generate a 
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER           = 
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
-# contain links (just like the HTML output) instead of page references 
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
-# plain latex in the generated Makefile. Set this option to YES to get a 
-# higher quality PDF documentation.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
-# command to the generated LaTeX files. This will instruct LaTeX to keep 
-# running if errors occur, instead of asking the user for help. 
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE        = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
-# include the index chapters (such as File Index, Compound Index, etc.) 
-# in the output.
-
-LATEX_HIDE_INDICES     = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
-# The RTF output is optimized for Word 97 and may not look very pretty with 
-# other RTF readers or editors.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
-# RTF documents. This may be useful for small projects and may help to 
-# save some trees in general.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
-# will contain hyperlink fields. The RTF file will 
-# contain links (just like the HTML output) instead of page references. 
-# This makes the output suitable for online browsing using WORD or other 
-# programs which support those fields. 
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's 
-# config file, i.e. a series of assignments. You only have to provide 
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE    = 
-
-# Set optional variables used in the generation of an rtf document. 
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE    = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
-# generate man pages
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to 
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION          = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
-# then it will generate one additional man file for each entity 
-# documented in the real man page(s). These additional files 
-# only source the real man page, but without them the man command 
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will 
-# generate an XML file that captures the structure of 
-# the code including all documentation.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT             = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema, 
-# which can be used by a validating XML parser to check the 
-# syntax of the XML files.
-
-XML_SCHEMA             = 
-
-# The XML_DTD tag can be used to specify an XML DTD, 
-# which can be used by a validating XML parser to check the 
-# syntax of the XML files.
-
-XML_DTD                = 
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
-# dump the program listings (including syntax highlighting 
-# and cross-referencing information) to the XML output. Note that 
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
-# generate an AutoGen Definitions (see autogen.sf.net) file 
-# that captures the structure of the code including all 
-# documentation. Note that this feature is still experimental 
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
-# generate a Perl module file that captures the structure of 
-# the code including all documentation. Note that this 
-# feature is still experimental and incomplete at the 
-# moment.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
-# nicely formatted so it can be parsed by a human reader. 
-# This is useful 
-# if you want to understand what is going on. 
-# On the other hand, if this 
-# tag is set to NO the size of the Perl module output will be much smaller 
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file 
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
-# This is useful so different doxyrules.make files included by the same 
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor   
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
-# evaluate all C-preprocessor directives found in the sources and include 
-# files.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
-# names in the source code. If set to NO (the default) only conditional 
-# compilation will be performed. Macro expansion can be done in a controlled 
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION        = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
-# then the macro expansion is limited to the macros specified with the 
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that 
-# contain include files that are not input files but should be processed by 
-# the preprocessor.
-
-INCLUDE_PATH           = 
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
-# patterns (like *.h and *.hpp) to filter out the header-files in the 
-# directories. If left blank, the patterns specified with FILE_PATTERNS will 
-# be used.
-
-INCLUDE_FILE_PATTERNS  = 
-
-# The PREDEFINED tag can be used to specify one or more macro names that 
-# are defined before the preprocessor is started (similar to the -D option of 
-# gcc). The argument of the tag is a list of macros of the form: name 
-# or name=definition (no spaces). If the definition and the = are 
-# omitted =1 is assumed. To prevent a macro definition from being 
-# undefined via #undef or recursively expanded use the := operator 
-# instead of the = operator.
-
-PREDEFINED             = 
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
-# this tag can be used to specify a list of macro names that should be expanded. 
-# The macro definition that is found in the sources will be used. 
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED      = 
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
-# doxygen's preprocessor will remove all function-like macros that are alone 
-# on a line, have an all uppercase name, and do not end with a semicolon. Such 
-# function macros are typically used for boiler-plate code, and will confuse 
-# the parser if not removed.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references   
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles. 
-# Optionally an initial location of the external documentation 
-# can be added for each tagfile. The format of a tag file without 
-# this location is as follows: 
-#  
-# TAGFILES = file1 file2 ... 
-# Adding location for the tag files is done as follows: 
-#  
-# TAGFILES = file1=loc1 "file2 = loc2" ... 
-# where "loc1" and "loc2" can be relative or absolute paths or 
-# URLs. If a location is present for each tag, the installdox tool 
-# does not have to be run to correct the links. 
-# Note that each tag file must have a unique name 
-# (where the name does NOT include the path) 
-# If a tag file is not located in the directory in which doxygen 
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES               = 
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE       = 
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
-# in the class index. If set to NO only the inherited external classes 
-# will be listed.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
-# in the modules index. If set to NO, only the current project's groups will 
-# be listed.
-
-EXTERNAL_GROUPS        = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script 
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool   
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
-# or super classes. Setting the tag to NO turns the diagrams off. Note that 
-# this option is superseded by the HAVE_DOT option below. This is only a 
-# fallback. It is recommended to install and use dot, since it yields more 
-# powerful graphs.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc 
-# command. Doxygen will then run the mscgen tool (see 
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
-# the mscgen tool resides. If left empty the tool is assumed to be found in the 
-# default search path.
-
-MSCGEN_PATH            = 
-
-# If set to YES, the inheritance and collaboration graphs will hide 
-# inheritance and usage relations if the target is undocumented 
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
-# available from the path. This tool is part of Graphviz, a graph visualization 
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT               = NO
-
-# By default doxygen will write a font called FreeSans.ttf to the output 
-# directory and reference it in all dot files that doxygen generates. This 
-# font does not include all possible unicode characters however, so when you need 
-# these (or just want a differently looking font) you can specify the font name 
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
-# which can be done by putting it in a standard location or by setting the 
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
-# containing the font.
-
-DOT_FONTNAME           = FreeSans
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
-# The default size is 10pt.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the output directory to look for the 
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
-# different font using DOT_FONTNAME you can set the path where dot 
-# can find it using this tag.
-
-DOT_FONTPATH           = 
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect inheritance relations. Setting this tag to YES will force the 
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect implementation dependencies (inheritance, containment, and 
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
-# collaboration diagrams in a style similar to the OMG's Unified Modeling 
-# Language.
-
-UML_LOOK               = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the 
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
-# tags are set to YES then doxygen will generate a graph for each documented 
-# file showing the direct and indirect include dependencies of the file with 
-# other documented files.
-
-INCLUDE_GRAPH          = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
-# documented header file showing the documented files that directly or 
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
-# doxygen will generate a call dependency graph for every global function 
-# or class method. Note that enabling this option will significantly increase 
-# the time of a run. So in most cases it will be better to enable call graphs 
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
-# doxygen will generate a caller dependency graph for every global function 
-# or class method. Note that enabling this option will significantly increase 
-# the time of a run. So in most cases it will be better to enable caller 
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
-# then doxygen will show the dependencies a directory has on other directories 
-# in a graphical way. The dependency relations are determined by the #include 
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
-# generated by dot. Possible values are png, jpg, or gif 
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT       = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be 
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH               = 
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that 
-# contain dot files that are included in the documentation (see the 
-# \dotfile command).
-
-DOTFILE_DIRS           = 
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
-# nodes that will be shown in the graph. If the number of nodes in a graph 
-# becomes larger than this value, doxygen will truncate the graph, which is 
-# visualized by representing a node as a red box. Note that doxygen if the 
-# number of direct children of the root node in a graph is already larger than 
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
-# graphs generated by dot. A depth value of 3 means that only nodes reachable 
-# from the root by following a path via at most 3 edges will be shown. Nodes 
-# that lay further from the root node will be omitted. Note that setting this 
-# option to 1 or 2 may greatly reduce the computation time needed for large 
-# code bases. Also note that the size of a graph can be further restricted by 
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
-# background. This is disabled by default, because dot on Windows does not 
-# seem to support this out of the box. Warning: Depending on the platform used, 
-# enabling this option may lead to badly anti-aliased labels on the edges of 
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
-# files in one run (i.e. multiple -o and -T options on the command line). This 
-# makes dot run faster, but since only newer versions of dot (>1.8.10) 
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
-# generate a legend page explaining the meaning of the various boxes and 
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
-# remove the intermediate dot files that are used to generate 
-# the various graphs.
-
-DOT_CLEANUP            = YES
-
-#---------------------------------------------------------------------------
-# Options related to the search engine
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be 
-# used. If set to NO the values of all tags below this one will be ignored.
-
-SEARCHENGINE           = NO
diff --git a/Kernel/Doxyfile.api b/Kernel/Doxyfile.api
deleted file mode 100644 (file)
index 6872e55..0000000
+++ /dev/null
@@ -1,1775 +0,0 @@
-# Doxyfile 1.7.5.1
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a hash (#) is considered a comment and will be ignored.
-# The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
-
-PROJECT_NAME           = Acess2
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER         =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF          =
-
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
-
-PROJECT_LOGO           =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = ../APIDoc
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS         = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF       =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES        = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH        =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH    =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF      = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES                =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
-
-OPTIMIZE_FOR_FORTRAN   = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
-
-OPTIMIZE_OUTPUT_VHDL   = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
-
-EXTENSION_MAPPING      =
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT        = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
-
-SIP_SUPPORT            = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
-
-IDL_PROPERTY_SUPPORT   = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING            = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
-
-#INLINE_SIMPLE_STRUCTS  = NO
-
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-
-TYPEDEF_HIDES_STRUCT   = YES
-
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE      = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL            = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC         = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES  = NO
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
-
-FORCE_LOCAL_INCLUDES   = NO
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS       = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
-
-SORT_GROUP_NAMES       = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
-
-STRICT_PROTO_MATCHING  = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS       =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES        = YES
-
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
-
-SHOW_FILES             = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
-
-SHOW_NAMESPACES        = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER    =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
-
-LAYOUT_FILE            =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE.
-
-#CITE_BIB_FILES         =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS               = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR      = YES
-
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE           =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT                  = include/apidoc_mainpage.h \
-                         include/acess.h \
-                         include/hal_proc.h \
-                         include/binary.h \
-                         include/modules.h \
-                         include/vfs.h \
-                         include/vfs_ext.h \
-                         include/fs_devfs.h \
-                         include/fs_sysfs.h \
-                         include/iocache.h \
-                         arch/archdoc.h \
-                         include/apidoc/arch_x86.h \
-                         include/api_drv_common.h \
-                         include/api_drv_video.h \
-                         include/api_drv_terminal.h \
-                         include/api_drv_disk.h \
-                         include/api_drv_keyboard.h \
-                         include/api_drv_joystick.h \
-                         include/api_drv_network.h
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
-
-FILE_PATTERNS          = api_drv_*.h
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE              = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-# Note that relative paths are relative to directory from which doxygen is run.
-
-EXCLUDE                =
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS        =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH           =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS       =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH             =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER           =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS        =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES    = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
-
-FILTER_SOURCE_PATTERNS =
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX     = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX          =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-#  for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is adviced to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
-
-HTML_HEADER            =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER            =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET        =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
-
-HTML_EXTRA_FILES       =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
-
-HTML_COLORSTYLE_HUE    = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
-
-HTML_COLORSTYLE_SAT    = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
-
-HTML_COLORSTYLE_GAMMA  = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
-
-HTML_TIMESTAMP         = YES
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-
-GENERATE_DOCSET        = NO
-
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
-
-DOCSET_FEEDNAME        = "Doxygen generated docs"
-
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
-
-DOCSET_BUNDLE_ID       = org.doxygen.Project
-
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-
-DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
-
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
-
-DOCSET_PUBLISHER_NAME  = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP      = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE               =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION           =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI           = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
-
-CHM_INDEX_ENCODING     =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND             = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
-
-GENERATE_QHP           = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
-
-QCH_FILE               =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
-
-QHP_NAMESPACE          =
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
-
-QHP_VIRTUAL_FOLDER     = doc
-
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
-
-QHP_CUST_FILTER_NAME   =
-
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
-
-QHP_CUST_FILTER_ATTRS  =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
-
-QHP_SECT_FILTER_ATTRS  =
-
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
-
-QHG_LOCATION           =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-#  will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
-
-GENERATE_ECLIPSEHELP   = NO
-
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
-
-ECLIPSE_DOC_ID         = org.doxygen.Project
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX          = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW      = NONE
-
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES       = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH         = 250
-
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
-
-EXT_LINKS_IN_WINDOW    = NO
-
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
-
-FORMULA_FONTSIZE       = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
-
-FORMULA_TRANSPARENT    = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
-
-USE_MATHJAX            = NO
-
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the
-# mathjax.org site, so you can quickly see the result without installing
-# MathJax, but it is strongly recommended to install a local copy of MathJax
-# before deployment.
-
-MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
-
-#MATHJAX_EXTENSIONS     =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-
-SEARCHENGINE           = NO
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
-
-SERVER_BASED_SEARCH    = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE             = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES         =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER           =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
-
-LATEX_FOOTER           =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS         = YES
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX           = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE        = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES     = NO
-
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
-
-LATEX_SOURCE_CODE      = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
-
-#LATEX_BIB_STYLE        = plain
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE    =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE    =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION          = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT             = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD                =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION        = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF     = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH           =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS  =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED             =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
-
-EXPAND_AS_DEFINED      =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-#
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-#
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES               =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE       =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS        = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT               = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
-
-DOT_NUM_THREADS        = 0
-
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
-# directory containing the font.
-
-DOT_FONTNAME           = FreeSans
-
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
-
-DOT_FONTSIZE           = 10
-
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
-
-DOT_FONTPATH           =
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK               = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH          = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible in IE 9+ (other browsers do not have this requirement).
-
-DOT_IMAGE_FORMAT       = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible. Older versions of IE do not have SVG support.
-
-#INTERACTIVE_SVG        = NO
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH               =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS           =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
-
-MSCFILE_DIRS           =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP            = YES
diff --git a/Kernel/DoxygenLayout.xml b/Kernel/DoxygenLayout.xml
deleted file mode 100644 (file)
index e8faa6d..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-<doxygenlayout version="1.0">
-  <!-- Navigation index tabs for HTML output -->
-  <navindex>
-    <tab type="mainpage" visible="yes" title=""/>
-    <tab type="pages" visible="yes" title="" intro=""/>
-    <tab type="modules" visible="yes" title="" intro=""/>
-    <tab type="namespaces" visible="yes" title="">
-      <tab type="namespaces" visible="yes" title="" intro=""/>
-      <tab type="namespacemembers" visible="yes" title="" intro=""/>
-    </tab>
-    <tab type="classes" visible="yes" title="">
-      <tab type="classes" visible="yes" title="" intro=""/>
-      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
-      <tab type="hierarchy" visible="yes" title="" intro=""/>
-      <tab type="classmembers" visible="yes" title="" intro=""/>
-    </tab>
-    <tab type="files" visible="yes" title="">
-      <tab type="files" visible="yes" title="" intro=""/>
-      <tab type="globals" visible="yes" title="" intro=""/>
-    </tab>
-    <tab type="dirs" visible="yes" title="" intro=""/>
-    <tab type="examples" visible="yes" title="" intro=""/>  
-  </navindex>
-
-  <!-- Layout definition for a class page -->
-  <class>
-    <briefdescription visible="yes"/>
-    <includes visible="$SHOW_INCLUDE_FILES"/>
-    <inheritancegraph visible="$CLASS_GRAPH"/>
-    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
-    <allmemberslink visible="yes"/>
-    <memberdecl>
-      <nestedclasses visible="yes" title=""/>
-      <publictypes title=""/>
-      <publicslots title=""/>
-      <signals title=""/>
-      <publicmethods title=""/>
-      <publicstaticmethods title=""/>
-      <publicattributes title=""/>
-      <publicstaticattributes title=""/>
-      <protectedtypes title=""/>
-      <protectedslots title=""/>
-      <protectedmethods title=""/>
-      <protectedstaticmethods title=""/>
-      <protectedattributes title=""/>
-      <protectedstaticattributes title=""/>
-      <packagetypes title=""/>
-      <packagemethods title=""/>
-      <packagestaticmethods title=""/>
-      <packageattributes title=""/>
-      <packagestaticattributes title=""/>
-      <properties title=""/>
-      <events title=""/>
-      <privatetypes title=""/>
-      <privateslots title=""/>
-      <privatemethods title=""/>
-      <privatestaticmethods title=""/>
-      <privateattributes title=""/>
-      <privatestaticattributes title=""/>
-      <friends title=""/>
-      <related title="" subtitle=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <typedefs title=""/>
-      <enums title=""/>
-      <constructors title=""/>
-      <functions title=""/>
-      <related title=""/>
-      <variables title=""/>
-      <properties title=""/>
-      <events title=""/>
-    </memberdef>
-    <usedfiles visible="$SHOW_USED_FILES"/>
-    <authorsection visible="yes"/>
-  </class>
-
-  <!-- Layout definition for a namespace page -->
-  <namespace>
-    <briefdescription visible="yes"/>
-    <memberdecl>
-      <nestednamespaces visible="yes" title=""/>
-      <classes visible="yes" title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-    </memberdef>
-    <authorsection visible="yes"/>
-  </namespace>
-
-  <!-- Layout definition for a file page -->
-  <file>
-    <briefdescription visible="yes"/>
-    <includes visible="$SHOW_INCLUDE_FILES"/>
-    <includegraph visible="$INCLUDE_GRAPH"/>
-    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
-    <sourcelink visible="yes"/>
-    <memberdecl>
-      <classes visible="yes" title=""/>
-      <namespaces visible="yes" title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-    </memberdef>
-    <authorsection/>
-  </file>
-
-  <!-- Layout definition for a group page -->
-  <group>
-    <briefdescription visible="yes"/>
-    <groupgraph visible="$GROUP_GRAPHS"/>
-    <memberdecl>
-      <classes visible="yes" title=""/>
-      <namespaces visible="yes" title=""/>
-      <dirs visible="yes" title=""/>
-      <nestedgroups visible="yes" title=""/>
-      <files visible="yes" title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <enumvalues title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <signals title=""/>
-      <publicslots title=""/>
-      <protectedslots title=""/>
-      <privateslots title=""/>
-      <events title=""/>
-      <properties title=""/>
-      <friends title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <pagedocs/>
-      <inlineclasses title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <enumvalues title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <signals title=""/>
-      <publicslots title=""/>
-      <protectedslots title=""/>
-      <privateslots title=""/>
-      <events title=""/>
-      <properties title=""/>
-      <friends title=""/>
-    </memberdef>
-    <authorsection visible="yes"/>
-  </group>
-
-  <!-- Layout definition for a directory page -->
-  <directory>
-    <briefdescription visible="yes"/>
-    <directorygraph visible="yes"/>
-    <memberdecl>
-      <dirs visible="yes"/>
-      <files visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-  </directory>
-</doxygenlayout>
diff --git a/Kernel/GenSyscalls.php b/Kernel/GenSyscalls.php
deleted file mode 100644 (file)
index d451d1d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-$gLines = file("syscalls.lst");
-
-$lSyscalls = array();
-$i = 0;
-foreach($gLines as $line)
-{
-       $line = trim($line);
-       if(empty($line))        continue;
-       
-       if( intVal($line) != 0)
-               $i = $line;
-       else
-               $lSyscalls[$i++] = explode("\t", $line, 3);
-}
-$lMax = $i;
-
-$lAsmInc = "; Acess2
-; System Calls List
-; 
-
-";
-$lHeader  = "/*
- * AcessOS Microkernel Version
- * syscalls.h
- */
-#ifndef _SYSCALLS_H
-#define _SYSCALLS_H
-
-";
-$i = 0;
-foreach($lSyscalls as $num=>$call)
-{
-       if($i != $num)  {
-               $lHeader .= "\n";
-               $lAsmInc .= "\n";
-       }
-       
-       $lHeader .= "#define {$call[0]}\t{$num}";
-       $lHeader .= "\t// {$num} - {$call[1]}\n";
-       
-       $lAsmInc .= "%define {$call[0]}\t{$num}\t; {$call[1]}\n";
-       
-       
-       if($i != $num)
-               $i = $num+1;
-       else
-               $i ++;
-}
-$lHeader .= "#define NUM_SYSCALLS\t$i\n";
-$lHeader .= "#define SYS_DEBUG\t0x100  // 0x100 - Print a debug string\n";
-$lHeader .= "\n";
-$lHeader .= "#ifdef __GNUC__\n";
-$lHeader .= "static const char *cSYSCALL_NAMES[] = {\n\t";
-
-$j = 0;
-for($i=0;$i<$lMax;$i++)
-{
-       if(!isset($lSyscalls[$i]))
-               $lHeader .= "\"\",";
-       else
-               $lHeader .= "\"".$lSyscalls[$i][0]."\",";
-       $j ++;
-       if($j == 6) {
-               $lHeader .= "\n\t";
-               $j = 0;
-       }
-}
-$lHeader .= "\"\"\n};\n"
-$lHeader .= "#endif\n";
-$lHeader .= "#endif\n";
-
-$fp = fopen("include/syscalls.h", "w");        fwrite($fp, $lHeader);  fclose($fp);
-$fp = fopen("include/syscalls.inc.asm", "w");  fwrite($fp, $lAsmInc);  fclose($fp);
-
-?>
diff --git a/Kernel/GenSyscalls.pl b/Kernel/GenSyscalls.pl
deleted file mode 100755 (executable)
index 487ceca..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/perl
-#
-#
-
-open(FILE, "syscalls.lst");
-
-$num = 0;
-@calls = ();
-while($_ = <FILE>)
-{
-       if(/(\d+)/)
-       {
-               $num = $1;
-       }
-       elsif(/([A-Z_]+)\s+(.+)/)
-       {
-               push @calls, [$num, $1, $2];
-               $num ++;
-       }
-}
-
-close(FILE);
-
-# C header
-open(HEADER, ">include/syscalls.h");
-print HEADER "/*
- * Acess2
- * syscalls.h
- * - System Call List
- *
- * NOTE: Generated from Kernel/syscalls.lst
- */
-#ifndef _SYSCALLS_H
-#define _SYSCALLS_H
-
-";
-
-$lastid = -1;
-$i = 0;
-foreach my $call (@calls)
-{
-       print HEADER "#define ", $call->[1], "\t", $call->[0], "\t// ", $call->[2], "\n";
-       $i = $call->[0] + 1;
-}
-print HEADER "
-#define NUM_SYSCALLS   ",$i,"
-#define SYS_DEBUG      0x100
-
-#ifndef __ASSEMBLER__
-static const char *cSYSCALL_NAMES[] = {
-";
-
-$lastid = -1;
-foreach $call (@calls)
-{
-       while( $lastid + 1 < $call->[0] )
-       {
-               print HEADER "\t\"\",\n";
-               $lastid = $lastid + 1;
-       }
-       print HEADER "\t\"", $call->[1], "\",\n";
-       $lastid = $lastid + 1;
-}
-print HEADER  "
-\t\"\"
-};
-#endif
-
-#endif
-";
-
-close(HEADER);
-
-# Assembly Header
-open(ASM, ">include/syscalls.inc.asm");
-print ASM "; Acess2
-; System Calls List
-; 
-
-";
-foreach $call (@calls)
-{
-       print ASM "%define ", $call->[1], "\t", $call->[0], "\t ;", $call->[2], "\n";
-}
-close(ASM);
diff --git a/Kernel/Makefile b/Kernel/Makefile
deleted file mode 100644 (file)
index d0c8dbf..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-# Acess2 Kernel
-# Root Makefile
-# NOTE: Does some voodoo to allow differing architecture builds to co-exist
-# - The built objects and dependency files are suffixed with the arch name
-# - The final binary is Acess2.<ARCH>.bin
-
--include ../Makefile.cfg
-
--include arch/$(ARCHDIR)/Makefile
-
--include Makefile.BuildNum.$(ARCH)
-
-ifeq ($(BUILD_NUM),)
-BUILD_NUM = 0
-endif
-
-KERNEL_VERSION = $(ACESS_VERSION)
-MAKEDEP                = $(CC) -M
-
-ifeq ($(AS_SUFFIX),)
-       AS_SUFFIX = S
-endif
-
-ASFLAGS         += -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
-CPPFLAGS       += -I./include -I./arch/$(ARCHDIR)/include -D_MODULE_NAME_=\"Kernel\"
-CPPFLAGS       += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D PLATFORM=\"$(PLATFORM)\" -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
-CPPFLAGS       += -D KERNEL_VERSION=$(KERNEL_VERSION)
-CFLAGS         += -Wall -fno-stack-protector -Wstrict-prototypes -g
-CFLAGS         += -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wuninitialized
-CFLAGS          += -O3
-LDFLAGS                += -T arch/$(ARCHDIR)/link.ld -g
-
-ifeq ($(PLATFORM),default)
-       OBJDIR := obj-$(ARCH)/
-       #OBJSUFFIX := .$(ARCH)
-       BIN := ../Acess2.$(ARCH).bin
-       GZBIN := ../Acess2.$(ARCH).gz
-else
-       OBJDIR := obj-$(ARCH)-$(PLATFORM)/
-       #OBJSUFFIX := .$(ARCH)-$(PLATFORM)
-       BIN := ../Acess2.$(ARCH)-$(PLATFORM).bin
-       GZBIN := ../Acess2.$(ARCH)-$(PLATFORM).gz
-endif
-
-ifeq ($(DEBUG_BUILD),yes)
-       LDFLAGS += -g
-       CFLAGS += -g
-endif
-
-BUILDINFO_OBJ := $(OBJDIR)buildinfo.o$(OBJSUFFIX)
-BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX)
-
-OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
-OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
-OBJ += messages.o modules.o syscalls.o system.o
-OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
-OBJ += drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
-OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
-OBJ += binary.o bin/elf.o bin/pe.o
-OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
-OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o
-OBJ += vfs/fs/root.o vfs/fs/devfs.o
-OBJ += $(addprefix drv/, $(addsuffix .o,$(DRIVERS)))
-
-OBJ := $(addsuffix $(OBJSUFFIX), $(OBJ))
-OBJ := $(addprefix $(OBJDIR), $(OBJ))
-
-MODS += $(addprefix ../Modules/, $(addsuffix .xo.$(ARCH),$(MODULES)))
-
-DEPFILES := $(OBJ:%$(OBJSUFFIX)=%.dep$(OBJSUFFIX))
-
-SRCFILES  = $(OBJ:$(OBJDIR)%.o$(OBJSUFFIX)=%.c)
-SRCFILES := $(SRCFILES:$(OBJDIR)%.ao$(OBJSUFFIX)=%.$(AS_SUFFIX))
-
-OBJ += $(BUILDINFO_OBJ)
-
-.PHONY: all clean install apidoc
-
-all: $(BIN)
-
-clean:
-       @$(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt
-       @$(RM) -r $(OBJDIR) $(OBJ) $(DEPFILES) $(BUILDINFO_SRC)
-
-install: $(BIN) 
-       @cp $(BIN) $(BIN)_
-       @$(STRIP) $(BIN)_
-       @gzip -c $(BIN)_ > $(GZBIN)
-       @$(RM) $(BIN)_
-       $(xCP) $(GZBIN) $(DISTROOT)
-
-apidoc:
-       doxygen Doxyfile.api
-
-$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile ../BuildConf/$(ARCH)/Makefile.cfg ../BuildConf/$(ARCH)/$(PLATFORM).mk
-       @echo --- LD -o $(BIN)
-       @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
-       @$(DISASM) -S $(BIN) > $(BIN).dsm
-       @wc -l $(SRCFILES) include/*.h > LineCounts.$(ARCH).txt
-       @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum.$(ARCH)
-       $(POSTBUILD)
-
-$(OBJDIR)%.ao$(OBJSUFFIX): %.$(AS_SUFFIX) Makefile
-       @echo --- AS -o $@
-       @mkdir -p $(dir $@)
-       @$(AS) $(ASFLAGS) $< -o $@
-ifeq ($(AS_SUFFIX),S)
-       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $<
-endif
-
-$(OBJDIR)%.o$(OBJSUFFIX): %.c Makefile
-#      if exists %*/Makefile
-#      @make -C %*/ all
-#      else
-       @echo --- CC -o $@
-       @mkdir -p $(dir $@)
-       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
-       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $<
-#      endif
-
-%.xo.$(ARCH):
-       @BUILDTYPE=static make -C $* all
-
-include/syscalls.h include/syscalls.inc.asm:   syscalls.lst Makefile GenSyscalls.pl
-       perl GenSyscalls.pl
-
-Makefile:      ../Makefile.cfg arch/$(ARCHDIR)/Makefile
-
-$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
-       @echo "#include <acess.h>" > $@
-       @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
-       @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@
-$(BUILDINFO_OBJ): $(BUILDINFO_SRC)
-       @echo --- CC -o $@
-       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
-
-# Dependency Files
--include $(DEPFILES)
diff --git a/Kernel/adt.c b/Kernel/adt.c
deleted file mode 100644 (file)
index ef2ae05..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Acess2 Kernel
- * 
- * adt.c
- * - Complex data type code
- */
-#include <acess.h>
-#include <adt.h>
-
-
-// === CODE ===
-// --- Ring Buffers ---
-tRingBuffer *RingBuffer_Create(size_t Space)
-{
-       tRingBuffer     *ret = malloc(sizeof(tRingBuffer)+Space);
-       ret->Start = 0;
-       ret->Length = 0;
-       ret->Space = Space;
-       return ret;
-}
-
-size_t RingBuffer_Read(void *Dest, tRingBuffer *Buffer, size_t Length)
-{
-       size_t  tmpLen;
-
-       tmpLen = Buffer->Length;        // Changed in Write, so cache it for our read
-
-       if(Length > tmpLen)     Length = tmpLen;
-       
-       if( Buffer->Start + Length > Buffer->Space )
-       {
-                int    endData = Buffer->Space - Buffer->Start;
-               memcpy(Dest, &Buffer->Data[Buffer->Start], endData);
-               memcpy((Uint8*)Dest + endData, Buffer->Data, Length - endData);
-       }
-       else
-       {
-               memcpy(Dest, &Buffer->Data[Buffer->Start], Length);
-       }
-
-       // Lock then modify
-       SHORTLOCK( &Buffer->Lock );
-       Buffer->Start += Length;
-       if( Buffer->Start > Buffer->Space )
-               Buffer->Start -= Buffer->Space;
-       Buffer->Length -= Length;
-       SHORTREL( &Buffer->Lock );
-
-       return Length;
-}
-
-size_t RingBuffer_Write(tRingBuffer *Buffer, const void *Source, size_t Length)
-{
-       size_t  bufEnd, endSpace;
-       size_t  tmpLen, tmpStart;
-       
-       // Cache Start and Length because _Read can change these
-       SHORTLOCK( &Buffer->Lock );
-       tmpStart = Buffer->Start;
-       tmpLen = Buffer->Length;
-       SHORTREL( &Buffer->Lock );
-
-       bufEnd = (tmpStart + Buffer->Length) % Buffer->Space;
-       endSpace = Buffer->Space - bufEnd;
-       
-       // Force to bounds
-       if(Length > Buffer->Space - tmpLen)     Length = Buffer->Space - tmpLen;
-       
-       if(endSpace < Length)
-       {
-               memcpy( &Buffer->Data[bufEnd], Source, endSpace );
-               memcpy( Buffer->Data, (Uint8*)Source + endSpace, Length - endSpace );
-       }
-       else
-       {
-               memcpy( &Buffer->Data[bufEnd], Source, Length );
-       }
-
-       // Lock then modify
-       SHORTLOCK( &Buffer->Lock );
-       Buffer->Length += Length;
-       SHORTREL( &Buffer->Lock );
-       
-       return Length;
-}
-
diff --git a/Kernel/arch/archdoc.h b/Kernel/arch/archdoc.h
deleted file mode 100644 (file)
index ef3331f..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * \file archdoc.h
- * \brief Documentation Definitions for the Acess 2 Architecture Interface
- * \author John Hodge (thePowersGang)
- * 
- * Acess 2 allows different architecture builds to be made off almost
- * the same source tree. The difference between the trees is the inclusion
- * of a different directory from the "Kernel/arch/" directory that
- * contains the architecture specific intialisation and management code.
- * Each achitecture tree must provide all the definitions from this
- * document in some form or another (usually in the most efficient way
- * avaliable)
- * The values and types used in this documentation are a guide only and
- * will most probably be incorrect for most architectures.
- */
-#ifndef _ARCHDOC_H_
-#define _ARCHDOC_H_
-
-/**
- * \brief Maximum number of CPUs supported by this architecture driver
- *        (in the current build)
- */
-#define        MAX_CPUS        1
-/**
- * \brief Number of bits in a machine word (Uint)
- */
-#define        BITS    32
-/**
- * \brief Number of valid bits in a \a tPAddr
- */
-#define        PHYS_BITS       32
-
-/**
- * \name Syncronisation Primitives
- * \{
- */
-/**
- * \brief Spinlock type
- */
-typedef volatile int   tSpinlock;
-/**
- * \brief Acquire a spinlock
- */
-#define LOCK(lockptr)  do{while(*(tSpinlock*)lockptr)Threads_Yield();*(tSpinlock*)lockptr=1;}while(0)
-/**
- * \brief Release a held spinlock
- */
-#define RELEASE(lockptr)       do{*(tSpinlock*)lockptr=0;}while(0)
-/**
- * \}
- */
-//#define      HALT()  __asm__ __volatile__ ("hlt")
-
-
-/**
- * \name Atomic Types
- * \{
- */
-typedef unsigned int   Uint;   //!< Unsigned machine native integer
-typedef unsigned char  Uint8;  //!< Unsigned 8-bit integer
-typedef unsigned short Uint16; //!< Unsigned 16-bit integer
-typedef unsigned long  Uint32; //!< Unsigned 32-bit integer
-typedef unsigned long long     Uint64; //!< Unsigned 64-bit integer
-typedef signed int             Sint;   //!< Signed Machine Native integer
-typedef signed char            Sint8;  //!< Signed 8-bit integer
-typedef signed short   Sint16; //!< Signed 16-bit integer
-typedef signed long            Sint32; //!< Signed 32-bit integer
-typedef signed long long       Sint64; //!< Signed 16-bit integer
-/**
- * \}
- */
-
-typedef Uint   size_t; //!< Counter/Byte count type
-typedef Uint32 tVAddr; //!< Virtual address type
-typedef Uint32 tPAddr; //!< Physical Address type
-
-/**
- * \brief Register state passed to the syscall handler
- * 
- * The \a tSyscallRegs structure allows the system call handler to read
- * the user state to get the arguments for the call. It also allows the
- * handler to alter specific parts of the user state to reflect the
- * result of the call.
- * \note The fields shown here are need only be present in the actual
- *       structure, in any order. The implementation may also add more
- *       fields for padding purposes.
- */
-typedef struct {
-       Uint    Arg4;   //!< Fourth argument
-       Uint    Arg3;   //!< Third argument
-       Uint    Arg2;   //!< Second argument
-       union {
-               Uint    Arg1;   //!< First arugment
-               Uint    RetHi;  //!< High part of the return
-       };
-       union {
-               Uint    Num;    //!< Call Number
-               Uint    Return; //!< Low return value
-       };
-       
-       Uint    StackPointer;   //!< User stack pointer
-}      tSyscallRegs;
-
-/**
- * \brief Opaque structure definining the MMU state for a task
- */
-typedef struct sMemoryState    tMemoryState;
-
-/**
- * \brief Opque structure defining the CPU state for a task
- */
-typedef struct sTaskState      tTaskState;
-
-
-/**
- * \name Memory Management
- * \{
- */
-/**
- * \}
- */
-
-
-#endif
diff --git a/Kernel/arch/armv7/Makefile b/Kernel/arch/armv7/Makefile
deleted file mode 100644 (file)
index fad1b55..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Acess2 Kernel
-# arm7 Architecture Makefile
-# arch/arm7/Makefile
-
-CPPFLAGS       =
-CFLAGS         =
-ASFLAGS                =
-
-CPPFLAGS += -DMMU_PRESENT=1
-LDFLAGS += `$(CC) --print-libgcc-file-name`
-
-A_OBJ  = start.ao main.o lib.o lib.ao time.o pci.o debug.o
-A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
-
-#main.c: Makefile.BuildNum.$(ARCH)
-
-ifeq ($(PLATFORM),tegra2)
-       POSTBUILD = arm-elf-objcopy $(BIN) -O binary $(BIN)
-endif
diff --git a/Kernel/arch/armv7/debug.c b/Kernel/arch/armv7/debug.c
deleted file mode 100644 (file)
index 7b9e55d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Acess2
- * - By John Hodge (thePowersGang)
- *
- * arch/arm7/debug.c
- * - ARM7 Debug output
- * NOTE: Currently designed for the realview-pb-a8 emulated by Qemu
- */
-#include <acess.h>
-
-// === CONSTANTS ===
-//#define UART0_BASE   0x10009000
-#define UART0_BASE     0xF1000000      // Boot time mapped
-
-// === PROTOTYPES ===
-void   KernelPanic_SetMode(void);
-void   KernelPanic_PutChar(char Ch);
-void   StartupPrint(const char *str);
-
-// === GLOBALS ===
- int   giDebug_SerialInitialised = 0;
-
-// === CODE ===
-void Debug_PutCharDebug(char ch)
-{
-       if(ch == '\n')
-               Debug_PutCharDebug('\r');
-
-       #if PLATFORM_is_tegra2
-       // Tegra2
-       while( !(*(volatile Uint32*)(UART0_BASE + 0x14) & (1 << 5)) )
-               ;
-       #endif
-       
-//     *(volatile Uint32*)(SERIAL_BASE + SERIAL_REG_DATA) = ch;
-       *(volatile Uint32*)(UART0_BASE) = ch;
-}
-
-void Debug_PutStringDebug(const char *str)
-{
-       for( ; *str; str++ )
-               Debug_PutCharDebug( *str );
-}
-
-void KernelPanic_SetMode(void)
-{
-}
-
-void KernelPanic_PutChar(char ch)
-{
-//     Debug_PutCharDebug(ch);
-}
-
-void StartupPrint(const char *str)
-{
-}
-
diff --git a/Kernel/arch/armv7/include/arch.h b/Kernel/arch/armv7/include/arch.h
deleted file mode 100644 (file)
index 837a5e1..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Acess2
- * ARM7 Architecture Header
- */
-#ifndef _ARCH_H_
-#define _ARCH_H_
-
-// === CONSTANTS ===
-#define INVLPTR        ((void*)-1)
-#define BITS   32
-#define PAGE_SIZE      0x1000
-#define KERNEL_BASE    0x80000000      // 2GiB
-
-// === TYPES ===
-typedef unsigned int   Uint;
-typedef unsigned char  Uint8;
-typedef unsigned short Uint16;
-typedef unsigned long  Uint32;
-typedef unsigned long long     Uint64;
-typedef signed int     Sint;
-typedef signed char    Sint8;
-typedef signed short   Sint16;
-typedef signed long    Sint32;
-typedef signed long long       Sint64;
-
-typedef int    size_t;
-typedef char   BOOL;
-
-typedef Uint32 tVAddr;
-typedef Uint32 tPAddr;
-
-#include "lock.h"
-
-// --- Debug
-extern void    Debug_PutCharDebug(char Ch);
-extern void    Debug_PutStringDebug(const char *String);
-
-// This should be elsewhere, but CBF
-extern void    MM_SetupPhys(void);
-extern int     MM_InitialiseVirtual(void);
-
-#define NO_IO_BUS      1
-
-#endif
diff --git a/Kernel/arch/armv7/include/assembly.h b/Kernel/arch/armv7/include/assembly.h
deleted file mode 100644 (file)
index 0c5c57f..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Acess2 ARMv7
- * - By John Hodge (thePowersGang)
- *
- * arch/arm7/include/assembly.h
- * - Assembly specific macros
- */
-#ifndef _ASSEMBLY_H_
-#define _ASSEMBLY_H_
-
-#define PUSH_GPRS \
-       str r0, [sp,#-1*4];\
-       str r1, [sp,#-2*4];\
-       str r2, [sp,#-3*4];\
-       str r3, [sp,#-4*4];\
-       str r4, [sp,#-5*4];\
-       str r5, [sp,#-6*4];\
-       str r6, [sp,#-7*4];\
-       str r7, [sp,#-8*4];\
-       str r8, [sp,#-9*4];\
-       str r9, [sp,#-10*4];\
-       str r10, [sp,#-11*4];\
-       str r11, [sp,#-12*4];\
-       str r12, [sp,#-13*4];\
-       str sp, [sp,#-14*4];\
-       str lr, [sp,#-15*4];\
-       sub sp, #16*4
-
-#define POP_GPRS add sp, #16*4; \
-       ldr r0, [sp,#-1*4]; \
-       ldr r1, [sp,#-2*4]; \
-       ldr r2, [sp,#-3*4]; \
-       ldr r3, [sp,#-4*4]; \
-       ldr r4, [sp,#-5*4]; \
-       ldr r5, [sp,#-6*4]; \
-       ldr r6, [sp,#-7*4]; \
-       ldr r7, [sp,#-8*4]; \
-       ldr r8, [sp,#-9*4]; \
-       ldr r9, [sp,#-10*4]; \
-       ldr r10, [sp,#-11*4]; \
-       ldr r11, [sp,#-12*4]; \
-       ldr r12, [sp,#-13*4]; \
-       ldr lr, [sp,#-15*4];
-
-#endif
-
diff --git a/Kernel/arch/armv7/include/lock.h b/Kernel/arch/armv7/include/lock.h
deleted file mode 100644 (file)
index 6688af4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Acess2
- * ARM7 Architecture
- *
- * lock.h - Hardware level spinlocks
- */
-#ifndef _LOCK_H_
-#define _LOCK_H_
-
-// === CODE ===
-struct sShortSpinlock {
-        int    Lock;
-};
-
-// --- Spinlocks ---
-static inline int IS_LOCKED(struct sShortSpinlock *Lock)
-{
-       return !!Lock->Lock;
-}
-
-static inline int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
-{
-       // TODO: Handle multiple CPUs
-       return !!Lock->Lock;
-}
-
-static inline int SHORTLOCK(struct sShortSpinlock *Lock)
-{
-       #if 0
-       // Coped from linux, yes, but I know what it does now :)
-       Uint    tmp;
-       __asm__ __volatile__ (
-       "1:     ldrex   %0, [%1]\n"     // Exclusive LOAD
-       "       teq     %0, #0\n"       // Check if zero
-       "       strexeq %0, %2, [%1]\n" // Set to one if it is zero (releasing lock on the memory)
-       "       teqeq   %0, #0\n"       // If the lock was avaliable, check if the write succeeded
-       "       bne     1b"     // If the lock was unavaliable, or the write failed, loop
-               : "=&r" (tmp)   // Temp
-               : "r" (&Lock->Lock), "r" (1)
-               : "cc"  // Condition codes clobbered
-               );
-       #elif 1
-       while( *(volatile int*)&Lock->Lock )    ;
-       Lock->Lock = 1;
-       #else
-        int    v = 1;
-       while( v )
-               __asm__ __volatile__ (
-                       "swp %0, %0, [%1]"
-                       : "=r" (v) : "r" (&Lock->Lock)
-                       : "cc"
-                       );
-       #endif
-       return 1;
-}
-
-static inline void SHORTREL(struct sShortSpinlock *Lock)
-{
-       Lock->Lock = 0;
-}
-
-#endif
-
diff --git a/Kernel/arch/armv7/include/mm_virt.h b/Kernel/arch/armv7/include/mm_virt.h
deleted file mode 100644 (file)
index c1f10de..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Acess2
- * ARM7 Virtual Memory Manager Header
- */
-#ifndef _MM_VIRT_H_
-#define _MM_VIRT_H_
-
-#include "options.h"
-
-#define USER_STACK_COMM    0x04000     // Pages to allocate up front
-#define USER_STACK_SIZE           0x10000      // Stack space
-#define USER_STACK_TOP 0x78000000
-
-#define MM_USER_MIN    0x00001000
-#define USER_LIB_MAX   0x70000000
-#define MM_PPD_HANDLES 0x7F800000
-#define MM_TABLE1USER  0x7FC00000      // 2 GiB - 4 MiB
-#define MM_TABLE0USER  0x7FE00000      // 2 GiB - 2 MiB
-#define MM_KSTACK_BASE 0x7FE00000
-#define MM_KSTACK_END  0x80000000
-
-// Page Blocks are 12-bits wide (12 address bits used)
-// Hence, the table is 16KiB large (and must be so aligned)
-// and each block addresses 1MiB of data
-
-// First level table is aligned to 16KiB (restriction of TTBR reg)
-// - VMSAv6 uses two TTBR regs, determined by bit 31
-
-//#define KERNEL_BASE  0x80000000      // 2GiB
-
-#define MM_KHEAP_BASE  0x80800000      // 8MiB of kernel code
-#define MM_KHEAP_MAX   0xC0000000      // ~1GiB of kernel heap
-
-#define MM_MODULE_MIN  0xC0000000      // - 0xD0000000
-#define MM_MODULE_MAX  0xCF000000
-
-#define MM_GLOBALSTACKS        0xCF000000      // Global stacks
-#define MM_GLOBALSTACKS_END    0xD0000000
-
-// PMM Data, giving it 256MiB is overkill, but it's unused atm
-#define MM_MAXPHYSPAGE (1024*1024)
-// 2^(32-12) max pages
-// 8.125 bytes per page (for bitmap allocation)
-// = 8.125 MiB
-#define MM_PMM_BASE    0xE0000000
-#define MM_PMM_END     0xF0000000
-
-#define MM_HWMAP_BASE  0xF0000000      // Ent 0xF00
-#define MM_HWMAP_END   0xFE000000
-#define MM_TMPMAP_BASE 0xFE000000
-#define MM_TMPMAP_END  0xFF000000
-
-#define MM_KERNEL_VFS  0xFF000000      // 
-#define MM_TABLE1KERN  0xFF800000      // - 0x???????? 4MiB
-//#define MM_TABLE0KERN        0xFFC00000      // - 0xFFE04000 16KiB
-
-#endif
diff --git a/Kernel/arch/armv7/include/options.h b/Kernel/arch/armv7/include/options.h
deleted file mode 100644 (file)
index 95345ed..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Acess2 ARMv7 Port
- * - By John Hodge (thePowersGang)
- *
- * options.h
- * - C/ASM Shared constants
- */
-#ifndef _ARMV7_OPTIONS_H_
-#define _ARMV7_OPTIONS_H_
-
-#define KERNEL_BASE    0x80000000
-
-//#define PCI_PADDR    0x60000000      // Realview (Non-PB)
-
-#if PLATFORM_is_realview_pb
-# define UART0_PADDR   0x10009000      // Realview
-# define GICI_PADDR    0x1e000000
-# define GICD_PADDR    0x1e001000
-# define PL110_BASE    0x10020000      // Integrator
-
-#endif
-
-#if PLATFORM_is_tegra2 // Tegra2
-# define UART0_PADDR   0x70006000
-# define GICD_PADDR    0x50041000
-# define GICI_PADDR    0x50040100
-//# define PL110_BASE  0x10020000      // Integrator
-#endif
-
-#define MM_KSTACK_SIZE 0x2000  // 2 Pages
-
-#endif
-
diff --git a/Kernel/arch/armv7/include/proc.h b/Kernel/arch/armv7/include/proc.h
deleted file mode 100644 (file)
index d6ef3d5..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Acess2
- * ARM7 Architecture
- *
- * proc.h - Arch-Dependent Process Management
- */
-#ifndef _PROC_H_
-#define _PROC_H_
-
-#define MAX_CPUS       4
-#define USER_MAX       0x80000000
-
-// === STRUCTURES ===
-typedef struct {
-       Uint32  IP, SP;
-       Uint32  UserIP, UserSP;
-} tTaskState;
-
-typedef struct {
-       Uint32  Base;
-} tMemoryState;
-
-typedef struct {
-       union {
-               Uint32  Num;
-               Uint32  Error;
-       };
-       union {
-               Uint32  Arg1;
-               Uint32  Return;
-       };
-       union {
-               Uint32  Arg2;
-               Uint32  RetHi;
-       };
-       Uint32  Arg3;
-       Uint32  Arg4;
-       Uint32  Arg5;
-       Uint32  Arg6;   // R6
-} tSyscallRegs;
-
-// === MACROS ===
-#define HALT() do{}while(0)
-
-// === PROTOTYPES ===
-
-#endif
-
diff --git a/Kernel/arch/armv7/lib.S b/Kernel/arch/armv7/lib.S
deleted file mode 100644 (file)
index e2f0613..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Acess2 ARM
- * - By John Hodge (thePowersGang)
- *
- * arch/arm7/lib.S
- * - Assembly editions of library functions
- */
-#include "include/assembly.h"
-
-.globl __memcpy_byte
-__memcpy_byte:
-1:
-       tst r2, r2      @ Check counter
-       moveq pc, lr    @ Return if zero
-       ldrb r3, [r1],#1        @ Read
-       strb r3, [r0],#1        @ Write
-       sub r2, #1
-       b 1b
-
-@ 
-@ Pre-aligned memcpy (32-bit blocks)
-@ 
-.globl __memcpy_align4
-__memcpy_align4:
-       push {r4}
-       mvn r3, #3      @ Mask for checking length
-       
-       @ 4 byte chunk copies
-1:     tst r2, r3
-       ldrne r4, [r1],#4
-       strne r4, [r0],#4
-       subne r2, #4
-       bne 1b
-
-       @ single byte copies to finish off
-2:     tst r2, #3
-       beq 3f
-       ldrb r4, [r1],#1
-       strb r4, [r0],#1
-       sub r2, #1
-       b 2b
-
-3:     pop {r4}
-       mov pc, lr
-
-@
-@ Division
-@
-.globl __divmod32_asm
-__divmod32_asm:
-       push {r4}
-       mov r4, #0      @ Return value
-       mov r3, #1      @ add value
-
-       @ Scan up for first larger multiple of 2
-1:     cmp r0, r1      @ N < D
-       bmi 2f          @ ^^
-       lsl r1, r1, #1  @ D <<= 1
-       lsls r3, r3, #1 @ add <<= 1
-       beq .err        @ result is zero
-       b 1b
-       
-       @ Go back down
-2:     lsrs r3, r3, #1 @ add >>= 1
-       beq 3f          @ Done (value is zero)
-       lsr r1, r1, #1  @ D >>= 1
-       cmp r0, r1      @ N < D
-       bmi 2b
-       sub r0, r1      @ N -= D
-       add r4, r3      @ ret += add
-       b 2b
-3:
-       tst r2, r2      @ Remainder (if wanted)
-       strne r0,[r2]
-       mov r0, r4      @ Return value
-       pop {r4}
-       mov pc, lr
-.err:
-       mov r0, #0
-       tst r2, r2
-       strne r0, [r2]
-       pop {r4}
-       mov pc, lr
-
diff --git a/Kernel/arch/armv7/lib.c b/Kernel/arch/armv7/lib.c
deleted file mode 100644 (file)
index 5a6928e..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Acess2 ARM7 Port
- *
- * lib.c - Library Functions
- */
-#include <acess.h>
-#include "../helpers.h"
-
-// === IMPORTS ===
-extern void    __memcpy_align4(void *_dest, const void *_src, size_t _length);
-extern void    __memcpy_byte(void *_dest, const void *_src, size_t _length);
-extern Uint32  __divmod32_asm(Uint32 Num, Uint32 Den, Uint32 *Rem);
-
-// === PROTOTYPES ===
-Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
-Uint32 __divmod32(Uint32 Num, Uint32 Den, Uint32 *Rem);
-Uint64 __udivdi3(Uint64 Num, Uint64 Den);
-Uint64 __umoddi3(Uint64 Num, Uint64 Den);
-Uint32 __udivsi3(Uint32 Num, Uint32 Den);
-Uint32 __umodsi3(Uint32 Num, Uint32 Den);
-Sint32 __divsi3(Sint32 Num, Sint32 Den);
-Sint32 __modsi3(Sint32 Num, Sint32 Den);
-
-// === CODE ===
-void *memcpy(void *_dest, const void *_src, size_t _length)
-{
-       Uint8   *dst8 = _dest;
-       const Uint8     *src8 = _src;
-
-       if( ((tVAddr)_dest & 3) == 0 && ((tVAddr)_src & 3) == 0 )
-       {
-               __memcpy_align4(_dest, _src, _length);
-               return _dest;
-       }
-
-       // Handle small copies / Non-aligned
-       if( _length < 4 || ((tVAddr)_dest & 3) != ((tVAddr)_src & 3) )
-       {
-               __memcpy_byte(_dest, _src, _length);
-               return _dest;
-       }
-
-       // Force alignment
-       while( (tVAddr)dst8 & 3 ) *dst8 ++ = *src8++, _length --;
-
-       __memcpy_align4(dst8, src8, _length);
-       
-       return _dest;
-}
-
-int memcmp(const void *_m1, const void *_m2, size_t _length)
-{
-       const Uint32    *m1, *m2;
-       const Uint8     *m1_8 = _m1, *m2_8 = _m2;
-
-       // Handle small copies / Non-aligned
-       if( _length < 4 || ((tVAddr)_m1 & 3) != ((tVAddr)_m1 & 3) )
-       {
-               for( ; _length--; m1_8++,m2_8++ ) {
-                       if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
-               }
-               return 0;
-       }
-
-       // Force alignment
-       for( ; (tVAddr)m1_8 & 3; m1_8 ++, m2_8 ++) {
-               if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
-       }
-       m1 = (void *)m1_8;      m2 = (void *)m2_8;
-
-       // DWORD copies
-       for( ; _length > 3; _length -= 4, m1++, m2++)
-               if(*m1 != *m2)  return *m1 - *m2;
-
-       // Trailing bytes
-       m1_8 = (void*)m1;       m2_8 = (void*)m2;
-       for( ; _length; _length --, m1_8++, m2_8++ )
-               if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
-       
-       return 0;
-}
-
-void *memset(void *_dest, int _value, size_t _length)
-{
-       Uint32  *dst, val32;
-       Uint8   *dst8 = _dest;
-
-       _value = (Uint8)_value;
-
-       // Handle small copies
-       if( _length < 4 )
-       {
-               for( ; _length--; dst8++ )
-                       *dst8 = _value;
-               return _dest;
-       }
-
-       val32 = _value;
-       val32 |= val32 << 8;
-       val32 |= val32 << 16;
-       
-       // Force alignment
-       while( (tVAddr)dst8 & 3 ) *dst8 ++ = _value;
-       dst = (void *)dst8;
-
-       // DWORD copies
-       for( ; _length > 3; _length -= 4)
-               *dst++ = val32;
-
-       // Trailing bytes
-       dst8 = (void*)dst;
-       for( ; _length; _length -- )
-               *dst8 ++ = _value;
-       
-       return _dest;
-}
-
-DEF_DIVMOD(64)
-DEF_DIVMOD(32)
-
-Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
-{
-       Uint64  ret;
-       if(Den == 0)    return 0;       // TODO: #div0
-       if(Num < Den) {
-               if(Rem) *Rem = Num;
-               return 0;
-       }
-       if(Num == 0) {
-               if(Rem) *Rem = 0;
-               return 0;
-       }
-       if(Den == 1) {
-               if(Rem) *Rem = 0;
-               return Num;
-       }
-       if(Den == 2) {
-               if(Rem) *Rem = Num & 1;
-               return Num >> 1;
-       }
-       if(Den == 16) {
-               if(Rem) *Rem = Num & 0xF;
-               return Num >> 4;
-       }
-       if(Den == 32) {
-               if(Rem) *Rem = Num & 0x1F;
-               return Num >> 5;
-       }
-       if(Den == 0x1000) {
-               if(Rem) *Rem = Num & 0xFFF;
-               return Num >> 12;
-       }
-       
-       if( !(Den >> 32) && !(Num >> 32) ) {
-               if(Rem) *Rem = 0;       // Clear high bits
-               return __divmod32_asm(Num, Den, (Uint32*)Rem);
-       }
-
-       ret = __divmod64(Num, Den, Rem);
-       return ret;
-}
-
-// Unsigned Divide 64-bit Integer
-Uint64 __udivdi3(Uint64 Num, Uint64 Den)
-{
-       return DivMod64U(Num, Den, NULL);
-}
-
-// Unsigned Modulus 64-bit Integer
-Uint64 __umoddi3(Uint64 Num, Uint64 Den)
-{
-       Uint64  ret = 0;
-       DivMod64U(Num, Den, &ret);
-       return ret;
-}
-
-Uint32 __udivsi3(Uint32 Num, Uint32 Den)
-{
-       return __divmod32_asm(Num, Den, NULL);
-}
-
-Uint32 __umodsi3(Uint32 Num, Uint32 Den)
-{
-       Uint32  rem;
-       __divmod32_asm(Num, Den, &rem);
-       return rem;
-}
-
-static inline Sint32 DivMod32S(Sint32 Num, Sint32 Den, Sint32 *Rem)
-{
-       Sint32  ret = 1;
-       if( Num < 0 ) {
-               ret = -ret;
-               Num = -Num;
-       }
-       if( Den < 0 ) {
-               ret = -ret;
-               Den = -Den;
-       }
-       if(ret < 0)
-               ret = -__divmod32(Num, Den, (Uint32*)Rem);
-       else
-               ret = __divmod32(Num, Den, (Uint32*)Rem);
-       return ret;
-}
-
-Sint32 __divsi3(Sint32 Num, Sint32 Den)
-{
-       return DivMod32S(Num, Den, NULL);
-}
-
-Sint32 __modsi3(Sint32 Num, Sint32 Den)
-{
-       Sint32  rem;
-       DivMod32S(Num, Den, &rem);
-       return rem;
-}
diff --git a/Kernel/arch/armv7/link.ld b/Kernel/arch/armv7/link.ld
deleted file mode 100644 (file)
index d10dcc4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-ENTRY (_start)
-
-_kernel_base = 0x80000000;
-_usertext_vbase = 0xFFFFE000;
-
-SECTIONS
-{
-       . = 0;
-       .init :
-       {
-               *(.init)
-       }
-       . += _kernel_base;
-       .text : AT( ADDR(.text) - _kernel_base )
-       {
-               *(.text*)
-               *(.rodata*)
-       }
-                       
-
-       /* HACKS: User accesible .text section */
-       . = ALIGN(0x1000);
-       gUsertextPhysStart = . - _kernel_base;
-       . = _usertext_vbase;
-       .usertext : AT( gUsertextPhysStart )
-       {
-               *(.usertext)
-       }
-       . += gUsertextPhysStart + _kernel_base - _usertext_vbase;
-       
-       /* 0x4000 (4 pages) alignment needed for root table */
-       .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
-       {
-               *(.padata)
-               *(.data*)
-               
-               gKernelSymbols = .;
-               *(KEXPORT)
-               gKernelSymbolsEnd = .;
-               
-               gKernelModules = .;
-               *(KMODULES)
-               gKernelModulesEnd = .;
-       }
-       .bss : AT( ADDR(.bss) - _kernel_base )
-       {
-               bss_start = .;
-               *(.bss*)
-               *(COMMON*)
-               . = ALIGN(0x1000);
-               *(.pabss)
-               bss_end = .;
-       }
-       gKernelEnd = .;
-}
diff --git a/Kernel/arch/armv7/main.c b/Kernel/arch/armv7/main.c
deleted file mode 100644 (file)
index 248c17c..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Acess2
- *
- * ARM7 Entrypoint
- * arch/arm7/main.c
- */
-#define DEBUG  0
-
-#include <acess.h>
-#include <modules.h>
-
-// === IMPORTS ===
-extern void    Interrupts_Setup(void);
-extern void    Arch_LoadBootModules(void);
-extern void    Heap_Install(void);
-extern void    Threads_Init(void);
-extern void    System_Init(const char *Commandline);
-
-// === PROTOTYPES ===
- int   kmain(void);
-Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args);
-
-// === CODE ===
-int kmain(void)
-{
-       LogF("Acess2 ARMv7 v"EXPAND_STR(KERNEL_VERSION)"\n");
-       LogF(" Git Hash %s\n", gsGitHash);
-       LogF(" Build %i\n", BUILD_NUM);
-       
-       MM_SetupPhys();
-
-       LogF("Heap Setup...\n");
-       Heap_Install();
-
-       LogF("Threads Init...\n");
-       Threads_Init();
-       
-       LogF("VFS Init...\n");
-       VFS_Init();
-
-       // Boot modules?
-       Module_EnsureLoaded("armv7_GIC");
-
-       //
-       LogF("Moving to arch-independent init\n");
-       #if PLATFORM_is_tegra2
-       System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=Tegra2Vid");
-       #else
-       System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=PL110");
-       #endif
-//     System_Init("Acess2.armv7.bin /Acess=initrd:");
-       //TODO: 
-       LogF("End of kmain(), for(;;) Threads_Sleep();\n");
-       for(;;)
-               Threads_Sleep();
-}
-
-void Arch_LoadBootModules(void)
-{
-}
-
-Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args)
-{
-       Uint32  ret = -1, err = 0;
-       Uint32  addr;
-       ENTER("iNum xArgs[0] xArgs[1] xArgs[2] xArgs[3]",
-               Num, Args[0], Args[1], Args[2], Args[3]
-               );
-       switch(Num)
-       {
-       case 1:
-//             Log_Debug("ARMv7", "__clear_cache(%p, %p)", Args[0], Args[1]);
-               // Align
-               Args[0] &= ~0xFFF;
-               Args[1] += 0xFFF;       Args[1] &= ~0xFFF;
-               // Invalidate!
-               for( addr = Args[0]; addr < Args[1]; addr += 0x1000 )
-               {
-                       LOG("addr = %p", addr);
-                       __asm__ __volatile__ (
-                               "mcrlt p15, 0, %0, c7, c5, 1;\n\t"
-                               "mcrlt p15, 0, %0, c7, c6, 1;\n\t"
-                               :
-                               : "r" (addr)
-                               );
-               }
-               ret = 0;
-               break;
-       }
-       Args[0] = ret;  // RetLow
-       Args[1] = 0;    // RetHi
-       Args[2] = err;  // Errno
-       LEAVE('x', ret);
-       return ret;
-}
-
diff --git a/Kernel/arch/armv7/mm_phys.c b/Kernel/arch/armv7/mm_phys.c
deleted file mode 100644 (file)
index 5e4a242..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Acess2
- *
- * ARM7 Physical Memory Manager
- * arch/arm7/mm_phys.c
- */
-#define DEBUG  0
-
-#include <acess.h>
-#include <mm_virt.h>
-
-#define MM_NUM_RANGES  1       // Single range
-#define MM_RANGE_MAX   0
-#define TRACE_ALLOCS   0
-
-#define NUM_STATIC_ALLOC       4
-
-char   gStaticAllocPages[NUM_STATIC_ALLOC][PAGE_SIZE] __attribute__ ((section(".padata")));
-tPAddr gaiStaticAllocPages[NUM_STATIC_ALLOC] = {
-       (tPAddr)(&gStaticAllocPages[0]) - KERNEL_BASE,
-       (tPAddr)(&gStaticAllocPages[1]) - KERNEL_BASE,
-       (tPAddr)(&gStaticAllocPages[2]) - KERNEL_BASE,
-       (tPAddr)(&gStaticAllocPages[3]) - KERNEL_BASE
-};
-extern char    gKernelEnd[];
-
-
-#include <tpl_mm_phys_bitmap.h>
-
-//#define REALVIEW_LOWRAM_SIZE 0x10000000
-#define REALVIEW_LOWRAM_SIZE   (32*1024*1024)
-
-void MM_SetupPhys(void)
-{
-       LogF("MM_SetupPhys: ()\n");
-       MM_Tpl_InitPhys( REALVIEW_LOWRAM_SIZE/0x1000, NULL );
-}
-
-int MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length )
-{
-       switch(Index)
-       {
-       case 0:
-               *Start = ((tVAddr)&gKernelEnd - KERNEL_BASE + 0xFFF) & ~0xFFF;
-               *Length = REALVIEW_LOWRAM_SIZE - *Start;
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-/**
- * \brief Takes a physical address and returns the ID of its range
- * \param Addr Physical address of page
- * \return Range ID from eMMPhys_Ranges
- */
-int MM_int_GetRangeID( tPAddr Addr )
-{
-       return MM_RANGE_MAX;    // ARM doesn't need ranges
-}
diff --git a/Kernel/arch/armv7/mm_virt.c b/Kernel/arch/armv7/mm_virt.c
deleted file mode 100644 (file)
index 460b334..0000000
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*
- * Acess2
- * 
- * ARM7 Virtual Memory Manager
- * - arch/arm7/mm_virt.c
- */
-#define DEBUG  0
-#include <acess.h>
-#include <mm_virt.h>
-#include <hal_proc.h>
-
-#define TRACE_MAPS     0
-
-#define AP_KRW_ONLY    1       // Kernel page
-#define AP_KRO_ONLY    5       // Kernel RO page
-#define AP_RW_BOTH     3       // Standard RW
-#define AP_RO_BOTH     7       // COW Page
-#define AP_RO_USER     2       // User RO Page
-#define PADDR_MASK_LVL1        0xFFFFFC00
-
-// === IMPORTS ===
-extern Uint32  kernel_table0[];
-
-// === TYPES ===
-typedef struct
-{
-       tPAddr  PhysAddr;
-       Uint8   Size;
-       Uint8   Domain;
-       BOOL    bExecutable;
-       BOOL    bGlobal;
-       BOOL    bShared;
-        int    AP;
-} tMM_PageInfo;
-
-//#define FRACTAL(table1, addr)        ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
-#define FRACTAL(table1, addr)  ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
-#define USRFRACTAL(addr)       (*((Uint32*)(0x7FDFF000) + ((addr)>>22)))
-#define TLBIALL()      __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
-#define TLBIMVA(addr)  __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1;dsb;isb" : : "r" ((addr)&~0xFFF):"memory")
-#define DCCMVAC(addr)  __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" ((addr)&~0xFFF))
-
-// === PROTOTYPES ===
-void   MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
- int   MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
- int   MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
- int   MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
-tVAddr MM_NewUserStack(void);
-tPAddr MM_AllocateZero(tVAddr VAddr);
-tPAddr MM_AllocateRootTable(void);
-void   MM_int_CloneTable(Uint32 *DestEnt, int Table);
-tPAddr MM_Clone(void);
-tVAddr MM_NewKStack(int bGlobal);
-void   MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
-//void MM_DumpTables(tVAddr Start, tVAddr End);
-void   MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch);
-
-// === GLOBALS ===
-tPAddr giMM_ZeroPage;
-
-// === CODE ===
-int MM_InitialiseVirtual(void)
-{
-       return 0;
-}
-
-void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
-{
-       if(VAddr & 0x80000000) {
-               *Table0 = (void*)&kernel_table0;        // Level 0
-               *Table1 = (void*)MM_TABLE1KERN; // Level 1
-       }
-       else {
-               *Table0 = (void*)MM_TABLE0USER;
-               *Table1 = (void*)MM_TABLE1USER;
-       }
-}
-
-int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
-{
-       Uint32  *table0, *table1;
-       Uint32  *desc;
-       tPAddr  paddr;
-       
-       ENTER("xVAddr iDomain", VAddr, Domain);
-
-       MM_int_GetTables(VAddr, &table0, &table1);
-
-       VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
-
-       desc = &table0[ VAddr>>20];
-       LOG("desc = %p", desc);
-       
-       // table0: 4 bytes = 1 MiB
-
-       LOG("desc[0] = %x", desc[0]);
-       LOG("desc[1] = %x", desc[1]);
-       LOG("desc[2] = %x", desc[2]);
-       LOG("desc[3] = %x", desc[3]);
-
-       if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
-        || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
-       {
-               // Error?
-               LEAVE('i', 1);
-               return 1;
-       }
-
-       paddr = MM_AllocPhys();
-       if( !paddr )
-       {
-               // Error
-               LEAVE('i', 2);
-               return 2;
-       }
-       
-       *desc = paddr | (Domain << 5) | 1;
-       desc[1] = desc[0] + 0x400;
-       desc[2] = desc[0] + 0x800;
-       desc[3] = desc[0] + 0xC00;
-
-       if( VAddr < 0x80000000 ) {
-               USRFRACTAL(VAddr) = paddr | 0x13;
-       }
-       else {
-               FRACTAL(table1, VAddr) = paddr | 0x13;
-       }
-
-       // TLBIALL 
-       TLBIALL();
-       
-       memset( (void*)&table1[ (VAddr >> 12) & ~(1024-1) ], 0, 0x1000 );
-
-       LEAVE('i', 0);
-       return 0;
-}      
-
-int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
-{
-       Uint32  *table0, *table1;
-       Uint32  *desc;
-
-       ENTER("pVAddr ppi", VAddr, pi);
-
-       MM_int_GetTables(VAddr, &table0, &table1);
-
-       desc = &table0[ VAddr >> 20 ];
-       LOG("desc = %p", desc);
-
-       switch(pi->Size)
-       {
-       case 12:        // Small Page
-       case 16:        // Large Page
-               LOG("Page");
-               if( (*desc & 3) == 0 ) {
-                       MM_int_AllocateCoarse( VAddr, pi->Domain );
-               }
-               desc = &table1[ VAddr >> 12 ];
-               LOG("desc (2) = %p", desc);
-               if( pi->Size == 12 )
-               {
-                       // Small page
-                       // - Error if overwriting a large page
-                       if( (*desc & 3) == 1 )  LEAVE_RET('i', 1);
-                       if( pi->PhysAddr == 0 ) {
-                               *desc = 0;
-                               TLBIMVA( VAddr );
-                               DCCMVAC( (tVAddr) desc );
-                               #warning "HACK: TLBIALL"
-                               TLBIALL();
-                               LEAVE('i', 0);
-                               return 0;
-                       }
-
-                       *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
-                       if(!pi->bExecutable)    *desc |= 1;     // XN
-                       if(!pi->bGlobal)        *desc |= 1 << 11;       // nG
-                       if( pi->bShared)        *desc |= 1 << 10;       // S
-                       *desc |= (pi->AP & 3) << 4;     // AP
-                       *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
-                       TLBIMVA( VAddr );       
-                       #warning "HACK: TLBIALL"
-                       TLBIALL();
-                       DCCMVAC( (tVAddr) desc );
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               else
-               {
-                       // Large page
-                       Log_Warning("MMVirt", "TODO: Implement large pages in MM_int_SetPageInfo");
-               }
-               break;
-       case 20:        // Section or unmapped
-               Log_Warning("MMVirt", "TODO: Implement sections in MM_int_SetPageInfo");
-               break;
-       case 24:        // Supersection
-               // Error if not aligned
-               if( VAddr & 0xFFFFFF ) {
-                       LEAVE('i', 1);
-                       return 1;
-               }
-               if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
-               {
-                       if( pi->PhysAddr == 0 ) {
-                               *desc = 0;
-                       }
-                       else {
-                               // Apply
-                               *desc = pi->PhysAddr & 0xFF000000;
-//                             *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
-//                             *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
-                               *desc |= 2 | (1 << 18);
-                       }
-                       // TODO: Apply to all entries
-                       Log_Warning("MMVirt", "TODO: Apply changes to all entries of supersections");
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               // TODO: What here?
-               Log_Warning("MMVirt", "TODO: 24-bit not on supersection?");
-               LEAVE('i', 1);
-               return 1;
-       }
-
-       LEAVE('i', 1);
-       return 1;
-}
-
-int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
-{
-       Uint32  *table0, *table1;
-       Uint32  desc;
-
-//     LogF("MM_int_GetPageInfo: VAddr=%p, pi=%p\n", VAddr, pi);
-       
-       MM_int_GetTables(VAddr, &table0, &table1);
-
-       desc = table0[ VAddr >> 20 ];
-
-//     if( VAddr > 0x90000000)
-//             LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
-       
-       pi->bExecutable = 1;
-       pi->bGlobal = 0;
-       pi->bShared = 0;
-       pi->AP = 0;
-
-       switch( (desc & 3) )
-       {
-       // 0: Unmapped
-       case 0:
-               pi->PhysAddr = 0;
-               pi->Size = 20;
-               pi->Domain = 0;
-               return 1;
-
-       // 1: Coarse page table
-       case 1:
-               // Domain from top level table
-               pi->Domain = (desc >> 5) & 7;
-               // Get next level
-               desc = table1[ VAddr >> 12 ];
-//             LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
-               switch( desc & 3 )
-               {
-               // 0: Unmapped
-               case 0: 
-                       pi->Size = 12;
-                       return 1;
-               // 1: Large Page (64KiB)
-               case 1:
-                       pi->Size = 16;
-                       pi->PhysAddr = desc & 0xFFFF0000;
-                       pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
-                       pi->bExecutable = !(desc & 0x8000);
-                       pi->bShared = (desc >> 10) & 1;
-                       return 0;
-               // 2/3: Small page
-               case 2:
-               case 3:
-                       pi->Size = 12;
-                       pi->PhysAddr = desc & 0xFFFFF000;
-                       pi->bExecutable = !(desc & 1);
-                       pi->bGlobal = !(desc >> 11);
-                       pi->bShared = (desc >> 10) & 1;
-                       pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
-                       return 0;
-               }
-               return 1;
-       
-       // 2: Section (or Supersection)
-       case 2:
-               if( desc & (1 << 18) ) {
-                       // Supersection
-                       pi->PhysAddr = desc & 0xFF000000;
-                       pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
-                       pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
-                       pi->Size = 24;
-                       pi->Domain = 0; // Supersections default to zero
-                       pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
-                       return 0;
-               }
-               
-               // Section
-               pi->PhysAddr = desc & 0xFFF80000;
-               pi->Size = 20;
-               pi->Domain = (desc >> 5) & 7;
-               pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
-               return 0;
-
-       // 3: Reserved (invalid)
-       case 3:
-               pi->PhysAddr = 0;
-               pi->Size = 20;
-               pi->Domain = 0;
-               return 2;
-       }
-       return 2;
-}
-
-// --- Exports ---
-tPAddr MM_GetPhysAddr(tVAddr VAddr)
-{
-       tMM_PageInfo    pi;
-       if( MM_int_GetPageInfo(VAddr, &pi) )
-               return 0;
-       return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
-}
-
-Uint MM_GetFlags(tVAddr VAddr)
-{
-       tMM_PageInfo    pi;
-        int    ret;
-
-       if( MM_int_GetPageInfo(VAddr, &pi) )
-               return 0;
-
-       ret = 0;
-       
-       switch(pi.AP)
-       {
-       case 0:
-               break;
-       case AP_KRW_ONLY:
-               ret |= MM_PFLAG_KERNEL;
-               break;
-       case AP_KRO_ONLY:
-               ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
-               break;
-       case AP_RW_BOTH:
-               break;
-       case AP_RO_BOTH:
-               ret |= MM_PFLAG_COW;
-               break;
-       case AP_RO_USER:
-               ret |= MM_PFLAG_RO;
-               break;
-       }
-
-       if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
-       return ret;
-}
-
-void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
-{
-       tMM_PageInfo    pi;
-       Uint    curFlags;
-       
-       if( MM_int_GetPageInfo(VAddr, &pi) )
-               return ;
-       
-       curFlags = MM_GetFlags(VAddr);
-       if( (curFlags & Mask) == Flags )
-               return ;
-       curFlags &= ~Mask;
-       curFlags |= Flags;
-
-       if( curFlags & MM_PFLAG_COW )
-               pi.AP = AP_RO_BOTH;
-       else
-       {
-               switch(curFlags & (MM_PFLAG_KERNEL|MM_PFLAG_RO) )
-               {
-               case 0:
-                       pi.AP = AP_RW_BOTH;     break;
-               case MM_PFLAG_KERNEL:
-                       pi.AP = AP_KRW_ONLY;    break;
-               case MM_PFLAG_RO:
-                       pi.AP = AP_RO_USER;     break;
-               case MM_PFLAG_KERNEL|MM_PFLAG_RO:
-                       pi.AP = AP_KRO_ONLY;    break;
-               }
-       }
-       
-       pi.bExecutable = !!(curFlags & MM_PFLAG_EXEC);
-
-       MM_int_SetPageInfo(VAddr, &pi);
-}
-
-int MM_IsValidBuffer(tVAddr Addr, size_t Size)
-{
-       tMM_PageInfo    pi;
-        int    bUser = 0;
-       
-       Size += Addr & (PAGE_SIZE-1);
-       Addr &= ~(PAGE_SIZE-1);
-
-       if( MM_int_GetPageInfo(Addr, &pi) )     return 0;
-       Addr += PAGE_SIZE;
-
-       if(pi.AP != AP_KRW_ONLY && pi.AP != AP_KRO_ONLY)
-               bUser = 1;
-
-       while( Size >= PAGE_SIZE )
-       {
-               if( MM_int_GetPageInfo(Addr, &pi) )
-                       return 0;
-               if(bUser && (pi.AP == AP_KRW_ONLY || pi.AP == AP_KRO_ONLY))
-                       return 0;
-               Addr += PAGE_SIZE;
-               Size -= PAGE_SIZE;
-       }
-       
-       return 1;
-}
-
-int MM_Map(tVAddr VAddr, tPAddr PAddr)
-{
-       tMM_PageInfo    pi = {0};
-       #if TRACE_MAPS
-       Log("MM_Map %P=>%p", PAddr, VAddr);
-       #endif
-       
-       pi.PhysAddr = PAddr;
-       pi.Size = 12;
-       if(VAddr < USER_STACK_TOP)
-               pi.AP = AP_RW_BOTH;
-       else
-               pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
-       pi.bExecutable = 1;
-       if( MM_int_SetPageInfo(VAddr, &pi) ) {
-//             MM_DerefPhys(pi.PhysAddr);
-               return 0;
-       }
-       return pi.PhysAddr;
-}
-
-tPAddr MM_Allocate(tVAddr VAddr)
-{
-       tMM_PageInfo    pi = {0};
-       
-       ENTER("pVAddr", VAddr);
-
-       pi.PhysAddr = MM_AllocPhys();
-       if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
-       pi.Size = 12;
-       if(VAddr < USER_STACK_TOP)
-               pi.AP = AP_RW_BOTH;
-       else
-               pi.AP = AP_KRW_ONLY;
-       pi.bExecutable = 0;
-       if( MM_int_SetPageInfo(VAddr, &pi) ) {
-               MM_DerefPhys(pi.PhysAddr);
-               LEAVE('i', 0);
-               return 0;
-       }
-       LEAVE('x', pi.PhysAddr);
-       return pi.PhysAddr;
-}
-
-tPAddr MM_AllocateZero(tVAddr VAddr)
-{
-       if( !giMM_ZeroPage ) {
-               giMM_ZeroPage = MM_Allocate(VAddr);
-               MM_RefPhys(giMM_ZeroPage);
-               memset((void*)VAddr, 0, PAGE_SIZE);
-       }
-       else {
-               MM_RefPhys(giMM_ZeroPage);
-               MM_Map(VAddr, giMM_ZeroPage);
-       }
-       MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
-       return giMM_ZeroPage;
-}
-
-void MM_Deallocate(tVAddr VAddr)
-{
-       tMM_PageInfo    pi;
-       
-       if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
-       if( pi.PhysAddr == 0 )  return;
-       MM_DerefPhys(pi.PhysAddr);
-       
-       pi.PhysAddr = 0;
-       pi.AP = 0;
-       pi.bExecutable = 0;
-       MM_int_SetPageInfo(VAddr, &pi);
-}
-
-tPAddr MM_AllocateRootTable(void)
-{
-       tPAddr  ret;
-       
-       ret = MM_AllocPhysRange(2, -1);
-       if( ret & 0x1000 ) {
-               MM_DerefPhys(ret);
-               MM_DerefPhys(ret+0x1000);
-               ret = MM_AllocPhysRange(3, -1);
-               if( ret & 0x1000 ) {
-                       MM_DerefPhys(ret);
-                       ret += 0x1000;
-//                     Log("MM_AllocateRootTable: Second try not aligned, %P", ret);
-               }
-               else {
-                       MM_DerefPhys(ret + 0x2000);
-//                     Log("MM_AllocateRootTable: Second try aligned, %P", ret);
-               }
-       }
-//     else
-//             Log("MM_AllocateRootTable: Got it in one, %P", ret);
-       return ret;
-}
-
-void MM_int_CloneTable(Uint32 *DestEnt, int Table)
-{
-       tPAddr  table;
-       Uint32  *tmp_map;
-       Uint32  *cur = (void*)MM_TABLE1USER;
-//     Uint32  *cur = &FRACTAL(MM_TABLE1USER,0);
-        int    i;
-       
-       table = MM_AllocPhys();
-       if(!table)      return ;
-
-       cur += 256*Table;
-       
-       tmp_map = (void*)MM_MapTemp(table);
-       
-       for( i = 0; i < 1024; i ++ )
-       {
-//             Log_Debug("MMVirt", "cur[%i] (%p) = %x", Table*256+i, &cur[Table*256+i], cur[Table*256+i]);
-               switch(cur[i] & 3)
-               {
-               case 0: tmp_map[i] = 0; break;
-               case 1:
-                       tmp_map[i] = 0;
-                       Log_Error("MMVirt", "TODO: Support large pages in MM_int_CloneTable (%p)", (Table*256+i)*0x1000);
-                       // Large page?
-                       break;
-               case 2:
-               case 3:
-                       // Small page
-                       // - If full RW
-//                     Debug("%p cur[%i] & 0x230 = 0x%x", Table*256*0x1000, i, cur[i] & 0x230);
-                       if( (cur[i] & 0x230) == 0x010 )
-                       {
-                               void    *dst, *src;
-                               tPAddr  newpage;
-                               newpage = MM_AllocPhys();
-                               src = (void*)( (Table*256+i)*0x1000 );
-                               dst = (void*)MM_MapTemp(newpage);
-//                             Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF);
-                               memcpy(dst, src, PAGE_SIZE);
-                               MM_FreeTemp( (tVAddr)dst );
-                               tmp_map[i] = newpage | (cur[i] & 0xFFF);
-                       }
-                       else
-                       {
-                               if( (cur[i] & 0x230) == 0x030 )
-                                       cur[i] |= 0x200;        // Set to full RO (Full RO=COW, User RO = RO)
-                               tmp_map[i] = cur[i];
-                               MM_RefPhys( tmp_map[i] & ~0xFFF );
-                       }
-                       break;
-               }
-       }
-       MM_FreeTemp( (tVAddr) tmp_map );
-
-       DestEnt[0] = table + 0*0x400 + 1;
-       DestEnt[1] = table + 1*0x400 + 1;
-       DestEnt[2] = table + 2*0x400 + 1;
-       DestEnt[3] = table + 3*0x400 + 1;
-}
-
-tPAddr MM_Clone(void)
-{
-       tPAddr  ret;
-       Uint32  *new_lvl1_1, *new_lvl1_2, *cur;
-       Uint32  *tmp_map;
-        int    i;
-
-//     MM_DumpTables(0, KERNEL_BASE);
-       
-       ret = MM_AllocateRootTable();
-
-       cur = (void*)MM_TABLE0USER;
-       new_lvl1_1 = (void*)MM_MapTemp(ret);
-       new_lvl1_2 = (void*)MM_MapTemp(ret+0x1000);
-       tmp_map = new_lvl1_1;
-       for( i = 0; i < 0x800-4; i ++ )
-       {
-               // HACK! Ignore the original identity mapping
-               if( i == 0 && Threads_GetTID() == 0 ) {
-                       tmp_map[0] = 0;
-                       continue;
-               }
-               if( i == 0x400 )
-                       tmp_map = &new_lvl1_2[-0x400];
-               switch( cur[i] & 3 )
-               {
-               case 0: tmp_map[i] = 0; break;
-               case 1:
-                       MM_int_CloneTable(&tmp_map[i], i);
-                       i += 3; // Tables are alocated in blocks of 4
-                       break;
-               case 2:
-               case 3:
-                       Log_Error("MMVirt", "TODO: Support Sections/Supersections in MM_Clone (i=%i)", i);
-                       tmp_map[i] = 0;
-                       break;
-               }
-       }
-
-       // Allocate Fractal table
-       {
-                int    j, num;
-               tPAddr  tmp = MM_AllocPhys();
-               Uint32  *table = (void*)MM_MapTemp(tmp);
-               Uint32  sp;
-               register Uint32 __SP asm("sp");
-
-               // Map table to last 4MiB of user space
-               new_lvl1_2[0x3FC] = tmp + 0*0x400 + 1;
-               new_lvl1_2[0x3FD] = tmp + 1*0x400 + 1;
-               new_lvl1_2[0x3FE] = tmp + 2*0x400 + 1;
-               new_lvl1_2[0x3FF] = tmp + 3*0x400 + 1;
-               
-               tmp_map = new_lvl1_1;
-               for( j = 0; j < 512; j ++ )
-               {
-                       if( j == 256 )
-                               tmp_map = &new_lvl1_2[-0x400];
-                       if( (tmp_map[j*4] & 3) == 1 )
-                       {
-                               table[j] = tmp_map[j*4] & PADDR_MASK_LVL1;// 0xFFFFFC00;
-                               table[j] |= 0x813;      // nG, Kernel Only, Small page, XN
-                       }
-                       else
-                               table[j] = 0;
-               }
-               // Fractal
-               table[j++] = (ret + 0x0000) | 0x813;
-               table[j++] = (ret + 0x1000) | 0x813;
-               // Nuke the rest
-               for(      ; j < 1024; j ++ )
-                       table[j] = 0;
-               
-               // Get kernel stack bottom
-               sp = __SP & ~(MM_KSTACK_SIZE-1);
-               j = (sp / 0x1000) % 1024;
-               num = MM_KSTACK_SIZE/0x1000;
-
-//             Log("num = %i, sp = %p, j = %i", num, sp, j);
-               
-               // Copy stack pages
-               for(; num--; j ++, sp += 0x1000)
-               {
-                       tVAddr  page;
-                       void    *tmp_page;
-                       
-                       page = MM_AllocPhys();
-//                     Log("page = %P", page);
-                       table[j] = page | 0x813;
-
-                       tmp_page = (void*)MM_MapTemp(page);
-                       memcpy(tmp_page, (void*)sp, 0x1000);
-                       MM_FreeTemp( (tVAddr) tmp_page );
-               }
-
-               MM_FreeTemp( (tVAddr)table );
-       }
-
-       MM_FreeTemp( (tVAddr)new_lvl1_1 );
-       MM_FreeTemp( (tVAddr)new_lvl1_2 );
-
-//     Log("MM_Clone: ret = %P", ret);
-
-       return ret;
-}
-
-void MM_ClearUser(void)
-{
-        int    i, j;
-       const int       user_table_count = USER_STACK_TOP / (256*0x1000);
-       Uint32  *cur = (void*)MM_TABLE0USER;
-       Uint32  *tab;
-       
-//     MM_DumpTables(0, 0x80000000);
-
-//     Log("user_table_count = %i (as opposed to %i)", user_table_count, 0x800-4);
-
-       for( i = 0; i < user_table_count; i ++ )
-       {
-               switch( cur[i] & 3 )
-               {
-               case 0: break;  // Already unmapped
-               case 1: // Sub pages
-                       tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
-                       for( j = 0; j < 1024; j ++ )
-                       {
-                               switch( tab[j] & 3 )
-                               {
-                               case 0: break;  // Unmapped
-                               case 1:
-                                       Log_Error("MMVirt", "TODO: Support large pages in MM_ClearUser");
-                                       break;
-                               case 2:
-                               case 3:
-                                       MM_DerefPhys( tab[j] & ~(PAGE_SIZE-1) );
-                                       break;
-                               }
-                       }
-                       MM_DerefPhys( cur[i] & ~(PAGE_SIZE-1) );
-                       cur[i+0] = 0;
-                       cur[i+1] = 0;
-                       cur[i+2] = 0;
-                       i += 3;
-                       break;
-               case 2:
-               case 3:
-                       Log_Error("MMVirt", "TODO: Implement sections/supersections in MM_ClearUser");
-                       break;
-               }
-               cur[i] = 0;
-       }
-       
-       // Final block of 4 tables are KStack
-       i = 0x800 - 4;
-       
-       // Clear out unused stacks
-       {
-               register Uint32 __SP asm("sp");
-                int    cur_stack_base = ((__SP & ~(MM_KSTACK_SIZE-1)) / PAGE_SIZE) % 1024;
-
-               tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
-               
-               // First 512 is the Table1 mapping + 2 for Table0 mapping
-               for( j = 512+2; j < 1024; j ++ )
-               {
-                       // Skip current stack
-                       if( j == cur_stack_base ) {
-                               j += (MM_KSTACK_SIZE / PAGE_SIZE) - 1;
-                               continue ;
-                       }
-                       if( !(tab[j] & 3) )     continue;
-                       ASSERT( (tab[j] & 3) == 2 );
-                       MM_DerefPhys( tab[j] & ~(PAGE_SIZE) );
-                       tab[j] = 0;
-               }
-       }
-       
-
-//     MM_DumpTables(0, 0x80000000);
-}
-
-tVAddr MM_MapTemp(tPAddr PAddr)
-{
-       tVAddr  ret;
-       tMM_PageInfo    pi;
-
-       for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
-       {
-               if( MM_int_GetPageInfo(ret, &pi) == 0 )
-                       continue;
-
-//             Log("MapTemp %P at %p by %p", PAddr, ret, __builtin_return_address(0));
-               MM_RefPhys(PAddr);      // Counter the MM_Deallocate in FreeTemp
-               MM_Map(ret, PAddr);
-               
-               return ret;
-       }
-       Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
-       return 0;
-}
-
-void MM_FreeTemp(tVAddr VAddr)
-{
-       if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
-               Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
-               return ;
-       }
-       
-       MM_Deallocate(VAddr);
-}
-
-tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
-{
-       tVAddr  ret;
-        int    i;
-       tMM_PageInfo    pi;
-
-       ENTER("xPAddr iNPages", PAddr, NPages);
-
-       // Scan for a location
-       for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
-       {
-//             LOG("checking %p", ret);
-               // Check if there is `NPages` free pages
-               for( i = 0; i < NPages; i ++ )
-               {
-                       if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
-                               break;
-               }
-               // Nope, jump to after the used page found and try again
-//             LOG("i = %i, ==? %i", i, NPages);
-               if( i != NPages ) {
-                       ret += i * PAGE_SIZE;
-                       continue ;
-               }
-       
-               // Map the pages        
-               for( i = 0; i < NPages; i ++ )
-                       MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAGE_SIZE);
-               // and return
-               LEAVE('p', ret);
-               return ret;
-       }
-       Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
-       LEAVE('p', 0);
-       return 0;
-}
-
-tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
-{
-       tPAddr  phys;
-       tVAddr  ret;
-
-       phys = MM_AllocPhysRange(Pages, MaxBits);
-       if(!phys) {
-               Log_Warning("MMVirt", "No space left for a %i page block (MM_AllocDMA)", Pages);
-               return 0;
-       }
-       
-       ret = MM_MapHWPages(phys, Pages);
-       *PAddr = phys;
-
-       return ret;
-}
-
-void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
-{
-       Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
-}
-
-tVAddr MM_NewKStack(int bShared)
-{
-       tVAddr  min_addr, max_addr;
-       tVAddr  addr, ofs;
-
-       if( bShared ) {
-               min_addr = MM_GLOBALSTACKS;
-               max_addr = MM_GLOBALSTACKS_END;
-       }
-       else {
-               min_addr = MM_KSTACK_BASE;
-               max_addr = MM_KSTACK_END;
-       }
-
-       // Locate a free slot
-       for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
-       {
-               tMM_PageInfo    pi;
-               if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) )    break;
-       }
-
-       // Check for an error   
-       if(addr >= max_addr) {
-               return 0;
-       }
-
-       // 1 guard page
-       for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
-       {
-               if( MM_Allocate(addr + ofs) == 0 )
-               {
-                       while(ofs)
-                       {
-                               ofs -= PAGE_SIZE;
-                               MM_Deallocate(addr + ofs);
-                       }
-                       Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
-                       return 0;
-               }
-       }
-       return addr + ofs;
-}
-
-tVAddr MM_NewUserStack(void)
-{
-       tVAddr  addr, ofs;
-
-       addr = USER_STACK_TOP - USER_STACK_SIZE;
-       if( MM_GetPhysAddr(addr + PAGE_SIZE) ) {
-               Log_Error("MMVirt", "Unable to create initial user stack, addr %p taken",
-                       addr + PAGE_SIZE
-                       );
-               return 0;
-       }
-
-       // 1 guard page
-       for( ofs = PAGE_SIZE; ofs < USER_STACK_SIZE; ofs += PAGE_SIZE )
-       {
-               tPAddr  rv;
-               if(ofs >= USER_STACK_SIZE - USER_STACK_COMM)
-                       rv = MM_Allocate(addr + ofs);
-               else
-                       rv = MM_AllocateZero(addr + ofs);
-               if(rv == 0)
-               {
-                       while(ofs)
-                       {
-                               ofs -= PAGE_SIZE;
-                               MM_Deallocate(addr + ofs);
-                       }
-                       Log_Warning("MMVirt", "MM_NewUserStack: Unable to allocate");
-                       return 0;
-               }
-               MM_SetFlags(addr+ofs, 0, MM_PFLAG_KERNEL);
-       }
-//     Log("Return %p", addr + ofs);
-//     MM_DumpTables(0, 0x80000000);
-       return addr + ofs;
-}
-
-void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
-{
-       if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
-       {
-               Debug("%p => %8s - 0x%7x %i %x %s",
-                       Start, "ZERO", Len,
-                       Info->Domain, Info->AP,
-                       Info->bGlobal ? "G" : "nG"
-                       );
-       }
-       else
-       {
-               Debug("%p => %8x - 0x%7x %i %x %s",
-                       Start, Info->PhysAddr-Len, Len,
-                       Info->Domain, Info->AP,
-                       Info->bGlobal ? "G" : "nG"
-                       );
-       }
-}
-
-void MM_DumpTables(tVAddr Start, tVAddr End)
-{
-       tVAddr  range_start = 0, addr;
-       tMM_PageInfo    pi, pi_old;
-        int    i = 0, inRange=0;
-       
-       memset(&pi_old, 0, sizeof(pi_old));
-
-       Debug("Page Table Dump (%p to %p):", Start, End);
-       range_start = Start;
-       for( addr = Start; i == 0 || (addr && addr < End); i = 1 )
-       {
-                int    rv;
-//             Log("addr = %p", addr);
-               rv = MM_int_GetPageInfo(addr, &pi);
-               if( rv
-                || pi.Size != pi_old.Size
-                || pi.Domain != pi_old.Domain
-                || pi.AP != pi_old.AP
-                || pi.bGlobal != pi_old.bGlobal
-                || pi_old.PhysAddr != pi.PhysAddr )
-               {
-                       if(inRange) {
-                               MM_int_DumpTableEnt(range_start, addr - range_start, &pi_old);
-                       }
-                       addr &= ~((1 << pi.Size)-1);
-                       range_start = addr;
-               }
-               
-               pi_old = pi;
-               // Handle the zero page
-               if( !giMM_ZeroPage || pi_old.Size != 12 || pi_old.PhysAddr != giMM_ZeroPage )
-                       pi_old.PhysAddr += 1 << pi_old.Size;
-               addr += 1 << pi_old.Size;
-               inRange = (rv == 0);
-       }
-       if(inRange)
-               MM_int_DumpTableEnt(range_start, addr - range_start, &pi);
-       Debug("Done");
-}
-
-// NOTE: Runs in abort context, not much difference, just a smaller stack
-void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
-{
-        int    rv;
-       tMM_PageInfo    pi;
-       
-       rv = MM_int_GetPageInfo(Addr, &pi);
-       
-       // Check for COW
-       if( rv == 0 &&  pi.AP == AP_RO_BOTH )
-       {
-               pi.AP = AP_RW_BOTH;
-               if( giMM_ZeroPage && pi.PhysAddr == giMM_ZeroPage )
-               {
-                       tPAddr  newpage;
-                       newpage = MM_AllocPhys();
-                       if( !newpage ) {
-                               Log_Error("MMVirt", "Unable to allocate new page for COW of ZERO");
-                               for(;;);
-                       }
-                       
-                       #if TRACE_COW
-                       Log_Notice("MMVirt", "COW %p caused by %p, ZERO duped to %P (RefCnt(%i)--)", Addr, PC,
-                               newpage, MM_GetRefCount(pi.PhysAddr));
-                       #endif
-
-                       MM_DerefPhys(pi.PhysAddr);
-                       pi.PhysAddr = newpage;
-                       pi.AP = AP_RW_BOTH;
-                       MM_int_SetPageInfo(Addr, &pi);
-                       
-                       memset( (void*)(Addr & ~(PAGE_SIZE-1)), 0, PAGE_SIZE );
-
-                       return ;
-               }
-               else if( MM_GetRefCount(pi.PhysAddr) > 1 )
-               {
-                       // Duplicate the page
-                       tPAddr  newpage;
-                       void    *dst, *src;
-                       
-                       newpage = MM_AllocPhys();
-                       if(!newpage) {
-                               Log_Error("MMVirt", "Unable to allocate new page for COW");
-                               for(;;);
-                       }
-                       dst = (void*)MM_MapTemp(newpage);
-                       src = (void*)(Addr & ~(PAGE_SIZE-1));
-                       memcpy( dst, src, PAGE_SIZE );
-                       MM_FreeTemp( (tVAddr)dst );
-                       
-                       #if TRACE_COW
-                       Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
-                               pi.PhysAddr, newpage, MM_GetRefCount(pi.PhysAddr));
-                       #endif
-
-                       MM_DerefPhys(pi.PhysAddr);
-                       pi.PhysAddr = newpage;
-               }
-               #if TRACE_COW
-               else {
-                       Log_Notice("MMVirt", "COW %p caused by %p, took last reference to %P",
-                               Addr, PC, pi.PhysAddr);
-               }
-               #endif
-               // Unset COW
-               pi.AP = AP_RW_BOTH;
-               MM_int_SetPageInfo(Addr, &pi);
-               return ;
-       }
-       
-
-       Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR,
-               (bPrefetch ? " - Prefetch" : "")
-               );
-       if( Addr < 0x80000000 )
-               MM_DumpTables(0, 0x80000000);
-       else
-               MM_DumpTables(0x80000000, -1);
-       for(;;);
-}
-
diff --git a/Kernel/arch/armv7/pci.c b/Kernel/arch/armv7/pci.c
deleted file mode 100644 (file)
index 2e674bb..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *
- */
-#include <acess.h>
-#include <drv_pci_int.h>
-
-// Realview
-//#define PCI_BASE     0x60000000
-
-//#define PCI_BASE     0xF0400000      // VMM Mapping
-#define PCI_BASE       0
-
-// === CODE ===
-void PCI_CfgWriteDWord(Uint32 Addr, Uint32 Data)
-{
-       #if PCI_BASE
-       Uint32  address = PCI_BASE | Addr;
-       *(Uint32*)(address) = Data;
-       #else
-       #endif
-}
-
-Uint32 PCI_CfgReadDWord(Uint32 Addr)
-{
-       #if PCI_BASE
-       Uint32  address = PCI_BASE | Addr;
-       return *(Uint32*)address;
-       #else
-       return 0xFFFFFFFF;
-       #endif
-}
-
diff --git a/Kernel/arch/armv7/proc.S b/Kernel/arch/armv7/proc.S
deleted file mode 100644 (file)
index 531de29..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Acess2 ARM
- * - By John Hodge (thePowersGang)
- *
- * arch/arm7/proc.S
- * - Process management assembly
- */
-
-#include "include/assembly.h"
-
-.globl KernelThreadHeader
-@ SP+12: Argument 1
-@ SP+8: Argument Count
-@ SP+4: Function
-@ SP+0: Thread Pointer
-KernelThreadHeader:
-       ldr r0, [sp],#4
-       @ TODO: Do something with the thread pointer
-       
-       ldr r4, [sp],#4 @ Function
-       @ Get argument
-       ldr r0, [sp],#4
-
-       blx r4
-       
-       ldr r0, =0
-       bl Threads_Exit
-       b .
-
-.globl SwitchTask
-@ R0: New stack
-@ R1: Pointer to where to save old stack
-@ R2: New IP
-@ R3: Pointer to save old IP
-@ SP+0: New address space
-SwitchTask:
-       push {r4-r12,lr}
-
-       @ Save IP       
-       ldr r4, =.return
-       str r4, [r3]
-       @ Save SP
-       str sp, [r1]
-
-       @ Only update TTBR0 if the task has an explicit address space
-       ldr r1, [sp,#4*10]
-       tst r1, r1
-       mcrne p15, 0, r1, c2, c0, 0     @ Set TTBR0 to r0
-       mov r1, #0
-       mcrne p15, 0, r1, c8, c7, 0     @ TLBIALL - Invalidate all
-
-       @ Restore SP
-       mov sp, r0
-
-       bx r2
-
-.return:
-       pop {r4-r12,pc}
-
-.extern MM_Clone
-.extern MM_DumpTables
-.globl Proc_CloneInt
-Proc_CloneInt:
-       @ R0: SP Destination
-       @ R1: Mem Destination
-       push {r4-r12,lr}
-       mov r4, r1      @ Save mem destination
-       str sp, [r0]    @ Save SP to SP dest
-
-       bl MM_Clone
-       str r0, [r4]    @ Save clone return to Mem Dest
-
-       ldr r0, =Proc_CloneInt_new
-       pop {r4-r12,pc}
-Proc_CloneInt_new:
-       mov r0, #0
-       pop {r4-r12,pc}
-
-@ R0: New user SP
-@ Return: Old user SP
-.globl Proc_int_SwapUserSP
-Proc_int_SwapUserSP:
-       cps #31 @ Go to system mode
-       mov r1, sp
-       tst r0, r0      @ Only update if non-zero
-       movne sp, r0
-       mov r0, r1
-       cps #19
-       mov pc, lr
-
-.section .usertext, "ax"
-.globl Proc_int_DropToUser
-@ R0: User IP
-@ R1: User SP
-Proc_int_DropToUser:
-       cps #16
-       mov sp, r1
-       mov pc, r0
-
-.section .rodata
-csProc_CloneInt_NewTaskMessage:
-       .asciz "New task PC=%p, R4=%p, sp=%p"
-csProc_CloneInt_OldTaskMessage:
-       .asciz "Parent task PC=%p, R4=%p, SP=%p"
diff --git a/Kernel/arch/armv7/proc.c b/Kernel/arch/armv7/proc.c
deleted file mode 100644 (file)
index cd998f2..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Acess2
- * - By John Hodge (thePowersGang)
- *
- * arch/arm7/proc.c
- * - ARM7 Process Switching
- */
-#include <acess.h>
-#include <threads_int.h>
-#include <hal_proc.h>
-
-// === IMPORTS ===
-extern tThread gThreadZero;
-extern tProcess        gProcessZero;
-extern void    SwitchTask(Uint32 NewSP, Uint32 *OldSP, Uint32 NewIP, Uint32 *OldIP, Uint32 MemPtr);
-extern void    KernelThreadHeader(void);       // Actually takes args on stack
-extern void    Proc_int_DropToUser(Uint32 IP, Uint32 SP) NORETURN __attribute__((long_call));
-extern Uint32  Proc_int_SwapUserSP(Uint32 NewSP);
-extern Uint32  Proc_CloneInt(Uint32 *SP, Uint32 *MemPtr);
-extern tVAddr  MM_NewKStack(int bGlobal);      // TODO: Move out into a header
-extern tVAddr  MM_NewUserStack(void);
-extern char    kernel_table0[];
-
-// === PROTOTYPES ===
-void   Proc_IdleThread(void *unused);
-
-// === GLOBALS ===
-tThread        *gpCurrentThread = &gThreadZero;
-tThread *gpIdleThread = NULL;
-
-// === CODE ===
-void ArchThreads_Init(void)
-{
-       gProcessZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
-}
-
-void Proc_IdleThread(void *unused)
-{
-       Threads_SetPriority(gpIdleThread, -1);
-       for(;;) {
-               Proc_Reschedule();
-               __asm__ __volatile__ ("wfi");
-       }
-}
-
-void Proc_Start(void)
-{
-       tTID    tid;
-
-       tid = Proc_NewKThread( Proc_IdleThread, NULL );
-       gpIdleThread = Threads_GetThread(tid);
-       gpIdleThread->ThreadName = (char*)"Idle Thread";
-}
-
-int GetCPUNum(void)
-{
-       return 0;
-}
-
-tThread *Proc_GetCurThread(void)
-{
-       return gpCurrentThread;
-}
-
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
-{
-       Uint32  *usr_sp;
-        int    i;
-       const char      **envp;
-       tVAddr  delta;
-
-//     Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
-//             Entrypoint, Base, ArgC, ArgV, DataSize);
-
-       // Write data to the user's stack
-       usr_sp = (void*)MM_NewUserStack();
-       usr_sp -= (DataSize+3)/4;
-       memcpy(usr_sp, ArgV, DataSize);
-       free(ArgV);
-
-       // Adjust user's copy of the arguments
-       delta = (tVAddr)usr_sp -  (tVAddr)ArgV;
-       ArgV = (void*)usr_sp;
-       for(i = 0; ArgV[i]; i ++)       ArgV[i] += delta;
-       envp = &ArgV[i+1];
-       for(i = 0; envp[i]; i ++)       envp[i] += delta;
-       
-       *--usr_sp = (Uint32)envp;
-       *--usr_sp = (Uint32)ArgV;
-       *--usr_sp = (Uint32)ArgC;
-       *--usr_sp = Base;
-       
-       // Drop to user code
-       Log_Debug("Proc", "Proc_int_DropToUser(%p, %p)", Entrypoint, usr_sp);
-       Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
-}
-
-void Proc_ClearProcess(tProcess *Process)
-{
-       Log_Warning("Proc", "TODO: Nuke address space etc");
-}
-
-void Proc_ClearThread(tThread *Thread)
-{
-}
-
-tTID Proc_Clone(Uint Flags)
-{
-       tThread *new;
-       Uint32  pc, sp, mem;
-
-       new = Threads_CloneTCB(Flags);
-       if(!new)        return -1;
-
-       // Actual clone magic
-       pc = Proc_CloneInt(&sp, &mem);
-       if(pc == 0) {
-               Log("Proc_Clone: In child");
-               return 0;
-       }
-       
-       new->SavedState.IP = pc;
-       new->SavedState.SP = sp;
-       new->SavedState.UserSP = Proc_int_SwapUserSP(0);
-       new->SavedState.UserIP = Proc_GetCurThread()->SavedState.UserIP;
-       new->Process->MemState.Base = mem;
-
-       Threads_AddActive(new);
-
-       return new->TID;
-}
-
-int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
-{
-       tThread *new;
-       Uint32  sp;
-
-       new = Threads_CloneThreadZero();
-       if(!new)        return -1;
-       if(new->ThreadName)     free(new->ThreadName);
-       new->ThreadName = NULL;
-
-       new->KernelStack = MM_NewKStack(1);
-       if(!new->KernelStack) {
-               // TODO: Delete thread
-               Log_Error("Proc", "Unable to allocate kernel stack");
-               return -1;
-       }       
-
-       sp = new->KernelStack;
-       
-       *(Uint32*)(sp -= 4) = (Uint)Ptr;
-       *(Uint32*)(sp -= 4) = (Uint)Fnc;
-       *(Uint32*)(sp -= 4) = (Uint)new;
-
-       new->SavedState.SP = sp;
-       new->SavedState.IP = (Uint)KernelThreadHeader;
-
-       Threads_AddActive(new);
-
-       return new->TID;
-}
-
-tTID Proc_NewKThread( void (*Fnc)(void*), void *Ptr )
-{
-       tThread *new;
-       Uint32  sp;
-
-       new = Threads_CloneTCB(0);
-       if(!new)        return -1;
-       free(new->ThreadName);
-       new->ThreadName = NULL;
-
-       // TODO: Non-shared stack
-       new->KernelStack = MM_NewKStack(1);
-       if(!new->KernelStack) {
-               // TODO: Delete thread
-               Log_Error("Proc", "Unable to allocate kernel stack");
-               return -1;
-       }       
-
-       sp = new->KernelStack;
-       
-       *(Uint32*)(sp -= 4) = (Uint)Ptr;
-       *(Uint32*)(sp -= 4) = (Uint)Fnc;
-       *(Uint32*)(sp -= 4) = (Uint)new;
-
-       new->SavedState.SP = sp;
-       new->SavedState.IP = (Uint)KernelThreadHeader;
-
-       Threads_AddActive(new);
-
-       return new->TID;
-}
-
-void Proc_CallFaultHandler(tThread *Thread)
-{
-
-}
-
-void Proc_Reschedule(void)
-{
-       tThread *cur, *next;
-
-       cur = gpCurrentThread;
-
-       next = Threads_GetNextToRun(0, cur);
-       if(!next)       next = gpIdleThread;
-       if(!next || next == cur)        return;
-
-       Log("Switching to %p (%i %s) IP=%p SP=%p TTBR0=%p UsrSP=%p",
-               next, next->TID, next->ThreadName,
-               next->SavedState.IP, next->SavedState.SP, next->Process->MemState.Base,
-               next->SavedState.UserSP
-               );
-
-       Log("Requested by %p", __builtin_return_address(0));
-       
-       gpCurrentThread = next;
-
-       cur->SavedState.UserSP = Proc_int_SwapUserSP( next->SavedState.UserSP );
-
-       SwitchTask(
-               next->SavedState.SP, &cur->SavedState.SP,
-               next->SavedState.IP, &cur->SavedState.IP,
-               next->Process->MemState.Base
-               );
-       
-}
-
-void Proc_DumpThreadCPUState(tThread *Thread)
-{
-       
-}
-
diff --git a/Kernel/arch/armv7/start.S b/Kernel/arch/armv7/start.S
deleted file mode 100644 (file)
index 8d9f3e4..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-
-#include "include/assembly.h"
-#include "include/options.h"
-
-@
-@ Exception defs taken from ARM DDI 0406B
-@ 
-.section .init
-interrupt_vector_table:
-ivt_reset:     b _start        @ 0x00 Reset
-ivt_undef:     b Undef_Handler @ 0x04 #UD
-ivt_svc:       b SVC_Handler   @ 0x08 SVC (used to be called SWI)
-ivt_prefetch:  b PrefetchAbort @ 0x0C Prefetch abort
-ivt_data:      b DataAbort     @ 0x10 Data abort
-ivt_unused:    b .             @ 0x14 Not Used
-ivt_irq:       b IRQHandler    @ 0x18 IRQ
-ivt_fiq:       b .             @ 0x1C FIQ (Fast interrupt)
-
-.globl _start
-_start:
-       ldr r2, =UART0_PADDR
-       mov r1, #'A'
-       str r1, [r2]    
-
-       ldr r0, =kernel_table0-KERNEL_BASE
-       mcr p15, 0, r0, c2, c0, 1       @ Set TTBR1 to r0
-       mcr p15, 0, r0, c2, c0, 0       @ Set TTBR0 to r0 too (for identity)
-
-       mov r1, #'c'
-       str r1, [r2]    
-
-       mov r0, #1
-       mcr p15, 0, r0, c2, c0, 2       @ Set TTCR to 1 (50/50 split)
-
-       mov r1, #'e'
-       str r1, [r2]    
-       
-       mov r0, #3
-       mcr p15, 0, r0, c3, c0, 0       @ Set Domain 0 to Manager
-
-       mov r1, #'s'
-       str r1, [r2]    
-
-       @ Enable VMSA
-       mrc p15, 0, r0, c1, c0, 0
-       orr r0, r0, #1
-       orr r0, r0, #1 << 23
-       mvn r1, #1 << 2
-       and r0, r0, r1
-       mcr p15, 0, r0, c1, c0, 0
-
-       @ HACK! Disable caching
-       mrc p15, 0, r1, c1, c0, 0
-
-       ldr r2, =0xF1000000
-       mov r1, #'s'
-       str r1, [r2]    
-
-       @ Enable access faults on domains 0 & 1
-       mov r0, #0x55   @ 01010101b
-       mcr p15, 0, r0, c3, c0, 0
-
-       mov r1, #'2'
-       str r1, [r2]    
-
-       @
-       @ Check for security extensions
-       @
-       mrc p15, 0, r0, c0, c1, 1
-       and r0, #0xF0
-       @ - Present
-       ldrne r0,=KERNEL_BASE
-       mcrne p15, 0, r0, c12, c0, 0    @ Set the VBAR (brings exceptions into high memory)
-       @ - Absent
-       mrceq p15, 0, r0, c1, c0, 0     @ Set SCTLR.V
-       orreq r0, #0x2000
-       mcreq p15, 0, r0, c1, c0, 0
-
-       mov r1, #'-'
-       str r1, [r2]    
-
-       @ Prepare for interrupts
-       cps #18 @ IRQ Mode
-       ldr sp, =irqstack+0x1000        @ Set up stack
-       cps #23 @ Abort Mode
-       ldr sp, =abortstack+0x1000
-       cps #19
-
-       mov r1, #'a'
-       str r1, [r2]    
-       mov r1, #'r'
-       str r1, [r2]    
-       mov r1, #'m'
-       str r1, [r2]    
-       mov r1, #13
-       str r1, [r2]    
-       mov r1, #10
-       str r1, [r2]    
-
-.extern bss_start
-.extern bss_size_div_4
-.zero_bss:
-       ldr r0, =bss_start
-       ldr r1, =bss_end
-       mov r3, #0
-.zero_bss_loop:
-       str r3, [r0],#4
-       cmp r0, r1
-       bls .zero_bss_loop
-
-.goto_c:
-       ldr sp, =0x80000000-8   @ Set up stack (top of user range)
-       ldr r0, =kmain
-       mov pc, r0
-1:     b 1b    @ Infinite loop
-
-.comm irqstack, 0x1000 @ ; 4KiB Stack
-.comm abortstack, 0x1000       @ ; 4KiB Stack
-
-.extern SyscallHandler
-SVC_Handler:
-@      sub lr, #4
-       srsdb sp!, #19  @ Save state to stack
-       cpsie ifa, #19  @ Ensure we're in supervisor with interrupts enabled (should already be there)
-       push {r0-r12}
-
-       ldr r4, [lr,#-4]
-       mvn r5, #0xFF000000
-       and r4, r5
-
-       tst r4, #0x1000 
-       bne .arm_specifics
-
-       push {r4}
-
-       mov r0, sp
-       ldr r4, =SyscallHandler
-       blx r4
-       
-@      ldr r0, =csSyscallPrintRetAddr
-@      ldr r1, [sp,#9*4+5*4]
-@      ldr r4, =Log
-@      blx r4
-       
-       pop {r2}        @ errno
-       pop {r0,r1}     @ Ret/RetHi
-       add sp, #2*4    @ Saved r2/r3
-
-       pop {r4-r12}
-       rfeia sp!       @ Pop state (actually RFEFD)
-.arm_specifics:
-       and r4, #0xFF
-       mov r0, r4      @ Number
-       mov r1, sp      @ Arguments
-       
-       ldr r4, =ARMv7_int_HandleSyscalls
-       blx r4
-
-       add sp, #4*4
-       pop {r4-r12}
-       rfeia sp!
-
-
-.globl gpIRQHandler
-gpIRQHandler:  .long   0
-IRQ_saved_sp:  .long   0
-IRQ_saved_lr:  .long   0
-.globl IRQHandler
-IRQHandler:
-       sub lr, #4      @ Adjust LR to the correct value
-       srsdb sp!, #19  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
-       cps #19
-
-       PUSH_GPRS
-
-@      ldr r0, =csIRQ_Tag
-@      ldr r1, =csIRQ_Fmt
-@      ldr r4, =Log_Debug
-@      blx r4
-       
-       @ Call the registered handler
-       ldr r0, gpIRQHandler
-       blx r0
-
-       @ Restore CPU state
-       POP_GPRS
-       cpsie i
-       rfeia sp!       @ Pop state (actually RFEFD)
-       bx lr
-
-.globl DataAbort
-DataAbort:
-       sub lr, #8      @ Adjust LR to the correct value
-       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
-@      cpsid ifa, #19
-       PUSH_GPRS
-
-       mov r3, #0      @ not a prefetch abort
-       mrc p15, 0, r2, c5, c0, 0       @ Read DFSR (Data Fault Status Register) to R2
-       mrc p15, 0, r1, c6, c0, 0       @ Read DFAR (Data Fault Address Register) into R1
-       mov r0, lr      @ PC
-       ldr r4, =MM_PageFault
-       blx r4
-
-       POP_GPRS
-       rfeia sp!       @ Pop state (actually RFEFD)
-
-.globl PrefetchAbort
-PrefetchAbort:
-       sub lr, #4      @ Adjust LR to the correct value
-       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
-@      cpsid ifa, #19
-       PUSH_GPRS
-
-       ldr r0, =csAbort_Tag
-       ldr r1, =csPrefetchAbort_Fmt
-#      mov r2, lr
-       mrc p15, 0, r2, c6, c0, 2       @ Read IFAR (Instruction Fault Address Register) into R3
-       mrc p15, 0, r3, c5, c0, 1       @ Read IFSR (Instruction Fault Status Register) into R3
-       ldr r5, =Log_Error
-       blx r5
-
-.loop:
-       wfi
-       b .loop
-.globl Undef_Handler
-Undef_Handler:
-       wfi
-       b Undef_Handler
-
-
-
-.section .rodata
-csIRQ_Tag:
-csAbort_Tag:
-       .asciz "ARMv7"
-csIRQ_Fmt:
-       .asciz "IRQ"
-csDataAbort_Fmt:
-       .asciz "Data Abort - %p accessed %p, DFSR=%x Unk:%x Unk:%x"
-csPrefetchAbort_Fmt:
-       .asciz "Prefetch Abort at %p, IFSR=%x"
-csSyscallPrintRetAddr:
-       .asciz "Syscall ret to %p"
-
-.section .padata
-.globl kernel_table0
-
-kernel_table0:
-       .long 0x00000402        @ Identity map the first 1 MiB
-       .rept 0x7FC - 1
-               .long 0
-       .endr
-       .long user_table1_map + 0x000 - KERNEL_BASE + 1 @ 0x7FC00000
-       .long user_table1_map + 0x400 - KERNEL_BASE + 1 @ 0x7FD00000
-       .long user_table1_map + 0x800 - KERNEL_BASE + 1 @ KStacks
-       .long user_table1_map + 0xC00 - KERNEL_BASE + 1
-       @ 0x80000000 - User/Kernel split
-       .long 0x00000402        @ Map first 4 MiB to 2GiB (KRW only)
-       .long 0x00100402        @ 
-       .long 0x00200402        @ 
-       .long 0x00300402        @ 
-       .rept 0xF00 - 0x800 - 4
-               .long 0
-       .endr
-#if PCI_PADDR
-       .long PCI_PADDR +  0*(1 << 20) + 0x402  @ Map PCI config space
-       .long PCI_PADDR +  1*(1 << 20) + 0x402
-       .long PCI_PADDR +  2*(1 << 20) + 0x402
-       .long PCI_PADDR +  3*(1 << 20) + 0x402
-       .long PCI_PADDR +  4*(1 << 20) + 0x402
-       .long PCI_PADDR +  5*(1 << 20) + 0x402
-       .long PCI_PADDR +  6*(1 << 20) + 0x402
-       .long PCI_PADDR +  7*(1 << 20) + 0x402
-       .long PCI_PADDR +  8*(1 << 20) + 0x402
-       .long PCI_PADDR +  9*(1 << 20) + 0x402
-       .long PCI_PADDR + 10*(1 << 20) + 0x402
-       .long PCI_PADDR + 11*(1 << 20) + 0x402
-       .long PCI_PADDR + 12*(1 << 20) + 0x402
-       .long PCI_PADDR + 13*(1 << 20) + 0x402
-       .long PCI_PADDR + 14*(1 << 20) + 0x402
-       .long PCI_PADDR + 15*(1 << 20) + 0x402
-#else
-       .rept 16
-               .long 0
-       .endr
-#endif
-       .long hwmap_table_0 + 0x000 - KERNEL_BASE + 1
-       .long hwmap_table_0 + 0x400 - KERNEL_BASE + 1
-       .long hwmap_table_0 + 0x800 - KERNEL_BASE + 1
-       .long hwmap_table_0 + 0xC00 - KERNEL_BASE + 1
-       .rept 0xFF8 - 0xF00 - 16 - 4
-               .long 0
-       .endr
-       @ Page fractals
-       .long kernel_table1_map + 0x000 - KERNEL_BASE + 1
-       .long kernel_table1_map + 0x400 - KERNEL_BASE + 1
-       .long kernel_table1_map + 0x800 - KERNEL_BASE + 1
-       .long kernel_table1_map + 0xC00 - KERNEL_BASE + 1
-       .long kernel_exception_map + 0x000 - KERNEL_BASE + 1
-       .long kernel_exception_map + 0x400 - KERNEL_BASE + 1
-       .long kernel_exception_map + 0x800 - KERNEL_BASE + 1
-       .long kernel_exception_map + 0xC00 - KERNEL_BASE + 1
-
-@ PID0 user table
-.globl user_table1_map
-@ User table1 data table (only the first half is needed)
-@ - Abused to provide kernel stacks in the unused half of the table
-user_table1_map:       @ Size = 4KiB (only 2KiB used)
-       .rept 0x800/4-1
-               .long 0
-       .endr
-       .long user_table1_map - KERNEL_BASE + 0x13      @ ...1FF000 = 0x7FDFF000
-       @ Kernel stack zone
-       .long kernel_table0 + 0x0000 - KERNEL_BASE + 0x13       @ ...200000 = 0x7FE00000
-       .long kernel_table0 + 0x1000 - KERNEL_BASE + 0x13       @ ...201000 = 0x7FE01000
-       .rept (0x800/4)-(MM_KSTACK_SIZE/0x1000)-2
-               .long 0
-       .endr
-       #if MM_KSTACK_SIZE != 0x2000
-       #error Kernel stack size not changed in start.S
-       #endif
-       .long stack + 0x0000 - KERNEL_BASE + 0x13       @ Kernel Stack
-       .long stack + 0x1000 - KERNEL_BASE + 0x13       @ 
-
-.globl kernel_table1_map
-kernel_table1_map:     @ Size = 4KiB
-       .rept (0xF00+16)/4
-               .long 0
-       .endr
-       .long hwmap_table_0 - KERNEL_BASE + 0x13
-       .rept 0xFF8/4 - (0xF00+16)/4 - 1
-               .long 0
-       .endr
-       .long kernel_table1_map - KERNEL_BASE + 0x13
-       .long kernel_exception_map - KERNEL_BASE + 0x13
-
-@ Hardware mappings 
-.globl hwmap_table_0
-hwmap_table_0:
-       .long UART0_PADDR + 0x13        @ UART0
-       .rept 1024 - 1
-               .long 0
-       .endr
-.globl kernel_exception_map
-kernel_exception_map:
-       @ Padding
-       .rept 1024-256
-               .long 0
-       .endr
-       @ Align to nearly the end
-       .rept 256-16
-               .long   0
-       .endr
-       .long 0x212     @ Map first page for exceptions (Kernel RO, Execute)
-       .rept 16-1-2
-               .long 0
-       .endr
-       .long gUsertextPhysStart + 0x22 @ User .text (User RO, Kernel RW, because both is COW)
-       .long 0
-       
-.section .padata
-stack:
-       .space MM_KSTACK_SIZE, 0        @ Original kernel stack
-
-// vim: ts=8 ft=armv7
-
diff --git a/Kernel/arch/armv7/time.c b/Kernel/arch/armv7/time.c
deleted file mode 100644 (file)
index d4ae4fa..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Acess2
- *
- * ARM7 Time code
- * arch/arm7/time.c
- */
-#include <acess.h>
-
-// === GLOBALS ===
-tTime  giTimestamp;
-
-// === CODE ===
-tTime now(void)
-{
-       return giTimestamp;
-}
diff --git a/Kernel/arch/helpers.h b/Kernel/arch/helpers.h
deleted file mode 100644 (file)
index 4d85fcb..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * arch/helpers.h
- * - Misc helper functions for the arch code
- */
-#ifndef _ARCH_HELPERS_H_
-#define _ARCH_HELPERS_H_
-
-// Divide
-// - Find what power of two times Den is > Num
-// - Iterate down in bit significance
-//  > If the `N` value is greater than `D`, we can set this bit
-#define DEF_DIVMOD(s) Uint##s __divmod##s(Uint##s N, Uint##s D, Uint##s*Rem){\
-       Uint##s ret=0,add=1;\
-       while(N>=D&&add) {D<<=1;add<<=1;}\
-       while(add>1){\
-               add>>=1;D>>=1;\
-               if(N>=D){ret+=add;N-=D;}\
-       }\
-       if(Rem)*Rem = N;\
-       return ret;\
-}
-
-#endif
-
diff --git a/Kernel/arch/m68k/Makefile b/Kernel/arch/m68k/Makefile
deleted file mode 100644 (file)
index 4caea1e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Acess2 Kernel
-# m68k Architecture Makefile
-# arch/m68k/Makefile
-
-CFLAGS = 
-
-A_OBJ = main.o debug.o lib.o time.o proc.o mm_virt.o mm_phys.o
-
-LDFLAGS += `$(CC) --print-libgcc-file-name`
-
diff --git a/Kernel/arch/m68k/debug.c b/Kernel/arch/m68k/debug.c
deleted file mode 100644 (file)
index 8c7de3b..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/debug.c
- * - Debugging output
- */
-#include <acess.h>
-
-// === PROTOTYPES ===
-void   StartupPrint(const char *Str);
-void   KernelPanic_SetMode(void);
-void   KernelPanic_PutChar(char ch);
-
-// === CODE ===
-void StartupPrint(const char *Str)
-{
-}
-
-void KernelPanic_SetMode(void)
-{
-}
-
-void KernelPanic_PutChar(char ch)
-{
-}
-
diff --git a/Kernel/arch/m68k/include/arch.h b/Kernel/arch/m68k/include/arch.h
deleted file mode 100644 (file)
index 0b2dc5b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Acess2 M68000 port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/include/arch.h
- * - Architectre config
- */
-#ifndef _M68K_ARCH_H_
-#define _M68K_ARCH_H_
-
-#define INVLPTR        ((void*)-1)
-#define BITS   32
-
-typedef unsigned long long     Uint64;
-typedef unsigned long  Uint32;
-typedef unsigned short Uint16;
-typedef unsigned char  Uint8;
-
-typedef signed long long       Sint64;
-typedef signed long    Sint32;
-typedef signed short   Sint16;
-typedef signed char    Sint8;
-
-typedef unsigned int   Uint;
-typedef unsigned int   size_t;
-
-typedef char   BOOL;
-
-typedef Uint32 tVAddr;
-typedef Uint32 tPAddr;
-
-struct sShortSpinlock
-{
-       int v;
-};
-
-// Non preemptive and no SMP, no need for these
-#define SHORTLOCK(lock)        do{}while(0)
-#define SHORTREL(lock) do{}while(0)
-#define IS_LOCKED(lock)        (0)
-#define CPU_HAS_LOCK(lock)     (0)
-
-#define Debug_PutCharDebug(ch) do{}while(0)
-#define Debug_PutStringDebug(ch)       do{}while(0)
-
-#define HALT() do{}while(0)
-
-#define USER_MAX       0
-
-#define        PAGE_SIZE       0x1000
-
-#endif
-
diff --git a/Kernel/arch/m68k/include/mm_virt.h b/Kernel/arch/m68k/include/mm_virt.h
deleted file mode 100644 (file)
index 01480b9..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Acess2 M68000 port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/include/mm_virt.h
- * - Virtual memory addresses
- */
-#ifndef _M68K_MM_VIRT_H_
-#define _M68K_MM_VIRT_H_
-
-#define MM_KHEAP_BASE  0
-#define MM_KHEAP_MAX   0
-
-#define MM_USER_MIN    0
-#define USER_LIB_MAX   0
-#define MM_MODULE_MIN  0
-#define MM_MODULE_MAX  0
-
-#define MM_PPD_HANDLES 0
-#define MM_KERNEL_VFS  0
-
-#endif
-
diff --git a/Kernel/arch/m68k/include/proc.h b/Kernel/arch/m68k/include/proc.h
deleted file mode 100644 (file)
index 8cf6aa0..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Acess2 M68000 port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/include/proc.h
- * - Task management defs
- */
-#ifndef _M68K_PROC_H_
-#define _M68K_PROC_H_
-
-#define MAX_CPUS       1
-
-typedef int    tMemoryState;   // Unused
-
-typedef struct {
-       Uint32  IP;
-       Uint32  SP;
-} tTaskState;
-
-typedef struct {
-       Uint32  Num;
-       union {
-               Uint32  Arg1;
-               Uint32  Return;
-       };
-       union {
-               Uint32  Arg2;
-               Uint32  RetHi;
-       };
-       union {
-               Uint32  Arg3;
-               Uint32  Error;
-       };
-       Uint32  Arg4;
-       Uint32  Arg5;
-       Uint32  Arg6;
-} tSyscallRegs;
-
-#endif
-
diff --git a/Kernel/arch/m68k/lib.c b/Kernel/arch/m68k/lib.c
deleted file mode 100644 (file)
index 2888a31..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/lib.c
- * - Library functions
- */
-#include <acess.h>
-#include "../helpers.h"
-#include <drv_pci_int.h>
-
-Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
-Uint64 __udivdi3(Uint64 Num, Uint64 Den);
-Uint64 __umoddi3(Uint64 Num, Uint64 Den);
-
-// === CODE ===
-void *memcpy(void *__dest, const void *__src, size_t __len)
-{
-       register Uint8  *dest = __dest;
-       register const Uint8 *src = __src;
-
-       while(__len --)
-               *dest++ = *src++;
-
-       return __dest;
-}
-
-void *memset(void *__dest, int __val, size_t __count)
-{
-       register Uint8  *dest = __dest;
-       
-       while(__count --)
-               *dest = __val;
-       
-       return __dest;
-}
-
-int memcmp(const void *__p1, const void *__p2, size_t __maxlen)
-{
-       const char      *m1 = __p1, *m2 = __p2;
-       while( __maxlen-- )
-       {
-               if(*m1 != *m2)  return *m1 - *m2;
-       }
-       return 0;
-}
-
-DEF_DIVMOD(64)
-
-Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
-{
-       Uint64  ret;
-       if(Den == 0)    return 0;       // TODO: #div0
-       if(Num < Den) {
-               if(Rem) *Rem = Num;
-               return 0;
-       }
-       if(Num == 0) {
-               if(Rem) *Rem = 0;
-               return 0;
-       }
-       if(Den == 1) {
-               if(Rem) *Rem = 0;
-               return Num;
-       }
-       if(Den == 2) {
-               if(Rem) *Rem = Num & 1;
-               return Num >> 1;
-       }
-       if(Den == 16) {
-               if(Rem) *Rem = Num & 0xF;
-               return Num >> 4;
-       }
-       if(Den == 32) {
-               if(Rem) *Rem = Num & 0x1F;
-               return Num >> 5;
-       }
-       if(Den == 0x1000) {
-               if(Rem) *Rem = Num & 0xFFF;
-               return Num >> 12;
-       }
-       
-       if( !(Den >> 32) && !(Num >> 32) ) {
-               if(Rem) *Rem = (Uint32)Num % (Uint32)Den;       // Clear high bits
-               return (Uint32)Num / (Uint32)Den;
-       }
-
-       ret = __divmod64(Num, Den, Rem);
-       return ret;
-}
-
-// Unsigned Divide 64-bit Integer
-Uint64 __udivdi3(Uint64 Num, Uint64 Den)
-{
-       return DivMod64U(Num, Den, NULL);
-}
-
-// Unsigned Modulus 64-bit Integer
-Uint64 __umoddi3(Uint64 Num, Uint64 Den)
-{
-       Uint64  ret = 0;
-       DivMod64U(Num, Den, &ret);
-       return ret;
-}
-
-// ---- PCI (stubbed)
-Uint32 PCI_CfgReadDWord(Uint32 Addr)
-{
-       return 0xFFFFFFFF;
-}
-void PCI_CfgWriteDWord(Uint32 Addr, Uint32 Data)
-{
-}
-
diff --git a/Kernel/arch/m68k/link.ld b/Kernel/arch/m68k/link.ld
deleted file mode 100644 (file)
index c0b0c9d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-ENTRY (_start)
-
-_kernel_base = 0x0;
-
-SECTIONS
-{
-       . = 0;
-       .init :
-       {
-               *(.init)
-       }
-       . += _kernel_base;
-       .text : AT( ADDR(.text) - _kernel_base )
-       {
-               *(.text*)
-               *(.rodata*)
-       }
-       /* 0x4000 (4 pages) alignment needed for root table */
-       .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
-       {
-               *(.padata)
-               *(.data*)
-               
-               gKernelSymbols = .;
-               *(KEXPORT)
-               gKernelSymbolsEnd = .;
-               
-               gKernelModules = .;
-               *(KMODULES)
-               gKernelModulesEnd = .;
-       }
-       .bss : AT( ADDR(.bss) - _kernel_base )
-       {
-               *(.bss*)
-               *(COMMON*)
-               . = ALIGN(0x1000);
-               *(.pabss)
-       }
-       gKernelEnd = .;
-}
diff --git a/Kernel/arch/m68k/main.c b/Kernel/arch/m68k/main.c
deleted file mode 100644 (file)
index 3f78e4b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/main.c
- * - C entrypoint
- */
-#include <acess.h>
-#include <init.h>
-
-// === PROTOTYPES ===
-void   kmain(void);
-
-// === CODE ===
-void kmain(void)
-{
-       LogF("Acess2 m68k v"EXPAND_STR(KERNEL_VERSION)"\n");
-       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
-       
-}
-
-void Arch_LoadBootModules(void)
-{
-       
-}
-
diff --git a/Kernel/arch/m68k/mm_phys.c b/Kernel/arch/m68k/mm_phys.c
deleted file mode 100644 (file)
index 24fd1f2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/mm_phys.c
- * - Stubbed physical memory management
- */
-#include <acess.h>
-
-// === CODE ===
-void MM_RefPhys(tPAddr Page)
-{
-       // TODO: Refcount pages
-       Log_Warning("MMPhys", "TODO: Implement MM_RefPhys");
-}
-
-int MM_SetPageNode(tPAddr Page, void *Node)
-{
-       Log_Warning("MMPhys", "TODO: Implement MM_SetPageNode");
-       return -1;
-}
-
diff --git a/Kernel/arch/m68k/mm_virt.c b/Kernel/arch/m68k/mm_virt.c
deleted file mode 100644 (file)
index 88990a1..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/mm_virt.c
- * - Stubbed virtual memory management (no MMU)
- */
-#include <acess.h>
-#include <mm_virt.h>
-#include <hal_proc.h>
-
-// === CODE ===
-tPAddr MM_GetPhysAddr(tVAddr Addr)
-{
-       return Addr;
-}
-
-void MM_SetFlags(tVAddr Addr, Uint Val, Uint Mask)
-{
-       return ;
-}
-
-Uint MM_GetFlags(tVAddr Addr)
-{
-       return 0;
-}
-
-int MM_Map(tVAddr Dest, tPAddr Src)
-{
-       Dest &= (PAGE_SIZE-1);
-       Src &= (PAGE_SIZE-1);
-       if(Dest != Src)
-               memcpy((void*)Dest, (void*)Src, PAGE_SIZE);
-       return 0;
-}
-
-tPAddr MM_Allocate(tVAddr Dest)
-{
-       return Dest;
-}
-
-void MM_Deallocate(tVAddr Addr)
-{
-}
-
-void MM_ClearUser(void)
-{
-}
-
-void MM_DumpTables(tVAddr Start, tVAddr End)
-{
-
-}
-
diff --git a/Kernel/arch/m68k/proc.c b/Kernel/arch/m68k/proc.c
deleted file mode 100644 (file)
index c148bff..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/proc.c
- * - Multithreading
- */
-#include <acess.h>
-#include <threads_int.h>
-#include <hal_proc.h>
-
-// === IMPORTS ===
-extern tThread gThreadZero;
-
-// === GLOBALS ===
-tThread        *gpCurrentThread = &gThreadZero;
-
-// === CODE ===
-void ArchThreads_Init(void)
-{
-}
-
-void Proc_Start(void)
-{      
-}
-
-tThread *Proc_GetCurThread(void)
-{
-       return gpCurrentThread;
-}
-
-int GetCPUNum(void)
-{
-       return 0;
-}
-
-tTID Proc_Clone(Uint Flags)
-{
-       UNIMPLEMENTED();
-       return -1;
-}
-
-tTID Proc_NewKThread(tThreadFunction Fcn, void *Arg)
-{
-       UNIMPLEMENTED();
-       return -1;
-}
-
-tTID Proc_SpawnWorker(tThreadFunction Fcn, void *Arg)
-{
-       UNIMPLEMENTED();
-       return -1;
-}
-
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
-{
-       Log_KernelPanic("Proc", "TODO: Implement Proc_StartUser");
-       for(;;);
-}
-
-void Proc_CallFaultHandler(tThread *Thread)
-{
-       
-}
-
-void Proc_DumpThreadCPUState(tThread *Thread)
-{
-       
-}
-
-void Proc_Reschedule(void)
-{
-       Log_Notice("Proc", "TODO: Implement Proc_Reschedule");
-}
-
diff --git a/Kernel/arch/m68k/time.c b/Kernel/arch/m68k/time.c
deleted file mode 100644 (file)
index 0fffaf6..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Acess2 M68K port
- * - By John Hodge (thePowersGang)
- *
- * arch/m68k/time.c
- * - Timekeeping
- */
-#include <acess.h>
-
-// === CODE ===
-Sint64 now(void)
-{
-       return 0;
-}
diff --git a/Kernel/arch/x86/Makefile b/Kernel/arch/x86/Makefile
deleted file mode 100644 (file)
index c83a5af..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Acess2 Kernel
-# i386 Architecture Makefile
-# arch/i386/Makefile
-
-AS_SUFFIX = asm
-
-CPPFLAGS       =
-CFLAGS         =
-ASFLAGS                = -f elf
-
-USE_MP=0
-
-ifeq ($(PLATFORM),default)
-       USE_MP=0
-else ifeq ($(PLATFORM),smp)
-       USE_MP=1
-endif
-
-ASFLAGS += -D USE_MP=$(USE_MP)
-CPPFLAGS += -DUSE_MP=$(USE_MP)
-
-A_OBJ  = start.ao main.o lib.o desctab.ao errors.o irq.o
-A_OBJ += mm_phys.o mm_virt.o
-A_OBJ += proc.o proc.ao time.o vm8086.o
-A_OBJ += kpanic.o pci.o
diff --git a/Kernel/arch/x86/desctab.asm b/Kernel/arch/x86/desctab.asm
deleted file mode 100644 (file)
index 6eaa651..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-; AcessOS Microkernel Version
-;
-; desctab.asm
-[BITS 32]
-
-
-[section .data]
-; IDT
-ALIGN 8
-[global gIDT]
-gIDT:
-       ; CS = 0x08, Type = 32-bit Interrupt (0xE = 1 110)
-       times   256     dd      0x00080000,0x00000E00
-[global gIDTPtr]
-gIDTPtr:
-       dw      256 * 16 - 1    ; Limit
-       dd      gIDT            ; Base
-
-[section .text]
-
-[global Desctab_Install]
-Desctab_Install:
-       ; Set up IDT
-       ; Helper Macros
-       ; - Set an IDT entry to an ISR
-%macro SETISR  1
-       mov eax, Isr%1
-       mov     WORD [gIDT + %1*8], ax
-       shr eax, 16
-       mov     WORD [gIDT + %1*8+6], ax
-       ; Enable
-       mov     ax, WORD [gIDT + %1*8 + 4]
-       or ax, 0x8000
-       mov     WORD [gIDT + %1*8 + 4], ax
-%endmacro
-       ; Enable user calling of an ISR
-%macro SET_USER        1
-       or WORD [gIDT + %1*8 + 4], 0x6000
-%endmacro
-       ; Set an ISR as a trap (leaves interrupts enabled when invoked)
-%macro SET_TRAP        1
-       or WORD [gIDT + %1*8 + 4], 0x0100
-%endmacro
-
-       ; Error handlers
-       %assign i       0
-       %rep 32
-       SETISR  i
-       %assign i i+1
-       %endrep
-       
-       ; User Syscall
-       SETISR  0xAC
-       SET_USER        0xAC
-       SET_TRAP        0xAC    ; Interruptable
-       
-       ; MP ISRs
-       %if USE_MP
-       SETISR  0xED    ; 0xED Inter-processor HALT
-       SETISR  0xEE    ; 0xEE Timer
-       SETISR  0xEF    ; 0xEF Spurious Interrupt
-       %endif
-
-       ; IRQs
-       %assign i       0xF0
-       %rep 16
-       SETISR  i
-       %assign i i+1
-       %endrep
-
-       ; Load IDT
-       lidt [gIDTPtr]
-
-       ; Remap PIC
-       push edx        ; Save EDX
-       mov dx, 0x20
-       mov al, 0x11
-       out dx, al      ;       Init Command
-       mov dx, 0x21
-       mov al, 0xF0
-       out dx, al      ;       Offset (Start of IDT Range)
-       mov al, 0x04
-       out dx, al      ;       IRQ connected to Slave (00000100b) = IRQ2
-       mov al, 0x01
-       out dx, al      ;       Set Mode
-       mov al, 0x00
-       out dx, al      ;       Set Mode
-       
-       mov dx, 0xA0
-       mov al, 0x11
-       out dx, al      ;       Init Command
-       mov dx, 0xA1
-       mov al, 0xF8
-       out dx, al      ;       Offset (Start of IDT Range)
-       mov al, 0x02
-       out dx, al      ;       IRQ Line connected to master
-       mov al, 0x01
-       out dx, al      ;       Set Mode
-       mov dl, 0x00
-       out dx, al      ;       Set Mode
-       pop edx
-       
-       ret
-
-
-; ===============
-; = Define ISRs =
-; ===============
-%macro ISR_ERRNO       1
-[global Isr%1]
-Isr%1:
-       ;xchg bx, bx
-       push    %1
-       jmp     ErrorCommon
-%endmacro
-%macro ISR_NOERR       1
-[global Isr%1]
-Isr%1:
-       ;xchg bx, bx
-       push    0
-       push    %1
-       jmp     ErrorCommon
-%endmacro
-
-%macro DEF_SYSCALL     1
-[global Isr%1]
-Isr%1:
-       push    0
-       push    %1
-       jmp     SyscallCommon
-%endmacro
-
-%macro DEF_IRQ 1
-[global Isr%1]
-Isr%1:
-       push    0
-       push    %1
-       jmp     IRQCommon
-%endmacro
-
-ISR_NOERR      0;  0: Divide By Zero Exception
-ISR_NOERR      1;  1: Debug Exception
-ISR_NOERR      2;  2: Non Maskable Interrupt Exception
-ISR_NOERR      3;  3: Int 3 Exception
-ISR_NOERR      4;  4: INTO Exception
-ISR_NOERR      5;  5: Out of Bounds Exception
-ISR_NOERR      6;  6: Invalid Opcode Exception
-ISR_NOERR      7;  7: Coprocessor Not Available Exception
-ISR_ERRNO      8;  8: Double Fault Exception (With Error Code!)
-ISR_NOERR      9;  9: Coprocessor Segment Overrun Exception
-ISR_ERRNO      10; 10: Bad TSS Exception (With Error Code!)
-ISR_ERRNO      11; 11: Segment Not Present Exception (With Error Code!)
-ISR_ERRNO      12; 12: Stack Fault Exception (With Error Code!)
-ISR_ERRNO      13; 13: General Protection Fault Exception (With Error Code!)
-ISR_ERRNO      14; 14: Page Fault Exception (With Error Code!)
-ISR_NOERR      15; 15: Reserved Exception
-ISR_NOERR      16; 16: Floating Point Exception
-ISR_NOERR      17; 17: Alignment Check Exception
-ISR_NOERR      18; 18: Machine Check Exception
-ISR_NOERR      19; 19: Reserved
-ISR_NOERR      20; 20: Reserved
-ISR_NOERR      21; 21: Reserved
-ISR_NOERR      22; 22: Reserved
-ISR_NOERR      23; 23: Reserved
-ISR_NOERR      24; 24: Reserved
-ISR_NOERR      25; 25: Reserved
-ISR_NOERR      26; 26: Reserved
-ISR_NOERR      27; 27: Reserved
-ISR_NOERR      28; 28: Reserved
-ISR_NOERR      29; 29: Reserved
-ISR_NOERR      30; 30: Reserved
-ISR_NOERR      31; 31: Reserved
-
-DEF_SYSCALL    0xAC    ; Acess System Call
-
-%if USE_MP
-[global Isr0xED]
-; 0xED - Interprocessor HALT
-Isr0xED:
-       cli
-.jmp:  hlt
-       jmp .jmp
-
-[global Isr0xEE]
-[extern SchedulerBase]
-; AP's Timer Interrupt
-Isr0xEE:
-       push eax        ; Line up with interrupt number
-       mov eax, dr1    ; CPU Number
-       push eax
-       mov eax, [esp+4]        ; Load EAX back
-       jmp SchedulerBase
-; Spurious Interrupt
-[global Isr0xEF]
-Isr0xEF:
-       xchg bx, bx     ; MAGIC BREAK
-       iret
-%endif
-
-; IRQs
-; - Timer
-[global Isr240]
-[global Isr240.jmp]
-[extern SchedulerBase]
-[extern SetAPICTimerCount]
-Isr240:
-       push 0  ; Line up with Argument in errors
-       push 0  ; CPU Number
-       ;xchg bx, bx    ; MAGIC BREAK
-Isr240.jmp:
-       %if USE_MP
-       jmp SetAPICTimerCount   ; This is reset once the bus speed has been calculated
-       %else
-       jmp SchedulerBase
-       %endif
-; - Assignable
-%assign i      0xF1
-%rep 16
-       DEF_IRQ i
-%assign i i+1
-%endrep
-
-; ---------------------
-; Common error handling
-; ---------------------
-[extern ErrorHandler]
-ErrorCommon:
-       ;xchg bx, bx    ; MAGIC BREAK
-       
-       pusha
-       push ds
-       push es
-       push fs
-       push gs
-
-       ; Clear TF      
-;      pushf
-;      and WORD [esp], 0xFEFF
-;      popf
-
-       mov ax, 0x10
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       
-       push esp
-       call ErrorHandler
-       add esp, 4
-       
-       pop gs
-       pop fs
-       pop es
-       pop ds
-       popa
-       add esp, 8      ; Error Code and ID
-       iret
-
-; --------------------------
-; Common System Call Handler
-; --------------------------
-[extern SyscallHandler]
-SyscallCommon:
-       pusha
-       push ds
-       push es
-       push fs
-       push gs
-       
-       push esp
-       call SyscallHandler
-       add esp, 4
-       
-       ; Pass changes to TF on to the user
-       ; EFLAGS is stored at ESP[4+8+2+2]
-       ; 4 Segment Registers
-       ; 8 GPRs
-       ; 2 Error Code / Interrupt ID
-       ; 2 CS/EIP
-       pushf
-       pop eax
-       and eax, 0x100  ; 0x100 = Trace Flag
-       and WORD [esp+(4+8+2+2)*4], ~0x100      ; Clear
-       or DWORD [esp+(4+8+2+2)*4], eax ; Set for user
-       
-       pop gs
-       pop fs
-       pop es
-       pop ds
-       popa
-       add esp, 8      ; Error Code and ID
-       iret
-
-; ------------
-; IRQ Handling
-; ------------
-[extern IRQ_Handler]
-[global IRQCommon]
-[global IRQCommon_handled]
-IRQCommon_handled equ IRQCommon.handled
-IRQCommon:
-       pusha
-       push ds
-       push es
-       push fs
-       push gs
-       
-       mov ax, 0x10
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       
-       push esp
-       call IRQ_Handler
-.handled:
-       add esp, 4
-       
-       pop gs
-       pop fs
-       pop es
-       pop ds
-       popa
-       add esp, 8      ; Error Code and ID
-       iret
-
-; vim: ft=nasm ts=8
diff --git a/Kernel/arch/x86/errors.c b/Kernel/arch/x86/errors.c
deleted file mode 100644 (file)
index d2d2cef..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Acess2 - x86 Architecture
- * arch/x86/errors.c
- * - CPU Error Handler
- */
-#include <acess.h>
-#include <proc.h>
-#include <mm_virt.h>
-
-// === CONSTANTS ===
-#define        MAX_BACKTRACE   8       //!< Maximum distance to trace the stack backwards
-
-// === IMPORTS ===
-extern void    MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
-extern void    VM8086_GPF(tRegs *Regs);
-extern void    Threads_Dump(void);
-extern void    Threads_Fault(int Num);
-extern int     GetCPUNum(void);
-extern void    MM_DumpTables(tVAddr, tVAddr);
-extern void    Proc_EnableSSE(void);
-extern void    Proc_RestoreSSE(Uint32 Data);
-
-// === PROTOTYPES ===
-void   __stack_chk_fail(void);
-void   ErrorHandler(tRegs *Regs);
-void   Proc_PrintBacktrace(void);
-void   Error_Backtrace(Uint eip, Uint ebp);
-void   StartupPrint(char *Str);
-
-// === GLOBALS ===
-const char *csaERROR_NAMES[] = {
-       "Divide By Zero", "Debug", "NMI Exception", "INT3",
-       "INTO Instr - Overflow", "BOUND Instr - Out of Bounds", "Invalid Opcode", "Coprocessor not avaliable",
-       "Double Fault", "Coprocessor Segment Overrun", "Bad TSS", "Segment Not Present",
-       "Stack Fault Exception", "GPF", "#PF", "Reserved",
-       "Floating Point Exception", "Alignment Check Exception", "Machine Check Exception",     "Reserved",
-       "Reserved", "Reserved", "Reserved", "Reserved",
-       "Reserved", "Reserved", "Reserved", "Reserved",
-       "Reserved", "Reserved", "Reserved", "Reserved"
-       };
-
-// === CODE ===
-/**
- * \brief Keeps GCC happy
- */
-void __stack_chk_fail(void)
-{
-       Panic("FATAL ERROR: Stack Check Failed\n");
-       for(;;);
-}
-
-/**
- * \fn void ErrorHandler(tRegs *Regs)
- * \brief General Error Handler
- * \param Regs Register state at error
- */
-void ErrorHandler(tRegs *Regs)
-{
-       Uint    cr;
-       
-       //if( Regs && !(Regs->int_num == 13 && Regs->eflags & 0x20000) )
-       //      __asm__ __volatile__ ("xchg %bx, %bx");
-       //Log_Debug("X86", "Regs = %p", Regs);
-       //Log_Debug("X86", "Error %i at 0x%08x", Regs->int_num, Regs->eip);
-       
-       __asm__ __volatile__ ("cli");
-       
-       // Debug exception (used for single-stepping)
-       if(Regs->int_num == 1)
-       {
-               static Uint32   lastEIP = 0;
-               tThread *thread = Proc_GetCurThread();
-               if( Regs->eip == lastEIP )
-                       return;
-               Log("%p(%i %s) IP=%08x", thread, thread->TID, thread->ThreadName, Regs->eip);
-               lastEIP = Regs->eip;
-               return ;
-       }
-       
-       // Page Fault
-       if(Regs->int_num == 14)
-       {
-               __asm__ __volatile__ ("sti");   // Should be OK, TODO: Test
-               __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
-               MM_PageFault( cr, Regs->err_code, Regs );
-               return ;
-       }
-
-       // #NM - Coprocessor unavaliable
-       if(Regs->int_num == 7)
-       {
-               tThread *thread = Proc_GetCurThread();
-               if(!thread->SavedState.bSSEModified)
-               {
-                       Proc_EnableSSE();
-                       if(!thread->SavedState.SSE)
-                               thread->SavedState.SSE = malloc(sizeof(tSSEState) + 0xF);
-                       else
-                               Proc_RestoreSSE( ((Uint)thread->SavedState.SSE + 0xF) & ~0xF );
-                       thread->SavedState.bSSEModified = 1;
-                       __asm__ __volatile__ ("sti");
-                       return ;
-               }
-               // oops, SSE enabled but a #NM, bad news
-       }
-       
-       // VM8086 GPF
-       if(Regs->int_num == 13 && Regs->eflags & 0x20000)
-       {
-               VM8086_GPF(Regs);
-               return ;
-       }
-       
-       // Check if it's a user mode fault
-       if( (Regs->cs & 3) == 3 ) {
-               Log_Warning("Arch", "User Fault -  %s, Code: 0x%x",
-                       csaERROR_NAMES[Regs->int_num], Regs->err_code);
-               Log_Warning("Arch", "at CS:EIP %04x:%08x",
-                       Regs->cs, Regs->eip);
-               MM_DumpTables(0, KERNEL_BASE);
-               switch( Regs->int_num )
-               {
-               // Division by Zero
-               case  0:        Threads_Fault(FAULT_DIV0);      break;
-               // Invalid opcode
-               case  6:        Threads_Fault(FAULT_OPCODE);    break;
-               // GPF
-               case 13:        Threads_Fault(FAULT_ACCESS);    break;
-               // Floating Point Exception
-               case 16:        Threads_Fault(FAULT_FLOAT);     break;
-               
-               default:        Threads_Fault(FAULT_MISC);      break;
-               }
-               return ;
-       }
-       
-       Debug_KernelPanic();
-       
-       LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x\n",
-               GetCPUNum(),
-               Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code,
-               Regs->eip);
-       
-       //Warning("CPU Error %i - %s, Code: 0x%x",
-       //      Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code);
-       //Warning(" CS:EIP = 0x%04x:%08x", Regs->cs, Regs->eip);
-       __ASM__ ("xchg %bx, %bx");
-       if(Regs->cs == 0x08)
-               Warning(" SS:ESP = 0x0010:%08x", (Uint)Regs+sizeof(tRegs));
-       else
-               Warning(" SS:ESP = 0x%04x:%08x", Regs->ss, Regs->esp);
-       Warning(" EFLAGS = 0x%08x", Regs->eflags);
-       Warning(" EAX %08x ECX %08x EDX %08x EBX %08x",
-               Regs->eax, Regs->ecx, Regs->edx, Regs->ebx);
-       Warning(" ESP %08x EBP %08x ESI %08x EDI %08x",
-               Regs->esp, Regs->ebp, Regs->esi, Regs->edi);
-       Warning(" DS %04x ES %04x FS %04x GS %04x",
-               Regs->ds, Regs->es, Regs->fs, Regs->gs);
-       
-       // Control Registers
-       __asm__ __volatile__ ("mov %%cr0, %0":"=r"(cr));
-       Warning(" CR0 0x%08x", cr);
-       __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
-       Warning(" CR2 0x%08x", cr);
-       __asm__ __volatile__ ("mov %%cr3, %0":"=r"(cr));
-       Warning(" CR3 0x%08x", cr);
-       
-       switch( Regs->int_num )
-       {
-       case 6: // #UD
-               Warning(" Offending bytes: %02x %02x %02x %02x",
-                       *(Uint8*)(Regs->eip+0), *(Uint8*)(Regs->eip+1),
-                       *(Uint8*)(Regs->eip+2), *(Uint8*)(Regs->eip+3));
-               break;
-       }
-       
-       // Print Stack Backtrace
-       Error_Backtrace(Regs->eip, Regs->ebp);
-       
-       // Dump running threads
-       Threads_Dump();
-       
-       for(;;) __asm__ __volatile__ ("hlt");
-}
-
-void Proc_PrintBacktrace(void)
-{
-       Uint32  ebp;
-       __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (ebp));
-       Error_Backtrace( *(Uint32*)(ebp+4), *(Uint32*)ebp );
-}
-
-/**
- * \fn void Error_Backtrace(Uint eip, Uint ebp)
- * \brief Unrolls the stack to trace execution
- * \param eip  Current Instruction Pointer
- * \param ebp  Current Base Pointer (Stack Frame)
- */
-void Error_Backtrace(Uint eip, Uint ebp)
-{
-        int    i = 0;
-//     Uint    delta = 0;
-//     char    *str = NULL;
-       
-       //if(eip < 0xC0000000 && eip > 0x1000)
-       //{
-       //      LogF("Backtrace: User - 0x%x\n", eip);
-       //      return;
-       //}
-
-       #if 0   
-       if(eip > 0xE0000000)
-       {
-               LogF("Backtrace: Data Area - 0x%x\n", eip);
-               return;
-       }
-       
-       if(eip > 0xC8000000)
-       {
-               LogF("Backtrace: Kernel Module - 0x%x\n", eip);
-               return;
-       }
-       #endif  
-
-       //str = Debug_GetSymbol(eip, &delta);
-//     if(str == NULL)
-               LogF("Backtrace: 0x%x", eip);
-//     else
-//             LogF("Backtrace: %s+0x%x", str, delta);
-       if(!MM_GetPhysAddr(ebp))
-       {
-               LogF("\nBacktrace: Invalid EBP, stopping\n");
-               return;
-       }
-       
-       
-       while( MM_GetPhysAddr(ebp) && i < MAX_BACKTRACE )
-       {
-               if( ebp >= MM_KERNEL_STACKS_END )       break;
-               //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
-//             if(str == NULL)
-                       LogF(" >> 0x%x", *(Uint*)(ebp+4));
-//             else
-//                     LogF(" >> %s+0x%x", str, delta);
-               ebp = *(Uint*)ebp;
-               i++;
-       }
-       LogF("\n");
-}
-
-/**
- * \fn void StartupPrint(char *Str)
- * \brief Str  String to print
- * \note WHY IS THIS HERE?!?!
- */
-void StartupPrint(char *Str)
-{
-       Uint16  *buf = (void*)0xC00B8000;
-        int    i = 0;
-       static int      line = 0;
-       while(*Str)
-       {
-               buf[line*80 + i++] = *Str | 0x0700;
-               Str ++;
-       }
-       
-       // Clear the rest of the line
-       while(i < 80)
-               buf[line*80 + i++] = 0x0720;
-       
-       line ++;
-       if(line == 25)
-       {
-               line --;
-               memcpy(buf, &buf[80], 80*24*2);
-               memset(&buf[80*24], 0, 80*2);
-       }
-}
-
-// === EXPORTS ===
-EXPORT(__stack_chk_fail);
diff --git a/Kernel/arch/x86/include/arch.h b/Kernel/arch/x86/include/arch.h
deleted file mode 100644 (file)
index 8a98705..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Acess2
- * - x86 Architecture
- * arch/x86/include/arch.h
- */
-#ifndef _ARCH_H_
-#define _ARCH_H_
-
-// - Base Defintions
-#define        KERNEL_BASE     0xC0000000
-#define BITS   32
-#define PAGE_SIZE      0x1000
-
-#define INVLPTR        ((void*)-1)
-
-// Allow nested spinlocks?
-#define LOCK_DISABLE_INTS      1
-
-// - Processor/Machine Specific Features
-#if ARCH != x86 && ARCH != x86_smp
-# error "Unknown architecture '" #ARCH "'"
-#endif
-
-#if USE_MP
-# define       MAX_CPUS        8
-#else
-# define       MAX_CPUS        1
-#endif
-
-#if USE_PAE
-# define       PHYS_BITS       48
-#else
-# define       PHYS_BITS       32
-#endif
-
-#define __ASM__        __asm__ __volatile__
-
-// === Spinlocks ===
-/**
- * \brief Short Spinlock structure
- */
-struct sShortSpinlock {
-       volatile int    Lock;   //!< Lock value
-       
-       #if LOCK_DISABLE_INTS
-        int    IF;     //!< Interrupt state on call to SHORTLOCK
-       #endif
-};
-
-// === MACROS ===
-/**
- * \brief Halt the CPU (shorter version of yield)
- */
-#if 1
-#define        HALT()  do { \
-       Uint32  flags; \
-       __asm__ __volatile__ ("pushf;pop %0" : "=a"(flags)); \
-       if( !(flags & 0x200) )  Panic("HALT called with interrupts disabled"); \
-       __asm__ __volatile__ ("hlt"); \
-} while(0)
-#else
-#define        HALT()  __asm__ __volatile__ ("hlt")
-#endif
-/**
- * \brief Fire a magic breakpoint (bochs)
- */
-#define        MAGIC_BREAK()   __asm__ __volatile__ ("xchg %bx, %bx")
-
-// === TYPES ===
-typedef unsigned int   Uint;   // Unsigned machine native integer
-typedef unsigned char  Uint8;
-typedef unsigned short Uint16;
-typedef unsigned long  Uint32;
-typedef unsigned long long     Uint64;
-typedef signed int             Sint;   // Signed Machine Native integer
-typedef signed char            Sint8;
-typedef signed short   Sint16;
-typedef signed long            Sint32;
-typedef signed long long       Sint64;
-typedef Uint   size_t;
-typedef char   BOOL;
-
-typedef Uint32 tPAddr;
-typedef Uint32 tVAddr;
-
-typedef struct {
-       Uint32  gs, fs, es, ds;
-       Uint32  edi, esi, ebp, kesp;
-       Uint32  ebx, edx, ecx, eax;
-       Uint32  int_num, err_code;
-       Uint32  eip, cs;
-       Uint32  eflags, esp, ss;
-} tRegs;
-
-typedef struct {
-       Uint    Resvd1[4];      // GS, FS, ES, DS
-       Uint    Arg4, Arg5;     // EDI, ESI
-       Uint    Arg6;   // EBP
-       Uint    Resvd2[1];      // Kernel ESP
-       union {
-               Uint    Arg1;
-               Uint    Error;
-       };      // EBX
-       union {
-               Uint    Arg3;
-               Uint    RetHi;  // High 32 bits of ret
-       };      // EDX
-       Uint    Arg2;   // ECX
-       union {
-               Uint    Num;
-               Uint    Return;
-       };      // EAX
-       Uint    Resvd3[5];      // Int, Err, Eip, CS, ...
-       Uint    StackPointer;   // ESP
-       Uint    Resvd4[1];      // SS
-} tSyscallRegs;
-
-// === FUNCTIONS ===
-extern void    Debug_PutCharDebug(char ch);
-extern void    Debug_PutStringDebug(const char *String);
-
-extern int     IS_LOCKED(struct sShortSpinlock *Lock);
-extern int     CPU_HAS_LOCK(struct sShortSpinlock *Lock);
-extern void    SHORTLOCK(struct sShortSpinlock *Lock);
-extern void    SHORTREL(struct sShortSpinlock *Lock);
-
-#endif // !defined(_ARCH_H_)
diff --git a/Kernel/arch/x86/include/arch_int.h b/Kernel/arch/x86/include/arch_int.h
deleted file mode 100644 (file)
index 81ea2d7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * x86 Arch - Internal Definitions
- * - arch/x86/include/arch_int.h
- */
-#ifndef _ARCH_INT_H_
-#define _ARCH_INT_H_
-
-/**
- * \brief Spinlock primative atomic set-if-zero loop
- */
-extern void    __AtomicTestSetLoop(Uint *Ptr, Uint Value);
-
-/**
- * \brief Clear and free an address space
- */
-extern void    MM_ClearSpace(Uint32 CR3);
-
-#endif
-
diff --git a/Kernel/arch/x86/include/desctab.h b/Kernel/arch/x86/include/desctab.h
deleted file mode 100644 (file)
index 47a462a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- */
-#ifndef _DESCTAB_H_
-#define _DESCTAB_H_
-
-typedef struct {
-       Uint16  LimitLow;
-       Uint16  BaseLow;
-       Uint8   BaseMid;
-       Uint8   Access;
-       struct {
-               unsigned LimitHi:       4;
-               unsigned Flags:         4;
-       } __attribute__ ((packed));
-       Uint8   BaseHi;
-} __attribute__ ((packed)) tGDT;
-
-typedef struct {
-       Uint16  OffsetLo;
-       Uint16  CS;
-       Uint16  Flags;
-       Uint16  OffsetHi;
-} __attribute__ ((packed)) tIDT;
-
-#endif
diff --git a/Kernel/arch/x86/include/mm_phys.h b/Kernel/arch/x86/include/mm_phys.h
deleted file mode 100644 (file)
index 96d3e64..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * mm_phys.h
- */
-#ifndef _MM_PHYS_H
-#define _MM_PHYS_H
-
-// === FUNCTIONS ===
-//extern tPAddr        MM_AllocPhys(void);
-//extern tPAddr        MM_AllocPhysRange(int Pages, int MaxBits);
-//extern void  MM_RefPhys(tPAddr PAddr);
-//extern void  MM_DerefPhys(tPAddr PAddr);
-//extern int   MM_GetRefCount(tPAddr Addr);
-
-#endif
diff --git a/Kernel/arch/x86/include/mm_virt.h b/Kernel/arch/x86/include/mm_virt.h
deleted file mode 100644 (file)
index d84c965..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Acess2
- * - Virtual Memory Manager (Header)
- */
-#ifndef _MM_VIRT_H
-#define _MM_VIRT_H
-
-// NOTES:
-// - 1PD is 0x400000
-
-// - Memory Layout
-#define        MM_USER_MIN     0x00200000
-#define        USER_STACK_SZ   0x00020000      // 128 KiB
-#define        USER_STACK_TOP  0x00800000
-#define USER_LIB_MAX   0xBC000000
-#define        MM_USER_MAX     0xBC000000      // Top load address for user libraries
-#define        MM_PPD_MIN      0xBC000000      // Per-Process Data base
-#define        MM_PPD_HANDLES  0xBC000000      // - VFS Handles (Practically unlimited)
-#define        MM_PPD_MMAP     0xBD000000      // - MMap Entries (24b each = 0x2AAAA max)
-#define        MM_PPD_UNALLOC  0xBE000000      //
-#define MM_PPD_CFG     0xBFFFF000      // - Per-process config entries 
-#define        MM_PPD_MAX      0xC0000000      // 
-
-#define        MM_KHEAP_BASE   0xC0400000      // C+4MiB
-#define        MM_KHEAP_MAX    0xCF000000      //
-#define MM_KERNEL_VFS  0xCF000000      // 
-#define MM_KUSER_CODE  0xCFFF0000      // 16 Pages
-#define        MM_MODULE_MIN   0xD0000000      // Lowest Module Address
-#define MM_MODULE_MAX  0xE0000000      // 128 MiB
-
-// Page Info (Which VFS node owns each physical page)
-// 2^32/2^12*16
-// = 2^24 = 16 MiB = 0x4000000
-// 256 items per page
-#define MM_PAGENODE_BASE       0xE0000000
-
-// Needs (2^32/2^12*4 bytes)
-// - 2^22 bytes max = 4 MiB = 0x1000000
-// 1024 items per page
-#define        MM_REFCOUNT_BASE        0xE4000000
-
-#define MM_KERNEL_STACKS       0xF0000000
-#define        MM_KERNEL_STACK_SIZE    0x00008000
-#define MM_KERNEL_STACKS_END   0xFC000000
-
-// === FUNCTIONS ===
-extern void    MM_FinishVirtualInit(void);
-extern void    MM_SetCR3(Uint CR3);
-extern tPAddr  MM_Clone(int bCloneUser);
-extern tVAddr  MM_NewKStack(void);
-extern tVAddr  MM_NewWorkerStack(Uint *InitialStack, size_t StackSize);
-
-#endif
diff --git a/Kernel/arch/x86/include/mp.h b/Kernel/arch/x86/include/mp.h
deleted file mode 100644 (file)
index 0dd5a1e..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- */
-#ifndef _MP_H
-#define _MP_H
-
-#define MPPTR_IDENT    ('_'|('M'<<8)|('P'<<16)|('_'<<24))
-#define MPTABLE_IDENT  ('P'|('C'<<8)|('M'<<16)|('P'<<24))
-
-typedef struct sMPInfo {
-       Uint32  Sig;    // '_MP_'
-       Uint32  MPConfig;
-       Uint8   Length;
-       Uint8   Version;
-       Uint8   Checksum;
-       Uint8   Features[5];    // 2-4 are unused
-} tMPInfo;
-
-typedef union uMPTable_Ent {
-       Uint8   Type;
-       struct {
-               Uint8   Type;
-               Uint8   APICID;
-               Uint8   APICVer;
-               Uint8   CPUFlags;       // bit 0: Enabled, bit 1: Boot Processor
-               Uint32  CPUSignature;   // Stepping, Model, Family
-               Uint32  FeatureFlags;
-               Uint32  Reserved[2];
-       } __attribute__((packed))       Proc;   // 0x00
-       struct {
-               Uint8   Type;
-               Uint8   ID;
-               char    TypeString[6];
-       } __attribute__((packed))       Bus;    // 0x01
-       struct {
-               Uint8   Type;
-               Uint8   ID;
-               Uint8   Version;
-               Uint8   Flags;  // bit 0: Enabled
-               Uint32  Addr;
-       } __attribute__((packed))       IOAPIC; // 0x02
-       struct {
-               Uint8   Type;
-               Uint8   IntType;
-               Uint16  Flags;  // 0,1: Polarity, 2,3: Trigger Mode
-               Uint8   SourceBusID;
-               Uint8   SourceBusIRQ;
-               Uint8   DestAPICID;
-               Uint8   DestAPICIRQ;
-       } __attribute__((packed))       IOInt;
-       struct {
-               Uint8   Type;
-               Uint8   IntType;
-               Uint16  Flags;  // 0,1: Polarity, 2,3: Trigger Mode
-               Uint8   SourceBusID;
-               Uint8   SourceBusIRQ;
-               Uint8   DestLocalAPICID;
-               Uint8   DestLocalAPICIRQ;
-       } __attribute__((packed))       LocalInt;
-} __attribute__((packed)) tMPTable_Ent;
-
-typedef struct sMPTable {
-       Uint32  Sig;
-       Uint16  BaseTableLength;
-       Uint8   SpecRev;
-       Uint8   Checksum;
-       
-       char    OemID[8];
-       char    ProductID[12];
-       
-       Uint32  OEMTablePtr;
-       Uint16  OEMTableSize;
-       Uint16  EntryCount;
-       
-       Uint32  LocalAPICMemMap;        //!< Address used to access the local APIC
-       Uint16  ExtendedTableLen;
-       Uint8   ExtendedTableChecksum;
-       Uint8   Reserved;
-       
-       tMPTable_Ent    Entries[];
-} tMPTable;
-
-typedef volatile struct {
-       Uint32  Addr;
-       Uint32  Resvd1[3];
-       union {
-               Uint8   Byte;
-               Uint16  Word;
-               Uint32  DWord;
-       }       Value;
-       Uint32  Resvd2[3];
-}      tIOAPIC;
-
-typedef struct {
-       Uint32  Val;
-       Uint32  Padding[3];
-} volatile     tReg;
-
-typedef volatile struct {
-       tReg    _unused1[2];
-       tReg    ID;
-       tReg    Version;
-       tReg    _unused2[4];
-       tReg    TPR;    // Task Priority Register
-       tReg    APR;    // Arbitration Priority Register (RO)
-       tReg    PPR;    // Processor Priority Register (RO)
-       tReg    EOI;    // EOI Register (Write Only)
-       tReg    _unused3[1];
-       tReg    LogDest;        // Logical Destination Register
-       tReg    DestFmt;        // Destination Format Register (0-27: RO, 28-31: RW)
-       tReg    SIV;    // Spurious Interrupt Vector Register (0-8: RW, 9-31: RO)
-       tReg    ISR[8]; // In-Service Register - Total 256 Bits (RO)
-       tReg    TMR[8]; // Trigger Mode Register - Total 256 Bits (RO)
-       tReg    IRR[8]; // Interrupt Request Register - Total 256 Bits (RO)
-       tReg    ErrorStatus;    // Error Status Register (RO)
-       tReg    _unused4[6];
-       tReg    LVTCMI; // LVT CMI Registers
-       // 0x300
-       tReg    ICR[2]; // Interrupt Command Register (RW)
-       // LVT Registers (Controls Local Vector Table)
-       // Structure:
-       // 0-7:   Vector - IDT Vector for the interrupt
-       // 12:    Delivery Status (0: Idle, 1: Send Pending)
-       // 16:    Mask (0: Enabled, 1: Disabled)
-       // 0x320
-       tReg    LVTTimer;       // LVT Timer Register (RW)
-       tReg    LVTThermalSensor;       // LVT Thermal Sensor Register (RW)
-       tReg    LVTPerfMonCounters;     // LVT Performance Monitor Counters Register (RW)
-       tReg    LVTLInt0;       // LVT Local Interrupt (LINT) #0 Register (RW);
-       tReg    LVTLInt1;       // LVT Local Interrupt (LINT) #1 Register (RW);
-       tReg    LVTError;       // LVT Error Register (RW);
-       // 0x380
-       tReg    InitialCount;   // Initial Count Register (Used for the timer) (RW)
-       tReg    CurrentCount;   // Current Count Register (Used for the timer) (RW)
-       tReg    _unused5[4];
-       // 0x3E0
-       tReg    DivideConifg;   // Divide Configuration Register (RW)
-       tReg    _unused6[1];
-} volatile     tAPIC;
-
-#endif
diff --git a/Kernel/arch/x86/include/multiboot2.h b/Kernel/arch/x86/include/multiboot2.h
deleted file mode 100644 (file)
index 735109a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Acess 2
- * By John Hodge (thePowersGang)
- *
- * multiboot2.h
- * - Multiboot 2 Header
- */
-#ifndef _MULTIBOOT2_H_
-#define _MULTIBOOT2_H_
-
-#define MULTIBOOT2_MAGIC       0x36D76289
-
-typedef struct sMultiboot2Info
-{
-       Uint32  TotalSize;
-       Uint32  Reserved;       // SBZ
-}      tMultiboot2Info;
-
-#endif
diff --git a/Kernel/arch/x86/include/proc.h b/Kernel/arch/x86/include/proc.h
deleted file mode 100644 (file)
index 9ecd98b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * proc.h
- */
-#ifndef _PROC_H
-#define _PROC_H
-
-// === TYPES ==
-typedef struct sTSS {
-       Uint32  Link;
-       Uint32  ESP0, SS0;
-       Uint32  ESP1, SS1;
-       Uint32  ESP2, SS2;
-       Uint32  CR3;
-       Uint32  EIP;
-       Uint32  EFLAGS;
-       Uint32  EAX, ECX, EDX, EBX;
-       Uint32  ESP, EBP, ESI, EDI;
-       Uint32  ES, CS, DS, SS, FS, GS;
-       Uint32  LDTR;
-       Uint16  Resvd, IOPB;    // IO Permissions Bitmap
-} __attribute__((packed)) tTSS;
-
-typedef struct {
-       #if USE_PAE
-       Uint    PDPT[4];
-       #else
-       Uint32  CR3;
-       #endif
-} tMemoryState;
-
-// 512 bytes, 16 byte aligned
-typedef struct sSSEState
-{
-       char    data[512];
-} tSSEState;
-
-typedef struct {
-       Uint    EIP, ESP;
-       Uint32  UserCS, UserEIP;
-       tSSEState       *SSE;
-        int    bSSEModified;
-} tTaskState;
-
-#include <threads_int.h>
-
-#define USER_MAX       KERNEL_BASE
-
-#endif
diff --git a/Kernel/arch/x86/include/vm8086.h b/Kernel/arch/x86/include/vm8086.h
deleted file mode 100644 (file)
index 7c8dd47..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Acess2 VM8086 BIOS Interface
- * - By John Hodge (thePowersGang)
- *
- * vm8086.h
- * - Core Header
- */
-#ifndef _VM80806_H_
-#define _VM80806_H_
-
-// === TYPES ===
-/**
- * \note Semi-opaque - Past \a .IP, the implementation may add any data
- *       it needs to the state.
- */
-typedef struct sVM8086
-{
-       Uint16  AX, CX, DX, BX;
-       Uint16  BP, SP, SI, DI;
-       
-       Uint16  SS, DS, ES;
-       
-       Uint16  CS, IP;
-       
-       struct sVM8086_InternalData     *Internal;
-}      tVM8086;
-
-// === FUNCTIONS ===
-/**
- * \brief Create an instance of the VM8086 Emulator
- * \note Do not free this pointer with ::free, instead use ::VM8086_Free
- * \return Pointer to a tVM8086 structure, this structure may be larger than
- *         tVM8086 due to internal data.
- */
-extern tVM8086 *VM8086_Init(void);
-/**
- * \brief Free an allocated tVM8086 structure
- * \param State        Emulator state to free
- */
-extern void    VM8086_Free(tVM8086 *State);
-/**
- * \brief Allocate a piece of memory in the emulated address space and
- *        return a host and emulated pointer to it.
- * \param State        Emulator state
- * \param Size Size of memory block
- * \param Segment      Pointer to location to store the allocated memory's segment
- * \param Offset       Pointet to location to store the allocated memory's offset
- * \return Host pointer to the allocated memory
- */
-extern void    *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset);
-/**
- * \brief Gets a pointer to a piece of emulated memory
- * \todo Only 1 machine page is garenteed to be contiguous
- * \param State        Emulator State
- * \param Segment      Source Segment
- * \param Offset       Source Offset
- * \return Host pointer to the emulated memory
- */
-extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset);
-/**
- * \brief Calls a real-mode interrupt described by the current state of the IVT.
- * \param State        Emulator State
- * \param Interrupt    BIOS Interrupt to call
- */
-extern void    VM8086_Int(tVM8086 *State, Uint8 Interrupt);
-
-#endif
diff --git a/Kernel/arch/x86/irq.c b/Kernel/arch/x86/irq.c
deleted file mode 100644 (file)
index e2dcf0e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * irq.c
- */
-#include <acess.h>
-
-// === CONSTANTS ===
-#define        MAX_CALLBACKS_PER_IRQ   4
-#define TRACE_IRQS     0
-
-// === TYPES ===
-typedef void (*tIRQ_Callback)(int, void *);
-
-// === PROTOTYPES ===
-void   IRQ_Handler(tRegs *Regs);
-
-// === GLOBALS ===
-tIRQ_Callback  gIRQ_Handlers[16][MAX_CALLBACKS_PER_IRQ];
-void   *gaIRQ_DataPointers[16][MAX_CALLBACKS_PER_IRQ];
-
-// === CODE ===
-/**
- * \fn void IRQ_Handler(tRegs *Regs)
- * \brief Handle an IRQ
- */
-void IRQ_Handler(tRegs *Regs)
-{
-        int    i, irq = Regs->int_num - 0xF0;
-
-       //Log("IRQ_Handler: (Regs={int_num:%i})", Regs->int_num);
-
-       for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
-       {
-               if( gIRQ_Handlers[irq][i] ) {
-                       gIRQ_Handlers[irq][i](irq, gaIRQ_DataPointers[irq][i]);
-                       #if TRACE_IRQS
-                       if( irq != 8 )
-                               Log("IRQ %i: Call %p", Regs->int_num, gIRQ_Handlers[Regs->int_num][i]);
-                       #endif
-               }
-       }
-
-       //Log(" IRQ_Handler: Resetting");
-       if(irq >= 8)
-               outb(0xA0, 0x20);       // ACK IRQ (Secondary PIC)
-       outb(0x20, 0x20);       // ACK IRQ
-       //Log("IRQ_Handler: RETURN");
-}
-
-/**
- * \fn int IRQ_AddHandler( int Num, void (*Callback)(int) )
- */
-int IRQ_AddHandler( int Num, void (*Callback)(int, void*), void *Ptr )
-{
-        int    i;
-       for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
-       {
-               if( gIRQ_Handlers[Num][i] == NULL ) {
-                       Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
-                       gIRQ_Handlers[Num][i] = Callback;
-                       gaIRQ_DataPointers[Num][i] = Ptr;
-                       return 1;
-               }
-       }
-
-       Log_Warning("IRQ", "No free callbacks on IRQ%i", Num);
-       return 0;
-}
diff --git a/Kernel/arch/x86/kpanic.c b/Kernel/arch/x86/kpanic.c
deleted file mode 100644 (file)
index 9300c69..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Acess 2 Kernel
- * - By John Hodge (thePowersGang)
- * 
- * kpanic.c
- * - x86 Kernel Panic Handler
- */
-
-#include <acess.h>
-#include <proc.h>
-
-// === CONSTANTS ===
-#define        FB      ((Uint16 *)(KERNEL_BASE|0xB8000))
-#define BGC    0x4F00  // White on Red
-//#define BGC  0xC000  // Black on Bright Red
-//#define BGC  0x1F00  // White on Blue (BSOD!)
-
-// === IMPORTS ===
-extern Uint32  GetEIP(void);
-extern void    Error_Backtrace(Uint32 eip, Uint32 ebp);
-#if USE_MP
-extern void    MP_SendIPIVector(int CPU, Uint8 Vector);
-extern int     giNumCPUs;
-extern int     GetCPUNum(void);
-#endif
-
-// === PROTOTYPES ===
-void   KernelPanic_SetMode(void);
-void   KernelPanic_PutChar(char Ch);
-
-// === CONSTANTS ===
-const struct {
-       Uint16  IdxPort;
-       Uint16  DatPort;
-       Uint8   Index;
-       Uint8   Value;
-}      caRegValues[] = {
-       //{0x3C0, 0x3C0, 0x10, 0x0C},   // Mode Control (Blink Enabled)
-       {0x3C0, 0x3C0, 0x10, 0x04},     // Mode Control (Blink Disabled)
-       {0x3C0, 0x3C0, 0x11, 0x00},     // Overscan Register
-       {0x3C0, 0x3C0, 0x12, 0x0F},     // Color Plane Enable
-       {0x3C0, 0x3C0, 0x13, 0x08},     // Horizontal Panning
-       {0x3C0, 0x3C0, 0x14, 0x00},     // Color Select
-       {0    , 0x3C2, 0   , 0x67},     // Miscellaneous Output Register
-       {0x3C4, 0x3C5, 0x01, 0x00},     // Clock Mode Register
-       {0x3C4, 0x3C5, 0x03, 0x00},     // Character select
-       {0x3C4, 0x3C5, 0x04, 0x07},     // Memory Mode Register
-       {0x3CE, 0x3CF, 0x05, 0x10},     // Mode Register
-       {0x3CE, 0x3CF, 0x06, 0x0E},     // Miscellaneous Register
-       {0x3D4, 0x3D5, 0x00, 0x5F},     // Horizontal Total
-       {0x3D4, 0x3D5, 0x01, 0x4F},     // Horizontal Display Enable End
-       {0x3D4, 0x3D5, 0x02, 0x50},     // Horizontal Blank Start
-       {0x3D4, 0x3D5, 0x03, 0x82},     // Horizontal Blank End
-       {0x3D4, 0x3D5, 0x04, 0x55},     // Horizontal Retrace Start
-       {0x3D4, 0x3D5, 0x05, 0x81},     // Horizontal Retrace End
-       {0x3D4, 0x3D5, 0x06, 0xBF},     // Vertical Total
-       {0x3D4, 0x3D5, 0x07, 0x1F},     // Overflow Register
-       {0x3D4, 0x3D5, 0x08, 0x00},     // Preset row scan
-       {0x3D4, 0x3D5, 0x09, 0x4F},     // Maximum Scan Line
-       {0x3D4, 0x3D5, 0x10, 0x9C},     // Vertical Retrace Start
-       {0x3D4, 0x3D5, 0x11, 0x8E},     // Vertical Retrace End
-       {0x3D4, 0x3D5, 0x12, 0x8F},     // Vertical Display Enable End
-       {0x3D4, 0x3D5, 0x13, 0x28},     // Logical Width
-       {0x3D4, 0x3D5, 0x14, 0x1F},     // Underline Location
-       {0x3D4, 0x3D5, 0x15, 0x96},     // Vertical Blank Start
-       {0x3D4, 0x3D5, 0x16, 0xB9},     // Vertical Blank End
-       {0x3D4, 0x3D5, 0x17, 0xA3}      // CRTC Mode Control
-};
-#define        NUM_REGVALUES   (sizeof(caRegValues)/sizeof(caRegValues[0]))
-
-// === GLOBALS ===
- int   giKP_Pos = 0;
-
-// === CODE ===
-/**
- * \brief Sets the screen mode for a kernel panic
- */
-void KernelPanic_SetMode(void)
-{
-        int    i;
-       
-       // This function is called by Panic(), but MM_PageFault and the
-       // CPU exception handers also call it, so let's not clear the screen
-       // twice
-       if( giKP_Pos )  return ;
-       
-       // Restore VGA 0xB8000 text mode
-       #if 1
-       for( i = 0; i < NUM_REGVALUES; i++ )
-       {
-               // Reset Flip-Flop
-               if( caRegValues[i].IdxPort == 0x3C0 )   inb(0x3DA);
-               
-               if( caRegValues[i].IdxPort )
-                       outb(caRegValues[i].IdxPort, caRegValues[i].Index);
-               outb(caRegValues[i].DatPort, caRegValues[i].Value);
-       }
-       
-       inb(0x3DA);
-       outb(0x3C0, 0x20);
-       #endif
-
-       #if USE_MP
-       // Send halt to all processors
-       for( i = 0; i < giNumCPUs; i ++ )
-       {
-               if(i == GetCPUNum())    continue ;
-               FB[i] = BGC|('A'+i);
-               MP_SendIPIVector(i, 0xED);
-       }
-       #endif
-       
-       // Clear Screen
-       for( i = 0; i < 80*25; i++ )
-       {
-               FB[i] = BGC;
-       }
-       
-       {
-               Uint32  eip = GetEIP();
-               Uint32  ebp;
-               __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (ebp));
-               Error_Backtrace(eip, ebp);
-       }
-}
-
-void KernelPanic_PutChar(char Ch)
-{
-       if( giKP_Pos > 80*25 )  return ;
-       switch(Ch)
-       {
-       case '\t':
-               do {
-                       FB[giKP_Pos] &= 0xFF00;
-                       FB[giKP_Pos++] |= ' ';
-               } while(giKP_Pos & 7);
-               break;
-       
-       case '\n':
-               giKP_Pos += 80;
-       case '\r':
-               giKP_Pos -= giKP_Pos % 80;
-               break;
-       
-       default:
-               if(' ' <= Ch && Ch < 0x7F)
-               {
-                       FB[giKP_Pos] &= 0xFF00;
-                       FB[giKP_Pos] |= Ch;
-               }
-               giKP_Pos ++;
-               break;
-       }
-}
diff --git a/Kernel/arch/x86/lib.c b/Kernel/arch/x86/lib.c
deleted file mode 100644 (file)
index 175f9a5..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Acess2
- *
- * arch/x86/lib.c
- * - General arch-specific stuff
- */
-#include <acess.h>
-#include <threads_int.h>
-#include <arch_int.h>
-#include <hal_proc.h>  // GetCPUNum
-
-#define TRACE_LOCKS    0
-
-#define DEBUG_TO_E9    1
-#define DEBUG_TO_SERIAL        1
-#define        SERIAL_PORT     0x3F8
-#define        GDB_SERIAL_PORT 0x2F8
-
-// === IMPRORTS ===
-#if TRACE_LOCKS
-extern struct sShortSpinlock   glDebug_Lock;
-extern tMutex  glPhysAlloc;
-#define TRACE_LOCK_COND        (Lock != &glDebug_Lock && Lock != &glThreadListLock && Lock != &glPhysAlloc.Protector)
-//#define TRACE_LOCK_COND      (Lock != &glDebug_Lock && Lock != &glPhysAlloc.Protector)
-#endif
-
-// === PROTOTYPES ==
-Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
-Uint64 __udivdi3(Uint64 Num, Uint64 Den);
-Uint64 __umoddi3(Uint64 Num, Uint64 Den);
-
-// === GLOBALS ===
- int   gbDebug_SerialSetup = 0;
- int   gbGDB_SerialSetup = 0;
-
-// === CODE ===
-/**
- * \brief Determine if a short spinlock is locked
- * \param Lock Lock pointer
- */
-int IS_LOCKED(struct sShortSpinlock *Lock)
-{
-       return !!Lock->Lock;
-}
-
-/**
- * \brief Check if the current CPU has the lock
- * \param Lock Lock pointer
- */
-int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
-{
-       return Lock->Lock == GetCPUNum() + 1;
-}
-
-void __AtomicTestSetLoop(Uint *Ptr, Uint Value)
-{
-       __ASM__(
-               "1:\n\t"
-               "xor %%eax, %%eax;\n\t"
-               "lock cmpxchgl %0, (%1);\n\t"
-               "jnz 1b;\n\t"
-               :: "r"(Value), "r"(Ptr)
-               : "eax" // EAX clobbered
-               );
-}
-/**
- * \brief Acquire a Short Spinlock
- * \param Lock Lock pointer
- * 
- * This type of mutex should only be used for very short sections of code,
- * or in places where a Mutex_* would be overkill, such as appending
- * an element to linked list (usually two assignement lines in C)
- * 
- * \note This type of lock halts interrupts, so ensure that no timing
- * functions are called while it is held. As a matter of fact, spend as
- * little time as possible with this lock held
- * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
- */
-void SHORTLOCK(struct sShortSpinlock *Lock)
-{
-        int    IF;
-        int    cpu = GetCPUNum() + 1;
-       
-       // Save interrupt state
-       __ASM__ ("pushf;\n\tpop %0" : "=r"(IF));
-       IF &= 0x200;    // AND out all but the interrupt flag
-       
-       #if TRACE_LOCKS
-       if( TRACE_LOCK_COND )
-       {
-               //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
-               Debug("%i %p obtaining %p (Called by %p)", cpu-1,  __builtin_return_address(0), Lock, __builtin_return_address(1));
-       }
-       #endif
-       
-       __ASM__("cli");
-       
-       // Wait for another CPU to release
-       __AtomicTestSetLoop( (Uint*)&Lock->Lock, cpu );
-       Lock->IF = IF;
-       
-       #if TRACE_LOCKS
-       if( TRACE_LOCK_COND )
-       {
-               //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
-               Debug("%i %p locked by %p\t%p", cpu-1, Lock, __builtin_return_address(0), __builtin_return_address(1));
-//             Debug("got it");
-       }
-       #endif
-}
-/**
- * \brief Release a short lock
- * \param Lock Lock pointer
- */
-void SHORTREL(struct sShortSpinlock *Lock)
-{      
-       #if TRACE_LOCKS
-       if( TRACE_LOCK_COND )
-       {
-               //Log_Log("LOCK", "%p released by %p", Lock, __builtin_return_address(0));
-               Debug("Lock %p released by %p\t%p", Lock, __builtin_return_address(0), __builtin_return_address(1));
-       }
-       #endif
-       
-       // Lock->IF can change anytime once Lock->Lock is zeroed
-       if(Lock->IF) {
-               Lock->Lock = 0;
-               __ASM__ ("sti");
-       }
-       else {
-               Lock->Lock = 0;
-       }
-}
-
-// === DEBUG IO ===
-#if USE_GDB_STUB
-int putDebugChar(char ch)
-{
-       if(!gbGDB_SerialSetup) {
-               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
-               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
-               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
-               outb(GDB_SERIAL_PORT + 1, 0x00);    //  (base is         (hi byte)
-               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit (8N1)
-               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
-               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
-               gbGDB_SerialSetup = 1;
-       }
-       while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
-       outb(GDB_SERIAL_PORT, ch);
-       return 0;
-}
-int getDebugChar(void)
-{
-       if(!gbGDB_SerialSetup) {
-               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
-               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
-               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
-               outb(GDB_SERIAL_PORT + 1, 0x00);    //                   (hi byte)
-               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
-               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
-               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
-               gbGDB_SerialSetup = 1;
-       }
-       while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0)     ;
-       return inb(GDB_SERIAL_PORT);
-}
-#endif /* USE_GDB_STUB */
-
-void Debug_PutCharDebug(char ch)
-{
-       #if DEBUG_TO_E9
-       __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
-       #endif
-       
-       #if DEBUG_TO_SERIAL
-       if(!gbDebug_SerialSetup) {
-               outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
-               outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
-               outb(SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
-               outb(SERIAL_PORT + 1, 0x00);    //                   (hi byte)
-               outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
-               outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
-               outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
-               gbDebug_SerialSetup = 1;
-       }
-       while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
-       outb(SERIAL_PORT, ch);
-       #endif
-}
-
-void Debug_PutStringDebug(const char *String)
-{
-       while(*String)
-               Debug_PutCharDebug(*String++);
-}
-
-// === IO Commands ===
-void outb(Uint16 Port, Uint8 Data)
-{
-       __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
-}
-void outw(Uint16 Port, Uint16 Data)
-{
-       __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
-}
-void outd(Uint16 Port, Uint32 Data)
-{
-       __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
-}
-Uint8 inb(Uint16 Port)
-{
-       Uint8   ret;
-       __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
-       return ret;
-}
-Uint16 inw(Uint16 Port)
-{
-       Uint16  ret;
-       __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
-       return ret;
-}
-Uint32 ind(Uint16 Port)
-{
-       Uint32  ret;
-       __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
-       return ret;
-}
-
-/**
- * \fn void *memset(void *Dest, int Val, size_t Num)
- * \brief Do a byte granuality set of Dest
- */
-void *memset(void *Dest, int Val, size_t Num)
-{
-       Uint32  val = Val&0xFF;
-       val |= val << 8;
-       val |= val << 16;
-       __asm__ __volatile__ (
-               "rep stosl;\n\t"
-               "mov %3, %%ecx;\n\t"
-               "rep stosb"
-               :: "D" (Dest), "a" (val), "c" (Num/4), "r" (Num&3));
-       return Dest;
-}
-/**
- * \brief Set double words
- */
-void *memsetd(void *Dest, Uint32 Val, size_t Num)
-{
-       __asm__ __volatile__ ("rep stosl" :: "D" (Dest), "a" (Val), "c" (Num));
-       return Dest;
-}
-
-/**
- * \fn int memcmp(const void *m1, const void *m2, size_t Num)
- * \brief Compare two pieces of memory
- */
-int memcmp(const void *m1, const void *m2, size_t Num)
-{
-       const Uint8     *d1 = m1;
-       const Uint8     *d2 = m2;
-       if( Num == 0 )  return 0;       // No bytes are always identical
-       
-       while(Num--)
-       {
-               if(*d1 != *d2)
-                       return *d1 - *d2;
-               d1 ++;
-               d2 ++;
-       }
-       return 0;
-}
-
-/**
- * \fn void *memcpy(void *Dest, const void *Src, size_t Num)
- * \brief Copy \a Num bytes from \a Src to \a Dest
- */
-void *memcpy(void *Dest, const void *Src, size_t Num)
-{
-       tVAddr  dst = (tVAddr)Dest;
-       tVAddr  src = (tVAddr)Src;
-       if( (dst & 3) != (src & 3) )
-       {
-               __asm__ __volatile__ ("rep movsb" :: "D" (dst), "S" (src), "c" (Num));
-//             Debug("\nmemcpy:Num=0x%x by %p (UA)", Num, __builtin_return_address(0));
-       }
-       #if 1
-       else if( Num > 128 && (dst & 15) == (src & 15) )
-       {
-               char    tmp[16+15];     // Note, this is a hack to save/restor xmm0
-                int    count = 16 - (dst & 15);
-//             Debug("\nmemcpy:Num=0x%x by %p (SSE)", Num, __builtin_return_address(0));
-               if( count < 16 )
-               {
-                       Num -= count;
-                       __asm__ __volatile__ ("rep movsb" : "=D"(dst),"=S"(src): "0"(dst), "1"(src), "c"(count));
-               }
-               
-               count = Num / 16;
-               __asm__ __volatile__ (
-                       "movdqa 0(%5), %%xmm0;\n\t"
-                       "1:\n\t"
-                       "movdqa 0(%1), %%xmm0;\n\t"
-                       "movdqa %%xmm0, 0(%0);\n\t"
-                       "add $16,%0;\n\t"
-                       "add $16,%1;\n\t"
-                       "loop 1b;\n\t"
-                       "movdqa %%xmm0, 0(%5);\n\t"
-                       : "=r"(dst),"=r"(src)
-                       : "0"(dst), "1"(src), "c"(count), "r" (((tVAddr)tmp+15)&~15)
-                       );
-
-               count = Num & 15;
-               if(count)
-                       __asm__ __volatile__ ("rep movsb" :: "D"(dst), "S"(src), "c"(count));
-       }
-       #endif
-       else
-       {
-//             Debug("\nmemcpy:Num=0x%x by %p", Num, __builtin_return_address(0));
-               __asm__ __volatile__ (
-                       "rep movsl;\n\t"
-                       "mov %3, %%ecx;\n\t"
-                       "rep movsb"
-                       :: "D" (Dest), "S" (Src), "c" (Num/4), "r" (Num&3));
-       }
-       return Dest;
-}
-
-/**
- * \fn void *memcpyd(void *Dest, const void *Src, size_t Num)
- * \brief Copy \a Num DWORDs from \a Src to \a Dest
- */
-void *memcpyd(void *Dest, const void *Src, size_t Num)
-{
-       __asm__ __volatile__ ("rep movsl" :: "D" (Dest), "S" (Src), "c" (Num));
-       return Dest;
-}
-
-#include "../helpers.h"
-
-DEF_DIVMOD(64);
-
-Uint64 DivMod64U(Uint64 Num, Uint64 Div, Uint64 *Rem)
-{
-       if( Div < 0x100000000ULL && Num < 0xFFFFFFFF * Div ) {
-               Uint32  rem, ret_32;
-               __asm__ __volatile__(
-                       "div %4"
-                       : "=a" (ret_32), "=d" (rem)
-                       : "a" ( (Uint32)(Num & 0xFFFFFFFF) ), "d" ((Uint32)(Num >> 32)), "r" (Div)
-                       );
-               if(Rem) *Rem = rem;
-               return ret_32;
-       }
-
-       return __divmod64(Num, Div, Rem);
-}
-
-/**
- * \fn Uint64 __udivdi3(Uint64 Num, Uint64 Den)
- * \brief Divide two 64-bit integers
- */
-Uint64 __udivdi3(Uint64 Num, Uint64 Den)
-{
-       if(Den == 0) {
-               __asm__ __volatile__ ("int $0x0");
-               return -1;
-       }
-       // Common speedups
-       if(Num <= 0xFFFFFFFF && Den <= 0xFFFFFFFF)
-               return (Uint32)Num / (Uint32)Den;
-       if(Den == 1)    return Num;
-       if(Den == 2)    return Num >> 1;        // Speed Hacks
-       if(Den == 4)    return Num >> 2;        // Speed Hacks
-       if(Den == 8)    return Num >> 3;        // Speed Hacks
-       if(Den == 16)   return Num >> 4;        // Speed Hacks
-       if(Den == 32)   return Num >> 5;        // Speed Hacks
-       if(Den == 1024) return Num >> 10;       // Speed Hacks
-       if(Den == 2048) return Num >> 11;       // Speed Hacks
-       if(Den == 4096) return Num >> 12;
-       if(Num < Den)   return 0;
-       if(Num < Den*2) return 1;
-       if(Num == Den*2)        return 2;
-
-       return __divmod64(Num, Den, NULL);
-}
-
-/**
- * \fn Uint64 __umoddi3(Uint64 Num, Uint64 Den)
- * \brief Get the modulus of two 64-bit integers
- */
-Uint64 __umoddi3(Uint64 Num, Uint64 Den)
-{
-       Uint64  ret = 0;
-       if(Den == 0) {
-               __asm__ __volatile__ ("int $0x0");      // Call Div by Zero Error
-               return -1;
-       }
-       if(Den == 1)    return 0;       // Speed Hacks
-       if(Den == 2)    return Num & 1; // Speed Hacks
-       if(Den == 4)    return Num & 3; // Speed Hacks
-       if(Den == 8)    return Num & 7; // Speed Hacks
-       if(Den == 16)   return Num & 15;        // Speed Hacks
-       if(Den == 32)   return Num & 31;        // Speed Hacks
-       if(Den == 1024) return Num & 1023;      // Speed Hacks
-       if(Den == 2048) return Num & 2047;      // Speed Hacks
-       if(Den == 4096) return Num & 4095;      // Speed Hacks
-       
-       if(Num >> 32 == 0 && Den >> 32 == 0)
-               return (Uint32)Num % (Uint32)Den;
-       
-       __divmod64(Num, Den, &ret);
-       return ret;
-}
-
-
-// --- EXPORTS ---
-EXPORT(memcpy);        EXPORT(memset);
-EXPORT(memcmp);
-//EXPORT(memcpyw);     EXPORT(memsetw);
-EXPORT(memcpyd);       EXPORT(memsetd);
-EXPORT(inb);   EXPORT(inw);    EXPORT(ind);
-EXPORT(outb);  EXPORT(outw);   EXPORT(outd);
-EXPORT(__udivdi3);     EXPORT(__umoddi3);
-
-EXPORT(SHORTLOCK);
-EXPORT(SHORTREL);
-EXPORT(IS_LOCKED);
diff --git a/Kernel/arch/x86/link.ld b/Kernel/arch/x86/link.ld
deleted file mode 100644 (file)
index a09b29a..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * AcessMicro Kernel
- * Linker Script
- */
-
-lowStart = start - 0xC0000000;
-ENTRY(lowStart)
-OUTPUT_FORMAT(elf32-i386)
-
-SECTIONS {
-       . = 0x100000;
-       __load_addr = .;
-       .multiboot : AT(ADDR(.multiboot)) {
-               *(.multiboot)
-       }
-       
-       . += 0xC0000000;
-       
-       .text ALIGN(0x1000): AT(ADDR(.text) - 0xC0000000) {
-               *(.text)
-       }
-       
-       .usertext ALIGN(0x1000): AT(ADDR(.usertext) - 0xC0000000) {
-               _UsertextBase = .;
-               *(.usertext)
-       }
-       _UsertextEnd = .;
-       
-       .rodata ALIGN(0x1000): AT(ADDR(.rodata) - 0xC0000000) {
-               *(.initpd)
-               *(.rodata)
-               *(.rdata)
-               gKernelModules = .;
-               *(KMODULES)
-               gKernelModulesEnd = .;
-               . = ALIGN(4);
-               gKernelSymbols = .;
-               *(KEXPORT)
-               gKernelSymbolsEnd = .;
-
-
-       }
-       /*
-       .debug_abbrev : { *(.debug_abbrev) }
-       .debug_info : { *(.debug_info) }
-       .debug_line : { *(.debug_line) }
-       .debug_loc : { *(.debug_loc) }
-       .debug_pubnames : { *(.debug_pubnames) }
-       .debug_aranges : { *(.debug_aranges) }
-       .debug_ranges : { *(.debug_ranges) }
-       .debug_str : { *(.debug_str) }
-       .debug_frame : { *(.debug_frame) }
-       */
-       
-       .padata ALIGN (0x1000) : AT(ADDR(.padata) - 0xC0000000) {
-               *(.padata)
-       }
-       
-       .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
-               *(.data)
-       }
-
-       __bss_start = .;
-       .bss : AT(ADDR(.bss) - 0xC0000000) {
-               _sbss = .;
-               *(COMMON)
-               *(.bss)
-               _ebss = .;
-       }
-       gKernelEnd = (. + 0xFFF)&0xFFFFF000;
-}
diff --git a/Kernel/arch/x86/main.c b/Kernel/arch/x86/main.c
deleted file mode 100644 (file)
index 2106b6a..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Acess 2
- * x86 Kernel Main
- * arch/x86/main.c
- */
-#include <acess.h>
-#include <mboot.h>
-#include <multiboot2.h>
-#include <init.h>
-#include <mm_virt.h>
-#include <mp.h>
-
-#define        VGA_ERRORS      0
-
-#define MAX_ARGSTR_POS (0x400000-0x2000)
-
-// === IMPORTS ===
-extern void    Heap_Install(void);
-extern void    Desctab_Install(void);
-extern void    MM_PreinitVirtual(void);
-extern void    MM_Install(tMBoot_Info *MBoot);
-extern void    MM_InstallVirtual(void);
-extern void    Threads_Init(void);
-extern int     Time_Setup(void);
-// --- Core ---
-extern void    System_Init(char *Commandline);
-
-// === PROTOTYPES ===
- int   kmain(Uint MbMagic, void *MbInfoPtr);
-
-// === GLOBALS ===
-char   *gsBootCmdLine = NULL;
-struct {
-       Uint32  PBase;
-       void    *Base;
-       Uint    Size;
-       char    *ArgString;
-}      *gaArch_BootModules;
- int   giArch_NumBootModules = 0;
-
-// === CODE ===
-int kmain(Uint MbMagic, void *MbInfoPtr)
-{
-        int    i;
-       tMBoot_Module   *mods;
-       tMBoot_Info     *mbInfo;
-
-       LogF("Acess2 x86-"PLATFORM" v"EXPAND_STR(KERNEL_VERSION)"\n");
-       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
-       
-       Log("MbMagic = %08x, MbInfoPtr = %p", MbMagic, MbInfoPtr);
-       
-       // Set up non-boot info dependent stuff
-       Desctab_Install();      // Set up GDT and IDT
-       MM_PreinitVirtual();    // Initialise virtual mappings
-       
-       switch(MbMagic)
-       {
-       // Multiboot 1
-       case MULTIBOOT_MAGIC:
-               // Adjust Multiboot structure address
-               mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
-               gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE);
-               
-               MM_Install( mbInfo );   // Set up physical memory manager
-               break;
-       
-       // Multiboot 2
-       case MULTIBOOT2_MAGIC:
-               Panic("Multiboot 2 not yet supported");
-               //MM_InstallMBoot2( MbInfo );   // Set up physical memory manager
-               return 0;
-               break;
-       
-       default:
-               Panic("Multiboot magic invalid %08x, expected %08x or %08x\n",
-                       MbMagic, MULTIBOOT_MAGIC, MULTIBOOT2_MAGIC);
-               return 0;
-       }
-       
-       MM_InstallVirtual();    // Clean up virtual address space
-       Heap_Install();         // Create initial heap
-       
-       // Start Multitasking
-       Threads_Init();
-       
-       // Start Timers
-       Time_Setup();
-       
-       Log_Log("Arch", "Starting VFS...");
-       // Load Virtual Filesystem
-       VFS_Init();
-       
-       // Load initial modules
-       mods = (void*)( mbInfo->Modules + KERNEL_BASE );
-       giArch_NumBootModules = mbInfo->ModuleCount;
-       gaArch_BootModules = malloc( giArch_NumBootModules * sizeof(*gaArch_BootModules) );
-       for( i = 0; i < mbInfo->ModuleCount; i ++ )
-       {
-                int    ofs;
-       
-               Log_Log("Arch", "Multiboot Module at 0x%08x, 0x%08x bytes (String at 0x%08x)",
-                       mods[i].Start, mods[i].End-mods[i].Start, mods[i].String);
-       
-               gaArch_BootModules[i].PBase = mods[i].Start;
-               gaArch_BootModules[i].Size = mods[i].End - mods[i].Start;
-       
-               // Always HW map the module data        
-               ofs = mods[i].Start&0xFFF;
-               gaArch_BootModules[i].Base = (void*)( MM_MapHWPages(mods[i].Start,
-                       (gaArch_BootModules[i].Size+ofs+0xFFF) / 0x1000
-                       ) + ofs );
-               
-               // Only map the string if needed
-               if( (tVAddr)mods[i].String > MAX_ARGSTR_POS )
-               {
-                       // Assumes the string is < 4096 bytes long)
-                       gaArch_BootModules[i].ArgString = (void*)(
-                               MM_MapHWPages(mods[i].String, 2) + (mods[i].String&0xFFF)
-                               );
-               }
-               else
-                       gaArch_BootModules[i].ArgString = (char *)mods[i].String + KERNEL_BASE;
-       }
-       
-       // Pass on to Independent Loader
-       Log_Log("Arch", "Starting system");
-       System_Init(gsBootCmdLine);
-       
-       // Sleep forever (sleeping beauty)
-       for(;;)
-               Threads_Sleep();
-       return 0;
-}
-
-void Arch_LoadBootModules(void)
-{
-        int    i, j, numPages;
-       for( i = 0; i < giArch_NumBootModules; i ++ )
-       {
-               Log_Log("Arch", "Loading '%s'", gaArch_BootModules[i].ArgString);
-               
-               if( !Module_LoadMem( gaArch_BootModules[i].Base, gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString ) )
-               {
-                       Log_Warning("Arch", "Unable to load module");
-               }
-               
-               // Unmap and free
-               numPages = (gaArch_BootModules[i].Size + ((Uint)gaArch_BootModules[i].Base&0xFFF) + 0xFFF) >> 12;
-               MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].Base, numPages );
-               
-               for( j = 0; j < numPages; j++ )
-                       MM_DerefPhys( gaArch_BootModules[i].PBase + (j << 12) );
-               
-               if( (tVAddr) gaArch_BootModules[i].ArgString > MAX_ARGSTR_POS )
-                       MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].ArgString, 2 );
-       }
-       Log_Log("Arch", "Boot modules loaded");
-       free( gaArch_BootModules );
-}
diff --git a/Kernel/arch/x86/mm_phys.c b/Kernel/arch/x86/mm_phys.c
deleted file mode 100644 (file)
index aa1b260..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * Acess2
- * - Physical memory manager
- */
-#define DEBUG  0
-#include <acess.h>
-#include <mboot.h>
-#include <mm_virt.h>
-
-//#define USE_STACK    1
-#define TRACE_ALLOCS   0       // Print trace messages on AllocPhys/DerefPhys
-
-
-// === IMPORTS ===
-extern char    gKernelEnd[];
-extern void    Proc_PrintBacktrace(void);
-
-// === PROTOTYPES ===
-void   MM_Install(tMBoot_Info *MBoot);
-//tPAddr       MM_AllocPhys(void);
-//tPAddr       MM_AllocPhysRange(int Pages, int MaxBits);
-//void MM_RefPhys(tPAddr PAddr);
-//void MM_DerefPhys(tPAddr PAddr);
-// int MM_GetRefCount(tPAddr PAddr);
-
-// === GLOBALS ===
-tMutex glPhysAlloc;
-Uint64 giPhysAlloc = 0;        // Number of allocated pages
-Uint64 giPageCount = 0;        // Total number of pages
-Uint64 giLastPossibleFree = 0; // Last possible free page (before all pages are used)
-
-Uint32 gaSuperBitmap[1024];    // Blocks of 1024 Pages
-Uint32 gaPageBitmap[1024*1024/32];     // Individual pages
- int   *gaPageReferences;
-void   **gaPageNodes = (void*)MM_PAGENODE_BASE;
-#define REFENT_PER_PAGE        (0x1000/sizeof(gaPageReferences[0]))
-
-// === CODE ===
-void MM_Install(tMBoot_Info *MBoot)
-{
-       Uint    kernelPages, num;
-       Uint    i;
-       Uint64  maxAddr = 0;
-       tMBoot_Module   *mods;
-       tMBoot_MMapEnt  *ent;
-       
-       // --- Find largest address
-       MBoot->MMapAddr |= KERNEL_BASE;
-       ent = (void *)( MBoot->MMapAddr );
-       while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
-       {
-               // Adjust for size
-               ent->Size += 4;
-               
-               // If entry is RAM and is above `maxAddr`, change `maxAddr`
-               if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
-                       maxAddr = ent->Base + ent->Length;
-               // Go to next entry
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
-       }
-       
-       if(maxAddr == 0) {      
-               giPageCount = (MBoot->HighMem >> 2) + 256;      // HighMem is a kByte value
-       }
-       else {
-               giPageCount = maxAddr >> 12;
-       }
-       giLastPossibleFree = giPageCount - 1;
-       
-       memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
-       
-       // Set up allocateable space
-       ent = (void *)( MBoot->MMapAddr );
-       while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
-       {               
-               memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) );
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
-       }
-       
-       // Get used page count (Kernel)
-       kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
-       kernelPages += 0xFFF;   // Page Align
-       kernelPages >>= 12;
-       
-       // Fill page bitmap
-       num = kernelPages/32;
-       memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num );
-       gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1;
-       
-       // Fill Superpage bitmap
-       num = kernelPages/(32*32);
-       memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num );
-       gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1;
-       
-       // Mark Multiboot's pages as taken
-       // - Structure
-       MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
-       // - Module List
-       for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
-               MM_RefPhys( MBoot->Modules + (i << 12) );
-       // - Modules
-       mods = (void*)(MBoot->Modules + KERNEL_BASE);
-       for(i = 0; i < MBoot->ModuleCount; i++)
-       {
-               num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
-               while(num--)
-                       MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
-       }
-
-       gaPageReferences = (void*)MM_REFCOUNT_BASE;
-
-       Log_Log("PMem", "Physical memory set up");
-}
-
-/**
- * \fn tPAddr MM_AllocPhys(void)
- * \brief Allocates a physical page from the general pool
- */
-tPAddr MM_AllocPhys(void)
-{
-       // int  a, b, c;
-        int    indx = -1;
-       tPAddr  ret;
-       
-       ENTER("");
-       
-       Mutex_Acquire( &glPhysAlloc );
-       
-       // Classful scan
-       #if 1
-       {
-       const int addrClasses[] = {0,16,20,24,32,64};
-       const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
-        int    i;
-        int    first, last;
-       for( i = numAddrClasses; i -- > 1; )
-       {
-               first = 1UL << (addrClasses[i-1] - 12);
-               last = (1UL << (addrClasses[i] - 12)) - 1;
-               // Range is above the last free page
-               if( first > giLastPossibleFree )
-                       continue;
-               // Last possible free page is in the range
-               if( last > giLastPossibleFree )
-                       last = giLastPossibleFree;
-                       
-               // Scan the range
-               for( indx = first; indx < last; )
-               {
-                       if( gaSuperBitmap[indx>>10] == -1 ) {
-                               indx += 1024;
-                               continue;
-                       }
-                       
-                       if( gaPageBitmap[indx>>5] == -1 ) {
-                               indx += 32;
-                               continue;
-                       }
-                       
-                       if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
-                               indx ++;
-                               continue;
-                       }
-                       break;
-               }
-               if( indx < last )       break;
-               
-               giLastPossibleFree = first;     // Well, we couldn't find any in this range
-       }
-       // Out of memory?
-       if( i <= 1 )    indx = -1;
-       }
-       #elif 0
-       // Find free page
-       // Scan downwards
-       LOG("giLastPossibleFree = %i", giLastPossibleFree);
-       for( indx = giLastPossibleFree; indx >= 0; )
-       {
-               if( gaSuperBitmap[indx>>10] == -1 ) {
-                       indx -= 1024;
-                       continue;
-               }
-               
-               if( gaPageBitmap[indx>>5] == -1 ) {
-                       indx -= 32;
-                       continue;
-               }
-               
-               if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
-                       indx --;
-                       continue;
-               }
-               break;
-       }
-       if( indx >= 0 )
-               giLastPossibleFree = indx;
-       LOG("indx = %i", indx);
-       #else
-       c = giLastPossibleFree % 32;
-       b = (giLastPossibleFree / 32) % 32;
-       a = giLastPossibleFree / 1024;
-       
-       LOG("a=%i,b=%i,c=%i", a, b, c);
-       for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
-       if(a < 0) {
-               Mutex_Release( &glPhysAlloc );
-               Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used",
-                       __builtin_return_address(0), giPhysAlloc, giPageCount);
-               LEAVE('i', 0);
-               return 0;
-       }
-       for( ; gaSuperBitmap[a] & (1<<b); b-- );
-       for( ; gaPageBitmap[a*32+b] & (1<<c); c-- );
-       LOG("a=%i,b=%i,c=%i", a, b, c);
-       indx = (a << 10) | (b << 5) | c;
-       if( indx >= 0 )
-               giLastPossibleFree = indx;
-       #endif
-       
-       if( indx < 0 ) {
-               Mutex_Release( &glPhysAlloc );
-               Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used (indx = %x)",
-                       __builtin_return_address(0), giPhysAlloc, giPageCount, indx);
-               Log_Debug("PMem", "giLastPossibleFree = %lli", giLastPossibleFree);
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       if( indx > 0xFFFFF ) {
-               Panic("The fuck? Too many pages! (indx = 0x%x)", indx);
-       }
-       
-       if( indx >= giPageCount ) {
-               Mutex_Release( &glPhysAlloc );
-               Log_Error("PMem", "MM_AllocPhys - indx(%i) > giPageCount(%i)", indx, giPageCount);
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Mark page used
-       if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
-               gaPageReferences[indx] = 1;
-       gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
-       
-       giPhysAlloc ++;
-       
-       // Get address
-       ret = indx << 12;
-       
-       // Mark used block
-       if(gaPageBitmap[ indx>>5 ] == -1) {
-               gaSuperBitmap[indx>>10] |= 1 << ((indx>>5)&31);
-       }
-
-       // Release Spinlock
-       Mutex_Release( &glPhysAlloc );
-       
-       LEAVE('X', ret);
-       #if TRACE_ALLOCS
-       if( now() > 4000 ) {
-       Log_Debug("PMem", "MM_AllocPhys: RETURN %P (%i free)", ret, giPageCount-giPhysAlloc);
-       Proc_PrintBacktrace();
-       }
-       #endif
-       return ret;
-}
-
-/**
- * \fn tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
- * \brief Allocate a range of physical pages
- * \param Pages        Number of pages to allocate
- * \param MaxBits      Maximum number of address bits to use
- */
-tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
-{
-        int    a, b;
-        int    i, idx, sidx;
-       tPAddr  ret;
-       
-       ENTER("iPages iMaxBits", Pages, MaxBits);
-       
-       // Sanity Checks
-       if(MaxBits < 0) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       if(MaxBits > PHYS_BITS) MaxBits = PHYS_BITS;
-       
-       // Lock
-       Mutex_Acquire( &glPhysAlloc );
-       
-       // Set up search state
-       if( giLastPossibleFree > ((tPAddr)1 << (MaxBits-12)) ) {
-               sidx = (tPAddr)1 << (MaxBits-12);
-       }
-       else {
-               sidx = giLastPossibleFree;
-       }
-       idx = sidx / 32;
-       sidx %= 32;
-       b = idx % 32;
-       a = idx / 32;
-       
-       #if 0
-       LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
-       
-       // Find free page
-       for( ; gaSuperBitmap[a] == -1 && a --; )        b = 31;
-       if(a < 0) {
-               Mutex_Release( &glPhysAlloc );
-               Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
-               LEAVE('i', 0);
-               return 0;
-       }
-       LOG("a = %i", a);
-       for( ; gaSuperBitmap[a] & (1 << b); b-- )       sidx = 31;
-       LOG("b = %i", b);
-       idx = a * 32 + b;
-       for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
-               LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
-       
-       LOG("idx = %i, sidx = %i", idx, sidx);
-       #else
-       
-       #endif
-       
-       // Check if the gap is large enough
-       while( idx >= 0 )
-       {
-               // Find a free page
-               for( ; ; )
-               {
-                       // Bulk Skip
-                       if( gaPageBitmap[idx] == -1 ) {
-                               idx --;
-                               sidx = 31;
-                               continue;
-                       }
-                       
-                       if( gaPageBitmap[idx] & (1 << sidx) ) {
-                               sidx --;
-                               if(sidx < 0) {  sidx = 31;      idx --; }
-                               if(idx < 0)     break;
-                               continue;
-                       }
-                       break;
-               }
-               if( idx < 0 )   break;
-               
-               // Check if it is a free range
-               for( i = 0; i < Pages; i++ )
-               {
-                       // Used page? break
-                       if( gaPageBitmap[idx] & (1 << sidx) )
-                               break;
-                       
-                       sidx --;
-                       if(sidx < 0) {  sidx = 31;      idx --; }
-                       if(idx < 0)     break;
-               }
-               
-               if( i == Pages )
-                       break;
-       }
-       
-       // Check if an address was found
-       if( idx < 0 ) {
-               Mutex_Release( &glPhysAlloc );
-               Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Mark pages used
-       for( i = 0; i < Pages; i++ )
-       {
-               if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[idx*32+sidx] ) )
-                       gaPageReferences[idx*32+sidx] = 1;
-               gaPageBitmap[ idx ] |= 1 << sidx;
-               sidx ++;
-               giPhysAlloc ++;
-               if(sidx == 32) { sidx = 0;      idx ++; }
-       }
-       
-       // Get address
-       ret = (idx << 17) | (sidx << 12);
-       
-       // Mark used block
-       if(gaPageBitmap[ idx ] == -1)   gaSuperBitmap[idx/32] |= 1 << (idx%32);
-
-       // Release Spinlock
-       Mutex_Release( &glPhysAlloc );
-       
-       LEAVE('X', ret);
-       #if TRACE_ALLOCS
-       Log_Debug("PMem", "MM_AllocPhysRange: RETURN 0x%llx-0x%llx (%i free)",
-               ret, ret + (1<<Pages)-1, giPageCount-giPhysAlloc);
-       #endif
-       return ret;
-}
-
-/**
- * \fn void MM_RefPhys(tPAddr PAddr)
- */
-void MM_RefPhys(tPAddr PAddr)
-{
-       // Get page number
-       PAddr >>= 12;
-
-       // We don't care about non-ram pages
-       if(PAddr >= giPageCount)        return;
-       
-       // Lock Structures
-       Mutex_Acquire( &glPhysAlloc );
-       
-       // Reference the page
-       if( gaPageReferences )
-       {
-               if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
-               {
-                        int    i, base;
-                       tVAddr  addr = ((tVAddr)&gaPageReferences[PAddr]) & ~0xFFF;
-//                     Log_Debug("PMem", "MM_RefPhys: Allocating info for %X", PAddr);
-                       Mutex_Release( &glPhysAlloc );
-                       if( MM_Allocate( addr ) == 0 ) {
-                               Log_KernelPanic("PMem", "MM_RefPhys: Out of physical memory allocating info for %X", PAddr*PAGE_SIZE);
-                       }
-                       Mutex_Acquire( &glPhysAlloc );
-                       
-                       base = PAddr & ~(1024-1);
-                       for( i = 0; i < 1024; i ++ ) {
-                               gaPageReferences[base + i] = (gaPageBitmap[(base+i)/32] & (1 << (base+i)%32)) ? 1 : 0;
-                       }
-               }
-               gaPageReferences[ PAddr ] ++;
-       }
-       
-       // Mark as used
-       gaPageBitmap[ PAddr / 32 ] |= 1 << (PAddr&31);
-       
-       // Mark used block
-       if(gaPageBitmap[ PAddr / 32 ] == -1)
-               gaSuperBitmap[PAddr/1024] |= 1 << ((PAddr/32)&31);
-       
-       // Release Spinlock
-       Mutex_Release( &glPhysAlloc );
-}
-
-/**
- * \fn void MM_DerefPhys(tPAddr PAddr)
- * \brief Dereferences a physical page
- */
-void MM_DerefPhys(tPAddr PAddr)
-{
-       // Get page number
-       PAddr >>= 12;
-
-       // We don't care about non-ram pages
-       if(PAddr >= giPageCount)        return;
-       
-       // Check if it is freed
-       if( !(gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ) {
-               Log_Warning("MMVirt", "MM_DerefPhys - Non-referenced memory dereferenced");
-               return;
-       }
-       
-       // Lock Structures
-       Mutex_Acquire( &glPhysAlloc );
-       
-       if( giLastPossibleFree < PAddr )
-               giLastPossibleFree = PAddr;
-
-       // Dereference
-       if( !MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
-       {
-               #if TRACE_ALLOCS
-               Log_Debug("PMem", "MM_DerefPhys: Free'd %P (%i free)", PAddr<<12, giPageCount-giPhysAlloc);
-               Proc_PrintBacktrace();
-               #endif
-               //LOG("Freed 0x%x by %p\n", PAddr<<12, __builtin_return_address(0));
-               giPhysAlloc --;
-               gaPageBitmap[ PAddr / 32 ] &= ~(1 << (PAddr&31));
-               if(gaPageBitmap[ PAddr / 32 ] == 0)
-                       gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
-
-               if( MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) )
-               {
-                       gaPageNodes[PAddr] = NULL;
-                       // TODO: Free Node Page when fully unused
-               }
-       }
-
-       // Release spinlock
-       Mutex_Release( &glPhysAlloc );
-}
-
-/**
- * \fn int MM_GetRefCount(tPAddr Addr)
- */
-int MM_GetRefCount(tPAddr PAddr)
-{
-       // Get page number
-       PAddr >>= 12;
-       
-       // We don't care about non-ram pages
-       if(PAddr >= giPageCount)        return -1;
-
-       if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
-               return (gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ? 1 : 0;
-       
-       // Check if it is freed
-       return gaPageReferences[ PAddr ];
-}
-
-int MM_SetPageNode(tPAddr PAddr, void *Node)
-{
-       tVAddr  block_addr;
-       
-       if( MM_GetRefCount(PAddr) == 0 )        return 1;
-        
-       PAddr /= PAGE_SIZE;
-
-       block_addr = (tVAddr) &gaPageNodes[PAddr];
-       block_addr &= ~(PAGE_SIZE-1);
-       
-       if( !MM_GetPhysAddr( block_addr ) )
-       {
-               if( !MM_Allocate( block_addr ) ) {
-                       Log_Warning("PMem", "Unable to allocate Node page");
-                       return -1;
-               }
-               memset( (void*)block_addr, 0, PAGE_SIZE );
-       }
-
-       gaPageNodes[PAddr] = Node;
-//     Log("gaPageNodes[0x%x] = %p", PAddr, Node);
-       return 0;
-}
-
-int MM_GetPageNode(tPAddr PAddr, void **Node)
-{
-       if( MM_GetRefCount(PAddr) == 0 )        return 1;
-       
-       PAddr /= PAGE_SIZE;
-       if( !MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) ) {
-               *Node = NULL;
-               return 0;
-       }
-       *Node = gaPageNodes[PAddr];
-       return 0;
-}
-
diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c
deleted file mode 100644 (file)
index bd7b1df..0000000
+++ /dev/null
@@ -1,1151 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * mm_virt.c
- * 
- * Memory Map
- * 0xE0 - Kernel Base
- * 0xF0 - Kernel Stacks
- * 0xFD - Fractals
- * 0xFE - Unused
- * 0xFF - System Calls / Kernel's User Code
- */
-#define DEBUG  0
-#define SANITY 1
-#include <acess.h>
-#include <mm_virt.h>
-#include <mm_phys.h>
-#include <proc.h>
-#include <hal_proc.h>
-#include <arch_int.h>
-
-#define TAB    22
-
-#define WORKER_STACKS          0x00100000      // Thread0 Only!
-#define        WORKER_STACK_SIZE       MM_KERNEL_STACK_SIZE
-#define WORKER_STACKS_END      0xB0000000
-#define        NUM_WORKER_STACKS       ((WORKER_STACKS_END-WORKER_STACKS)/WORKER_STACK_SIZE)
-
-#define PAE_PAGE_TABLE_ADDR    0xFC000000      // 16 MiB
-#define PAE_PAGE_DIR_ADDR      0xFCFC0000      // 16 KiB
-#define PAE_PAGE_PDPT_ADDR     0xFCFC3F00      // 32 bytes
-#define PAE_TMP_PDPT_ADDR      0xFCFC3F20      // 32 bytes
-#define PAE_TMP_DIR_ADDR       0xFCFE0000      // 16 KiB
-#define PAE_TMP_TABLE_ADDR     0xFD000000      // 16 MiB
-
-#define PAGE_TABLE_ADDR        0xFC000000
-#define PAGE_DIR_ADDR  0xFC3F0000
-#define PAGE_CR3_ADDR  0xFC3F0FC0
-#define TMP_CR3_ADDR   0xFC3F0FC4      // Part of core instead of temp
-#define TMP_DIR_ADDR   0xFC3F1000      // Same
-#define TMP_TABLE_ADDR 0xFC400000
-
-#define HW_MAP_ADDR            0xFE000000
-#define        HW_MAP_MAX              0xFFEF0000
-#define        NUM_HW_PAGES    ((HW_MAP_MAX-HW_MAP_ADDR)/0x1000)
-#define        TEMP_MAP_ADDR   0xFFEF0000      // Allows 16 "temp" pages
-#define        NUM_TEMP_PAGES  16
-#define LAST_BLOCK_ADDR        0xFFFF0000      // Free space for kernel provided user code/ *(-1) protection
-
-#define        PF_PRESENT      0x1
-#define        PF_WRITE        0x2
-#define        PF_USER         0x4
-#define PF_GLOBAL      0x80
-#define        PF_COW          0x200
-#define        PF_NOPAGE       0x400
-
-#define INVLPG(addr)   __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
-
-#define GET_TEMP_MAPPING(cr3) do { \
-       __ASM__("cli"); \
-       __AtomicTestSetLoop( (Uint *)gpTmpCR3, cr3 | 3 ); \
-} while(0)
-#define REL_TEMP_MAPPING() do { \
-       *gpTmpCR3 = 0; \
-       __ASM__("sti"); \
-} while(0)
-
-typedef Uint32 tTabEnt;
-
-// === IMPORTS ===
-extern char    _UsertextEnd[], _UsertextBase[];
-extern Uint32  gaInitPageDir[1024];
-extern Uint32  gaInitPageTable[1024];
-extern void    Threads_SegFault(tVAddr Addr);
-extern void    Error_Backtrace(Uint eip, Uint ebp);
-
-// === PROTOTYPES ===
-void   MM_PreinitVirtual(void);
-void   MM_InstallVirtual(void);
-void   MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
-//void MM_DumpTables(tVAddr Start, tVAddr End);
-//void MM_ClearUser(void);
-tPAddr MM_DuplicatePage(tVAddr VAddr);
-
-// === GLOBALS ===
-#define gaPageTable    ((tTabEnt*)PAGE_TABLE_ADDR)
-#define gaPageDir      ((tTabEnt*)PAGE_DIR_ADDR)
-#define gaTmpTable     ((tTabEnt*)TMP_TABLE_ADDR)
-#define gaTmpDir       ((tTabEnt*)TMP_DIR_ADDR)
-#define gpPageCR3      ((tTabEnt*)PAGE_CR3_ADDR)
-#define gpTmpCR3       ((tTabEnt*)TMP_CR3_ADDR)
-
-#define gaPAE_PageTable        ((tTabEnt*)PAE_PAGE_TABLE_ADDR)
-#define gaPAE_PageDir  ((tTabEnt*)PAE_PAGE_DIR_ADDR)
-#define gaPAE_MainPDPT ((tTabEnt*)PAE_PAGE_PDPT_ADDR)
-#define gaPAE_TmpTable ((tTabEnt*)PAE_TMP_DIR_ADDR)
-#define gaPAE_TmpDir   ((tTabEnt*)PAE_TMP_DIR_ADDR)
-#define gaPAE_TmpPDPT  ((tTabEnt*)PAE_TMP_PDPT_ADDR)
- int   gbUsePAE = 0;
-tMutex glTempMappings;
-tMutex glTempFractal;
-Uint32 gWorkerStacks[(NUM_WORKER_STACKS+31)/32];
- int   giLastUsedWorker = 0;
-struct sPageInfo {
-       void    *Node;
-       tVAddr  Base;
-       Uint64  Offset;
-        int    Length;
-        int    Flags;
-}      *gaMappedRegions;       // sizeof = 24 bytes
-
-// === CODE ===
-/**
- * \fn void MM_PreinitVirtual(void)
- * \brief Maps the fractal mappings
- */
-void MM_PreinitVirtual(void)
-{
-       gaInitPageDir[ PAGE_TABLE_ADDR >> 22 ] = ((tTabEnt)&gaInitPageDir - KERNEL_BASE) | 3;
-       INVLPG( PAGE_TABLE_ADDR );
-}
-
-/**
- * \fn void MM_InstallVirtual(void)
- * \brief Sets up the constant page mappings
- */
-void MM_InstallVirtual(void)
-{
-        int    i;
-       
-       // --- Pre-Allocate kernel tables
-       for( i = KERNEL_BASE>>22; i < 1024; i ++ )
-       {
-               if( gaPageDir[ i ] )    continue;
-               // Skip stack tables, they are process unique
-               if( i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) {
-                       gaPageDir[ i ] = 0;
-                       continue;
-               }
-               // Preallocate table
-               gaPageDir[ i ] = MM_AllocPhys() | 3;
-               INVLPG( &gaPageTable[i*1024] );
-               memset( &gaPageTable[i*1024], 0, 0x1000 );
-       }
-       
-       // Unset kernel on the User Text pages
-       for( i = ((tVAddr)&_UsertextEnd-(tVAddr)&_UsertextBase+0xFFF)/4096; i--; ) {
-               MM_SetFlags( (tVAddr)&_UsertextBase + i*4096, 0, MM_PFLAG_KERNEL );
-       }
-       
-       *gpTmpCR3 = 0;
-}
-
-/**
- * \brief Cleans up the SMP required mappings
- */
-void MM_FinishVirtualInit(void)
-{
-       gaInitPageDir[ 0 ] = 0;
-}
-
-/**
- * \fn void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
- * \brief Called on a page fault
- */
-void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
-{
-       //ENTER("xAddr bErrorCode", Addr, ErrorCode);
-       
-       // -- Check for COW --
-       if( gaPageDir  [Addr>>22] & PF_PRESENT  && gaPageTable[Addr>>12] & PF_PRESENT
-        && gaPageTable[Addr>>12] & PF_COW )
-       {
-               tPAddr  paddr;
-               if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
-               {
-                       gaPageTable[Addr>>12] &= ~PF_COW;
-                       gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
-               }
-               else
-               {
-                       //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr);
-                       paddr = MM_DuplicatePage( Addr );
-                       MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
-                       gaPageTable[Addr>>12] &= PF_USER;
-                       gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
-               }
-               
-//             Log_Debug("MMVirt", "COW for %p (%P)", Addr, gaPageTable[Addr>>12]);
-               
-               INVLPG( Addr & ~0xFFF );
-               return;
-       }
-
-       // Disable instruction tracing  
-       __ASM__("pushf; andw $0xFEFF, 0(%esp); popf");
-       Proc_GetCurThread()->bInstrTrace = 0;
-
-       // If it was a user, tell the thread handler
-       if(ErrorCode & 4) {
-               Log_Warning("MMVirt", "User %s %s memory%s",
-                       (ErrorCode&2?"write to":"read from"),
-                       (ErrorCode&1?"bad/locked":"non-present"),
-                       (ErrorCode&16?" (Instruction Fetch)":"")
-                       );
-               Log_Warning("MMVirt", "Instruction %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr);
-               __ASM__("sti"); // Restart IRQs
-               #if 1
-               Error_Backtrace(Regs->eip, Regs->ebp);
-               #endif
-               Threads_SegFault(Addr);
-               return ;
-       }
-       
-       Debug_KernelPanic();
-       
-       // -- Check Error Code --
-       if(ErrorCode & 8)
-               Warning("Reserved Bits Trashed!");
-       else
-       {
-               Warning("Kernel %s %s memory%s",
-                       (ErrorCode&2?"write to":"read from"),
-                       (ErrorCode&1?"bad/locked":"non-present"),
-                       (ErrorCode&16?" (Instruction Fetch)":"")
-                       );
-       }
-       
-       Log("CPU %i - Code at %p accessed %p", GetCPUNum(), Regs->eip, Addr);
-       // Print Stack Backtrace
-       Error_Backtrace(Regs->eip, Regs->ebp);
-
-       #if 0   
-       Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]);
-       if( gaPageDir[Addr>>22] & PF_PRESENT )
-               Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]);
-       #endif
-       //MM_DumpTables(0, -1); 
-       
-       // Register Dump
-       Log("EAX %08x ECX %08x EDX %08x EBX %08x", Regs->eax, Regs->ecx, Regs->edx, Regs->ebx);
-       Log("ESP %08x EBP %08x ESI %08x EDI %08x", Regs->esp, Regs->ebp, Regs->esi, Regs->edi);
-       //Log("SS:ESP %04x:%08x", Regs->ss, Regs->esp);
-       Log("CS:EIP %04x:%08x", Regs->cs, Regs->eip);
-       Log("DS %04x ES %04x FS %04x GS %04x", Regs->ds, Regs->es, Regs->fs, Regs->gs);
-       {
-               Uint    dr0, dr1;
-               __ASM__ ("mov %%dr0, %0":"=r"(dr0):);
-               __ASM__ ("mov %%dr1, %0":"=r"(dr1):);
-               Log("DR0 %08x DR1 %08x", dr0, dr1);
-       }
-       
-       Panic("Page Fault at 0x%x (Accessed 0x%x)", Regs->eip, Addr);
-}
-
-/**
- * \fn void MM_DumpTables(tVAddr Start, tVAddr End)
- * \brief Dumps the layout of the page tables
- */
-void MM_DumpTables(tVAddr Start, tVAddr End)
-{
-       tVAddr  rangeStart = 0;
-       tPAddr  expected = 0;
-       void    *expected_node = NULL, *tmpnode = NULL;
-       tVAddr  curPos;
-       Uint    page;
-       const tPAddr    MASK = ~0xF78;
-       
-       Start >>= 12;   End >>= 12;
-       
-       #if 0
-       Log("Directory Entries:");
-       for(page = Start >> 10;
-               page < (End >> 10)+1;
-               page ++)
-       {
-               if(gaPageDir[page])
-               {
-                       Log(" 0x%08x-0x%08x :: 0x%08x",
-                               page<<22, ((page+1)<<22)-1,
-                               gaPageDir[page]&~0xFFF
-                               );
-               }
-       }
-       #endif
-       
-       Log("Table Entries:");
-       for(page = Start, curPos = Start<<12;
-               page < End;
-               curPos += 0x1000, page++)
-       {
-               if( !(gaPageDir[curPos>>22] & PF_PRESENT)
-               ||  !(gaPageTable[page] & PF_PRESENT)
-               ||  (gaPageTable[page] & MASK) != expected
-               ||  (tmpnode=NULL,MM_GetPageNode(expected, &tmpnode), tmpnode != expected_node))
-               {
-                       if(expected) {
-                               tPAddr  orig = gaPageTable[rangeStart>>12];
-                               Log(" 0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s) %p",
-                                       rangeStart,
-                                       orig & ~0xFFF,
-                                       curPos - rangeStart,
-                                       (orig & PF_NOPAGE ? "P" : "-"),
-                                       (orig & PF_COW ? "C" : "-"),
-                                       (orig & PF_GLOBAL ? "G" : "-"),
-                                       (orig & PF_USER ? "U" : "-"),
-                                       (orig & PF_WRITE ? "W" : "-"),
-                                       expected_node
-                                       );
-                               expected = 0;
-                       }
-                       if( !(gaPageDir[curPos>>22] & PF_PRESENT) )     continue;
-                       if( !(gaPageTable[curPos>>12] & PF_PRESENT) )   continue;
-                       
-                       expected = (gaPageTable[page] & MASK);
-                       MM_GetPageNode(expected, &expected_node);
-                       rangeStart = curPos;
-               }
-               if(expected)    expected += 0x1000;
-       }
-       
-       if(expected) {
-               tPAddr  orig = gaPageTable[rangeStart>>12];
-               Log("0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s) %p",
-                       rangeStart,
-                       orig & ~0xFFF,
-                       curPos - rangeStart,
-                       (orig & PF_NOPAGE ? "p" : "-"),
-                       (orig & PF_COW ? "C" : "-"),
-                       (orig & PF_GLOBAL ? "G" : "-"),
-                       (orig & PF_USER ? "U" : "-"),
-                       (orig & PF_WRITE ? "W" : "-"),
-                       expected_node
-                       );
-               expected = 0;
-       }
-}
-
-/**
- * \fn tPAddr MM_Allocate(tVAddr VAddr)
- */
-tPAddr MM_Allocate(tVAddr VAddr)
-{
-       tPAddr  paddr;
-       //ENTER("xVAddr", VAddr);
-       //__ASM__("xchg %bx,%bx");
-       // Check if the directory is mapped
-       if( gaPageDir[ VAddr >> 22 ] == 0 )
-       {
-               // Allocate directory
-               paddr = MM_AllocPhys();
-               if( paddr == 0 ) {
-                       Warning("MM_Allocate - Out of Memory (Called by %p)", __builtin_return_address(0));
-                       //LEAVE('i',0);
-                       return 0;
-               }
-               // Map and mark as user (if needed)
-               gaPageDir[ VAddr >> 22 ] = paddr | 3;
-               if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
-               
-               INVLPG( &gaPageDir[ VAddr >> 22 ] );
-               memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
-       }
-       // Check if the page is already allocated
-       else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
-               Warning("MM_Allocate - Allocating to used address (%p)", VAddr);
-               //LEAVE('X', gaPageTable[ VAddr >> 12 ] & ~0xFFF);
-               return gaPageTable[ VAddr >> 12 ] & ~0xFFF;
-       }
-       
-       // Allocate
-       paddr = MM_AllocPhys();
-       //LOG("paddr = 0x%llx", paddr);
-       if( paddr == 0 ) {
-               Warning("MM_Allocate - Out of Memory when allocating at %p (Called by %p)",
-                       VAddr, __builtin_return_address(0));
-               //LEAVE('i',0);
-               return 0;
-       }
-       // Map
-       gaPageTable[ VAddr >> 12 ] = paddr | 3;
-       // Mark as user
-       if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
-       // Invalidate Cache for address
-       INVLPG( VAddr & ~0xFFF );
-       
-       //LEAVE('X', paddr);
-       return paddr;
-}
-
-/**
- * \fn void MM_Deallocate(tVAddr VAddr)
- */
-void MM_Deallocate(tVAddr VAddr)
-{
-       if( gaPageDir[ VAddr >> 22 ] == 0 ) {
-               Warning("MM_Deallocate - Directory not mapped");
-               return;
-       }
-       
-       if(gaPageTable[ VAddr >> 12 ] == 0) {
-               Warning("MM_Deallocate - Page is not allocated");
-               return;
-       }
-       
-       // Dereference page
-       MM_DerefPhys( gaPageTable[ VAddr >> 12 ] & ~0xFFF );
-       // Clear page
-       gaPageTable[ VAddr >> 12 ] = 0;
-}
-
-/**
- * \fn tPAddr MM_GetPhysAddr(tVAddr Addr)
- * \brief Checks if the passed address is accesable
- */
-tPAddr MM_GetPhysAddr(tVAddr Addr)
-{
-       if( !(gaPageDir[Addr >> 22] & 1) )
-               return 0;
-       if( !(gaPageTable[Addr >> 12] & 1) )
-               return 0;
-       return (gaPageTable[Addr >> 12] & ~0xFFF) | (Addr & 0xFFF);
-}
-
-/**
- * \fn void MM_SetCR3(Uint CR3)
- * \brief Sets the current process space
- */
-void MM_SetCR3(Uint CR3)
-{
-       __ASM__("mov %0, %%cr3"::"r"(CR3));
-}
-
-/**
- * \fn int MM_Map(tVAddr VAddr, tPAddr PAddr)
- * \brief Map a physical page to a virtual one
- */
-int MM_Map(tVAddr VAddr, tPAddr PAddr)
-{
-       //ENTER("xVAddr xPAddr", VAddr, PAddr);
-       // Sanity check
-       if( PAddr & 0xFFF || VAddr & 0xFFF ) {
-               Log_Warning("MM_Virt", "MM_Map - Physical or Virtual Addresses are not aligned");
-               //LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Align addresses
-       PAddr &= ~0xFFF;        VAddr &= ~0xFFF;
-       
-       // Check if the directory is mapped
-       if( gaPageDir[ VAddr >> 22 ] == 0 )
-       {
-               tPAddr  tmp = MM_AllocPhys();
-               if( tmp == 0 )
-                       return 0;
-               gaPageDir[ VAddr >> 22 ] = tmp | 3;
-               
-               // Mark as user
-               if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
-               
-               INVLPG( &gaPageTable[ (VAddr >> 12) & ~0x3FF ] );
-               memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
-       }
-       // Check if the page is already allocated
-       else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
-               Warning("MM_Map - Allocating to used address");
-               //LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Map
-       gaPageTable[ VAddr >> 12 ] = PAddr | 3;
-       // Mark as user
-       if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
-       
-       //LOG("gaPageTable[ 0x%x ] = (Uint)%p = 0x%x",
-       //      VAddr >> 12, &gaPageTable[ VAddr >> 12 ], gaPageTable[ VAddr >> 12 ]);
-       
-       // Reference
-       MM_RefPhys( PAddr );
-       
-       //LOG("INVLPG( 0x%x )", VAddr);
-       INVLPG( VAddr );
-       
-       //LEAVE('i', 1);
-       return 1;
-}
-
-/**
- * \brief Clear user's address space
- */
-void MM_ClearUser(void)
-{
-       Uint    i, j;
-       
-       for( i = 0; i < (MM_USER_MAX>>22); i ++ )
-       {
-               // Check if directory is not allocated
-               if( !(gaPageDir[i] & PF_PRESENT) ) {
-                       gaPageDir[i] = 0;
-                       continue;
-               }
-               
-               // Deallocate tables
-               for( j = 0; j < 1024; j ++ )
-               {
-                       if( gaPageTable[i*1024+j] & 1 )
-                               MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF );
-                       gaPageTable[i*1024+j] = 0;
-               }
-               
-               // Deallocate directory
-               MM_DerefPhys( gaPageDir[i] & ~0xFFF );
-               gaPageDir[i] = 0;
-               INVLPG( &gaPageTable[i*1024] );
-       }
-       INVLPG( gaPageDir );
-}
-
-/**
- * \brief Deallocate an address space
- */
-void MM_ClearSpace(Uint32 CR3)
-{
-        int    i, j;
-       
-       if(CR3 == (*gpPageCR3 & ~0xFFF)) {
-               Log_Error("MMVirt", "Can't clear current address space");
-               return ;
-       }
-
-       if( MM_GetRefCount(CR3) > 1 ) {
-               MM_DerefPhys(CR3);
-               Log_Log("MMVirt", "CR3 %P is still referenced, not cleaning (but dereferenced)", CR3);
-               return ;
-       }
-
-       Log_Debug("MMVirt", "Clearing out address space 0x%x from 0x%x", CR3, *gpPageCR3);
-       
-       GET_TEMP_MAPPING(CR3);
-       INVLPG( gaTmpDir );
-
-       for( i = 0; i < 1024; i ++ )
-       {
-               Uint32  *table = &gaTmpTable[i*1024];
-               if( !(gaTmpDir[i] & PF_PRESENT) )
-                       continue ;
-
-               INVLPG( table );        
-
-               if( i < 768 || (i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) )
-               {
-                       for( j = 0; j < 1024; j ++ )
-                       {
-                               if( !(table[j] & 1) )
-                                       continue;
-                               MM_DerefPhys( table[j] & ~0xFFF );
-                       }
-               }
-
-               if( i != (PAGE_TABLE_ADDR >> 22) )
-               {               
-                       MM_DerefPhys( gaTmpDir[i] & ~0xFFF );
-               }
-       }
-
-
-       MM_DerefPhys( CR3 );
-
-       REL_TEMP_MAPPING();
-}
-
-/**
- * \fn tPAddr MM_Clone(void)
- * \brief Clone the current address space
- */
-tPAddr MM_Clone(int bNoUserCopy)
-{
-       Uint    i, j;
-       tPAddr  ret;
-       Uint    page = 0;
-       tVAddr  kStackBase = Proc_GetCurThread()->KernelStack - MM_KERNEL_STACK_SIZE;
-       void    *tmp;
-       
-       // Create Directory Table
-       ret = MM_AllocPhys();
-       if( ret == 0 ) {
-               return 0;
-       }
-       
-       // Map
-       GET_TEMP_MAPPING( ret );
-       INVLPG( gaTmpDir );
-       memsetd( gaTmpDir, 0, 1024 );
-       
-       if( Threads_GetPID() != 0 && !bNoUserCopy )
-       {       
-               // Copy Tables
-               for( i = 0; i < 768; i ++)
-               {
-                       // Check if table is allocated
-                       if( !(gaPageDir[i] & PF_PRESENT) ) {
-                               gaTmpDir[i] = 0;
-                               page += 1024;
-                               continue;
-                       }
-                       
-                       // Allocate new table
-                       gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7);
-                       INVLPG( &gaTmpTable[page] );
-                       // Fill
-                       for( j = 0; j < 1024; j ++, page++ )
-                       {
-                               if( !(gaPageTable[page] & PF_PRESENT) ) {
-                                       gaTmpTable[page] = 0;
-                                       continue;
-                               }
-                               
-                               // Refrence old page
-                               MM_RefPhys( gaPageTable[page] & ~0xFFF );
-                               // Add to new table
-                               if(gaPageTable[page] & PF_WRITE) {
-                                       gaTmpTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
-                                       gaPageTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
-                                       INVLPG( page << 12 );
-                               }
-                               else
-                                       gaTmpTable[page] = gaPageTable[page];
-                       }
-               }
-       }
-       
-       // Map in kernel tables (and make fractal mapping)
-       for( i = 768; i < 1024; i ++ )
-       {
-               // Fractal
-               if( i == (PAGE_TABLE_ADDR >> 22) ) {
-                       gaTmpDir[ PAGE_TABLE_ADDR >> 22 ] = *gpTmpCR3;
-                       continue;
-               }
-               if( i == (TMP_TABLE_ADDR >> 22) ) {
-                       gaTmpDir[ TMP_TABLE_ADDR >> 22 ] = 0;
-                       continue ;
-               }
-               
-               if( gaPageDir[i] == 0 ) {
-                       gaTmpDir[i] = 0;
-                       continue;
-               }
-               
-               //LOG("gaPageDir[%x/4] = 0x%x", i*4, gaPageDir[i]);
-               MM_RefPhys( gaPageDir[i] & ~0xFFF );
-               gaTmpDir[i] = gaPageDir[i];
-       }
-       
-       // Allocate kernel stack
-       for(i = MM_KERNEL_STACKS >> 22; i < MM_KERNEL_STACKS_END >> 22; i ++ )
-       {
-               // Check if directory is allocated
-               if( (gaPageDir[i] & 1) == 0 ) {
-                       gaTmpDir[i] = 0;
-                       continue;
-               }               
-               
-               // We don't care about other kernel stacks, just the current one
-               if( i != kStackBase >> 22 ) {
-                       MM_DerefPhys( gaPageDir[i] & ~0xFFF );
-                       gaTmpDir[i] = 0;
-                       continue;
-               }
-               
-               // Create a copy
-               gaTmpDir[i] = MM_AllocPhys() | 3;
-               INVLPG( &gaTmpTable[i*1024] );
-               for( j = 0; j < 1024; j ++ )
-               {
-                       // Is the page allocated? If not, skip
-                       if( !(gaPageTable[i*1024+j] & 1) ) {
-                               gaTmpTable[i*1024+j] = 0;
-                               continue;
-                       }
-                       
-                       // We don't care about other kernel stacks
-                       if( ((i*1024+j)*4096 & ~(MM_KERNEL_STACK_SIZE-1)) != kStackBase ) {
-                               gaTmpTable[i*1024+j] = 0;
-                               continue;
-                       }
-                       
-                       // Allocate page
-                       gaTmpTable[i*1024+j] = MM_AllocPhys() | 3;
-                       
-                       MM_RefPhys( gaTmpTable[i*1024+j] & ~0xFFF );
-                       
-                       tmp = (void *) MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
-                       memcpy( tmp, (void *)( (i*1024+j)*0x1000 ), 0x1000 );
-                       MM_FreeTemp( (Uint)tmp );
-               }
-       }
-       
-       REL_TEMP_MAPPING();
-       
-       //LEAVE('x', ret);
-       return ret;
-}
-
-/**
- * \fn tVAddr MM_NewKStack(void)
- * \brief Create a new kernel stack
- */
-tVAddr MM_NewKStack(void)
-{
-       tVAddr  base;
-       Uint    i;
-       for(base = MM_KERNEL_STACKS; base < MM_KERNEL_STACKS_END; base += MM_KERNEL_STACK_SIZE)
-       {
-               // Check if space is free
-               if(MM_GetPhysAddr(base) != 0)   continue;
-               // Allocate
-               //for(i = MM_KERNEL_STACK_SIZE; i -= 0x1000 ; )
-               for(i = 0; i < MM_KERNEL_STACK_SIZE; i += 0x1000 )
-               {
-                       if( MM_Allocate(base+i) == 0 )
-                       {
-                               // On error, print a warning and return error
-                               Warning("MM_NewKStack - Out of memory");
-                               // - Clean up
-                               //for( i += 0x1000 ; i < MM_KERNEL_STACK_SIZE; i += 0x1000 )
-                               //      MM_Deallocate(base+i);
-                               return 0;
-                       }
-               }
-               // Success
-//             Log("MM_NewKStack - Allocated %p", base + MM_KERNEL_STACK_SIZE);
-               return base+MM_KERNEL_STACK_SIZE;
-       }
-       // No stacks left
-       Log_Warning("MMVirt", "MM_NewKStack - No address space left");
-       return 0;
-}
-
-/**
- * \fn tVAddr MM_NewWorkerStack()
- * \brief Creates a new worker stack
- */
-tVAddr MM_NewWorkerStack(Uint *StackContents, size_t ContentsSize)
-{
-       Uint    base, addr;
-       tVAddr  tmpPage;
-       tPAddr  page;
-       
-       // TODO: Thread safety
-       // Find a free worker stack address
-       for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++)
-       {
-               // Used block
-               if( gWorkerStacks[base/32] == -1 ) {
-                       base += 31;     base &= ~31;
-                       base --;        // Counteracted by the base++
-                       continue;
-               }
-               // Used stack
-               if( gWorkerStacks[base/32] & (1 << base) ) {
-                       continue;
-               }
-               break;
-       }
-       if(base >= NUM_WORKER_STACKS) {
-               Warning("Uh-oh! Out of worker stacks");
-               return 0;
-       }
-       
-       // It's ours now!
-       gWorkerStacks[base/32] |= (1 << base);
-       // Make life easier for later calls
-       giLastUsedWorker = base;
-       // We have one
-       base = WORKER_STACKS + base * WORKER_STACK_SIZE;
-       //Log(" MM_NewWorkerStack: base = 0x%x", base);
-       
-       // Set the temp fractals to TID0's address space
-       GET_TEMP_MAPPING( ((Uint)gaInitPageDir - KERNEL_BASE) );
-       INVLPG( gaTmpDir );
-       
-       // Check if the directory is mapped (we are assuming that the stacks
-       // will fit neatly in a directory)
-       //Log(" MM_NewWorkerStack: gaTmpDir[ 0x%x ] = 0x%x", base>>22, gaTmpDir[ base >> 22 ]);
-       if(gaTmpDir[ base >> 22 ] == 0) {
-               gaTmpDir[ base >> 22 ] = MM_AllocPhys() | 3;
-               INVLPG( &gaTmpTable[ (base>>12) & ~0x3FF ] );
-       }
-       
-       // Mapping Time!
-       for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 )
-       {
-               page = MM_AllocPhys();
-               gaTmpTable[ (base + addr) >> 12 ] = page | 3;
-       }
-
-       // Release temporary fractal
-       REL_TEMP_MAPPING();
-
-       // NOTE: Max of 1 page
-       // `page` is the last allocated page from the previious for loop
-       tmpPage = MM_MapTemp( page );
-       memcpy( (void*)( tmpPage + (0x1000 - ContentsSize) ), StackContents, ContentsSize);
-       MM_FreeTemp(tmpPage);   
-       
-       //Log("MM_NewWorkerStack: RETURN 0x%x", base);
-       return base + WORKER_STACK_SIZE;
-}
-
-/**
- * \fn void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
- * \brief Sets the flags on a page
- */
-void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
-{
-       tTabEnt *ent;
-       if( !(gaPageDir[VAddr >> 22] & 1) )     return ;
-       if( !(gaPageTable[VAddr >> 12] & 1) )   return ;
-       
-       ent = &gaPageTable[VAddr >> 12];
-       
-       // Read-Only
-       if( Mask & MM_PFLAG_RO )
-       {
-               if( Flags & MM_PFLAG_RO ) {
-                       *ent &= ~PF_WRITE;
-               }
-               else {
-                       gaPageDir[VAddr >> 22] |= PF_WRITE;
-                       *ent |= PF_WRITE;
-               }
-       }
-       
-       // Kernel
-       if( Mask & MM_PFLAG_KERNEL )
-       {
-               if( Flags & MM_PFLAG_KERNEL ) {
-                       *ent &= ~PF_USER;
-               }
-               else {
-                       gaPageDir[VAddr >> 22] |= PF_USER;
-                       *ent |= PF_USER;
-               }
-       }
-       
-       // Copy-On-Write
-       if( Mask & MM_PFLAG_COW )
-       {
-               if( Flags & MM_PFLAG_COW ) {
-                       *ent &= ~PF_WRITE;
-                       *ent |= PF_COW;
-               }
-               else {
-                       *ent &= ~PF_COW;
-                       *ent |= PF_WRITE;
-               }
-       }
-       
-       //Log("MM_SetFlags: *ent = 0x%08x, gaPageDir[%i] = 0x%08x",
-       //      *ent, VAddr >> 22, gaPageDir[VAddr >> 22]);
-}
-
-/**
- * \brief Get the flags on a page
- */
-Uint MM_GetFlags(tVAddr VAddr)
-{
-       tTabEnt *ent;
-       Uint    ret = 0;
-       
-       // Validity Check
-       if( !(gaPageDir[VAddr >> 22] & 1) )     return 0;
-       if( !(gaPageTable[VAddr >> 12] & 1) )   return 0;
-       
-       ent = &gaPageTable[VAddr >> 12];
-       
-       // Read-Only
-       if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
-       // Kernel
-       if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
-       // Copy-On-Write
-       if( *ent & PF_COW )     ret |= MM_PFLAG_COW;
-       
-       return ret;
-}
-
-/**
- * \brief Check if the provided buffer is valid
- * \return Boolean valid
- */
-int MM_IsValidBuffer(tVAddr Addr, size_t Size)
-{
-        int    bIsUser;
-        int    dir, tab;
-
-       Size += Addr & (PAGE_SIZE-1);
-       Addr &= ~(PAGE_SIZE-1);
-
-       dir = Addr >> 22;
-       tab = Addr >> 12;
-       
-//     Debug("Addr = %p, Size = 0x%x, dir = %i, tab = %i", Addr, Size, dir, tab);
-
-       if( !(gaPageDir[dir] & 1) )     return 0;
-       if( !(gaPageTable[tab] & 1) )   return 0;
-       
-       bIsUser = !!(gaPageTable[tab] & PF_USER);
-
-       while( Size >= PAGE_SIZE )
-       {
-               if( (tab & 1023) == 0 )
-               {
-                       dir ++;
-                       if( !(gaPageDir[dir] & 1) )     return 0;
-               }
-               
-               if( !(gaPageTable[tab] & 1) )   return 0;
-               if( bIsUser && !(gaPageTable[tab] & PF_USER) )  return 0;
-
-               tab ++;
-               Size -= PAGE_SIZE;
-       }
-       return 1;
-}
-
-/**
- * \fn tPAddr MM_DuplicatePage(tVAddr VAddr)
- * \brief Duplicates a virtual page to a physical one
- */
-tPAddr MM_DuplicatePage(tVAddr VAddr)
-{
-       tPAddr  ret;
-       Uint    temp;
-        int    wasRO = 0;
-       
-       //ENTER("xVAddr", VAddr);
-       
-       // Check if mapped
-       if( !(gaPageDir  [VAddr >> 22] & PF_PRESENT) )  return 0;
-       if( !(gaPageTable[VAddr >> 12] & PF_PRESENT) )  return 0;
-       
-       // Page Align
-       VAddr &= ~0xFFF;
-       
-       // Allocate new page
-       ret = MM_AllocPhys();
-       if( !ret ) {
-               return 0;
-       }
-       
-       // Write-lock the page (to keep data constistent), saving its R/W state
-       wasRO = (gaPageTable[VAddr >> 12] & PF_WRITE ? 0 : 1);
-       gaPageTable[VAddr >> 12] &= ~PF_WRITE;
-       INVLPG( VAddr );
-       
-       // Copy Data
-       temp = MM_MapTemp(ret);
-       memcpy( (void*)temp, (void*)VAddr, 0x1000 );
-       MM_FreeTemp(temp);
-       
-       // Restore Writeable status
-       if(!wasRO)      gaPageTable[VAddr >> 12] |= PF_WRITE;
-       INVLPG(VAddr);
-       
-       //LEAVE('X', ret);
-       return ret;
-}
-
-/**
- * \fn Uint MM_MapTemp(tPAddr PAddr)
- * \brief Create a temporary memory mapping
- * \todo Show Luigi Barone (C Lecturer) and see what he thinks
- */
-tVAddr MM_MapTemp(tPAddr PAddr)
-{
-        int    i;
-       
-       //ENTER("XPAddr", PAddr);
-       
-       PAddr &= ~0xFFF;
-       
-       //LOG("glTempMappings = %i", glTempMappings);
-       
-       for(;;)
-       {
-               Mutex_Acquire( &glTempMappings );
-               
-               for( i = 0; i < NUM_TEMP_PAGES; i ++ )
-               {
-                       // Check if page used
-                       if(gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] & 1)        continue;
-                       // Mark as used
-                       gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] = PAddr | 3;
-                       INVLPG( TEMP_MAP_ADDR + (i << 12) );
-                       //LEAVE('p', TEMP_MAP_ADDR + (i << 12));
-                       Mutex_Release( &glTempMappings );
-                       return TEMP_MAP_ADDR + (i << 12);
-               }
-               Mutex_Release( &glTempMappings );
-               Threads_Yield();        // TODO: Use a sleep queue here instead
-       }
-}
-
-/**
- * \fn void MM_FreeTemp(tVAddr PAddr)
- * \brief Free's a temp mapping
- */
-void MM_FreeTemp(tVAddr VAddr)
-{
-        int    i = VAddr >> 12;
-       //ENTER("xVAddr", VAddr);
-       
-       if(i >= (TEMP_MAP_ADDR >> 12))
-               gaPageTable[ i ] = 0;
-       
-       //LEAVE('-');
-}
-
-/**
- * \fn tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
- * \brief Allocates a contigous number of pages
- */
-tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
-{
-        int    i, j;
-       
-       PAddr &= ~0xFFF;
-       
-       // Scan List
-       for( i = 0; i < NUM_HW_PAGES; i ++ )
-       {               
-               // Check if addr used
-               if( gaPageTable[ (HW_MAP_ADDR >> 12) + i ] & 1 )
-                       continue;
-               
-               // Check possible region
-               for( j = 0; j < Number && i + j < NUM_HW_PAGES; j ++ )
-               {
-                       // If there is an allocated page in the region we are testing, break
-                       if( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] & 1 )    break;
-               }
-               // Is it all free?
-               if( j == Number )
-               {
-                       // Allocate
-                       for( j = 0; j < Number; j++ ) {
-                               MM_RefPhys( PAddr + (j<<12) );
-                               gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = (PAddr + (j<<12)) | 3;
-                       }
-                       return HW_MAP_ADDR + (i<<12);
-               }
-       }
-       // If we don't find any, return NULL
-       return 0;
-}
-
-/**
- * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
- * \brief Allocates DMA physical memory
- * \param Pages        Number of pages required
- * \param MaxBits      Maximum number of bits the physical address can have
- * \param PhysAddr     Pointer to the location to place the physical address allocated
- * \return Virtual address allocate
- */
-tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
-{
-       tPAddr  maxCheck = (1 << MaxBits);
-       tPAddr  phys;
-       tVAddr  ret;
-       
-       ENTER("iPages iMaxBits pPhysAddr", Pages, MaxBits, PhysAddr);
-       
-       // Sanity Check
-       if(MaxBits < 12 || !PhysAddr) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Bound
-       if(MaxBits >= PHYS_BITS)        maxCheck = -1;
-       
-       // Fast Allocate
-       if(Pages == 1 && MaxBits >= PHYS_BITS)
-       {
-               phys = MM_AllocPhys();
-               if( !phys ) {
-                       *PhysAddr = 0;
-                       LEAVE_RET('i', 0);
-               }
-               *PhysAddr = phys;
-               ret = MM_MapHWPages(phys, 1);
-               if(ret == 0) {
-                       MM_DerefPhys(phys);
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               LEAVE('x', ret);
-               return ret;
-       }
-       
-       // Slow Allocate
-       phys = MM_AllocPhysRange(Pages, MaxBits);
-       // - Was it allocated?
-       if(phys == 0) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Allocated successfully, now map
-       ret = MM_MapHWPages(phys, Pages);
-       if( ret == 0 ) {
-               // If it didn't map, free then return 0
-               for(;Pages--;phys+=0x1000)
-                       MM_DerefPhys(phys);
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       *PhysAddr = phys;
-       LEAVE('x', ret);
-       return ret;
-}
-
-/**
- * \fn void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
- * \brief Unmap a hardware page
- */
-void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
-{
-        int    i, j;
-       
-       //Log_Debug("VirtMem", "MM_UnmapHWPages: (VAddr=0x%08x, Number=%i)", VAddr, Number);
-       
-       // Sanity Check
-       if(VAddr < HW_MAP_ADDR || VAddr+Number*0x1000 > HW_MAP_MAX)     return;
-       
-       i = VAddr >> 12;
-       
-       Mutex_Acquire( &glTempMappings );       // Temp and HW share a directory, so they share a lock
-       
-       for( j = 0; j < Number; j++ )
-       {
-               MM_DerefPhys( gaPageTable[ i + j ] & ~0xFFF );
-               gaPageTable[ i + j ] = 0;
-       }
-       
-       Mutex_Release( &glTempMappings );
-}
-
diff --git a/Kernel/arch/x86/pci.c b/Kernel/arch/x86/pci.c
deleted file mode 100644 (file)
index 7a0a2c1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*\r
- * Acess2\r
- * arch/x86/pci.h - x86 PCI Bus Access\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <drv_pci_int.h>\r
-\r
-// === CODE ===\r
-Uint32 PCI_CfgReadDWord(Uint32 Address)\r
-{\r
-       Address |= 0x80000000;\r
-       outd(0xCF8, Address);\r
-       return ind(0xCFC);\r
-}\r
-\r
-void PCI_CfgWriteDWord(Uint32 Address, Uint32 Data)\r
-{\r
-       Address |= 0x80000000;\r
-       outd(0xCF8, Address);\r
-       outd(0xCFC, Data);\r
-}\r
diff --git a/Kernel/arch/x86/proc.asm b/Kernel/arch/x86/proc.asm
deleted file mode 100644 (file)
index 8da7971..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-; AcessOS Microkernel Version
-; Start.asm
-
-[bits 32]
-
-%define SAVEFLAG_FPU   0x1
-
-KERNEL_BASE    equ 0xC0000000
-
-KSTACK_USERSTATE_SIZE  equ     (4+8+1+5)*4     ; SRegs, GPRegs, CPU, IRET
-
-[section .text]
-
-[global NewTaskHeader]
-NewTaskHeader:
-       mov eax, [esp]
-       mov dr0, eax
-
-       mov eax, [esp+4]
-       add esp, 12     ; Thread, Function, Arg Count
-       call eax
-       
-       push eax        ; Ret val
-       push 0          ; 0 = This Thread
-       call Threads_Exit
-
-[extern MM_Clone]
-[global Proc_CloneInt]
-Proc_CloneInt:
-       pusha
-       ; Save RSP
-       mov eax, [esp+0x20+4]
-       mov [eax], esp
-       push DWORD [esp+0x20+12]
-       call MM_Clone
-       add esp, 4
-       ; Save CR3
-       mov esi, [esp+0x20+8]
-       mov [esi], eax
-       ; Undo the pusha
-       add esp, 0x20
-       mov eax, .newTask
-       ret
-.newTask:
-       popa
-       xor eax, eax
-       ret
-
-[global SwitchTasks]
-; + 4 = New RSP
-; + 8 = Old RSP save loc
-; +12 = New RIP
-; +16 = Old RIP save loc
-; +20 = CR3
-SwitchTasks:
-       pusha
-       
-       ; Old IP
-       mov eax, [esp+0x20+16]
-       test eax, eax
-       jz .nosave
-       mov DWORD [eax], .restore
-       ; Old SP
-       mov eax, [esp+0x20+8]
-       mov [eax], esp
-
-.nosave:
-       mov ecx, [esp+0x20+12]  ; New IP
-       mov eax, [esp+0x20+20]  ; New CR3
-       mov esp, [esp+0x20+ 4]  ; New SP
-       
-       test eax, eax
-       jz .setState
-       mov cr3, eax
-       invlpg [esp]
-       invlpg [esp+0x1000]
-.setState:
-       jmp ecx
-
-.restore:
-       popa
-       xor eax, eax
-       ret
-
-[global Proc_InitialiseSSE]
-Proc_InitialiseSSE:
-       mov eax, cr4
-       or eax, (1 << 9)|(1 << 10)      ; Set OSFXSR and OSXMMEXCPT
-       mov cr4, eax
-       mov eax, cr0
-       and ax, ~(1 << 2)       ; Clear EM
-       or eax, (1 << 1)        ; Set MP
-       mov eax, cr0
-       ret
-[global Proc_DisableSSE]
-Proc_DisableSSE:
-       mov eax, cr0
-       or ax, 1 << 3   ; Set TS
-       mov cr0, eax
-       ret
-[global Proc_EnableSSE]
-Proc_EnableSSE:
-       mov eax, cr0
-       and ax, ~(1 << 3)       ; Clear TS
-       mov cr0, eax
-       ret
-
-[global Proc_SaveSSE]
-Proc_SaveSSE:
-       mov eax, [esp+4]
-       fxsave [eax]
-       ret
-[global Proc_RestoreSSE]
-Proc_RestoreSSE:
-       mov eax, [esp+4]
-       fxrstor [eax]
-       ret
-
-%if USE_MP
-[extern giMP_TimerCount]
-[extern gpMP_LocalAPIC]
-[extern Isr240.jmp]
-[global SetAPICTimerCount]
-SetAPICTimerCount:
-       pusha
-       push ds
-       push es
-       push fs
-       push gs
-       
-       mov ax, 0x10
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       
-       mov eax, [gpMP_LocalAPIC]
-       mov ecx, [eax+0x320]
-       test ecx, 0x00010000
-       jz .setTime
-       mov DWORD [eax+0x380], 0xFFFFFFFF       ; Set Initial Count
-       mov DWORD [eax+0x320], 0x000000F0       ; Enable the timer on IVT#0xEF (One Shot)
-       jmp .ret
-
-.setTime:      
-       ; Get Timer Count
-       mov ecx, 0xFFFFFFFF
-       sub ecx, [eax+0x390]
-       mov DWORD [giMP_TimerCount], ecx
-       ; Disable APIC Timer
-       mov DWORD [eax+0x320], 0x000100EF
-       mov DWORD [eax+0x380], 0
-
-       ; Update Timer IRQ to the IRQ code
-       mov eax, SchedulerBase
-       sub eax, Isr240.jmp+5
-       mov DWORD [Isr240.jmp+1], eax
-
-       ;xchg bx, bx    ; MAGIC BREAK
-.ret:
-       mov dx, 0x20
-       mov al, 0x20
-       out dx, al              ; ACK IRQ
-       pop gs
-       pop fs
-       pop es
-       pop ds
-       popa
-       add esp, 8      ; CPU ID / Error Code
-       iret
-%endif
-; --------------
-; Task Scheduler
-; --------------
-[extern Proc_Scheduler]
-[global SchedulerBase]
-SchedulerBase:
-       pusha
-       push ds
-       push es
-       push fs
-       push gs
-       
-       pushf
-       and BYTE [esp+1], 0xFE  ; Clear Trap Flag
-       popf
-       
-       mov eax, dr0
-       push eax        ; Debug Register 0, Current Thread
-       
-       mov ax, 0x10
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       
-       %if USE_MP
-       call GetCPUNum
-       mov ebx, eax
-       push eax        ; Push as argument
-       %else
-       push 0
-       %endif
-       
-       call Proc_Scheduler
-[global scheduler_return]
-scheduler_return:      ; Used by some hackery in Proc_DumpThreadCPUState
-       
-       add esp, 4      ; Remove CPU Number (thread is poped later)
-
-       %if USE_MP
-       test ebx, ebx
-       jnz .sendEOI
-       %endif
-       
-       mov al, 0x20
-       out 0x20, al            ; ACK IRQ
-       %if USE_MP
-       jmp .ret
-       
-.sendEOI:
-       mov eax, DWORD [gpMP_LocalAPIC]
-       mov DWORD [eax+0x0B0], 0
-       %endif
-.ret:
-       pop eax ; Debug Register 0, Current Thread
-       mov dr0, eax
-
-       pop gs
-       pop fs
-       pop es
-       pop ds
-       
-       popa
-       add esp, 4*2    ; CPU ID + Dummy error code
-       ; No Error code / int num
-       iret
-
-[extern Proc_Clone]
-[extern Threads_Exit]
-[global SpawnTask]
-SpawnTask:
-       ; Call Proc_Clone with Flags=0
-       xor eax, eax
-;      push eax
-       push eax
-       call Proc_Clone
-       add esp, 8      ; Remove arguments from stack
-       
-       test eax, eax
-       jnz .parent
-       
-       ; In child, so now set up stack frame
-       mov ebx, [esp+4]        ; Child Function
-       mov edx, [esp+8]        ; Argument
-       ; Child Function
-       push edx        ; Argument
-       call ebx        ; Function
-       ; Kill thread once done
-       push eax        ; Exit Code
-       push   0        ; Kill this thread
-       call Threads_Exit       ; Kill Thread
-       
-.parent:
-       ret
-
-; void Proc_ReturnToUser(void *Method, Uint Parameter, tVAddr KernelStack)
-; Calls a user fault handler
-;
-[global Proc_ReturnToUser]
-[extern Proc_GetCurThread]
-Proc_ReturnToUser:
-       push ebp
-       mov ebp, esp
-       ; [EBP+8]: handler to use
-       ; [EBP+12]: parameter
-       ; [EBP+16]: kernel stack top
-       
-       ; Get kernel stack      
-       mov eax, [ebp+16]
-       sub eax, KSTACK_USERSTATE_SIZE
-       
-       ;
-       ; NOTE: This can cause corruption if the signal happens while the user
-       ;       has called a kernel operation.
-       ; Good thing this can only be called on a user fault.
-       ;
-       
-       ; Validate user ESP
-       ; - Page Table
-       mov edx, [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4
-       mov ecx, edx
-       shr ecx, 22
-       test BYTE [0xFC3F0000+ecx*4], 1
-       jnz .justKillIt
-       ; - Page
-       mov ecx, edx
-       shr ecx, 12
-       test BYTE [0xFC000000+ecx*4], 1
-       jnz .justKillIt
-       ; Adjust
-       sub edx, 8
-       ; - Page Table
-       mov ecx, edx
-       shr ecx, 22
-       test BYTE [0xFC3F0000+ecx*4], 1
-       jnz .justKillIt
-       ; - Page
-       mov ecx, edx
-       shr ecx, 12
-       test BYTE [0xFC000000+ecx*4], 1
-       jnz .justKillIt
-       
-       ; Get and alter User SP
-       mov edi, edx
-       mov edx, [ebp+12]       ; Get parameter
-       mov [edi+4], edx        ; save to user stack
-       mov [edi], DWORD User_Syscall_RetAndExit        ; Return Address
-       
-       ; Restore Segment Registers
-       mov ax, 0x23
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       
-       push 0x23       ; SS
-       push edi        ; ESP
-       push 0x202      ; EFLAGS (IP and Rsvd)
-       push 0x1B       ; CS
-       mov eax, [ebp+8]        ; Method to call
-       push eax        ; EIP
-       
-       iret
-       
-       ; Just kill the bleeding thing
-       ; (I know it calls int 0xAC in kernel mode, but meh)
-.justKillIt:
-       xor eax, eax
-       xor ebx, ebx
-       dec ebx ; EBX = -1
-       int 0xAC
-
-[global GetCPUNum]
-GetCPUNum:     ; TODO: Store in debug registers
-       mov eax, dr1
-       ret
-
-[extern GetEIP]
-[global GetEIP_Sched]
-[global GetEIP_Sched_ret]
-GetEIP_Sched_ret equ GetEIP_Sched.ret
-GetEIP_Sched:
-       call GetEIP
-GetEIP_Sched.ret:
-       ret
-
-; Usermode code exported by the kernel
-[section .usertext]
-; Export a place for the user to jump to to call a syscall
-; - Allows the kernel to change the method easily
-User_Syscall:
-       xchg bx, bx     ; MAGIC BREAKPOINT
-       int 0xAC
-
-; A place to return to and exit
-User_Syscall_RetAndExit:
-       push eax
-       call User_Syscall_Exit
-User_Syscall_Exit:
-       xor eax, eax
-       mov ebx, [esp+4]
-       int 0xAC
-
-; vim: ft=nasm ts=8
diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c
deleted file mode 100644 (file)
index 82a3f40..0000000
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * proc.c
- */
-#include <acess.h>
-#include <threads.h>
-#include <proc.h>
-#include <desctab.h>
-#include <mm_virt.h>
-#include <errno.h>
-#if USE_MP
-# include <mp.h>
-#endif
-#include <hal_proc.h>
-#include <arch_int.h>
-
-// === FLAGS ===
-#define DEBUG_TRACE_SWITCH     0
-#define DEBUG_DISABLE_DOUBLEFAULT      1
-#define DEBUG_VERY_SLOW_PERIOD 0
-
-// === CONSTANTS ===
-// Base is 1193182
-#define TIMER_BASE      1193182
-#if DEBUG_VERY_SLOW_PERIOD
-# define TIMER_DIVISOR 1193    //~10Hz switch, with 10 quantum = 1s per thread
-#else
-# define TIMER_DIVISOR 11932   //~100Hz
-#endif
-
-// === TYPES ===
-typedef struct sCPU
-{
-       Uint8   APICID;
-       Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
-       Uint16  Resvd;
-       tThread *Current;
-}      tCPU;
-
-// === IMPORTS ===
-extern tGDT    gGDT[];
-extern tIDT    gIDT[];
-extern void    APWait(void);   // 16-bit AP pause code
-extern void    APStartup(void);        // 16-bit AP startup code
-extern Uint    GetEIP(void);   // start.asm
-extern Uint    GetEIP_Sched(void);     // proc.asm
-extern void    NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...);      // Actually takes cdecl args
-extern Uint    Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
-extern Uint32  gaInitPageDir[1024];    // start.asm
-extern char    Kernel_Stack_Top[];
-extern int     giNumCPUs;
-extern int     giNextTID;
-extern tThread gThreadZero;
-extern tProcess        gProcessZero;
-extern void    Isr8(void);     // Double Fault
-extern void    Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
-extern char    scheduler_return[];     // Return address in SchedulerBase
-extern char    IRQCommon[];    // Common IRQ handler code
-extern char    IRQCommon_handled[];    // IRQCommon call return location
-extern char    GetEIP_Sched_ret[];     // GetEIP call return location
-extern void    SwitchTasks(Uint NewSP, Uint *OldSP, Uint NewIP, Uint *OldIO, Uint CR3);
-extern void    Proc_InitialiseSSE(void);
-extern void    Proc_SaveSSE(Uint DestPtr);
-extern void    Proc_DisableSSE(void);
-
-// === PROTOTYPES ===
-//void ArchThreads_Init(void);
-#if USE_MP
-void   MP_StartAP(int CPU);
-void   MP_SendIPIVector(int CPU, Uint8 Vector);
-void   MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
-#endif
-void   Proc_IdleThread(void *Ptr);
-//void Proc_Start(void);
-//tThread      *Proc_GetCurThread(void);
-void   Proc_ChangeStack(void);
-// int Proc_NewKThread(void (*Fcn)(void*), void *Data);
-// int Proc_Clone(Uint *Err, Uint Flags);
-Uint   Proc_MakeUserStack(void);
-//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
-void   Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NORETURN;
- int   Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
-//void Proc_CallFaultHandler(tThread *Thread);
-//void Proc_DumpThreadCPUState(tThread *Thread);
-void   Proc_Scheduler(int CPU);
-
-// === GLOBALS ===
-// --- Multiprocessing ---
-#if USE_MP
-volatile int   giNumInitingCPUs = 0;
-tMPInfo        *gMPFloatPtr = NULL;
-volatile Uint32        giMP_TimerCount;        // Start Count for Local APIC Timer
-tAPIC  *gpMP_LocalAPIC = NULL;
-Uint8  gaAPIC_to_CPU[256] = {0};
- int   giProc_BootProcessorID = 0;
-tTSS   gaTSSs[MAX_CPUS];       // TSS Array
-#endif
-tCPU   gaCPUs[MAX_CPUS] = {
-       {.Current = &gThreadZero}
-       };
-tTSS   *gTSSs = NULL;  // Pointer to TSS array
-tTSS   gTSS0 = {0};
-// --- Error Recovery ---
-char   gaDoubleFaultStack[1024] __attribute__ ((section(".padata")));
-tTSS   gDoubleFault_TSS = {
-       .ESP0 = (Uint)&gaDoubleFaultStack[1024],
-       .SS0 = 0x10,
-       .CR3 = (Uint)gaInitPageDir - KERNEL_BASE,
-       .EIP = (Uint)Isr8,
-       .ESP = (Uint)&gaDoubleFaultStack[1024],
-       .CS = 0x08,     .SS = 0x10,
-       .DS = 0x10,     .ES = 0x10,
-       .FS = 0x10,     .GS = 0x10,
-};
-
-// === CODE ===
-/**
- * \fn void ArchThreads_Init(void)
- * \brief Starts the process scheduler
- */
-void ArchThreads_Init(void)
-{
-       Uint    pos = 0;
-       
-       #if USE_MP
-       tMPTable        *mptable;
-       
-       // Mark BSP as active
-       gaCPUs[0].State = 2;
-       
-       // -- Initialise Multiprocessing
-       // Find MP Floating Table
-       // - EBDA/Last 1Kib (640KiB)
-       for(pos = KERNEL_BASE|0x9F000; pos < (KERNEL_BASE|0xA0000); pos += 16) {
-               if( *(Uint*)(pos) == MPPTR_IDENT ) {
-                       Log("Possible %p", pos);
-                       if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
-                       gMPFloatPtr = (void*)pos;
-                       break;
-               }
-       }
-       // - Last KiB (512KiB base mem)
-       if(!gMPFloatPtr) {
-               for(pos = KERNEL_BASE|0x7F000; pos < (KERNEL_BASE|0x80000); pos += 16) {
-                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
-                               Log("Possible %p", pos);
-                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
-                               gMPFloatPtr = (void*)pos;
-                               break;
-                       }
-               }
-       }
-       // - BIOS ROM
-       if(!gMPFloatPtr) {
-               for(pos = KERNEL_BASE|0xE0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
-                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
-                               Log("Possible %p", pos);
-                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
-                               gMPFloatPtr = (void*)pos;
-                               break;
-                       }
-               }
-       }
-       
-       // If the MP Table Exists, parse it
-       if(gMPFloatPtr)
-       {
-                int    i;
-               tMPTable_Ent    *ents;
-               #if DUMP_MP_TABLE
-               Log("gMPFloatPtr = %p", gMPFloatPtr);
-               Log("*gMPFloatPtr = {");
-               Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig);
-               Log("\t.MPConfig = 0x%08x", gMPFloatPtr->MPConfig);
-               Log("\t.Length = 0x%02x", gMPFloatPtr->Length);
-               Log("\t.Version = 0x%02x", gMPFloatPtr->Version);
-               Log("\t.Checksum = 0x%02x", gMPFloatPtr->Checksum);
-               Log("\t.Features = [0x%02x,0x%02x,0x%02x,0x%02x,0x%02x]",
-                       gMPFloatPtr->Features[0],       gMPFloatPtr->Features[1],
-                       gMPFloatPtr->Features[2],       gMPFloatPtr->Features[3],
-                       gMPFloatPtr->Features[4]
-                       );
-               Log("}");
-               #endif          
-
-               mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig );
-               #if DUMP_MP_TABLE
-               Log("mptable = %p", mptable);
-               Log("*mptable = {");
-               Log("\t.Sig = 0x%08x", mptable->Sig);
-               Log("\t.BaseTableLength = 0x%04x", mptable->BaseTableLength);
-               Log("\t.SpecRev = 0x%02x", mptable->SpecRev);
-               Log("\t.Checksum = 0x%02x", mptable->Checksum);
-               Log("\t.OEMID = '%8c'", mptable->OemID);
-               Log("\t.ProductID = '%8c'", mptable->ProductID);
-               Log("\t.OEMTablePtr = %p'", mptable->OEMTablePtr);
-               Log("\t.OEMTableSize = 0x%04x", mptable->OEMTableSize);
-               Log("\t.EntryCount = 0x%04x", mptable->EntryCount);
-               Log("\t.LocalAPICMemMap = 0x%08x", mptable->LocalAPICMemMap);
-               Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen);
-               Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum);
-               Log("}");
-               #endif
-               
-               gpMP_LocalAPIC = (void*)MM_MapHWPages(mptable->LocalAPICMemMap, 1);
-               
-               ents = mptable->Entries;
-               giNumCPUs = 0;
-               
-               for( i = 0; i < mptable->EntryCount; i ++ )
-               {
-                        int    entSize = 0;
-                       switch( ents->Type )
-                       {
-                       case 0: // Processor
-                               entSize = 20;
-                               #if DUMP_MP_TABLE
-                               Log("%i: Processor", i);
-                               Log("\t.APICID = %i", ents->Proc.APICID);
-                               Log("\t.APICVer = 0x%02x", ents->Proc.APICVer);
-                               Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags);
-                               Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature);
-                               Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags);
-                               #endif
-                               
-                               if( !(ents->Proc.CPUFlags & 1) ) {
-                                       Log("DISABLED");
-                                       break;
-                               }
-                               
-                               // Check if there is too many processors
-                               if(giNumCPUs >= MAX_CPUS) {
-                                       giNumCPUs ++;   // If `giNumCPUs` > MAX_CPUS later, it will be clipped
-                                       break;
-                               }
-                               
-                               // Initialise CPU Info
-                               gaAPIC_to_CPU[ents->Proc.APICID] = giNumCPUs;
-                               gaCPUs[giNumCPUs].APICID = ents->Proc.APICID;
-                               gaCPUs[giNumCPUs].State = 0;
-                               giNumCPUs ++;
-                               
-                               // Set BSP Variable
-                               if( ents->Proc.CPUFlags & 2 ) {
-                                       giProc_BootProcessorID = giNumCPUs-1;
-                               }
-                               
-                               break;
-                       
-                       #if DUMP_MP_TABLE >= 2
-                       case 1: // Bus
-                               entSize = 8;
-                               Log("%i: Bus", i);
-                               Log("\t.ID = %i", ents->Bus.ID);
-                               Log("\t.TypeString = '%6C'", ents->Bus.TypeString);
-                               break;
-                       case 2: // I/O APIC
-                               entSize = 8;
-                               Log("%i: I/O APIC", i);
-                               Log("\t.ID = %i", ents->IOAPIC.ID);
-                               Log("\t.Version = 0x%02x", ents->IOAPIC.Version);
-                               Log("\t.Flags = 0x%02x", ents->IOAPIC.Flags);
-                               Log("\t.Addr = 0x%08x", ents->IOAPIC.Addr);
-                               break;
-                       case 3: // I/O Interrupt Assignment
-                               entSize = 8;
-                               Log("%i: I/O Interrupt Assignment", i);
-                               Log("\t.IntType = %i", ents->IOInt.IntType);
-                               Log("\t.Flags = 0x%04x", ents->IOInt.Flags);
-                               Log("\t.SourceBusID = 0x%02x", ents->IOInt.SourceBusID);
-                               Log("\t.SourceBusIRQ = 0x%02x", ents->IOInt.SourceBusIRQ);
-                               Log("\t.DestAPICID = 0x%02x", ents->IOInt.DestAPICID);
-                               Log("\t.DestAPICIRQ = 0x%02x", ents->IOInt.DestAPICIRQ);
-                               break;
-                       case 4: // Local Interrupt Assignment
-                               entSize = 8;
-                               Log("%i: Local Interrupt Assignment", i);
-                               Log("\t.IntType = %i", ents->LocalInt.IntType);
-                               Log("\t.Flags = 0x%04x", ents->LocalInt.Flags);
-                               Log("\t.SourceBusID = 0x%02x", ents->LocalInt.SourceBusID);
-                               Log("\t.SourceBusIRQ = 0x%02x", ents->LocalInt.SourceBusIRQ);
-                               Log("\t.DestLocalAPICID = 0x%02x", ents->LocalInt.DestLocalAPICID);
-                               Log("\t.DestLocalAPICIRQ = 0x%02x", ents->LocalInt.DestLocalAPICIRQ);
-                               break;
-                       default:
-                               Log("%i: Unknown (%i)", i, ents->Type);
-                               break;
-                       #endif
-                       }
-                       ents = (void*)( (Uint)ents + entSize );
-               }
-               
-               if( giNumCPUs > MAX_CPUS ) {
-                       Warning("Too many CPUs detected (%i), only using %i of them", giNumCPUs, MAX_CPUS);
-                       giNumCPUs = MAX_CPUS;
-               }
-               gTSSs = gaTSSs;
-       }
-       else {
-               Log("No MP Table was found, assuming uniprocessor\n");
-               giNumCPUs = 1;
-               gTSSs = &gTSS0;
-       }
-       #else
-       giNumCPUs = 1;
-       gTSSs = &gTSS0;
-       #endif
-       
-       #if !DEBUG_DISABLE_DOUBLEFAULT
-       // Initialise Double Fault TSS
-       gGDT[5].BaseLow = (Uint)&gDoubleFault_TSS & 0xFFFF;
-       gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16;
-       gGDT[5].BaseHi = (Uint)&gDoubleFault_TSS >> 24;
-       
-       // Set double fault IDT to use the new TSS
-       gIDT[8].OffsetLo = 0;
-       gIDT[8].CS = 5<<3;
-       gIDT[8].Flags = 0x8500;
-       gIDT[8].OffsetHi = 0;
-       #endif
-       
-       // Set timer frequency
-       outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
-       outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
-       outb(0x40, (TIMER_DIVISOR>>8)&0xFF);    // High Byte
-       
-       Log_Debug("Proc", "PIT Frequency %i.%03i Hz",
-               TIMER_BASE/TIMER_DIVISOR,
-               ((Uint64)TIMER_BASE*1000/TIMER_DIVISOR)%1000
-               );
-       
-       #if USE_MP
-       // Get the count setting for APIC timer
-       Log("Determining APIC Count");
-       __asm__ __volatile__ ("sti");
-       while( giMP_TimerCount == 0 )   __asm__ __volatile__ ("hlt");
-       __asm__ __volatile__ ("cli");
-       Log("APIC Count %i", giMP_TimerCount);
-       {
-               Uint64  freq = giMP_TimerCount;
-               freq *= TIMER_BASE;
-               freq /= TIMER_DIVISOR;
-               if( (freq /= 1000) < 2*1000)
-                       Log("Bus Frequency %i KHz", freq);
-               else if( (freq /= 1000) < 2*1000)
-                       Log("Bus Frequency %i MHz", freq);
-               else if( (freq /= 1000) < 2*1000)
-                       Log("Bus Frequency %i GHz", freq);
-               else
-                       Log("Bus Frequency %i THz", freq);
-       }
-       
-       // Initialise Normal TSS(s)
-       for(pos=0;pos<giNumCPUs;pos++)
-       {
-       #else
-       pos = 0;
-       #endif
-               gTSSs[pos].SS0 = 0x10;
-               gTSSs[pos].ESP0 = 0;    // Set properly by scheduler
-               gGDT[6+pos].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
-               gGDT[6+pos].BaseMid = ((Uint)(&gTSSs[pos]) >> 16) & 0xFFFF;
-               gGDT[6+pos].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
-       #if USE_MP
-       }
-       #endif
-       
-       // Load the BSP's TSS
-       __asm__ __volatile__ ("ltr %%ax"::"a"(0x30));
-       // Set Current Thread and CPU Number in DR0 and DR1
-       __asm__ __volatile__ ("mov %0, %%db0"::"r"(&gThreadZero));
-       __asm__ __volatile__ ("mov %0, %%db1"::"r"(0));
-       
-       gaCPUs[0].Current = &gThreadZero;
-       gThreadZero.CurCPU = 0;
-       
-       gProcessZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
-       
-       // Create Per-Process Data Block
-       if( !MM_Allocate(MM_PPD_CFG) )
-       {
-               Panic("OOM - No space for initial Per-Process Config");
-       }
-
-       // Initialise SSE support
-       Proc_InitialiseSSE();
-       
-       // Change Stacks
-       Proc_ChangeStack();
-}
-
-#if USE_MP
-/**
- * \brief Start an AP
- */
-void MP_StartAP(int CPU)
-{
-       Log_Log("Proc", "Starting AP %i (APIC %i)", CPU, gaCPUs[CPU].APICID);
-       
-       // Set location of AP startup code and mark for a warm restart
-       *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APWait - (KERNEL_BASE|0xFFFF0);
-       *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
-       outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Set warm reset flag
-       MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);   // Init IPI
-       
-       // Delay
-       inb(0x80); inb(0x80); inb(0x80); inb(0x80);
-       
-       // TODO: Use a better address, preferably registered with the MM
-       // - MM_AllocDMA mabye?
-       // Create a far jump
-       *(Uint8*)(KERNEL_BASE|0x11000) = 0xEA;  // Far JMP
-       *(Uint16*)(KERNEL_BASE|0x11001) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0);     // IP
-       *(Uint16*)(KERNEL_BASE|0x11003) = 0xFFFF;       // CS
-       // Send a Startup-IPI to make the CPU execute at 0x11000 (which we
-       // just filled)
-       MP_SendIPI(gaCPUs[CPU].APICID, 0x11, 6);        // StartupIPI
-       
-       giNumInitingCPUs ++;
-}
-
-void MP_SendIPIVector(int CPU, Uint8 Vector)
-{
-       MP_SendIPI(gaCPUs[CPU].APICID, Vector, 0);
-}
-
-/**
- * \brief Send an Inter-Processor Interrupt
- * \param APICID       Processor's Local APIC ID
- * \param Vector       Argument of some kind
- * \param DeliveryMode Type of signal
- * \note 3A 10.5 "APIC/Handling Local Interrupts"
- */
-void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
-{
-       Uint32  val;
-       
-       // Hi
-       val = (Uint)APICID << 24;
-//     Log("%p = 0x%08x", &gpMP_LocalAPIC->ICR[1], val);
-       gpMP_LocalAPIC->ICR[1].Val = val;
-       // Low (and send)
-       val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
-//     Log("%p = 0x%08x", &gpMP_LocalAPIC->ICR[0], val);
-       gpMP_LocalAPIC->ICR[0].Val = val;
-}
-#endif
-
-void Proc_IdleThread(void *Ptr)
-{
-       tCPU    *cpu = &gaCPUs[GetCPUNum()];
-       cpu->Current->ThreadName = strdup("Idle Thread");
-       Threads_SetPriority( cpu->Current, -1 );        // Never called randomly
-       cpu->Current->Quantum = 1;      // 1 slice quantum
-       for(;;) {
-               __asm__ __volatile__ ("sti");   // Make sure interrupts are enabled
-               __asm__ __volatile__ ("hlt");   // Make sure interrupts are enabled
-               Proc_Reschedule();
-       }
-}
-
-/**
- * \fn void Proc_Start(void)
- * \brief Start process scheduler
- */
-void Proc_Start(void)
-{
-        int    tid;
-       #if USE_MP
-        int    i;
-       #endif
-       
-       #if USE_MP
-       // Start APs
-       for( i = 0; i < giNumCPUs; i ++ )
-       {
-               if(i)   gaCPUs[i].Current = NULL;
-               
-               // Create Idle Task
-               tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
-               
-               // Start the AP
-               if( i != giProc_BootProcessorID ) {
-                       MP_StartAP( i );
-               }
-       }
-       
-       // BSP still should run the current task
-       gaCPUs[0].Current = &gThreadZero;
-       
-       // Start interrupts and wait for APs to come up
-       Log_Debug("Proc", "Waiting for APs to come up");
-       __asm__ __volatile__ ("sti");
-       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
-       #else
-       // Create Idle Task
-       tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
-//     gaCPUs[0].IdleThread = Threads_GetThread(tid);
-       
-       // Set current task
-       gaCPUs[0].Current = &gThreadZero;
-
-       // Start Interrupts (and hence scheduler)
-       __asm__ __volatile__("sti");
-       #endif
-       MM_FinishVirtualInit();
-}
-
-/**
- * \fn tThread *Proc_GetCurThread(void)
- * \brief Gets the current thread
- */
-tThread *Proc_GetCurThread(void)
-{
-       #if USE_MP
-       return gaCPUs[ GetCPUNum() ].Current;
-       #else
-       return gaCPUs[ 0 ].Current;
-       #endif
-}
-
-/**
- * \fn void Proc_ChangeStack(void)
- * \brief Swaps the current stack for a new one (in the proper stack reigon)
- */
-void Proc_ChangeStack(void)
-{
-       Uint    esp, ebp;
-       Uint    tmpEbp, oldEsp;
-       Uint    curBase, newBase;
-
-       __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
-       __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
-
-       oldEsp = esp;
-
-       // Create new KStack
-       newBase = MM_NewKStack();
-       // Check for errors
-       if(newBase == 0) {
-               Panic("What the?? Unable to allocate space for initial kernel stack");
-               return;
-       }
-
-       curBase = (Uint)&Kernel_Stack_Top;
-       
-       LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
-
-       // Get ESP as a used size
-       esp = curBase - esp;
-       LOG("memcpy( %p, %p, 0x%x )", (void*)(newBase - esp), (void*)(curBase - esp), esp );
-       // Copy used stack
-       memcpy( (void*)(newBase - esp), (void*)(curBase - esp), esp );
-       // Get ESP as an offset in the new stack
-       esp = newBase - esp;
-       // Adjust EBP
-       ebp = newBase - (curBase - ebp);
-
-       // Repair EBPs & Stack Addresses
-       // Catches arguments also, but may trash stack-address-like values
-       for(tmpEbp = esp; tmpEbp < newBase; tmpEbp += 4)
-       {
-               if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < curBase)
-                       *(Uint*)tmpEbp += newBase - curBase;
-       }
-       
-       Proc_GetCurThread()->KernelStack = newBase;
-       
-       __asm__ __volatile__ ("mov %0, %%esp"::"r"(esp));
-       __asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
-}
-
-void Proc_ClearProcess(tProcess *Process)
-{
-       MM_ClearSpace(Process->MemState.CR3);
-}
-
-void Proc_ClearThread(tThread *Thread)
-{
-       if(Thread->SavedState.SSE) {
-               free(Thread->SavedState.SSE);
-               Thread->SavedState.SSE = NULL;
-       }
-}
-
-tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
-{
-       Uint    esp;
-       tThread *newThread, *cur;
-       
-       cur = Proc_GetCurThread();
-       newThread = Threads_CloneTCB(0);
-       if(!newThread)  return -1;
-       
-       // Create new KStack
-       newThread->KernelStack = MM_NewKStack();
-       // Check for errors
-       if(newThread->KernelStack == 0) {
-               free(newThread);
-               return -1;
-       }
-
-       esp = newThread->KernelStack;
-       *(Uint*)(esp-=4) = (Uint)Data;  // Data (shadowed)
-       *(Uint*)(esp-=4) = 1;   // Number of params
-       *(Uint*)(esp-=4) = (Uint)Fcn;   // Function to call
-       *(Uint*)(esp-=4) = (Uint)newThread;     // Thread ID
-       
-       newThread->SavedState.ESP = esp;
-       newThread->SavedState.EIP = (Uint)&NewTaskHeader;
-       newThread->SavedState.SSE = NULL;
-//     Log("New (KThread) %p, esp = %p", newThread->SavedState.EIP, newThread->SavedState.ESP);
-       
-//     MAGIC_BREAK();  
-       Threads_AddActive(newThread);
-
-       return newThread->TID;
-}
-
-/**
- * \fn int Proc_Clone(Uint *Err, Uint Flags)
- * \brief Clone the current process
- */
-tPID Proc_Clone(Uint Flags)
-{
-       tThread *newThread;
-       tThread *cur = Proc_GetCurThread();
-       Uint    eip;
-
-       // Sanity, please
-       if( !(Flags & CLONE_VM) ) {
-               Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
-               return -1;
-       }
-       
-       // New thread
-       newThread = Threads_CloneTCB(Flags);
-       if(!newThread)  return -1;
-
-       newThread->KernelStack = cur->KernelStack;
-
-       // Clone state
-       eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
-       if( eip == 0 ) {
-               return 0;
-       }
-       newThread->SavedState.EIP = eip;
-       newThread->SavedState.SSE = NULL;
-       newThread->SavedState.bSSEModified = 0;
-       
-       // Check for errors
-       if( newThread->Process->MemState.CR3 == 0 ) {
-               Log_Error("Proc", "Proc_Clone: MM_Clone failed");
-               Threads_Delete(newThread);
-               return -1;
-       }
-
-       // Add the new thread to the run queue
-       Threads_AddActive(newThread);
-       return newThread->TID;
-}
-
-/**
- * \fn int Proc_SpawnWorker(void)
- * \brief Spawns a new worker thread
- */
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
-{
-       tThread *new;
-       Uint    stack_contents[4];
-       
-       // Create new thread
-       new = Threads_CloneThreadZero();
-       if(!new) {
-               Warning("Proc_SpawnWorker - Out of heap space!\n");
-               return -1;
-       }
-
-       // Create the stack contents
-       stack_contents[3] = (Uint)Data;
-       stack_contents[2] = 1;
-       stack_contents[1] = (Uint)Fcn;
-       stack_contents[0] = (Uint)new;
-       
-       // Create a new worker stack (in PID0's address space)
-       new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
-
-       // Save core machine state
-       new->SavedState.ESP = new->KernelStack - sizeof(stack_contents);
-       new->SavedState.EIP = (Uint)NewTaskHeader;
-       new->SavedState.SSE = NULL;
-       new->SavedState.bSSEModified = 0;
-       
-       // Mark as active
-       new->Status = THREAD_STAT_PREINIT;
-       Threads_AddActive( new );
-       
-       return new->TID;
-}
-
-/**
- * \fn Uint Proc_MakeUserStack(void)
- * \brief Creates a new user stack
- */
-Uint Proc_MakeUserStack(void)
-{
-        int    i;
-       Uint    base = USER_STACK_TOP - USER_STACK_SZ;
-       
-       // Check Prospective Space
-       for( i = USER_STACK_SZ >> 12; i--; )
-               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
-                       break;
-       
-       if(i != -1)     return 0;
-       
-       // Allocate Stack - Allocate incrementally to clean up MM_Dump output
-       for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
-       {
-               if( !MM_Allocate( base + (i<<12) ) )
-               {
-                       Warning("OOM: Proc_MakeUserStack");
-                       return 0;
-               }
-       }
-       
-       return base + USER_STACK_SZ;
-}
-
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
-{
-       Uint    *stack;
-        int    i;
-       const char      **envp = NULL;
-       Uint16  ss, cs;
-       
-       // Copy data to the user stack and free original buffer
-       stack = (void*)Proc_MakeUserStack();
-       stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
-       memcpy( stack, ArgV, DataSize );
-       free(ArgV);
-       
-       // Adjust Arguments and environment
-       if( DataSize )
-       {
-               Uint delta = (Uint)stack - (Uint)ArgV;
-               ArgV = (const char**)stack;
-               for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
-               envp = &ArgV[i+1];
-               for( i = 0; envp[i]; i++ )      envp[i] += delta;
-       }
-       
-       // User Mode Segments
-       ss = 0x23;      cs = 0x1B;
-       
-       // Arguments
-       *--stack = (Uint)envp;
-       *--stack = (Uint)ArgV;
-       *--stack = (Uint)ArgC;
-       *--stack = Base;
-       
-       Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
-}
-
-void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
-{
-       Uint    *stack = (void*)Stack;
-       *--stack = SS;          //Stack Segment
-       *--stack = Stack;       //Stack Pointer
-       *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
-       *--stack = CS;          //Code Segment
-       *--stack = IP;  //EIP
-       //PUSHAD
-       *--stack = 0xAAAAAAAA;  // eax
-       *--stack = 0xCCCCCCCC;  // ecx
-       *--stack = 0xDDDDDDDD;  // edx
-       *--stack = 0xBBBBBBBB;  // ebx
-       *--stack = 0xD1D1D1D1;  // edi
-       *--stack = 0x54545454;  // esp - NOT POPED
-       *--stack = 0x51515151;  // esi
-       *--stack = 0xB4B4B4B4;  // ebp
-       //Individual PUSHs
-       *--stack = SS;  // ds
-       *--stack = SS;  // es
-       *--stack = SS;  // fs
-       *--stack = SS;  // gs
-       
-       __asm__ __volatile__ (
-       "mov %%eax,%%esp;\n\t"  // Set stack pointer
-       "pop %%gs;\n\t"
-       "pop %%fs;\n\t"
-       "pop %%es;\n\t"
-       "pop %%ds;\n\t"
-       "popa;\n\t"
-       "iret;\n\t" : : "a" (stack));
-       for(;;);
-}
-
-/**
- * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
- * \brief Demotes a process to a lower permission level
- * \param Err  Pointer to user's errno
- * \param Dest New Permission Level
- * \param Regs Pointer to user's register structure
- */
-int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
-{
-        int    cpl = Regs->cs & 3;
-       // Sanity Check
-       if(Dest > 3 || Dest < 0) {
-               *Err = -EINVAL;
-               return -1;
-       }
-       
-       // Permission Check
-       if(cpl > Dest) {
-               *Err = -EACCES;
-               return -1;
-       }
-       
-       // Change the Segment Registers
-       Regs->cs = (((Dest+1)<<4) | Dest) - 8;
-       Regs->ss = ((Dest+1)<<4) | Dest;
-       // Check if the GP Segs are GDT, then change them
-       if(!(Regs->ds & 4))     Regs->ds = ((Dest+1)<<4) | Dest;
-       if(!(Regs->es & 4))     Regs->es = ((Dest+1)<<4) | Dest;
-       if(!(Regs->fs & 4))     Regs->fs = ((Dest+1)<<4) | Dest;
-       if(!(Regs->gs & 4))     Regs->gs = ((Dest+1)<<4) | Dest;
-       
-       return 0;
-}
-
-/**
- * \brief Calls a signal handler in user mode
- * \note Used for signals
- */
-void Proc_CallFaultHandler(tThread *Thread)
-{
-       // Rewinds the stack and calls the user function
-       // Never returns
-       Proc_ReturnToUser( Thread->FaultHandler, Thread->CurFaultNum, Thread->KernelStack );
-       for(;;);
-}
-
-void Proc_DumpThreadCPUState(tThread *Thread)
-{
-       if( Thread->CurCPU > -1 )
-       {
-                int    maxBacktraceDistance = 6;
-               tRegs   *regs = NULL;
-               Uint32  *stack;
-               
-               if( Thread->CurCPU != GetCPUNum() ) {
-                       Log("  Currently running");
-                       return ;
-               }
-               
-               // Backtrace to find the IRQ entrypoint
-               // - This will usually only be called by an IRQ, so this should
-               //   work
-               __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
-               while( maxBacktraceDistance -- )
-               {
-                       // [ebp] = oldEbp
-                       // [ebp+4] = retaddr
-                       
-                       if( stack[1] == (tVAddr)&IRQCommon_handled ) {
-                               regs = (void*)stack[2];
-                               break;
-                       }
-                       
-                       stack = (void*)stack[0];
-               }
-               
-               if( !regs ) {
-                       Log("  Unable to find IRQ Entry");
-                       return ;
-               }
-               
-               Log("  at %04x:%08x", regs->cs, regs->eip);
-               return ;
-       }
-       
-       tVAddr  diffFromScheduler = Thread->SavedState.EIP - (tVAddr)SwitchTasks;
-       tVAddr  diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_CloneInt;
-       tVAddr  diffFromSpawn = Thread->SavedState.EIP - (tVAddr)NewTaskHeader;
-       
-       if( diffFromClone > 0 && diffFromClone < 40 )   // When I last checked, .newTask was at .+27
-       {
-               Log("  Creating process");
-               return ;
-       }
-       
-       if( diffFromSpawn == 0 )
-       {
-               Log("  Creating thread");
-               return ;
-       }
-       
-       if( diffFromScheduler > 0 && diffFromScheduler < 128 )  // When I last checked, GetEIP was at .+0x30
-       {
-               // Scheduled out
-               Log("  At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
-               return ;
-       }
-       
-       Log("  Just created (unknown %p)", Thread->SavedState.EIP);
-}
-
-void Proc_Reschedule(void)
-{
-       tThread *nextthread, *curthread;
-        int    cpu = GetCPUNum();
-
-       // TODO: Wait for the lock?
-       if(IS_LOCKED(&glThreadListLock))        return;
-       
-       curthread = Proc_GetCurThread();
-
-       nextthread = Threads_GetNextToRun(cpu, curthread);
-
-       if(!nextthread || nextthread == curthread)
-               return ;
-
-       #if DEBUG_TRACE_SWITCH
-       // HACK: Ignores switches to the idle threads
-       if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
-       {
-               LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
-                       GetCPUNum(),
-                       nextthread, nextthread->TID, nextthread->ThreadName,
-                       nextthread->Process->MemState.CR3,
-                       nextthread->SavedState.EIP,
-                       nextthread->SavedState.ESP
-                       );
-               LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
-       }
-       #endif
-
-       // Update CPU state
-       gaCPUs[cpu].Current = nextthread;
-       gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
-       __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
-
-       // Save FPU/MMX/XMM/SSE state
-       if( curthread && curthread->SavedState.SSE )
-       {
-               Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
-               curthread->SavedState.bSSEModified = 0;
-               Proc_DisableSSE();
-       }
-
-       if( curthread )
-       {
-               SwitchTasks(
-                       nextthread->SavedState.ESP, &curthread->SavedState.ESP,
-                       nextthread->SavedState.EIP, &curthread->SavedState.EIP,
-                       nextthread->Process->MemState.CR3
-                       );
-       }
-       else
-       {
-               SwitchTasks(
-                       nextthread->SavedState.ESP, 0,
-                       nextthread->SavedState.EIP, 0,
-                       nextthread->Process->MemState.CR3
-                       );
-       }
-
-       return ;
-}
-
-/**
- * \fn void Proc_Scheduler(int CPU)
- * \brief Swap current thread and clears dead threads
- */
-void Proc_Scheduler(int CPU)
-{
-#if 0
-       tThread *thread;
-       
-       // If the spinlock is set, let it complete
-       if(IS_LOCKED(&glThreadListLock))        return;
-       
-       // Get current thread
-       thread = gaCPUs[CPU].Current;
-       
-       if( thread )
-       {
-               tRegs   *regs;
-               Uint    ebp;
-               // Reduce remaining quantum and continue timeslice if non-zero
-               if( thread->Remaining-- )
-                       return;
-               // Reset quantum for next call
-               thread->Remaining = thread->Quantum;
-               
-               // TODO: Make this more stable somehow
-               __asm__ __volatile__("mov %%ebp, %0" : "=r" (ebp));
-               regs = (tRegs*)(ebp+(2+2)*4);   // EBP,Ret + CPU,CurThread
-               thread->SavedState.UserCS = regs->cs;
-               thread->SavedState.UserEIP = regs->eip;
-               
-               if(thread->bInstrTrace) {
-                       regs->eflags |= 0x100;  // Set TF
-                       Log("%p De-scheduled", thread);
-               }
-               else
-                       regs->eflags &= ~0x100; // Clear TF
-       }
-
-       // TODO: Ack timer?
-       #if USE_MP
-       if( GetCPUNum() )
-               gpMP_LocalAPIC->EOI.Val = 0;
-       else
-       #endif
-               outb(0x20, 0x20);
-       __asm__ __volatile__ ("sti");
-       Proc_Reschedule();
-#endif
-}
-
-// === EXPORTS ===
-EXPORT(Proc_SpawnWorker);
diff --git a/Kernel/arch/x86/start.asm b/Kernel/arch/x86/start.asm
deleted file mode 100644 (file)
index b6026de..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-; AcessOS Microkernel Version
-; Start.asm
-
-[bits 32]
-
-KERNEL_BASE    equ 0xC0000000
-%define MAX_CPUS       16
-
-[extern __load_addr]
-[extern __bss_start]
-[extern gKernelEnd]
-[section .multiboot]
-mboot:
-       ; Multiboot macros to make a few lines later more readable
-       MULTIBOOT_PAGE_ALIGN    equ 1<<0
-       MULTIBOOT_MEMORY_INFO   equ 1<<1
-       MULTIBOOT_HEADER_MAGIC  equ 0x1BADB002
-       MULTIBOOT_HEADER_FLAGS  equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
-       MULTIBOOT_CHECKSUM      equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
-       
-       ; This is the GRUB Multiboot header. A boot signature
-       dd MULTIBOOT_HEADER_MAGIC
-       dd MULTIBOOT_HEADER_FLAGS
-       dd MULTIBOOT_CHECKSUM
-       dd mboot; - KERNEL_BASE ;Location of Multiboot Header
-       
-; Multiboot 2 Header
-;mboot2:
-;      MULTIBOOT2_HEADER_MAGIC equ 0xE85250D6
-;      MULTIBOOT2_HEADER_ARCH  equ 0
-;      MULTIBOOT2_HEADER_LENGTH        equ (mboot2_end-mboot2)
-;      MULTIBOOT2_CHECKSUM     equ -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_HEADER_ARCH + MULTIBOOT2_HEADER_LENGTH)
-;      
-;      dd MULTIBOOT2_HEADER_MAGIC
-;      dd MULTIBOOT2_HEADER_ARCH
-;      dd MULTIBOOT2_HEADER_LENGTH
-;      dd MULTIBOOT2_CHECKSUM
-;      ; MBoot2 Address Header
-;      dw      2, 0
-;      dd      8 + 16
-;      dd      mboot2  ; Location of Multiboot Header
-;      dd      __load_addr - KERNEL_BASE       ; Kernel Load base
-;      dd      __bss_start - KERNEL_BASE       ; Kernel Data End
-;      dd      gKernelEnd - KERNEL_BASE        ; Kernel BSS End
-;      ; MBoot2 Entry Point Tag
-;      dw      3, 0
-;      dd      8 + 4
-;      dd      start - KERNEL_BASE
-;      ; MBoot2 Module Alignment Tag
-;      dw      6, 0
-;      dd      12      ; ???
-;      dd      0       ; Search me, seems it wants padding
-;      ; Terminator
-;      dw      0, 0
-;      dd      8
-;mboot2_end:
-       
-[section .text]
-[extern kmain]
-[global start]
-start:
-       ; Just show we're here
-       mov WORD [0xB8000], 0x0741      ; 'A'
-       
-       ; Set up stack
-       mov esp, Kernel_Stack_Top
-       
-       ; Start Paging
-       mov ecx, gaInitPageDir - KERNEL_BASE
-       mov cr3, ecx
-       mov ecx, cr0
-       or ecx, 0x80010000      ; PG and WP
-       mov cr0, ecx
-       
-       mov WORD [0xB8002], 0x0763      ; 'c'
-       
-       ; Set GDT
-       lgdt [gGDTPtr]
-       mov cx, 0x10    ; PL0 Data
-       mov ss, cx
-       mov ds, cx
-       mov es, cx
-       mov gs, cx
-       mov fs, cx
-       mov WORD [0xB8004], 0x0765      ; 'e'
-       jmp 0x08:.higher_half
-.higher_half:
-       
-       mov WORD [0xB8006], 0x0773      ; 's'
-       mov WORD [0xB8008], 0x0773      ; 's'
-
-       ; Call the kernel
-       push ebx        ; Multiboot Info
-       push eax        ; Multiboot Magic Value
-       mov WORD [0xB800A], 0x0732      ; '2'
-       call kmain
-
-       ; Halt the Machine
-       cli
-.hlt:
-       hlt
-       jmp .hlt
-
-; 
-; Multiprocessing AP Startup Code (Must be within 0 - 0x10FFF0)
-;
-%if USE_MP
-[extern gIDTPtr]
-[extern gpMP_LocalAPIC]
-[extern giMP_TimerCount]
-[extern gaAPIC_to_CPU]
-[extern gaCPUs]
-[extern giNumInitingCPUs]
-[extern MM_NewKStack]
-[extern Proc_InitialiseSSE]
-
-lGDTPtr:       ; Local GDT Pointer
-       dw      3*8-1
-       dd      gGDT-KERNEL_BASE
-
-[bits 16]
-[global APWait]
-APWait:
-       ;xchg bx, bx
-.hlt:
-       ;hlt
-       jmp .hlt
-[extern Proc_Reschedule]
-[global APStartup]
-APStartup:
-       ;xchg bx, bx    ; MAGIC BREAK!
-       ; Load initial GDT
-       mov ax, 0xFFFF
-       mov ds, ax
-       lgdt [DWORD ds:lGDTPtr-KERNEL_BASE-0xFFFF0]
-       ; Enable PMode in CR0
-       mov eax, cr0
-       or al, 1
-       mov cr0, eax
-       ; Jump into PMode
-       jmp 08h:DWORD .ProtectedMode-KERNEL_BASE
-[bits 32]
-.ProtectedMode:
-       ; Load segment registers
-       mov ax, 0x10
-       mov ss, ax
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       ; Start Paging
-       mov eax, gaInitPageDir - KERNEL_BASE
-       mov cr3, eax
-       mov eax, cr0
-       or eax, 0x80010000      ; PG and WP
-       mov cr0, eax
-       ; Jump to higher half
-       lea eax, [.higherHalf]
-       jmp eax
-.higherHalf:
-       ; Load True GDT & IDT
-       lgdt [gGDTPtr]
-       lidt [gIDTPtr]
-
-       mov ebp, [gpMP_LocalAPIC]
-       mov ebx, [ebp+0x20]     ; Read ID
-       shr ebx, 24
-       ;xchg bx, bx    ; MAGIC BREAK
-       ; BL is now local APIC ID
-       mov cl, BYTE [gaAPIC_to_CPU+ebx]
-       xor ebx, ebx
-       mov bl, cl
-       ; BL is now the CPU ID
-       mov dr1, ebx    ; Save the CPU number to a debug register
-       ; Mark the CPU as up
-       mov BYTE [gaCPUs+ebx*8+1], 1
-       ; Decrement the remaining CPU count
-       dec DWORD [giNumInitingCPUs]
-       
-       ; Create a stack
-       lea edx, [ebx+1]
-       shl edx, 5+2    ; *32 *4
-       lea esp, [gInitAPStacks+edx]
-       call MM_NewKStack
-       mov esp, eax
-       
-       ; Set TSS
-       lea ecx, [ebx*8+0x30]
-       ltr cx
-       
-       ;xchg bx, bx    ; MAGIC_BREAK
-       ; Enable Local APIC
-       mov DWORD [ebp+0x0F0], 0x000001EF       ; Spurious Interrupt Vector (0xEF)
-       mov ecx, DWORD [giMP_TimerCount]
-       mov DWORD [ebp+0x380], ecx      ; Set Initial Count
-       mov DWORD [ebp+0x320], 0x000200EE       ; Enable timer on IVT#0xEE
-       mov DWORD [ebp+0x330], 0x000100E0       ; ##Enable thermal sensor on IVT#0xE0
-       mov DWORD [ebp+0x340], 0x000100D0       ; ##Enable performance counters on IVT#0xD0
-       mov DWORD [ebp+0x350], 0x000100D1       ; ##Enable LINT0 on IVT#0xD1
-       mov DWORD [ebp+0x360], 0x000100D2       ; ##Enable LINT1 on IVT#0xD2
-       mov DWORD [ebp+0x370], 0x000100E1       ; ##Enable Error on IVT#0xE1
-       mov DWORD [ebp+0x0B0], 0        ; Send an EOI (just in case)
-
-       ; Initialise SSE support
-       call Proc_InitialiseSSE
-       
-       ; CPU is now marked as initialised
-
-.hlt:
-       sti
-       call Proc_Reschedule    
-       hlt
-       jmp .hlt
-%endif
-
-[global GetEIP]
-GetEIP:
-       mov eax, [esp]
-       ret
-
-; int CallWithArgArray(void *Ptr, int NArgs, Uint *Args)
-; Call a function passing the array as arguments
-[global CallWithArgArray]
-CallWithArgArray:
-       push ebp
-       mov ebp, esp
-       mov ecx, [ebp+12]       ; Get NArgs
-       mov edx, [ebp+16]
-
-.top:
-       mov eax, [edx+ecx*4-4]
-       push eax
-       loop .top
-       
-       mov eax, [ebp+8]
-       call eax
-       lea esp, [ebp]
-       pop ebp
-       ret
-
-[section .data]
-; GDT
-GDT_SIZE       equ     (1+2*2+1+MAX_CPUS)*8
-[global gGDT]
-gGDT:
-       ; PL0 - Kernel
-       ; PL3 - User
-       dd 0x00000000, 0x00000000       ; 00 NULL Entry
-       dd 0x0000FFFF, 0x00CF9A00       ; 08 PL0 Code
-       dd 0x0000FFFF, 0x00CF9200       ; 10 PL0 Data
-       dd 0x0000FFFF, 0x00CFFA00       ; 18 PL3 Code
-       dd 0x0000FFFF, 0x00CFF200       ; 20 PL3 Data
-       dd 26*4-1, 0x00408900   ; 28 Double Fault TSS
-       times MAX_CPUS  dd 26*4-1, 0x00408900   ; 30+ TSSes
-[global gGDTPtr]
-gGDTPtr:
-       dw      GDT_SIZE-1
-       dd      gGDT
-
-[section .initpd]
-[global gaInitPageDir]
-[global gaInitPageTable]
-align 4096
-gaInitPageDir:
-       dd      gaInitPageTable-KERNEL_BASE+3   ; 0x000 - Low kernel
-       times 0x300-0x000-1     dd      0
-       dd      gaInitPageTable-KERNEL_BASE+3   ; 0xC00 - High kernel
-       times 0x3F0-0x300-1     dd      0
-       dd      gaInitPageDir-KERNEL_BASE+3     ; 0xFC0 - Fractal
-       times 0x400-0x3F0-1     dd      0
-align 4096
-gaInitPageTable:
-       %assign i 0
-       %rep 1024
-       dd      i*0x1000+3
-       %assign i i+1
-       %endrep
-[global Kernel_Stack_Top]
-ALIGN 4096
-       times 1024      dd      0
-Kernel_Stack_Top:
-gInitAPStacks:
-       times 32*MAX_CPUS       dd      0
-
-; vim: ft=nasm ts=8    
diff --git a/Kernel/arch/x86/time.c b/Kernel/arch/x86/time.c
deleted file mode 100644 (file)
index 9b59b30..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Acess2 Kernel
- * Timekeeping
- * arch/x86/time.c
- */
-#include <acess.h>
-
-// === MACROS ===
-#define        TIMER_QUANTUM   100
-// 2^(15-rate), 14: 2Hz, 5: 1024Hz, 2: 8192Hz
-// (Max: 14, Min: 2) - 14 = 2Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
-//#define TIMER_RATE   10      // 32 Hz
-//#define TIMER_RATE   12      // 8 Hz
-#define TIMER_RATE     14      // 2 Hz - Lowest
-#define TIMER_FREQ     (0x8000>>TIMER_RATE)    //Hz
-#define MS_PER_TICK_WHOLE      (1000/(TIMER_FREQ))
-#define MS_PER_TICK_FRACT      ((0x80000000*(1000%TIMER_FREQ))/TIMER_FREQ)
-
-// === IMPORTS ===
-extern volatile Sint64 giTimestamp;
-extern volatile Uint64 giTicks;
-extern volatile Uint64 giPartMiliseconds;
-extern void    Timer_CallTimers(void);
-
-// === GLOBALS ===
-volatile Uint64        giTime_TSCAtLastTick = 0;
-volatile Uint64        giTime_TSCPerTick = 0;
-
-// === PROTOTYPES ===
-//Sint64       now(void);
- int   Time_Setup(void);
-void   Time_Interrupt(int IRQ, void *Ptr);
-Uint64 Time_ReadTSC(void);
-
-// === CODE ===
-/**
- * \fn Sint64 now()
- * \brief Return the current timestamp
- */
-Sint64 now(void)
-{
-       Uint64  tsc = Time_ReadTSC();
-       tsc -= giTime_TSCAtLastTick;
-       tsc *= MS_PER_TICK_WHOLE;
-       if( giTime_TSCPerTick ) {
-               tsc /= giTime_TSCPerTick;
-       }
-       else
-               tsc = 0;
-       return giTimestamp + tsc;
-}
-
-/**
- * \fn int Time_Setup(void)
- * \brief Sets the system time from the Realtime-Clock
- */
-int Time_Setup(void)
-{
-       Uint8   val;
-       
-       Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
-               TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
-       
-       outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
-       __asm__ __volatile__ ("cli");   // Disable normal interrupts
-       
-       // Set IRQ8 firing rate
-       outb(0x70, 0x0A);       // Set the index to register A
-       val = inb(0x71); // Get the current value of register A
-       val &= 0xF0;
-       val |= TIMER_RATE+1;
-       outb(0x70, 0x0A); // Reset index to A
-       outb(0x71, val);        // Update the timer rate
-               
-       // Enable IRQ8
-       outb(0x70, 0x0B);       // Set the index to register B
-       val = inb(0x71);        // Read the current value of register B
-       outb(0x70, 0x0B);       // Set the index again (a read will reset the index to register D)
-       outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
-       
-       __asm__ __volatile__ ("sti");   // Re-enable normal interrupts
-       outb(0x70, inb(0x70)|0x80);     // Re-enable NMIs
-       
-       // Install IRQ Handler
-       IRQ_AddHandler(8, Time_Interrupt, NULL);
-       
-       // Make sure the RTC actually fires
-       outb(0x70, 0x0C); // Select register C
-       inb(0x71);      // Just throw away contents.
-       
-       return 0;
-}
-
-/**
- * \brief Called on the timekeeping IRQ
- */
-void Time_Interrupt(int IRQ, void *Ptr)
-{
-       Uint64  curTSC = Time_ReadTSC();
-       
-       if( giTime_TSCAtLastTick )
-       {
-               giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
-       }
-       giTime_TSCAtLastTick = curTSC;
-       
-       giTicks ++;
-       giTimestamp += MS_PER_TICK_WHOLE;
-       giPartMiliseconds += MS_PER_TICK_FRACT;
-       if(giPartMiliseconds > 0x80000000) {
-               giTimestamp ++;
-               giPartMiliseconds -= 0x80000000;
-       }
-       
-       Timer_CallTimers();
-
-       // Make sure the RTC Fires again
-       outb(0x70, 0x0C); // Select register C
-       inb(0x71);      // Just throw away contents.
-}
-
-Uint64 Time_ReadTSC(void)
-{
-       Uint32  a, d;
-       __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
-       return ((Uint64)d << 32) | a;
-}
diff --git a/Kernel/arch/x86/vm8086.c b/Kernel/arch/x86/vm8086.c
deleted file mode 100644 (file)
index 6134862..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Acess2 VM8086 Driver
- * - By John Hodge (thePowersGang)
- */
-#define DEBUG  0
-#include <acess.h>
-#include <vm8086.h>
-#include <modules.h>
-#include <hal_proc.h>
-#include <semaphore.h>
-
-// === CONSTANTS ===
-#define VM8086_MAGIC_CS        0xFFFF
-#define VM8086_MAGIC_IP        0x0010
-#define VM8086_STACK_SEG       0x9F00
-#define VM8086_STACK_OFS       0x0AFE
-enum eVM8086_Opcodes
-{
-       VM8086_OP_PUSHF   = 0x9C,
-       VM8086_OP_POPF    = 0x9D,
-       VM8086_OP_INT_I   = 0xCD,
-       VM8086_OP_IRET    = 0xCF,
-       VM8086_OP_IN_AD   = 0xEC,
-       VM8086_OP_IN_ADX  = 0xED,
-       VM8086_OP_OUT_AD  = 0xEE,
-       VM8086_OP_OUT_ADX = 0xEF
-};
-#define VM8086_PAGES_PER_INST  4
-
-#define VM8086_BLOCKSIZE       128
-#define VM8086_BLOCKCOUNT      ((0x9F000-0x10000)/VM8086_BLOCKSIZE)
-
-// === TYPES ===
-struct sVM8086_InternalData
-{
-       struct {
-               Uint32  Bitmap; // 32 sections = 128 byte blocks
-               tVAddr  VirtBase;
-               tPAddr  PhysAddr;
-       }       AllocatedPages[VM8086_PAGES_PER_INST];
-};
-
-// === PROTOTYPES ===
- int   VM8086_Install(char **Arguments);
-void   VM8086_GPF(tRegs *Regs);
-//tVM8086      *VM8086_Init(void);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL);
-tMutex glVM8086_Process;
-tSemaphore     gVM8086_TaskComplete;
-tSemaphore     gVM8086_TasksToDo;
-tPID   gVM8086_WorkerPID;
-tTID   gVM8086_CallingThread;
-tVM8086        volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions
-Uint32 gaVM8086_MemBitmap[VM8086_BLOCKCOUNT/32];
-
-// === FUNCTIONS ===
-int VM8086_Install(char **Arguments)
-{
-       tPID    pid;    
-
-       Semaphore_Init(&gVM8086_TasksToDo, 0, 10, "VM8086", "TasksToDo");
-       
-       // Lock to avoid race conditions
-       Mutex_Acquire( &glVM8086_Process );
-       
-       // Create BIOS Call process
-       pid = Proc_Clone(CLONE_VM);
-       Log_Debug("VM8086", "pid = %i", pid);
-       if(pid == -1)
-       {
-               Log_Error("VM8086", "Unable to clone kernel into VM8086 worker");
-               return MODULE_ERR_MISC;
-       }
-       if(pid == 0)
-       {
-               Uint    * volatile stacksetup;  // Initialising Stack
-               Uint16  * volatile rmstack;     // Real Mode Stack
-                int    i;
-
-               Log_Debug("VM8086", "Initialising worker");     
-       
-               // Set Image Name
-               Threads_SetName("VM8086");
-
-               // Map ROM Area
-               for(i=0xA0;i<0x100;i++) {
-                       MM_Map( i * 0x1000, i * 0x1000 );
-               }
-               MM_Map( 0, 0 ); // IVT / BDA
-               // Map (but allow allocation) of 0x1000 - 0x9F000
-               // - So much hack, it isn't funny
-               for(i=1;i<0x9F;i++) {
-                       MM_Map( i * 0x1000, i * 0x1000 );
-                       MM_DerefPhys( i * 0x1000 );     // Above
-                       while(MM_GetRefCount(i*0x1000))
-                               MM_DerefPhys( i * 0x1000 );     // Phys setup
-               }
-               MM_Map( 0x9F000, 0x9F000 );     // Stack / EBDA
-               // System Stack / Stub
-               if( MM_Allocate( 0x100000 ) == 0 ) {
-                       Log_Error("VM8086", "Unable to allocate memory for stack/stub");
-                       gVM8086_WorkerPID = 0;
-                       Threads_Exit(0, 1);
-               }
-               
-               *(Uint8*)(0x100000) = VM8086_OP_IRET;
-               *(Uint8*)(0x100001) = 0x07;     // POP ES
-               *(Uint8*)(0x100002) = 0x1F;     // POP DS
-               *(Uint8*)(0x100003) = 0xCB;     // RET FAR
-               
-               rmstack = (Uint16*)(VM8086_STACK_SEG*16 + VM8086_STACK_OFS);
-               rmstack--;      *rmstack = 0xFFFF;      //CS
-               rmstack--;      *rmstack = 0x0010;      //IP
-               
-               // Setup Stack
-               stacksetup = (Uint*)0x101000;
-               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // GS
-               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // FS
-               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // DS
-               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // ES
-               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // SS
-               stacksetup--;   *stacksetup = VM8086_STACK_OFS-2;       // SP
-               stacksetup--;   *stacksetup = 0x20202;  // FLAGS
-               stacksetup--;   *stacksetup = 0xFFFF;   // CS
-               stacksetup--;   *stacksetup = 0x10;     // IP
-               stacksetup--;   *stacksetup = 0xAAAA;   // AX
-               stacksetup--;   *stacksetup = 0xCCCC;   // CX
-               stacksetup--;   *stacksetup = 0xDDDD;   // DX
-               stacksetup--;   *stacksetup = 0xBBBB;   // BX
-               stacksetup--;   *stacksetup = 0x5454;   // SP
-               stacksetup--;   *stacksetup = 0xB4B4;   // BP
-               stacksetup--;   *stacksetup = 0x5151;   // SI
-               stacksetup--;   *stacksetup = 0xD1D1;   // DI
-               stacksetup--;   *stacksetup = 0x20|3;   // DS - Kernel
-               stacksetup--;   *stacksetup = 0x20|3;   // ES - Kernel
-               stacksetup--;   *stacksetup = 0x20|3;   // FS
-               stacksetup--;   *stacksetup = 0x20|3;   // GS
-               __asm__ __volatile__ (
-               "mov %%eax,%%esp;\n\t"  // Set stack pointer
-               "pop %%gs;\n\t"
-               "pop %%fs;\n\t"
-               "pop %%es;\n\t"
-               "pop %%ds;\n\t"
-               "popa;\n\t"
-               "iret;\n\t" : : "a" (stacksetup));
-               for(;;);        // Shouldn't be reached
-       }
-       
-       gVM8086_WorkerPID = pid;
-
-       // It's released when the GPF fires
-       Mutex_Acquire( &glVM8086_Process );
-       Mutex_Release( &glVM8086_Process );
-       
-       // Worker killed itself
-       if( gVM8086_WorkerPID != pid ) {
-               return MODULE_ERR_MISC;
-       }
-       
-       return MODULE_ERR_OK;
-}
-
-void VM8086_GPF(tRegs *Regs)
-{
-       Uint8   opcode;
-       
-//     Log_Log("VM8086", "GPF - %04x:%04x", Regs->cs, Regs->eip);
-       
-       if(Regs->eip == VM8086_MAGIC_IP && Regs->cs == VM8086_MAGIC_CS
-       && Threads_GetPID() == gVM8086_WorkerPID)
-       {
-               if( gpVM8086_State == (void*)-1 ) {
-                       Log_Log("VM8086", "Worker thread ready and waiting");
-                       gpVM8086_State = NULL;
-                       Mutex_Release( &glVM8086_Process );     // Release lock obtained in VM8086_Install
-               }
-//             Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i",
-//                     gpVM8086_State, gVM8086_CallingThread);
-               if( gpVM8086_State ) {
-                       gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx;
-                       gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx;
-                       gpVM8086_State->BP = Regs->ebp;
-                       gpVM8086_State->SI = Regs->esi; gpVM8086_State->DI = Regs->edi;
-                       gpVM8086_State->DS = Regs->ds;  gpVM8086_State->ES = Regs->es;
-                       gpVM8086_State = NULL;
-                       // Wake the caller
-                       Semaphore_Signal(&gVM8086_TaskComplete, 1);
-               }
-               
-               //Log_Log("VM8086", "Waiting for something to do");
-               __asm__ __volatile__ ("sti");
-               Semaphore_Wait(&gVM8086_TasksToDo, 1);
-               
-               //Log_Log("VM8086", "We have a task (%p)", gpVM8086_State);
-               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS;
-               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP;
-               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS;
-               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP;
-               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS;
-               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES;
-               
-               // Set Registers
-               Regs->eip = 0x11;       Regs->cs = 0xFFFF;
-               Regs->eax = gpVM8086_State->AX; Regs->ecx = gpVM8086_State->CX;
-               Regs->edx = gpVM8086_State->DX; Regs->ebx = gpVM8086_State->BX;
-               Regs->esi = gpVM8086_State->SI; Regs->edi = gpVM8086_State->DI;
-               Regs->ebp = gpVM8086_State->BP;
-               Regs->ds = 0x23;        Regs->es = 0x23;
-               Regs->fs = 0x23;        Regs->gs = 0x23;
-               return ;
-       }
-       
-       opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip) );
-       Regs->eip ++;
-       switch(opcode)
-       {
-       case VM8086_OP_PUSHF:   //PUSHF
-               Regs->esp -= 2;
-               *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eflags & 0xFFFF;
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated PUSHF");
-               #endif
-               break;
-       case VM8086_OP_POPF:    //POPF
-               // Changing IF is not allowed
-               Regs->eflags &= 0xFFFF0202;
-               Regs->eflags |= *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) );
-               Regs->esp += 2;
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated POPF");
-               #endif
-               break;
-       
-       case VM8086_OP_INT_I:   //INT imm8
-               {
-                int    id;
-               id = *(Uint8*)( Regs->cs*16 +(Regs->eip&0xFFFF));
-               Regs->eip ++;
-               
-               Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs;
-               Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip;
-               
-               Regs->cs = *(Uint16*)(4*id + 2);
-               Regs->eip = *(Uint16*)(4*id);
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated INT 0x%x", id);
-               #endif
-               }
-               break;
-       
-       case VM8086_OP_IRET:    //IRET
-               Regs->eip = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) );     Regs->esp += 2;
-               Regs->cs  = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) );     Regs->esp += 2;
-               #if TRACE_EMU
-               Log_Debug("VM8086", "IRET to %04x:%04x", Regs->cs, Regs->eip);
-               #endif
-               break;
-       
-       
-       case VM8086_OP_IN_AD:   //IN AL, DX
-               Regs->eax &= 0xFFFFFF00;
-               Regs->eax |= inb(Regs->edx&0xFFFF);
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated IN AL, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
-               #endif
-               break;
-       case VM8086_OP_IN_ADX:  //IN AX, DX
-               Regs->eax &= 0xFFFF0000;
-               Regs->eax |= inw(Regs->edx&0xFFFF);
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated IN AX, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
-               #endif
-               break;
-               
-       case VM8086_OP_OUT_AD:  //OUT DX, AL
-               outb(Regs->edx&0xFFFF, Regs->eax&0xFF);
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated OUT DX, AL (*0x%04x = 0x%02x)\n", Regs->edx&0xFFFF, Regs->eax&0xFF);
-               #endif
-               break;
-       case VM8086_OP_OUT_ADX: //OUT DX, AX
-               outw(Regs->edx&0xFFFF, Regs->eax&0xFFFF);
-               #if TRACE_EMU
-               Log_Debug("VM8086", "Emulated OUT DX, AX (*0x%04x = 0x%04x)\n", Regs->edx&0xFFFF, Regs->eax&0xFFFF);
-               #endif
-               break;
-               
-       // TODO: Decide on allowing VM8086 Apps to enable/disable interrupts
-       case 0xFA:      //CLI
-               break;
-       case 0xFB:      //STI
-               break;
-       
-       case 0x66:
-               opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip&0xFFFF));
-               switch( opcode )
-               {
-               case VM8086_OP_IN_ADX:  //IN AX, DX
-                       Regs->eax = ind(Regs->edx&0xFFFF);
-                       #if TRACE_EMU
-                       Log_Debug("VM8086", "Emulated IN EAX, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
-                       #endif
-                       break;
-               case VM8086_OP_OUT_ADX: //OUT DX, AX
-                       outd(Regs->edx&0xFFFF, Regs->eax);
-                       #if TRACE_EMU
-                       Log_Debug("VM8086", "Emulated OUT DX, EAX (*0x%04x = 0x%08x)\n", Regs->edx&0xFFFF, Regs->eax);
-                       #endif
-                       break;
-               default:
-                       Log_Error("VM8086", "Error - Unknown opcode 66 %02x caused a GPF at %04x:%04x",
-                               Regs->cs, Regs->eip,
-                               opcode
-                               );
-                       // Force an end to the call
-                       Regs->cs = VM8086_MAGIC_CS;
-                       Regs->eip = VM8086_MAGIC_IP;
-                       break;
-               }
-               break;
-       
-       default:
-               Log_Error("VM8086", "Error - Unknown opcode %02x caused a GPF at %04x:%04x",
-                       opcode, Regs->cs, Regs->eip);
-               // Force an end to the call
-               Regs->cs = VM8086_MAGIC_CS;
-               Regs->eip = VM8086_MAGIC_IP;
-               break;
-       }
-}
-
-/**
- * \brief Create an instance of the VM8086 Emulator
- */
-tVM8086 *VM8086_Init(void)
-{
-       tVM8086 *ret;
-       ret = calloc( 1, sizeof(tVM8086) + sizeof(struct sVM8086_InternalData) );
-       ret->Internal = (void*)((tVAddr)ret + sizeof(tVM8086));
-       return ret;
-}
-
-void VM8086_Free(tVM8086 *State)
-{
-        int    i;
-       for( i = VM8086_PAGES_PER_INST; i --; )
-               MM_UnmapHWPages( State->Internal->AllocatedPages[i].VirtBase, 1);
-       free(State);
-}
-
-void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset)
-{
-        int    i, j, base = 0;
-        int    nBlocks, rem;
-       
-       Size = (Size + 127) & ~127;
-       nBlocks = Size / 128;
-       
-       if(Size > 4096) return NULL;
-       
-       for( i = 0; i < VM8086_PAGES_PER_INST; i++ )
-       {
-               if( State->Internal->AllocatedPages[i].VirtBase == 0 )  continue;
-               
-               
-               //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap);
-               
-               rem = nBlocks;
-               base = 0;
-               // Scan the bitmap for a free block
-               for( j = 0; j < 32; j++ ) {
-                       if( State->Internal->AllocatedPages[i].Bitmap & (1 << j) ) {
-                               base = j+1;
-                               rem = nBlocks;
-                       }
-                       
-                       rem --;
-                       if(rem == 0)    // Goodie, there's a gap
-                       {
-                               for( j = 0; j < nBlocks; j++ )
-                                       State->Internal->AllocatedPages[i].Bitmap |= 1 << (base + j);
-                               *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16 + base * 8;
-                               *Offset = 0;
-                               LOG("Allocated at #%i,%04x", i, base*128);
-                               LOG(" - %x:%x", *Segment, *Offset);
-                               return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 );
-                       }
-               }
-       }
-       
-       // No pages with free space?, allocate a new one
-       for( i = 0; i < VM8086_PAGES_PER_INST; i++ )
-       {
-               if( State->Internal->AllocatedPages[i].VirtBase == 0 )  break;
-       }
-       // Darn, we can't allocate any more
-       if( i == VM8086_PAGES_PER_INST ) {
-               Log_Warning("VM8086", "Out of pages in %p", State);
-               return NULL;
-       }
-       
-       State->Internal->AllocatedPages[i].VirtBase = MM_AllocDMA(
-               1, 20, &State->Internal->AllocatedPages[i].PhysAddr);
-       State->Internal->AllocatedPages[i].Bitmap = 0;
-               
-       for( j = 0; j < nBlocks; j++ )
-               State->Internal->AllocatedPages[i].Bitmap |= 1 << j;
-       LOG("AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap);
-       *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16;
-       *Offset = 0;
-       LOG(" - %x:%x", *Segment, *Offset);
-       return (void*) State->Internal->AllocatedPages[i].VirtBase;
-}
-
-void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset)
-{
-       return (void*)( KERNEL_BASE + Segment*16 + Offset );
-}
-
-void VM8086_Int(tVM8086 *State, Uint8 Interrupt)
-{
-       State->IP = *(Uint16*)(KERNEL_BASE+4*Interrupt);
-       State->CS = *(Uint16*)(KERNEL_BASE+4*Interrupt+2);
-
-//     Log_Debug("VM8086", "Software interrupt %i to %04x:%04x", Interrupt, State->CS, State->IP);
-       
-       Mutex_Acquire( &glVM8086_Process );
-       
-       gpVM8086_State = State;
-       gVM8086_CallingThread = Threads_GetTID();
-       Semaphore_Signal(&gVM8086_TasksToDo, 1);
-
-       Semaphore_Wait(&gVM8086_TaskComplete, 1);
-       
-       Mutex_Release( &glVM8086_Process );
-}
diff --git a/Kernel/arch/x86_64/Makefile b/Kernel/arch/x86_64/Makefile
deleted file mode 100644 (file)
index a72216a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Acess2 Kernel
-# i386 Architecture Makefile
-# arch/i386/Makefile
-
-MAX_CPUS := 4
-
-AS_SUFFIX = asm
-
-CPPFLAGS       := -DMAX_CPUS=$(MAX_CPUS) -D USE_MP=0
-CFLAGS         := $(KERNEL_CFLAGS) -mno-sse -mno-mmx
-ASFLAGS                := -f elf64 -D MAX_CPUS=$(MAX_CPUS) -D USE_MP=0
-LDFLAGS        := -nostdlib -nodefaultlibs
-
-ifeq ($(ARCH),amd64)
-       ASFLAGS += -D AMD64=1
-       CPPFLAGS += -DAMD64=1
-else
-       ifeq ($(ARCH),x86_64)
-               ASFLAGS += -D AMD64=0 -D X86_64=1
-               CPPFLAGS += -DAMD64=0 -DX86_64=1
-       endif
-endif
-       
-
-A_OBJ := start32.ao start64.ao desctab.ao proc.ao
-A_OBJ += main.o lib.o proc.o mm_virt.o mm_phys.o
-A_OBJ += kernelpanic.o errors.o time.o pci.o
-A_OBJ += vm8086.o
-# rme.o
-
-POSTBUILD = objcopy $(BIN) -F elf32-i386 $(BIN)
diff --git a/Kernel/arch/x86_64/desctab.asm b/Kernel/arch/x86_64/desctab.asm
deleted file mode 100644 (file)
index 6e8aa63..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-;
-;
-;
-%include "arch/x86_64/include/common.inc.asm"
-[BITS 64]
-
-[extern Log]
-[extern gGDTPtr]
-[extern gGDT]
-
-%define NUM_IRQ_CALLBACKS      4
-
-MM_LOCALAPIC   equ     0xFFFFFD0000000000
-
-[section .text]
-[global Desctab_Init]
-Desctab_Init:  
-       ; Save to make following instructions smaller
-       mov rdi, gIDT
-       
-       ; Set an IDT entry to a callback
-       %macro SETIDT 2
-       mov rax, %2
-       mov WORD [rdi + %1*16], ax
-       shr rax, 16
-       mov WORD [rdi + %1*16 + 6], ax
-       shr rax, 16
-       mov DWORD [rdi + %1*16 + 8], eax
-       ; Enable
-       mov ax, WORD [rdi + %1*16 + 4]
-       or  ax, 0x8000
-       mov WORD [rdi + %1*16 + 4], ax
-       %endmacro
-       
-       ; Install error handlers
-       %macro SETISR 1
-       SETIDT %1, Isr%1
-       %endmacro
-       
-       %assign i 0
-       %rep 32
-       SETISR i
-       %assign i i+1
-       %endrep
-       
-       ; Install IRQs
-       SETIDT  0xF0, PIT_IRQ
-       SETIDT  0xF1, Irq1
-       SETIDT  0xF2, Irq2
-       SETIDT  0xF3, Irq3
-       SETIDT  0xF4, Irq4
-       SETIDT  0xF5, Irq5
-       SETIDT  0xF6, Irq6
-       SETIDT  0xF7, Irq7
-       SETIDT  0xF8, Irq8
-       SETIDT  0xF9, Irq9
-       SETIDT  0xFA, Irq10
-       SETIDT  0xFB, Irq11
-       SETIDT  0xFC, Irq12
-       SETIDT  0xFD, Irq13
-       SETIDT  0xFE, Irq14
-       SETIDT  0xFF, Irq15
-
-       ; Remap PIC
-       push rdx        ; Save RDX
-       mov dx, 0x20
-       mov al, 0x11
-       out dx, al      ;       Init Command
-       mov dx, 0x21
-       mov al, 0xF0
-       out dx, al      ;       Offset (Start of IDT Range)
-       mov al, 0x04
-       out dx, al      ;       IRQ connected to Slave (00000100b) = IRQ2
-       mov al, 0x01
-       out dx, al      ;       Set Mode
-       mov al, 0x00
-       out dx, al      ;       Set Mode
-       
-       mov dx, 0xA0
-       mov al, 0x11
-       out dx, al      ;       Init Command
-       mov dx, 0xA1
-       mov al, 0xF8
-       out dx, al      ;       Offset (Start of IDT Range)
-       mov al, 0x02
-       out dx, al      ;       IRQ Line connected to master
-       mov al, 0x01
-       out dx, al      ;       Set Mode
-       mov dl, 0x00
-       out dx, al      ;       Set Mode
-       pop rdx
-       
-       
-       ; Install IDT
-       mov rax, gIDTPtr
-       lidt [rax]
-       
-       ; Re-install GDT (in higher address space)
-       mov rax, gGDTPtr
-       mov rcx, gGDT
-       mov QWORD [rax+2], rcx
-       lgdt [rax]
-       
-       ; Start interrupts
-       sti
-
-       ; Set IA32_LSTAR (RIP of handler)
-       mov ecx, 0xC0000082     ; IA32_LSTAR
-       mov eax, SyscallStub - 0xFFFFFFFF00000000
-       mov edx, 0xFFFFFFFF
-       wrmsr
-       ; Set IA32_FMASK (flags mask)
-       mov ecx, 0xC0000084
-       rdmsr
-       mov eax, ~0x202
-       wrmsr
-       ; Set IA32_STAR (Kernel/User CS)
-       mov ecx, 0xC0000081
-       rdmsr
-       mov edx, 0x8 | (0x1B << 16)     ; Kernel CS (and Kernel DS/SS - 8), User CS
-       wrmsr
-       
-       ret
-
-; int IRQ_AddHandler(int IRQ, void (*Handler)(int IRQ), void *Ptr)
-; Return Values:
-;  0 on Success
-; -1 on an invalid IRQ Number
-; -2 when no slots are avaliable
-[global IRQ_AddHandler]
-IRQ_AddHandler:
-       ; RDI - IRQ Number
-       ; RSI - Callback
-       ; RDX - Ptr
-       
-       ; Check for RDI >= 16
-       cmp rdi, 16
-       jb .numOK
-       xor rax, rax
-       dec rax
-       jmp .ret
-.numOK:
-
-       ; Get handler base into RAX
-       lea rax, [rdi*4]
-       mov rcx, gaIRQ_Handlers
-       lea rax, [rcx+rax*8]
-       
-       ; Find a free callback slot
-       %rep NUM_IRQ_CALLBACKS
-       mov rcx, [rax]
-       test rcx, rcx
-       jz .assign
-       add rax, 8
-       %endrep
-       ; None found, return -2
-       xor rax, rax
-       dec rax
-       dec rax
-       jmp .ret
-       
-       ; Assign the IRQ Callback
-.assign:
-       ; A little bit of debug
-       push rdi
-       push rsi
-       push rax
-       push rdx
-       sub rsp, 8
-       mov rcx, rdi    ; IRQ Number
-       mov rdx, rsi    ; Callback
-       mov rsi, rax    ; Pointer
-       mov rdi, csIRQ_Assigned
-       call Log
-       add rsp, 8
-       pop rdx
-       pop rax
-       pop rsi
-       pop rdi
-
-       ; Assign and return
-       mov [rax], rsi
-       add rax, gaIRQ_DataPtrs - gaIRQ_Handlers
-       mov [rax], rdx
-       xor rax, rax
-
-.ret:
-       ret
-       
-[section .rodata]
-csIRQ_Assigned:
-       db      "IRQ %p := %p (IRQ %i)",0
-csIRQ_Fired:
-       db      "IRQ %i fired",0
-[section .text]
-
-%macro ISR_NOERRNO     1
-Isr%1:
-       push    QWORD 0
-       push    QWORD %1
-       jmp     ErrorCommon
-%endmacro
-%macro ISR_ERRNO       1
-Isr%1:
-       push    QWORD %1
-       jmp     ErrorCommon
-%endmacro
-
-ISR_NOERRNO    0;  0: Divide By Zero Exception
-ISR_NOERRNO    1;  1: Debug Exception
-ISR_NOERRNO    2;  2: Non Maskable Interrupt Exception
-ISR_NOERRNO    3;  3: Int 3 Exception
-ISR_NOERRNO    4;  4: INTO Exception
-ISR_NOERRNO    5;  5: Out of Bounds Exception
-ISR_NOERRNO    6;  6: Invalid Opcode Exception
-ISR_NOERRNO    7;  7: Coprocessor Not Available Exception
-ISR_ERRNO      8;  8: Double Fault Exception (With Error Code!)
-ISR_NOERRNO    9;  9: Coprocessor Segment Overrun Exception
-ISR_ERRNO      10; 10: Bad TSS Exception (With Error Code!)
-ISR_ERRNO      11; 11: Segment Not Present Exception (With Error Code!)
-ISR_ERRNO      12; 12: Stack Fault Exception (With Error Code!)
-ISR_ERRNO      13; 13: General Protection Fault Exception (With Error Code!)
-ISR_ERRNO      14; 14: Page Fault Exception (With Error Code!)
-ISR_NOERRNO    15; 15: Reserved Exception
-ISR_NOERRNO    16; 16: Floating Point Exception
-ISR_NOERRNO    17; 17: Alignment Check Exception
-ISR_NOERRNO    18; 18: Machine Check Exception
-ISR_NOERRNO    19; 19: Reserved
-ISR_NOERRNO    20; 20: Reserved
-ISR_NOERRNO    21; 21: Reserved
-ISR_NOERRNO    22; 22: Reserved
-ISR_NOERRNO    23; 23: Reserved
-ISR_NOERRNO    24; 24: Reserved
-ISR_NOERRNO    25; 25: Reserved
-ISR_NOERRNO    26; 26: Reserved
-ISR_NOERRNO    27; 27: Reserved
-ISR_NOERRNO    28; 28: Reserved
-ISR_NOERRNO    29; 29: Reserved
-ISR_NOERRNO    30; 30: Reserved
-ISR_NOERRNO    31; 31: Reserved
-
-[extern Error_Handler]
-[global ErrorCommon]
-ErrorCommon:
-       PUSH_GPR
-       push gs
-       push fs
-       ;PUSH_FPU
-       ;PUSH_XMM
-       
-       mov rdi, rsp
-;      xchg bx, bx
-       call Error_Handler
-       
-       ;POP_XMM
-       ;POP_FPU
-       pop fs
-       pop gs
-       POP_GPR
-       add rsp, 2*8
-       iretq
-
-%macro DEFIRQ  1
-Irq%1:
-       push    0
-       push    %1
-       jmp     IrqCommon
-%endmacro
-
-%assign i 0
-%rep 16
-DEFIRQ i
-%assign i i+1
-%endrep
-
-[global IrqCommon]
-IrqCommon:
-       PUSH_GPR
-       push gs
-       push fs
-
-;      mov rdi, csIRQ_Fired
-;      mov rsi, [rsp+(16+2)*8]
-;      call Log
-       
-       mov ebx, [rsp+(16+2)*8] ; Get interrupt number (16 GPRS + 2 SRs)
-       shl ebx, 2      ; *4
-       mov rax, gaIRQ_Handlers
-       lea rbx, [rax+rbx*8]
-       
-       ; Check all callbacks
-       sub rsp, 8      ; Shadow of argument
-       %assign i 0
-       %rep NUM_IRQ_CALLBACKS
-       ; Get callback address
-       mov rax, [rbx]
-       test rax, rax   ; Check if it exists
-       jz .skip.%[i]
-       ; Set RDI to IRQ number
-       mov rdi, [rsp+(16+2+1)*8]       ; Get IRQ number
-       mov rsi, [rbx-gaIRQ_Handlers+gaIRQ_DataPtrs]
-       call rax        ; Call
-.skip.%[i]:
-       add rbx, 8      ; Next!
-       %assign i i+1
-       %endrep
-       add rsp, 8
-       
-       ; ACK
-       mov al, 0x20
-       mov rdi, [rsp+(16+2)*8] ; Get IRQ number
-       cmp rdi, 8
-       jb .skipAckSecondary
-       out 0xA0, al
-.skipAckSecondary:
-       out 0x20, al
-       
-       pop fs
-       pop gs
-       POP_GPR
-       add rsp, 8*2
-       iretq
-
-[extern Time_UpdateTimestamp]
-
-%if USE_MP
-[global APIC_Timer_IRQ]
-APIC_Timer_IRQ:
-       PUSH_GPR
-       push gs
-       push fs
-
-       ; TODO: What to do?
-
-       mov eax, DWORD [gpMP_LocalAPIC]
-       mov DWORD [eax+0x0B0], 0
-
-       pop fs
-       pop gs
-       POP_GPR
-       iretq
-%endif
-
-[global PIT_IRQ]
-PIT_IRQ:
-       PUSH_GPR
-       ;PUSH_FPU
-       ;PUSH_XMM
-       
-       call Time_UpdateTimestamp
-
-       %if 0
-[section .rodata]
-csUserSS:      db      "User SS: 0x%x",0
-[section .text]
-       mov rdi, csUserSS
-       mov rsi, [rsp+0x80+0x20]
-       call Log
-       %endif
-
-       ; Send EOI
-       mov al, 0x20
-       out 0x20, al            ; ACK IRQ
-       
-       ;POP_XMM
-       ;POP_FPU
-       POP_GPR
-       iretq
-
-[extern ci_offsetof_tThread_KernelStack]
-[extern SyscallHandler]
-[global SyscallStub]
-SyscallStub:
-       mov rbp, dr0
-       mov ebx, [rel ci_offsetof_tThread_KernelStack]
-       mov rbp, [rbp+rbx]      ; Get kernel stack
-       xchg rbp, rsp   ; Swap stacks
-
-       push rbp        ; Save User RSP
-       push rcx        ; RIP
-       push r11        ; RFLAGS
-
-       ; RDI
-       ; RSI
-       ; RDX
-       ; R10 (RCX for non syscall)
-       ; R8
-       ; R9
-       sub rsp, (6+2)*8
-       mov [rsp+0x00], rax     ; Number
-;      mov [rsp+0x08], rax     ; Errno (output only)
-       mov [rsp+0x10], rdi     ; Arg1
-       mov [rsp+0x18], rsi     ; Arg2
-       mov [rsp+0x20], rdx     ; Arg3
-       mov [rsp+0x28], r10     ; Arg4
-       mov [rsp+0x30], r8      ; Arg5
-       mov [rsp+0x38], r9      ; Arg6
-       
-       mov rdi, rsp
-       sub rsp, 8
-       call SyscallHandler
-
-       %if 0
-[section .rodata]
-csSyscallReturn:       db      "Syscall Return: 0x%x",0
-[section .text]
-       mov rdi, csSyscallReturn
-       mov rsi, [rsp+0+8]
-       call Log
-       %endif
-
-       add rsp, 8
-       mov ebx, [rsp+8]        ; Get errno
-       mov rax, [rsp+0]        ; Get return
-       add rsp, (6+2)*8
-
-       pop r11
-       pop rcx
-       pop rsp         ; Change back to user stack
-       ; TODO: Determine if user is 64 or 32 bit
-
-       db 0x48 ; REX, nasm doesn't have a sysretq opcode
-       sysret
-
-[section .data]
-gIDT:
-       ; 64-bit Interrupt Gate, CS = 0x8, IST0 (Disabled)
-       times 256       dd      0x00080000, 0x00000E00, 0, 0
-gIDTPtr:
-       dw      256*16-1
-       dq      gIDT
-
-gaIRQ_Handlers:
-       times   16*NUM_IRQ_CALLBACKS    dq      0
-gaIRQ_DataPtrs:
-       times   16*NUM_IRQ_CALLBACKS    dq      0
-
-; vim: ft=nasm
diff --git a/Kernel/arch/x86_64/errors.c b/Kernel/arch/x86_64/errors.c
deleted file mode 100644 (file)
index f7da7f9..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Acess2 x86_64 Project
- * - Error Handling
- */
-#include <acess.h>
-#include <proc.h>
-#include <mm_virt.h>
-#include <threads_int.h>       // Needed for SSE handling
-
-#define MAX_BACKTRACE  6
-
-// === IMPORTS ===
-extern int     MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
-extern void    Error_Backtrace(Uint IP, Uint BP);
-extern void    Proc_EnableSSE(void);
-extern void    Proc_RestoreSSE(Uint32 Data);
-
-// === PROTOTYPES ===
-void   Error_Handler(tRegs *Regs);
-
-// === GLOBALS ==
-const char * const csaERROR_NAMES[] = {
-       "Divide By Zero", "Debug", "NMI Exception", "INT3",
-       "INTO", "Out of Bounds", "Invalid Opcode", "Coprocessor not avaliable",
-       "Double Fault", "Coprocessor Segment Overrun", "Bad TSS", "Segment Not Present",
-       "Stack Fault Exception", "GPF", "#PF", "Reserved",
-       "Floating Point Exception", "Alignment Check Exception", "Machine Check Exception",     "Reserved",
-       "Reserved", "Reserved", "Reserved", "Reserved",
-       "Reserved", "Reserved", "Reserved", "Reserved",
-       "Reserved", "Reserved", "Reserved", "Reserved"
-       };
-
-// === CODE ===
-void Error_Handler(tRegs *Regs)
-{
-       Uint    cr;
-
-       if( Regs->IntNum == 7 )
-       {
-               tThread *thread = Proc_GetCurThread();
-               if(!thread->SavedState.bSSEModified)
-               {
-                       Proc_EnableSSE();
-                       if(!thread->SavedState.SSE)
-                               thread->SavedState.SSE = malloc(sizeof(tSSEState) + 0xF);
-                       else
-                               Proc_RestoreSSE( ((Uint)thread->SavedState.SSE + 0xF) & ~0xF );
-                       thread->SavedState.bSSEModified = 1;
-//                     __asm__ __volatile__ ("sti");
-                       return ;
-               }
-               // oops, SSE enabled but a #NM, bad news
-       }
-       
-       if( Regs->IntNum == 14 ) {
-               __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
-               if( MM_PageFault(cr, Regs->ErrorCode, Regs) == 0 )
-                       return ;
-       }
-       else {
-               Debug_KernelPanic();
-
-               Error_Backtrace(Regs->RIP, Regs->RBP);
-       }
-       
-       Log("CPU Error %x, Code: 0x%x", Regs->IntNum, Regs->ErrorCode);
-       Log(" - %s", csaERROR_NAMES[Regs->IntNum]);
-       Log(" CS:RIP = 0x%04x:%016llx", Regs->CS, Regs->RIP);
-       Log(" SS:RSP = 0x%04x:%016llx", Regs->SS, Regs->RSP);
-       Log(" RFLAGS = 0x%016llx", Regs->RFlags);
-       
-       Log(" RAX %016llx RCX %016llx RDX %016llx RBX %016llx",
-               Regs->RAX, Regs->RCX, Regs->RDX, Regs->RBX);
-       Log(" RSP %016llx RBP %016llx RSI %016llx RDI %016llx",
-               Regs->RSP, Regs->RBP, Regs->RSP, Regs->RDI);
-       Log(" R8  %016llx R9  %016llx R10 %016llx R11 %016llx",
-               Regs->R8, Regs->R9, Regs->R10, Regs->R11);
-       Log(" R12 %016llx R13 %016llx R14 %016llx R15 %016llx",
-               Regs->R12, Regs->R13, Regs->R14, Regs->R15);
-       Log(" FS %04x GS %04x", Regs->FS, Regs->GS);
-       
-       
-       // Control Registers
-       __asm__ __volatile__ ("mov %%cr0, %0":"=r"(cr));
-       Warning(" CR0 0x%08x", cr);
-       __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
-       Warning(" CR2 0x%016llx", cr);
-       __asm__ __volatile__ ("mov %%cr3, %0":"=r"(cr));
-       Warning(" CR3 0x%016llx", cr);
-       __asm__ __volatile__ ("mov %%cr4, %0":"=r"(cr));
-       Warning(" CR4 0x%08x", cr);
-       
-       switch( Regs->IntNum )
-       {
-       case 6: // #UD
-               Warning(" Offending bytes: %02x %02x %02x %02x",
-                       *(Uint8*)(Regs->RIP+0), *(Uint8*)(Regs->RIP+1),
-                       *(Uint8*)(Regs->RIP+2), *(Uint8*)(Regs->RIP+3)
-                       );
-               break;
-       }
-       
-       __asm__ __volatile__ ("cli");
-       for(;;)
-               __asm__ __volatile__ ("hlt");
-}
-
-/**
- * \fn void Error_Backtrace(Uint eip, Uint ebp)
- * \brief Unrolls the stack to trace execution
- * \param eip  Current Instruction Pointer
- * \param ebp  Current Base Pointer (Stack Frame)
- */
-void Error_Backtrace(Uint IP, Uint BP)
-{
-        int    i = 0;
-       
-       //if(eip < 0xC0000000 && eip > 0x1000)
-       //{
-       //      LogF("Backtrace: User - 0x%x\n", eip);
-       //      return;
-       //}
-       
-       if( IP > USER_MAX && IP < MM_KERNEL_CODE
-        && (MM_MODULE_MIN > IP || IP > MM_MODULE_MAX)
-               )
-       {
-               LogF("Backtrace: Data Area - %p\n", IP);
-               return;
-       }
-       
-       //str = Debug_GetSymbol(eip, &delta);
-       //if(str == NULL)
-               LogF("Backtrace: %p", IP);
-       //else
-       //      LogF("Backtrace: %s+0x%x", str, delta);
-       if( !MM_GetPhysAddr(BP) )
-       {
-               LogF("\nBacktrace: Invalid BP, stopping\n");
-               return;
-       }
-       
-       
-       while( MM_GetPhysAddr(BP) && MM_GetPhysAddr(BP+8+7) && i < MAX_BACKTRACE )
-       {
-               //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
-               //if(str == NULL)
-                       LogF(" >> 0x%llx", ((Uint*)BP)[1]);
-               //else
-               //      LogF(" >> %s+0x%x", str, delta);
-               BP = ((Uint*)BP)[0];
-               i++;
-       }
-       LogF("\n");
-}
diff --git a/Kernel/arch/x86_64/include/arch.h b/Kernel/arch/x86_64/include/arch.h
deleted file mode 100644 (file)
index bde7abd..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Acess2 x86-64 Architecure Module
- * - By John Hodge (thePowersGang)
- */
-#ifndef _ARCH_H_
-#define _ARCH_H_
-
-//#include <stdint.h>
-#define        USER_MAX        0x00007FFF##FFFFF000
-#define KERNEL_BASE    0xFFFFFFFF##80000000
-#define BITS   64
-#define PAGE_SIZE      0x1000
-
-#define STACKED_LOCKS  2       // 0: No, 1: Per-CPU, 2: Per-Thread
-#define LOCK_DISABLE_INTS      0
-
-#define INVLPTR        ((void*)0x0FFFFFFFFFFFFFFFULL)
-
-//#define INT_MAX      0x7FFFFFFF
-//#define UINT_MAX     0xFFFFFFFF
-
-// === Core Types ===
-typedef signed char    Sint8;
-typedef unsigned char  Uint8;
-typedef signed short   Sint16;
-typedef unsigned short Uint16;
-typedef signed int     Sint32;
-typedef unsigned int   Uint32;
-#if __WORDSIZE == 64
-typedef signed long int        Sint64;
-typedef unsigned long int      Uint64;
-#else
-typedef signed long long int   Sint64;
-typedef unsigned long long int Uint64;
-#endif
-
-typedef Sint64 Sint;
-typedef Uint64 Uint;
-typedef Uint64 tPAddr;
-typedef Uint64 tVAddr;
-
-typedef Uint64 size_t;
-typedef char   BOOL;
-
-#define __ASM__        __asm__ __volatile__
-
-// === MACROS ===
-/**
- * \brief Halt the CPU
- */
-#define        HALT()  __asm__ __volatile__ ("sti;\n\thlt")
-/**
- * \brief Fire a magic breakpoint (bochs)
- */
-#define        MAGIC_BREAK()   __asm__ __volatile__ ("xchg %bx, %bx")
-
-// Systemcall Registers
-// TODO: Fix this structure
-typedef struct sSyscallRegs
-{
-       union {
-               Uint    Num;
-               Uint    Return;
-       };      // RAX
-       Uint    Error;  // RBX
-       Uint    Arg1;   // RDI
-       Uint    Arg2;   // RSI
-       Uint    Arg3;   // RDX
-       Uint    Arg4;   // RCX
-       Uint    Arg5;   // R8
-       Uint    Arg6;   // R9
-       Uint    _Flags;
-       Uint    _IP;
-       Uint    StackPointer;   // RSP
-       
-}      tSyscallRegs;
-
-/**
- * \brief Short Spinlock structure
- */
-struct sShortSpinlock {
-       #if STACKED_LOCKS == 2
-       volatile void   *Lock;  //!< Lock value
-       #else
-       volatile int    Lock;   //!< Lock value
-       #endif
-       
-       #if LOCK_DISABLE_INTS
-        int    IF;     //!< Interrupt state on call to SHORTLOCK
-       #endif
-       #if STACKED_LOCKS
-        int    Depth;
-       #endif
-};
-
-// === FUNCTIONS ===
-extern int     IS_LOCKED(struct sShortSpinlock *Lock);
-extern int     CPU_HAS_LOCK(struct sShortSpinlock *Lock);
-extern void    SHORTLOCK(struct sShortSpinlock *Lock);
-extern void    SHORTREL(struct sShortSpinlock *Lock);
-
-extern void    Debug_PutCharDebug(char ch);
-extern void    Debug_PutStringDebug(const char *Str);
-
-// TODO: Move this to acess.h
-extern tPAddr  MM_AllocateZero(tVAddr VAddr);
-
-#endif
-
diff --git a/Kernel/arch/x86_64/include/arch_config.h b/Kernel/arch/x86_64/include/arch_config.h
deleted file mode 100644 (file)
index c9f47b0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- */
-#ifndef _ARCH_CONFIG_H_
-#define _ARCH_CONFIG_H_
-
-
-#define PIT_TIMER_BASE_N       3579545
-#define PIT_TIMER_BASE_D       3
-// PIT Ticks at 1.1931816666666 MHz
-// Base is 1193182 HZ
-#define PIT_TIMER_DIVISOR      11931   //~100Hz
-
-#endif
diff --git a/Kernel/arch/x86_64/include/common.inc.asm b/Kernel/arch/x86_64/include/common.inc.asm
deleted file mode 100644 (file)
index d230177..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-
-%define INITIAL_KSTACK_SIZE    8
-
-%macro SAVE_GPR 1
-       mov [%1-0x08], r15
-       mov [%1-0x10], r14
-       mov [%1-0x18], r13
-       mov [%1-0x20], r12
-       mov [%1-0x28], r11
-       mov [%1-0x30], r10
-       mov [%1-0x38], r9
-       mov [%1-0x40], r8
-       mov [%1-0x48], rdi
-       mov [%1-0x50], rsi
-       mov [%1-0x58], rbp
-       mov [%1-0x60], rsp
-       mov [%1-0x68], rbx
-       mov [%1-0x70], rdx
-       mov [%1-0x78], rcx
-       mov [%1-0x80], rax
-%endmacro
-
-%macro PUSH_GPR        0
-       SAVE_GPR rsp
-       sub rsp, 0x80
-%endmacro
-
-%macro RESTORE_GPR 1
-       mov r15, [%1-0x08]
-       mov r14, [%1-0x10]
-       mov r13, [%1-0x18]
-       mov r12, [%1-0x20]
-       mov r11, [%1-0x28]
-       mov r10, [%1-0x30]
-       mov r9,  [%1-0x38]
-       mov r8,  [%1-0x40]
-       mov rdi, [%1-0x48]
-       mov rsi, [%1-0x50]
-       mov rbp, [%1-0x58]
-       ;mov rsp, [%1-0x60]
-       mov rbx, [%1-0x68]
-       mov rdx, [%1-0x70]
-       mov rcx, [%1-0x78]
-       mov rax, [%1-0x80]
-%endmacro
-
-%macro POP_GPR 0
-       add rsp, 0x80
-       RESTORE_GPR rsp
-%endmacro
diff --git a/Kernel/arch/x86_64/include/desctab.h b/Kernel/arch/x86_64/include/desctab.h
deleted file mode 100644 (file)
index de3996c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- */
-#ifndef _DESCTAB_H_
-#define _DESCTAB_H_
-
-typedef struct {
-       union
-       {
-               struct
-               {
-                       Uint16  LimitLow;
-                       Uint16  BaseLow;
-                       Uint8   BaseMid;
-                       Uint8   Access;
-                       struct {
-                               unsigned LimitHi:       4;
-                               unsigned Flags:         4;
-                       } __attribute__ ((packed));
-                       Uint8   BaseHi;
-               };
-               Uint32  DWord[2];
-       };
-} __attribute__ ((packed)) tGDT;
-
-typedef struct {
-       Uint16  OffsetLo;
-       Uint16  CS;
-       Uint16  Flags;  // 0-2: IST, 3-7: 0, 8-11: Type, 12: 0, 13-14: DPL, 15: Present
-       Uint16  OffsetMid;
-       Uint32  OffsetHi;
-       Uint32  Reserved;
-} __attribute__ ((packed)) tIDT;
-
-typedef struct {
-       Uint32  Rsvd1;
-       
-       Uint64  RSP0;
-       Uint64  RSP1;
-       Uint64  RSP2;
-       
-       Uint32  Rsvd2[2];
-       
-       // Interrupt Stack Table Pointers
-       Uint64  IST1;
-       Uint64  IST2;
-       Uint64  IST3;
-       Uint64  IST4;
-       Uint64  IST5;
-       Uint64  IST6;
-       Uint64  IST7;
-       
-       Uint32  Rsvd3[2];
-       Uint16  Rsvd4;
-       Uint16  IOMapBase;
-} __attribute__ ((packed)) tTSS;
-
-#endif
diff --git a/Kernel/arch/x86_64/include/mm_virt.h b/Kernel/arch/x86_64/include/mm_virt.h
deleted file mode 100644 (file)
index 6cf25f0..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Acess2 x86_64 Architecture Code
- *
- * This file is published under the terms of the Acess Licence.
- * See the file COPYING for more details
- *
- * vmem.h - Virtual Memory Functions & Definitions
- */
-#ifndef _VMEM_H_
-#define _VMEM_H_
-
-#include <arch.h>
-
-#define PAGE_SIZE      0x1000
-
-// === Memory Location Definitions ===
-/*
- * Userland - Lower Half
- * Kernel land - Upper Half
- * 
- *    START ADDRESS          END ADDRESS       BITS   SIZE      NAME
- * 0x00000000 00000000 - 0x00007FFF FFFFFFFF   47      128 TiB User Space
- * 0x00008000 00000000 - 0xFFFF7FFF FFFFFFFF   --- SIGN EXTENSION NULL ZONE
- * 0xFFFF8000 00000000 - 0xFFFFFFFF FFFFFFFF   47      128     TiB     Kernel Range
- *       8000 00000000 -       9000 00000000   42      16      TiB     Kernel Heap
- *       9000 00000000 -       9800 00000000   43      8       TiB     Module Space
- *       9800 00000000 -       9A00 00000000   41      2       TiB     Kernel VFS
- *       ---- GAP ----                                 6       TiB
- *       A000 00000000 -       B000 00000000   44      16      TiB     Kernel Stacks
- *       C000 00000000 -       D000 00000000   44      16      TiB     Hardware Mappings
- *       D000 00000000 -       D080 00000000   39      512     GiB     Per-Process Data
- *       D080 00000000 -       D100 00000000   39      512     GiB     Kernel Supplied User Code
- *       ---- GAP ----                                 15      TiB
- *       E000 00000000 -       E800 00000000   43      8       TiB     Physical Page Nodes (2**40 pages * 8 bytes)
- *       E800 00000000 -       EC00 00000000   42      4       TiB     Physical Page Reference Counts (2**40 pg * 4 bytes)
- *       EC00 00000000 -       EC80 00000000   39      512     GiB     Physical Page Bitmap (1 page per bit)
- *       EC80 00000000 -       ED00 00000000   39      512     GiB     Physical Page DblAlloc Bitmap (1 page per bit)
- *       ED00 00000000 -       ED00 80000000   31      2       GiB     Physical Page Super Bitmap (64 pages per bit)
- *       ---- GAP ----                                 9       TiB
- *       FE00 00000000 -       FE80 00000000   39      512     GiB     Fractal Mapping (PML4 508)
- *       FE80 00000000 -       FF00 00000000   39      512     GiB     Temp Fractal Mapping
- *       FF00 00000000 -       FF80 00000000   39      512     GiB     Temporary page mappings
- *       FF80 00000000 -       FF80 80000000   31      2       GiB     Local APIC
- *       ---- GAP ----                                 506     GiB
- *       FFFF 00000000 -       FFFF 80000000   31      2       GiB     User Code
- *       FFFF 80000000 -       FFFF FFFFFFFF   31      2       GiB     Kernel code / data
- */
-
-#define        MM_USER_MIN     0x00000000##00010000
-#define USER_LIB_MAX   0x00007000##00000000
-#define USER_STACK_PREALLOC    0x00000000##00002000    // 8 KiB
-#define USER_STACK_SZ  0x00000000##00020000    // 64 KiB
-#define USER_STACK_TOP 0x00008000##00000000
-#define        MM_KERNEL_RANGE 0xFFFF8000##00000000
-#define MM_KHEAP_BASE  (MM_KERNEL_RANGE|(0x8000##00000000))
-#define MM_KHEAP_MAX   (MM_KERNEL_RANGE|(0x9000##00000000))
-#define MM_MODULE_MIN  (MM_KERNEL_RANGE|(0x9000##00000000))
-#define MM_MODULE_MAX  (MM_KERNEL_RANGE|(0x9800##00000000))
-#define MM_KERNEL_VFS  (MM_KERNEL_RANGE|(0x9800##00000000))
-#define MM_KSTACK_BASE (MM_KERNEL_RANGE|(0xA000##00000000))
-#define MM_KSTACK_TOP  (MM_KERNEL_RANGE|(0xB000##00000000))
-
-#define MM_HWMAP_BASE  (MM_KERNEL_RANGE|(0xC000##00000000))
-#define MM_HWMAP_TOP   (MM_KERNEL_RANGE|(0xD000##00000000))
-#define MM_PPD_BASE    (MM_KERNEL_RANGE|(0xD000##00000000))
-#define MM_PPD_CFG     MM_PPD_BASE
-#define MM_PPD_HANDLES         (MM_KERNEL_RANGE|(0xD008##00000000))
-#define MM_USER_CODE   (MM_KERNEL_RANGE|(0xD080##00000000))
-
-#define MM_PAGE_NODES  (MM_KERNEL_RANGE|(0xE000##00000000))
-#define MM_PAGE_COUNTS (MM_KERNEL_RANGE|(0xE800##00000000))
-#define MM_PAGE_BITMAP (MM_KERNEL_RANGE|(0xEC00##00000000))
-#define MM_PAGE_DBLBMP (MM_KERNEL_RANGE|(0xEC00##00000000))
-#define MM_PAGE_SUPBMP (MM_KERNEL_RANGE|(0xED00##00000000))
-
-#define MM_FRACTAL_BASE        (MM_KERNEL_RANGE|(0xFE00##00000000))
-#define MM_TMPFRAC_BASE        (MM_KERNEL_RANGE|(0xFE80##00000000))
-#define MM_TMPMAP_BASE (MM_KERNEL_RANGE|(0xFF00##00000000))
-#define MM_TMPMAP_END  (MM_KERNEL_RANGE|(0xFF80##00000000))
-#define MM_LOCALAPIC   (MM_KERNEL_RANGE|(0xFF80##00000000))
-#define MM_KERNEL_CODE (MM_KERNEL_RANGE|(0xFFFF##80000000))
-
-
-// === FUNCTIONS ===
-void   MM_FinishVirtualInit(void);
-tVAddr MM_NewKStack(void);
-tVAddr MM_Clone(void);
-tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize);
-
-#endif
diff --git a/Kernel/arch/x86_64/include/proc.h b/Kernel/arch/x86_64/include/proc.h
deleted file mode 100644 (file)
index dad8f06..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Acess2 x86_64 Port
- * 
- * proc.h - Process/Thread management code
- */
-#ifndef _PROC_H_
-#define _PROC_H_
-
-#include <arch.h>
-
-// Register Structure
-// TODO: Rebuild once IDT code is done
-typedef struct {
-       // MMX
-       // FPU
-       Uint    FS, GS;
-       
-       Uint    RAX, RCX, RDX, RBX;
-       Uint    KernelRSP, RBP, RSI, RDI;
-       Uint    R8,  R9,  R10, R11;
-       Uint    R12, R13, R14, R15;
-       
-       Uint    IntNum, ErrorCode;
-       Uint    RIP, CS;
-       Uint    RFlags, RSP, SS;
-} tRegs;
-
-/**
- * \brief Memory State for thread handler
- */
-typedef struct sMemoryState
-{
-       tPAddr  CR3;
-}      tMemoryState;
-
-// 512 bytes, 16 byte aligned
-typedef struct sSSEState
-{
-       char    data[512];
-} tSSEState;
-
-/**
- * \brief Task state for thread handler
- */
-typedef struct sTaskState
-{
-       Uint    RIP, RSP;
-       Uint64  UserRIP, UserCS;
-       tSSEState       *SSE;
-        int    bSSEModified;
-}      tTaskState;
-
-// === CONSTANTS ===
-#define KERNEL_STACK_SIZE      0x8000  // 32 KiB
-//#define KERNEL_STACK_SIZE    0x10000 // 64 KiB
-
-#endif
-
diff --git a/Kernel/arch/x86_64/include/vm8086.h b/Kernel/arch/x86_64/include/vm8086.h
deleted file mode 100644 (file)
index 7c8dd47..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Acess2 VM8086 BIOS Interface
- * - By John Hodge (thePowersGang)
- *
- * vm8086.h
- * - Core Header
- */
-#ifndef _VM80806_H_
-#define _VM80806_H_
-
-// === TYPES ===
-/**
- * \note Semi-opaque - Past \a .IP, the implementation may add any data
- *       it needs to the state.
- */
-typedef struct sVM8086
-{
-       Uint16  AX, CX, DX, BX;
-       Uint16  BP, SP, SI, DI;
-       
-       Uint16  SS, DS, ES;
-       
-       Uint16  CS, IP;
-       
-       struct sVM8086_InternalData     *Internal;
-}      tVM8086;
-
-// === FUNCTIONS ===
-/**
- * \brief Create an instance of the VM8086 Emulator
- * \note Do not free this pointer with ::free, instead use ::VM8086_Free
- * \return Pointer to a tVM8086 structure, this structure may be larger than
- *         tVM8086 due to internal data.
- */
-extern tVM8086 *VM8086_Init(void);
-/**
- * \brief Free an allocated tVM8086 structure
- * \param State        Emulator state to free
- */
-extern void    VM8086_Free(tVM8086 *State);
-/**
- * \brief Allocate a piece of memory in the emulated address space and
- *        return a host and emulated pointer to it.
- * \param State        Emulator state
- * \param Size Size of memory block
- * \param Segment      Pointer to location to store the allocated memory's segment
- * \param Offset       Pointet to location to store the allocated memory's offset
- * \return Host pointer to the allocated memory
- */
-extern void    *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset);
-/**
- * \brief Gets a pointer to a piece of emulated memory
- * \todo Only 1 machine page is garenteed to be contiguous
- * \param State        Emulator State
- * \param Segment      Source Segment
- * \param Offset       Source Offset
- * \return Host pointer to the emulated memory
- */
-extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset);
-/**
- * \brief Calls a real-mode interrupt described by the current state of the IVT.
- * \param State        Emulator State
- * \param Interrupt    BIOS Interrupt to call
- */
-extern void    VM8086_Int(tVM8086 *State, Uint8 Interrupt);
-
-#endif
diff --git a/Kernel/arch/x86_64/kernelpanic.c b/Kernel/arch/x86_64/kernelpanic.c
deleted file mode 100644 (file)
index 1ce8ae7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Acess2 x86_64 port
- * - Kernel Panic output
- */
-#include <acess.h>
-
-// === PROTOTYPES ===
-void   KernelPanic_SetMode(void);
-void   KernelPanic_PutChar(char ch);
-
-// === GLOBALS ===
-Uint16 *gpKernelPanic_Buffer = (void*)( KERNEL_BASE|0xB8000 );
- int   giKernelPanic_CurPos = 0;
-
-// === CODE ===
-void KernelPanic_SetMode(void)
-{
-       giKernelPanic_CurPos = 0;
-}
-
-void KernelPanic_PutChar(char ch)
-{
-       switch(ch)
-       {
-       case '\n':
-               giKernelPanic_CurPos += 80;
-       case '\r':
-               giKernelPanic_CurPos /= 80;
-               giKernelPanic_CurPos *= 80;
-               break;
-       
-       default:
-               if(' ' <= ch && ch <= 0x7F)
-                       gpKernelPanic_Buffer[giKernelPanic_CurPos] = 0x4F00|ch;
-               giKernelPanic_CurPos ++;
-               break;
-       }
-}
diff --git a/Kernel/arch/x86_64/lib.c b/Kernel/arch/x86_64/lib.c
deleted file mode 100644 (file)
index 5b9609a..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- */
-#include <acess.h>
-#include <arch.h>
-
-#define DEBUG_TO_E9    1
-#define DEBUG_TO_SERIAL        1
-#define        SERIAL_PORT     0x3F8
-#define        GDB_SERIAL_PORT 0x2F8
-
-
-// === IMPORTS ===
-extern int     GetCPUNum(void);
-extern void    *Proc_GetCurThread(void);
-
-// === GLOBALS ===
- int   gbDebug_SerialSetup = 0;
- int   gbGDB_SerialSetup = 0;
-
-// === PROTOTYPEs ===
- int   putDebugChar(char ch);
-
-// === CODE ===
-/**
- * \brief Determine if a short spinlock is locked
- * \param Lock Lock pointer
- */
-int IS_LOCKED(struct sShortSpinlock *Lock)
-{
-       return !!Lock->Lock;
-}
-
-/**
- * \brief Check if the current CPU has the lock
- * \param Lock Lock pointer
- */
-int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
-{
-       #if STACKED_LOCKS == 1
-       return Lock->Lock == GetCPUNum() + 1;
-       #elif STACKED_LOCKS == 2
-       return Lock->Lock == Proc_GetCurThread();
-       #else
-       return 0;
-       #endif
-}
-
-/**
- * \brief Acquire a Short Spinlock
- * \param Lock Lock pointer
- * 
- * This type of mutex should only be used for very short sections of code,
- * or in places where a Mutex_* would be overkill, such as appending
- * an element to linked list (usually two assignement lines in C)
- * 
- * \note This type of lock halts interrupts, so ensure that no timing
- * functions are called while it is held. As a matter of fact, spend as
- * little time as possible with this lock held
- * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
- */
-void SHORTLOCK(struct sShortSpinlock *Lock)
-{
-        int    v = 1;
-       #if LOCK_DISABLE_INTS
-        int    IF;
-       #endif
-       #if STACKED_LOCKS == 1
-        int    cpu = GetCPUNum() + 1;
-       #elif STACKED_LOCKS == 2
-       void    *thread = Proc_GetCurThread();
-       #endif
-       
-       #if LOCK_DISABLE_INTS
-       // Save interrupt state and clear interrupts
-       __ASM__ ("pushf;\n\tpop %0" : "=r"(IF));
-       IF &= 0x200;    // AND out all but the interrupt flag
-       #endif
-       
-       #if STACKED_LOCKS == 1
-       if( Lock->Lock == cpu ) {
-               Lock->Depth ++;
-               return ;
-       }
-       #elif STACKED_LOCKS == 2
-       if( Lock->Lock == thread ) {
-               Lock->Depth ++;
-               return ;
-       }
-       #endif
-       
-       // Wait for another CPU to release
-       while(v) {
-               // CMPXCHG:
-               //  If r/m32 == EAX, set ZF and set r/m32 = r32
-               //  Else, clear ZF and set EAX = r/m32
-               #if STACKED_LOCKS == 1
-               __ASM__("lock cmpxchgl %2, (%3)"
-                       : "=a"(v)
-                       : "a"(0), "r"(cpu), "r"(&Lock->Lock)
-                       );
-               #elif STACKED_LOCKS == 2
-               __ASM__("lock cmpxchgq %2, (%3)"
-                       : "=a"(v)
-                       : "a"(0), "r"(thread), "r"(&Lock->Lock)
-                       );
-               #else
-               __ASM__("xchgl %0, (%2)":"=a"(v):"a"(1),"D"(&Lock->Lock));
-               #endif
-               
-               #if LOCK_DISABLE_INTS
-               if( v ) __ASM__("sti"); // Re-enable interrupts
-               #endif
-       }
-       
-       #if LOCK_DISABLE_INTS
-       __ASM__("cli");
-       Lock->IF = IF;
-       #endif
-}
-/**
- * \brief Release a short lock
- * \param Lock Lock pointer
- */
-void SHORTREL(struct sShortSpinlock *Lock)
-{
-       #if STACKED_LOCKS
-       if( Lock->Depth ) {
-               Lock->Depth --;
-               return ;
-       }
-       #endif
-       
-       #if LOCK_DISABLE_INTS
-       // Lock->IF can change anytime once Lock->Lock is zeroed
-       if(Lock->IF) {
-               Lock->Lock = 0;
-               __ASM__ ("sti");
-       }
-       else {
-               Lock->Lock = 0;
-       }
-       #else
-       Lock->Lock = 0;
-       #endif
-}
-
-// === DEBUG IO ===
-#if USE_GDB_STUB
-int putDebugChar(char ch)
-{
-       if(!gbGDB_SerialSetup) {
-               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
-               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
-               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
-               outb(GDB_SERIAL_PORT + 1, 0x00);    //  (base is         (hi byte)
-               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit (8N1)
-               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
-               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
-               gbDebug_SerialSetup = 1;
-       }
-       while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
-       outb(GDB_SERIAL_PORT, ch);
-       return 0;
-}
-int getDebugChar(void)
-{
-       if(!gbGDB_SerialSetup) {
-               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
-               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
-               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
-               outb(GDB_SERIAL_PORT + 1, 0x00);    //                   (hi byte)
-               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
-               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
-               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
-               gbDebug_SerialSetup = 1;
-       }
-       while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0)     ;
-       return inb(GDB_SERIAL_PORT);
-}
-#endif
-
-void Debug_PutCharDebug(char ch)
-{
-       #if DEBUG_TO_E9
-       __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
-       #endif
-       
-       #if DEBUG_TO_SERIAL
-       if(!gbDebug_SerialSetup) {
-               outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
-               outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
-               outb(SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
-               outb(SERIAL_PORT + 1, 0x00);    //                   (hi byte)
-               outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
-               outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
-               outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
-               gbDebug_SerialSetup = 1;
-       }
-       while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
-       outb(SERIAL_PORT, ch);
-       #endif
-}
-
-void Debug_PutStringDebug(const char *String)
-{
-       while(*String)
-               Debug_PutCharDebug(*String++);
-}
-
-// === PORT IO ===
-void outb(Uint16 Port, Uint8 Data)
-{
-       __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
-}
-void outw(Uint16 Port, Uint16 Data)
-{
-       __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
-}
-void outd(Uint16 Port, Uint32 Data)
-{
-       __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
-}
-Uint8 inb(Uint16 Port)
-{
-       Uint8   ret;
-       __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
-       return ret;
-}
-Uint16 inw(Uint16 Port)
-{
-       Uint16  ret;
-       __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
-       return ret;
-}
-Uint32 ind(Uint16 Port)
-{
-       Uint32  ret;
-       __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
-       return ret;
-}
-
-// === Endianness ===
-/*
-Uint32 BigEndian32(Uint32 Value)
-{
-       Uint32  ret;
-       ret = (Value >> 24);
-       ret |= ((Value >> 16) & 0xFF) << 8;
-       ret |= ((Value >>  8) & 0xFF) << 16;
-       ret |= ((Value >>  0) & 0xFF) << 24;
-       return ret;
-}
-
-Uint16 BigEndian16(Uint16 Value)
-{
-       return  (Value>>8)|(Value<<8);
-}
-*/
-
-// === Memory Manipulation ===
-int memcmp(const void *__dest, const void *__src, size_t __count)
-{
-       if( ((tVAddr)__dest & 7) != ((tVAddr)__src & 7) ) {
-               const Uint8     *src = __src, *dst = __dest;
-               while(__count)
-               {
-                       if( *src != *dst )
-                               return *dst - *src;
-                       src ++; dst ++; __count --;
-               }
-               return 0;
-       }
-       else {
-               const Uint8     *src = __src;
-               const Uint8     *dst = __dest;
-               const Uint64    *src64, *dst64;
-               
-               while( (tVAddr)src & 7 && __count ) {
-                       if( *src != *dst )
-                               return *dst - *src;
-                       dst ++; src ++; __count --;
-               }
-
-               src64 = (void*)src;
-               dst64 = (void*)dst;
-
-               while( __count >= 8 )
-               {
-                       if( *src64 != *dst64 )
-                       {
-                               src = (void*)src64;
-                               dst = (void*)dst64;
-                               if(src[0] != dst[0])    return dst[0]-src[0];
-                               if(src[1] != dst[1])    return dst[1]-src[1];
-                               if(src[2] != dst[2])    return dst[2]-src[2];
-                               if(src[3] != dst[3])    return dst[3]-src[3];
-                               if(src[4] != dst[4])    return dst[4]-src[4];
-                               if(src[5] != dst[5])    return dst[5]-src[5];
-                               if(src[6] != dst[6])    return dst[6]-src[6];
-                               if(src[7] != dst[7])    return dst[7]-src[7];
-                               return -1;      // This should never happen
-                       }
-                       __count -= 8;
-                       src64 ++;
-                       dst64 ++;
-               }
-
-               src = (void*)src64;
-               dst = (void*)dst64;
-               while( __count-- )
-               {
-                       if(*dst != *src)        return *dst - *src;
-                       dst ++;
-                       src ++;
-               }
-       }
-       return 0;
-}
-
-void *memcpy(void *__dest, const void *__src, size_t __count)
-{
-       tVAddr  dst = (tVAddr)__dest, src = (tVAddr)__src;
-       if( (dst & 7) != (src & 7) )
-       {
-               __asm__ __volatile__ ("rep movsb" : : "D"(dst),"S"(src),"c"(__count));
-       }
-       else
-       {
-               while( (src & 7) && __count ) {
-                       *(char*)dst++ = *(char*)src++;
-                       __count --;
-               }
-
-               __asm__ __volatile__ ("rep movsq" : "=D"(dst),"=S"(src) : "0"(dst),"1"(src),"c"(__count/8));
-               __count = __count & 7;
-               while( __count-- )
-                       *(char*)dst++ = *(char*)src++;
-       }
-       return __dest;
-}
-
-void *memset(void *__dest, int __val, size_t __count)
-{
-       if( __val != 0 || ((tVAddr)__dest & 7) != 0 )
-               __asm__ __volatile__ ("rep stosb" : : "D"(__dest),"a"(__val),"c"(__count));
-       else {
-               Uint8   *dst = __dest;
-
-               __asm__ __volatile__ ("rep stosq" : : "D"(dst),"a"(0),"c"(__count/8));
-               dst += __count & ~7;
-               __count = __count & 7;
-               while( __count-- )
-                       *dst++ = 0;
-       }
-       return __dest;
-}
-
-void *memsetd(void *__dest, Uint32 __val, size_t __count)
-{
-       __asm__ __volatile__ ("rep stosl" : : "D"(__dest),"a"(__val),"c"(__count));
-       return __dest;
-}
-
-Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
-{
-       Uint64  ret, rem;
-       __asm__ __volatile__(
-               "div %4"
-               : "=a" (ret), "=d" (rem)
-               : "a" ( Num ), "d" (0), "r" (Den)
-               );
-       if(Rem) *Rem = rem;
-       return ret;
-}
-
diff --git a/Kernel/arch/x86_64/link.ld b/Kernel/arch/x86_64/link.ld
deleted file mode 100644 (file)
index 49fe7ae..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Acess2 x86_64 Kernel
- * Linker Script
- */
-
-/* _kernel_base = 0xFFFF800000000000; */
-/* -2 GiB */
-_kernel_base = 0xFFFFFFFF80000000;
-
-/*
-OUTPUT_FORMAT(elf32-i386)
-OUTPUT_ARCH(i386:x86-64)
-*/
-OUTPUT_FORMAT(elf64-x86-64)
-ENTRY(start)
-
-SECTIONS {
-       . = 0x100000;
-       gKernelBase = .;
-       . += SIZEOF_HEADERS;
-       __load_addr = .;
-       .multiboot : AT(ADDR(.multiboot)) {
-               *(.multiboot)
-       }
-       
-       . += _kernel_base;
-       
-       .text ALIGN(0x1000): AT(ADDR(.text) - _kernel_base) {
-               *(.text)
-       }
-       
-       .usertext ALIGN(0x1000): AT(ADDR(.usertext) - _kernel_base) {
-               _UsertextBase = .;
-               *(.usertext)
-               _UsertextEnd = .;
-       }
-       
-       .rodata ALIGN(0x1000): AT(ADDR(.rodata) - _kernel_base) {
-               *(.initpd)
-               *(.rodata .rodata.*)
-               *(.rdata)
-               
-               . = ALIGN(0x10);
-               gKernelModules = .;
-               *(KMODULES)
-               gKernelModulesEnd = .;
-               . = ALIGN(0x10);
-               gKernelSymbols = .;
-               *(KEXPORT)
-               gKernelSymbolsEnd = .;
-       }
-       
-       .data ALIGN (0x1000) : AT(ADDR(.data) - _kernel_base) {
-               *(.padata)
-               *(.data)
-       }
-
-       __bss_start = .;
-       .bss : AT(ADDR(.bss) - _kernel_base) {
-               *(COMMON)
-               *(.bss)
-       }
-       gKernelEnd = (. + 0xFFF)&0xFFFFFFFFFFFFF000;
-}
diff --git a/Kernel/arch/x86_64/main.c b/Kernel/arch/x86_64/main.c
deleted file mode 100644 (file)
index 3532c80..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Acess2 x86_64 Project
- */
-#include <acess.h>
-#include <mboot.h>
-#include <init.h>
-
-// === IMPORTS ===
-extern void    Desctab_Init(void);
-extern void    MM_InitVirt(void);
-extern void    Heap_Install(void);
-extern void    Threads_Init(void);
-extern int     Time_Setup(void);
-extern void    System_Init(char *Commandline);
-
-extern void    MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
-
-// === PROTOTYPES ===
-void   kmain(Uint MbMagic, void *MbInfoPtr);
-
-// === GLOBALS ==
-char   *gsBootCmdLine = NULL;
-
-// === CODE ===
-void kmain(Uint MbMagic, void *MbInfoPtr)
-{
-       tMBoot_Info     *mbInfo;
-
-       LogF("Acess2 x86_64 v"EXPAND_STR(KERNEL_VERSION)"\n");
-       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
-       
-       Desctab_Init();
-
-       MM_InitVirt();
-       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'C';
-       
-       switch(MbMagic)
-       {
-       // Multiboot 1
-       case MULTIBOOT_MAGIC:
-               // Adjust Multiboot structure address
-               mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
-               gsBootCmdLine = (char*)( (Uint)mbInfo->CommandLine + KERNEL_BASE);
-               MM_InitPhys_Multiboot( mbInfo );        // Set up physical memory manager
-               break;
-       default:
-               Panic("Multiboot magic invalid %08x, expected %08x\n",
-                       MbMagic, MULTIBOOT_MAGIC);
-               return ;
-       }
-       
-       Log("gsBootCmdLine = '%s'", gsBootCmdLine);
-       
-       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'D';
-       Heap_Install();
-       
-       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'E';
-       Threads_Init();
-       
-       Time_Setup();
-       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'F';
-       
-       // Load Virtual Filesystem
-       Log_Log("Arch", "Starting VFS...");
-       VFS_Init();
-       
-       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'Z';
-       
-       // Pass on to Independent Loader
-       Log_Log("Arch", "Starting system");
-       System_Init(gsBootCmdLine);
-       
-       // Sleep forever (sleeping beauty)
-       for(;;)
-               Threads_Sleep();
-}
-
-void Arch_LoadBootModules(void)
-{
-       
-}
-
-void StartupPrint(const char *String)
-{
-       
-}
diff --git a/Kernel/arch/x86_64/mm_phys.c b/Kernel/arch/x86_64/mm_phys.c
deleted file mode 100644 (file)
index c2c215b..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- * Acess2 x86_64 Port
- * 
- * Physical Memory Manager
- */
-#define DEBUG  0
-#include <acess.h>
-#include <mboot.h>
-#include <mm_virt.h>
-
-#define TRACE_REF      0
-
-enum eMMPhys_Ranges
-{
-       MM_PHYS_16BIT,  // Does anything need this?
-       MM_PHYS_20BIT,  // Real-Mode
-       MM_PHYS_24BIT,  // ISA DMA
-       MM_PHYS_32BIT,  // x86 Hardware
-       MM_PHYS_MAX,    // Doesn't care
-       NUM_MM_PHYS_RANGES
-};
-
-// === IMPORTS ===
-extern char    gKernelBase[];
-extern char    gKernelEnd[];
-
-// === PROTOTYPES ===
-void   MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
-//tPAddr       MM_AllocPhysRange(int Num, int Bits);
-//tPAddr       MM_AllocPhys(void);
-//void MM_RefPhys(tPAddr PAddr);
-//void MM_DerefPhys(tPAddr PAddr);
- int   MM_int_GetRangeID( tPAddr Addr );
-
-// === MACROS ===
-#define PAGE_ALLOC_TEST(__page)        (gaMainBitmap[(__page)>>6] & (1ULL << ((__page)&63)))
-#define PAGE_ALLOC_SET(__page)         do{gaMainBitmap[(__page)>>6] |= (1ULL << ((__page)&63));}while(0)
-#define PAGE_ALLOC_CLEAR(__page)       do{gaMainBitmap[(__page)>>6] &= ~(1ULL << ((__page)&63));}while(0)
-//#define PAGE_MULTIREF_TEST(__page)   (gaMultiBitmap[(__page)>>6] & (1ULL << ((__page)&63)))
-//#define PAGE_MULTIREF_SET(__page)    do{gaMultiBitmap[(__page)>>6] |= 1ULL << ((__page)&63);}while(0)
-//#define PAGE_MULTIREF_CLEAR(__page)  do{gaMultiBitmap[(__page)>>6] &= ~(1ULL << ((__page)&63));}while(0)
-
-// === GLOBALS ===
-tMutex glPhysicalPages;
-Uint64 *gaSuperBitmap = (void*)MM_PAGE_SUPBMP; // 1 bit = 64 Pages, 16 MiB per Word
-Uint64 *gaMainBitmap = (void*)MM_PAGE_BITMAP;  // 1 bit = 1 Page, 256 KiB per Word
-Uint64 *gaMultiBitmap = (void*)MM_PAGE_DBLBMP; // Each bit means that the page is being used multiple times
-Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS;     // Reference Counts
-void   **gapPageNodes = (void*)MM_PAGE_NODES;  // Reference Counts
-tPAddr giFirstFreePage;        // First possibly free page
-Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES];    // Number of free pages in each range
-Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES];   // First free page in each range
-Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES];    // Last free page in each range
-Uint64 giMaxPhysPage = 0;      // Maximum Physical page
-// Only used in init, allows the init code to provide pages for use by
-// the allocator before the bitmaps exist.
-// 3 entries because the are three calls to MM_AllocPhys in MM_Map
-#define NUM_STATIC_ALLOC       3
-tPAddr gaiStaticAllocPages[NUM_STATIC_ALLOC] = {0};
-
-// === CODE ===
-/**
- * \brief Initialise the physical memory map using a Multiboot 1 map
- */
-void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
-{
-       tMBoot_MMapEnt  *mmapStart;
-       tMBoot_MMapEnt  *ent;
-       Uint64  maxAddr = 0;
-        int    numPages, superPages;
-        int    i;
-       Uint64  base, size;
-       tVAddr  vaddr;
-       tPAddr  paddr, firstFreePage;
-       
-       ENTER("pMBoot=%p", MBoot);
-       
-       // Scan the physical memory map
-       // Looking for the top of physical memory
-       mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
-       LOG("mmapStart = %p", mmapStart);
-       ent = mmapStart;
-       while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
-       {
-               // Adjust for the size of the entry
-               ent->Size += 4;
-               LOG("ent={Type:%i,Base:0x%x,Length:%x",
-                       ent->Type, ent->Base, ent->Length);
-               
-               // If entry is RAM and is above `maxAddr`, change `maxAddr`
-               if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
-                       maxAddr = ent->Base + ent->Length;
-               
-               // Go to next entry
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
-       }
-       
-       // Did we find a valid end?
-       if(maxAddr == 0) {
-               // No, darn, let's just use the HighMem hack
-               giMaxPhysPage = (MBoot->HighMem >> 2) + 256;    // HighMem is a kByte value
-       }
-       else {
-               // Goodie, goodie gumdrops
-               giMaxPhysPage = maxAddr >> 12;
-       }
-       LOG("giMaxPhysPage = 0x%x", giMaxPhysPage);
-       
-       // Find a contigous section of memory to hold it in
-       // - Starting from the end of the kernel
-       // - We also need a region for the super bitmap
-       superPages = ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12;
-       numPages = (giMaxPhysPage + 7) / 8;
-       numPages = (numPages + 0xFFF) >> 12;
-       LOG("numPages = %i, superPages = %i", numPages, superPages);
-       if(maxAddr == 0)
-       {
-                int    todo = numPages*2 + superPages;
-               // Ok, naieve allocation, just put it after the kernel
-               // - Allocated Bitmap
-               vaddr = MM_PAGE_BITMAP;
-               paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
-               while(todo )
-               {
-                       // Allocate statics
-                       for( i = 0; i < NUM_STATIC_ALLOC; i++) {
-                               if(gaiStaticAllocPages[i] != 0) continue;
-                               gaiStaticAllocPages[i] = paddr;
-                               paddr += 0x1000;
-                       }
-                       
-                       MM_Map(vaddr, paddr);
-                       vaddr += 0x1000;
-                       paddr += 0x1000;
-                       
-                       todo --;
-                       
-                       if( todo == numPages + superPages )
-                               vaddr = MM_PAGE_DBLBMP;
-                       if( todo == superPages )
-                               vaddr = MM_PAGE_SUPBMP;
-               }
-       }
-       // Scan for a nice range
-       else
-       {
-                int    todo = numPages*2 + superPages;
-               paddr = 0;
-               vaddr = MM_PAGE_BITMAP;
-               // Scan!
-               for(
-                       ent = mmapStart;
-                       (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
-                       ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
-                       )
-               {
-                        int    avail;
-                       
-                       // RAM only please
-                       if( ent->Type != 1 )
-                               continue;
-                       
-                       // Let's not put it below the kernel, shall we?
-                       if( ent->Base + ent->Size < (tPAddr)&gKernelBase )
-                               continue;
-                       
-                       LOG("%x <= %x && %x > %x",
-                               ent->Base, (tPAddr)&gKernelBase,
-                               ent->Base + ent->Size, (tPAddr)&gKernelEnd - KERNEL_BASE
-                               );
-                       // Check if the kernel is in this range
-                       if( ent->Base <= (tPAddr)&gKernelBase
-                       && ent->Base + ent->Length > (tPAddr)&gKernelEnd - KERNEL_BASE )
-                       {
-                               avail = ent->Length >> 12;
-                               avail -= ((tPAddr)&gKernelEnd - KERNEL_BASE - ent->Base) >> 12;
-                               paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
-                       }
-                       // No? then we can use all of the block
-                       else
-                       {
-                               avail = ent->Length >> 12;
-                               paddr = ent->Base;
-                       }
-                       
-                       Log("MM_InitPhys_Multiboot: paddr=0x%x, avail=0x%x pg", paddr, avail);
-                       
-                       // Map
-                       while( todo && avail --)
-                       {
-                               // Static Allocations
-                               for( i = 0; i < NUM_STATIC_ALLOC && avail; i++) {
-                                       if(gaiStaticAllocPages[i] != 0) continue;
-                                       gaiStaticAllocPages[i] = paddr;
-                                       paddr += 0x1000;
-                                       avail --;
-                               }
-                               if(!avail)      break;
-                               
-                               // Map
-                               MM_Map(vaddr, paddr);
-                               todo --;
-                               vaddr += 0x1000;
-                               paddr += 0x1000;
-                               
-                               // Alter the destination address when needed
-                               if(todo == superPages+numPages)
-                                       vaddr = MM_PAGE_DBLBMP;
-                               if(todo == superPages)
-                                       vaddr = MM_PAGE_SUPBMP;
-                       }
-                       
-                       // Fast quit if there's nothing left to allocate
-                       if( !todo )             break;
-               }
-       }
-       // Save the current value of paddr to simplify the allocation later
-       firstFreePage = paddr;
-       
-       LOG("Clearing multi bitmap");
-       // Fill the bitmaps
-       memset(gaMultiBitmap, 0, (numPages<<12)/8);
-       // - initialise to one, then clear the avaliable areas
-       memset(gaMainBitmap, -1, (numPages<<12)/8);
-       memset(gaSuperBitmap, -1, (numPages<<12)/(8*64));
-       LOG("Setting main bitmap");
-       // - Clear all Type=1 areas
-       LOG("Clearing valid regions");
-       for(
-               ent = mmapStart;
-               (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
-               )
-       {
-               // Check if the type is RAM
-               if(ent->Type != 1)      continue;
-               
-               // Main bitmap
-               base = ent->Base >> 12;
-               size = ent->Size >> 12;
-               
-               if(base & 63) {
-                       Uint64  val = -1LL << (base & 63);
-                       gaMainBitmap[base / 64] &= ~val;
-                       size -= (base & 63);
-                       base += 64 - (base & 63);
-               }
-               memset( &gaMainBitmap[base / 64], 0, size/8 );
-               if( size & 7 ) {
-                       Uint64  val = -1LL << (size & 7);
-                       val <<= (size/8)&7;
-                       gaMainBitmap[base / 64] &= ~val;
-               }
-               
-               // Super Bitmap
-               base = ent->Base >> 12;
-               size = ent->Size >> 12;
-               size = (size + (base & 63) + 63) >> 6;
-               base = base >> 6;
-               if(base & 63) {
-                       Uint64  val = -1LL << (base & 63);
-                       gaSuperBitmap[base / 64] &= ~val;
-//                     size -= (base & 63);
-//                     base += 64 - (base & 63);
-               }
-       }
-       
-       // Reference the used pages
-       base = (tPAddr)&gKernelBase >> 12;
-       size = firstFreePage >> 12;
-       memset( &gaMainBitmap[base / 64], -1, size/8 );
-       if( size & 7 ) {
-               Uint64  val = -1LL << (size & 7);
-               val <<= (size/8)&7;
-               gaMainBitmap[base / 64] |= val;
-       }
-       
-       // Free the unused static allocs
-       for( i = 0; i < NUM_STATIC_ALLOC; i++) {
-               if(gaiStaticAllocPages[i] != 0)
-                       continue;
-               gaMainBitmap[ gaiStaticAllocPages[i] >> (12+6) ]
-                       &= ~(1LL << ((gaiStaticAllocPages[i]>>12)&63));
-       }
-       
-       // Fill the super bitmap
-       LOG("Filling super bitmap");
-       memset(gaSuperBitmap, 0, superPages<<12);
-       for( base = 0; base < (size+63)/64; base ++)
-       {
-               if( gaMainBitmap[ base ] + 1 == 0 )
-                       gaSuperBitmap[ base/64 ] |= 1LL << (base&63);
-       }
-       
-       // Set free page counts
-       for( base = 1; base < giMaxPhysPage; base ++ )
-       {
-                int    rangeID;
-               // Skip allocated
-               if( gaMainBitmap[ base >> 6 ] & (1LL << (base&63))  )   continue;
-               
-               // Get range ID
-               rangeID = MM_int_GetRangeID( base << 12 );
-               
-               // Increment free page count
-               giPhysRangeFree[ rangeID ] ++;
-               
-               // Check for first free page in range
-               if(giPhysRangeFirst[ rangeID ] == 0)
-                       giPhysRangeFirst[ rangeID ] = base;
-               // Set last (when the last free page is reached, this won't be
-               // updated anymore, hence will be correct)
-               giPhysRangeLast[ rangeID ] = base;
-       }
-       
-       LEAVE('-');
-}
-
-/**
- * \brief Allocate a contiguous range of physical pages with a maximum
- *        bit size of \a MaxBits
- * \param Pages        Number of pages to allocate
- * \param MaxBits      Maximum size of the physical address
- * \note If \a MaxBits is <= 0, any sized address is used (with preference
- *       to higher addresses)
- */
-tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
-{
-       tPAddr  addr, ret;
-        int    rangeID;
-        int    nFree = 0, i;
-       
-       ENTER("iPages iBits", Pages, MaxBits);
-       
-       if( MaxBits <= 0 || MaxBits >= 64 )     // Speedup for the common case
-               rangeID = MM_PHYS_MAX;
-       else
-               rangeID = MM_int_GetRangeID( (1LL << MaxBits) - 1 );
-       
-       LOG("rangeID = %i", rangeID);
-       
-       Mutex_Acquire(&glPhysicalPages);
-       
-       // Check if the range actually has any free pages
-       while(giPhysRangeFree[rangeID] == 0 && rangeID)
-               rangeID --;
-       
-       LOG("rangeID = %i", rangeID);
-       
-       // What the? Oh, man. No free pages
-       if(giPhysRangeFree[rangeID] == 0) {
-               Mutex_Release(&glPhysicalPages);
-               // TODO: Page out
-               // ATM. Just Warning
-               Warning(" MM_AllocPhysRange: Out of free pages");
-               Log_Warning("Arch",
-                       "Out of memory (unable to fulfil request for %i pages), zero remaining",
-                       Pages
-                       );
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Check if there is enough in the range
-       if(giPhysRangeFree[rangeID] >= Pages)
-       {
-               LOG("{%i,0x%x -> 0x%x}",
-                       giPhysRangeFree[rangeID],
-                       giPhysRangeFirst[rangeID], giPhysRangeLast[rangeID]
-                       );
-               // Do a cheap scan, scanning upwards from the first free page in
-               // the range
-               nFree = 0;
-               addr = giPhysRangeFirst[ rangeID ];
-               while( addr <= giPhysRangeLast[ rangeID ] )
-               {
-                       //Log(" MM_AllocPhysRange: addr = 0x%x", addr);
-                       // Check the super bitmap
-                       if( gaSuperBitmap[addr >> (6+6)] + 1 == 0 ) {
-                               LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr += 1LL << (6+6);
-                               addr &= ~0xFFF; // (1LL << 6+6) - 1
-                               continue;
-                       }
-                       // Check page block (64 pages)
-                       if( gaMainBitmap[addr >> 6] + 1 == 0) {
-                               LOG("nFree = %i = 0 (main) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr += 1LL << (6);
-                               addr &= ~0x3F;
-                               continue;
-                       }
-                       // Check individual page
-                       if( gaMainBitmap[addr >> 6] & (1LL << (addr & 63)) ) {
-                               LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr ++;
-                               continue;
-                       }
-                       nFree ++;
-                       addr ++;
-                       LOG("nFree(%i) == %i (0x%x)", nFree, Pages, addr);
-                       if(nFree == Pages)
-                               break;
-               }
-               LOG("nFree = %i", nFree);
-               // If we don't find a contiguous block, nFree will not be equal
-               // to Num, so we set it to zero and do the expensive lookup.
-               if(nFree != Pages)      nFree = 0;
-       }
-       
-       if( !nFree )
-       {
-               // Oops. ok, let's do an expensive check (scan down the list
-               // until a free range is found)
-//             nFree = 1;
-//             addr = giPhysRangeLast[ rangeID ];
-               // TODO: Expensive Check
-               Mutex_Release(&glPhysicalPages);
-               // TODO: Page out
-               // ATM. Just Warning
-               Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
-               Log_Warning("Arch",
-                       "Out of memory (unable to fulfil request for %i pages)",
-                       Pages   
-                       );
-               LEAVE('i', 0);
-               return 0;
-       }
-       LOG("nFree = %i, addr = 0x%08x", nFree, addr);
-       
-       // Mark pages as allocated
-       addr -= Pages;
-       for( i = 0; i < Pages; i++, addr++ )
-       {
-               gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
-               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) )
-                       gaiPageReferences[addr] = 1;
-//             Log("page %P refcount = %i", MM_GetRefCount(addr<<12)); 
-               rangeID = MM_int_GetRangeID(addr << 12);
-               giPhysRangeFree[ rangeID ] --;
-               LOG("%x == %x", addr, giPhysRangeFirst[ rangeID ]);
-               if(addr == giPhysRangeFirst[ rangeID ])
-                       giPhysRangeFirst[ rangeID ] += 1;
-       }
-       addr -= Pages;
-       ret = addr;     // Save the return address
-       
-       // Update super bitmap
-       Pages += addr & (64-1);
-       addr &= ~(64-1);
-       Pages = (Pages + (64-1)) & ~(64-1);
-       for( i = 0; i < Pages/64; i++ )
-       {
-               if( gaMainBitmap[ addr >> 6 ] + 1 == 0 )
-                       gaSuperBitmap[addr>>12] |= 1LL << ((addr >> 6) & 63);
-       }
-       
-       Mutex_Release(&glPhysicalPages);
-       #if TRACE_REF
-       Log("MM_AllocPhysRange: ret = %P (Ref %i)", ret << 12, MM_GetRefCount(ret<<12));
-       #endif
-       LEAVE('x', ret << 12);
-       return ret << 12;
-}
-
-/**
- * \brief Allocate a single physical page, with no preference as to address
- *        size.
- */
-tPAddr MM_AllocPhys(void)
-{
-        int    i;
-       
-       // Hack to allow allocation during setup
-       for(i = 0; i < NUM_STATIC_ALLOC; i++) {
-               if( gaiStaticAllocPages[i] ) {
-                       tPAddr  ret = gaiStaticAllocPages[i];
-                       gaiStaticAllocPages[i] = 0;
-                       Log("MM_AllocPhys: Return %P, static alloc %i", ret, i);
-                       return ret;
-               }
-       }
-       
-       return MM_AllocPhysRange(1, -1);
-}
-
-/**
- * \brief Reference a physical page
- */
-void MM_RefPhys(tPAddr PAddr)
-{
-       Uint64  page = PAddr >> 12;
-       
-       if( page > giMaxPhysPage )      return ;
-       
-       if( PAGE_ALLOC_TEST(page) )
-       {
-               tVAddr  ref_base = ((tVAddr)&gaiPageReferences[ page ]) & ~0xFFF;
-               // Allocate reference page
-               if( !MM_GetPhysAddr(ref_base) )
-               {
-                       const int       pages_per_refpage = PAGE_SIZE/sizeof(gaiPageReferences[0]);
-                        int    i;
-                        int    page_base = page / pages_per_refpage * pages_per_refpage;
-                       if( !MM_Allocate( ref_base ) ) {
-                               Log_Error("Arch", "Out of memory when allocating reference count page");
-                               return ;
-                       }
-                       // Fill block
-                       Log("Allocated references for %P-%P", page_base << 12, (page_base+pages_per_refpage)<<12);
-                       for( i = 0; i < pages_per_refpage; i ++ ) {
-                                int    pg = page_base + i;
-                               gaiPageReferences[pg] = !!PAGE_ALLOC_TEST(pg);
-                       }
-               }
-               gaiPageReferences[page] ++;
-       }
-       else
-       {
-               // Allocate
-               PAGE_ALLOC_SET(page);
-               if( gaMainBitmap[page >> 6] + 1 == 0 )
-                       gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
-               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
-                       gaiPageReferences[page] = 1;
-       }
-
-       #if TRACE_REF
-       Log("MM_RefPhys: %P referenced (%i)", page << 12, MM_GetRefCount(page << 12));
-       #endif
-}
-
-/**
- * \brief Dereference a physical page
- */
-void MM_DerefPhys(tPAddr PAddr)
-{
-       Uint64  page = PAddr >> 12;
-       
-       if( PAddr >> 12 > giMaxPhysPage )       return ;
-       
-       if( MM_GetPhysAddr( (tVAddr) &gaiPageReferences[page] ) )
-       {
-               gaiPageReferences[ page ] --;
-               if( gaiPageReferences[ page ] == 0 )
-                       PAGE_ALLOC_CLEAR(page);
-       }
-       else
-               PAGE_ALLOC_CLEAR(page);
-       
-       // Update the free counts if the page was freed
-       if( !PAGE_ALLOC_TEST(page) )
-       {
-                int    rangeID;
-               rangeID = MM_int_GetRangeID( PAddr );
-               giPhysRangeFree[ rangeID ] ++;
-               if( giPhysRangeFirst[rangeID] > page )
-                       giPhysRangeFirst[rangeID] = page;
-               if( giPhysRangeLast[rangeID] < page )
-                       giPhysRangeLast[rangeID] = page;
-       }
-       
-       // If the bitmap entry is not -1, unset the bit in the super bitmap
-       if(gaMainBitmap[ page >> 6 ] + 1 != 0 ) {
-               gaSuperBitmap[page >> 12] &= ~(1LL << ((page >> 6) & 63));
-       }
-       
-       #if TRACE_REF
-       Log("Page %P dereferenced (%i)", page << 12, MM_GetRefCount(page << 12));
-       #endif
-}
-
-int MM_GetRefCount( tPAddr PAddr )
-{
-       PAddr >>= 12;
-       
-       if( PAddr > giMaxPhysPage )     return 0;
-
-       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
-               return gaiPageReferences[PAddr];
-       }
-
-       if( PAGE_ALLOC_TEST(PAddr) )
-       {
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * \brief Takes a physical address and returns the ID of its range
- * \param Addr Physical address of page
- * \return Range ID from eMMPhys_Ranges
- */
-int MM_int_GetRangeID( tPAddr Addr )
-{
-       if(Addr >> 32)
-               return MM_PHYS_MAX;
-       else if(Addr >> 24)
-               return MM_PHYS_32BIT;
-       else if(Addr >> 20)
-               return MM_PHYS_24BIT;
-       else if(Addr >> 16)
-               return MM_PHYS_20BIT;
-       else
-               return MM_PHYS_16BIT;
-}
-
-int MM_SetPageNode(tPAddr PAddr, void *Node)
-{
-       tPAddr  page = PAddr >> 12;
-       tVAddr  node_page = ((tVAddr)&gapPageNodes[page]) & ~(PAGE_SIZE-1);
-
-//     if( !MM_GetRefCount(PAddr) )    return 1;
-       
-       if( !MM_GetPhysAddr(node_page) ) {
-               if( !MM_Allocate(node_page) )
-                       return -1;
-               memset( (void*)node_page, 0, PAGE_SIZE );
-       }
-
-       gapPageNodes[page] = Node;
-       return 0;
-}
-
-int MM_GetPageNode(tPAddr PAddr, void **Node)
-{
-//     if( !MM_GetRefCount(PAddr) )    return 1;
-       PAddr >>= 12;
-       
-       if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
-               *Node = NULL;
-               return 0;
-       }
-
-       *Node = gapPageNodes[PAddr];
-       return 0;
-}
-
diff --git a/Kernel/arch/x86_64/mm_virt.c b/Kernel/arch/x86_64/mm_virt.c
deleted file mode 100644 (file)
index 89aeaa1..0000000
+++ /dev/null
@@ -1,1110 +0,0 @@
-/*
- * Acess2 x86_64 Port
- * 
- * Virtual Memory Manager
- */
-#define DEBUG  0
-#include <acess.h>
-#include <mm_virt.h>
-#include <threads_int.h>
-#include <proc.h>
-#include <hal_proc.h>
-
-// === DEBUG OPTIONS ===
-#define TRACE_COW      0
-
-// === CONSTANTS ===
-#define PHYS_BITS      52      // TODO: Move out
-#define VIRT_BITS      48
-
-#define PML4_SHIFT     39
-#define PDP_SHIFT      30
-#define PDIR_SHIFT     21
-#define PTAB_SHIFT     12
-
-#define        PADDR_MASK      0x7FFFFFFF##FFFFF000
-#define PAGE_MASK      ((1LL << 36)-1)
-#define TABLE_MASK     ((1LL << 27)-1)
-#define PDP_MASK       ((1LL << 18)-1)
-#define PML4_MASK      ((1LL << 9)-1)
-
-#define        PF_PRESENT      0x001
-#define        PF_WRITE        0x002
-#define        PF_USER         0x004
-#define        PF_LARGE        0x080
-#define        PF_GLOBAL       0x100
-#define        PF_COW          0x200
-#define        PF_PAGED        0x400
-#define        PF_NX           0x80000000##00000000
-
-// === MACROS ===
-#define PAGETABLE(idx) (*((Uint64*)MM_FRACTAL_BASE+((idx)&PAGE_MASK)))
-#define PAGEDIR(idx)   PAGETABLE((MM_FRACTAL_BASE>>12)+((idx)&TABLE_MASK))
-#define PAGEDIRPTR(idx)        PAGEDIR((MM_FRACTAL_BASE>>21)+((idx)&PDP_MASK))
-#define PAGEMAPLVL4(idx)       PAGEDIRPTR((MM_FRACTAL_BASE>>30)+((idx)&PML4_MASK))
-
-#define TMPCR3()       PAGEMAPLVL4(MM_TMPFRAC_BASE>>39)
-#define TMPTABLE(idx)  (*((Uint64*)MM_TMPFRAC_BASE+((idx)&PAGE_MASK)))
-#define TMPDIR(idx)    PAGETABLE((MM_TMPFRAC_BASE>>12)+((idx)&TABLE_MASK))
-#define TMPDIRPTR(idx) PAGEDIR((MM_TMPFRAC_BASE>>21)+((idx)&PDP_MASK))
-#define TMPMAPLVL4(idx)        PAGEDIRPTR((MM_TMPFRAC_BASE>>30)+((idx)&PML4_MASK))
-
-#define INVLPG(__addr) __asm__ __volatile__ ("invlpg (%0)"::"r"(__addr))
-#define INVLPG_ALL()   __asm__ __volatile__ ("mov %cr3,%rax;\n\tmov %rax,%cr3;")
-#define INVLPG_GLOBAL()        __asm__ __volatile__ ("mov %cr4,%rax;\n\txorl $0x80, %eax;\n\tmov %rax,%cr4;\n\txorl $0x80, %eax;\n\tmov %rax,%cr4")
-
-// === CONSTS ===
-//tPAddr       * const gaPageTable = MM_FRACTAL_BASE;
-
-// === IMPORTS ===
-extern void    Error_Backtrace(Uint IP, Uint BP);
-extern tPAddr  gInitialPML4[512];
-extern void    Threads_SegFault(tVAddr Addr);
-extern char    _UsertextBase[];
-
-// === PROTOTYPES ===
-void   MM_InitVirt(void);
-//void MM_FinishVirtualInit(void);
-void   MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable );
- int   MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
-void   MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected);
-//void MM_DumpTables(tVAddr Start, tVAddr End);
- int   MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer);
- int   MM_MapEx(tVAddr VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge);
-// int MM_Map(tVAddr VAddr, tPAddr PAddr);
-void   MM_Unmap(tVAddr VAddr);
-void   MM_int_ClearTableLevel(tVAddr VAddr, int LevelBits, int MaxEnts);
-//void MM_ClearUser(void);
- int   MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags);
-
-// === GLOBALS ===
-tMutex glMM_TempFractalLock;
-tPAddr gMM_ZeroPage;
-
-// === CODE ===
-void MM_InitVirt(void)
-{
-//     Log_Debug("MMVirt", "&PAGEMAPLVL4(0) = %p", &PAGEMAPLVL4(0));
-//     MM_DumpTables(0, -1L);
-}
-
-void MM_FinishVirtualInit(void)
-{
-       PAGEMAPLVL4(0) = 0;
-}
-
-/**
- * \brief Clone a page from an entry
- * \param Ent  Pointer to the entry in the PML4/PDP/PD/PT
- * \param NextLevel    Pointer to contents of the entry
- * \param Addr Dest address
- * \note Used in COW
- */
-void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable )
-{
-       tPAddr  curpage = *Ent & PADDR_MASK; 
-        int    bCopied = 0;
-       
-       if( MM_GetRefCount( curpage ) <= 0 ) {
-               Log_KernelPanic("MMVirt", "Page %P still marked COW, but unreferenced", curpage);
-       }
-       if( MM_GetRefCount( curpage ) == 1 )
-       {
-               *Ent &= ~PF_COW;
-               *Ent |= PF_PRESENT|PF_WRITE;
-               #if TRACE_COW
-               Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
-               #endif
-       }
-       else
-       {
-               void    *tmp;
-               tPAddr  paddr;
-               
-               if( !(paddr = MM_AllocPhys()) ) {
-                       Threads_SegFault(Addr);
-                       return ;
-               }
-
-               ASSERT(paddr != curpage);
-                       
-               tmp = (void*)MM_MapTemp(paddr);
-               memcpy( tmp, NextLevel, 0x1000 );
-               MM_FreeTemp( (tVAddr)tmp );
-               
-               #if TRACE_COW
-               Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
-               #endif
-
-               MM_DerefPhys( curpage );
-               *Ent &= PF_USER;
-               *Ent |= paddr|PF_PRESENT|PF_WRITE;
-               
-               bCopied = 1;
-       }
-       INVLPG( (tVAddr)NextLevel );
-       
-       // Mark COW on contents if it's a PDPT, Dir or Table
-       if(bTable) 
-       {
-               Uint64  *dp = NextLevel;
-                int    i;
-               for( i = 0; i < 512; i ++ )
-               {
-                       if( !(dp[i] & PF_PRESENT) )
-                               continue;
-                       
-                       if( bCopied )
-                               MM_RefPhys( dp[i] & PADDR_MASK );
-                       if( dp[i] & PF_WRITE ) {
-                               dp[i] &= ~PF_WRITE;
-                               dp[i] |= PF_COW;
-                       }
-               }
-       }
-}
-
-/*
- * \brief Called on a page fault
- */
-int MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
-{
-//     Log_Debug("MMVirt", "Addr = %p, ErrorCode = %x", Addr, ErrorCode);
-
-       // Catch reserved bits first
-       if( ErrorCode & 0x8 )
-       {
-               Log_Warning("MMVirt", "Reserved bits trashed!");
-               Log_Warning("MMVirt", "PML4 Ent   = %P", PAGEMAPLVL4(Addr>>39));
-               if( !(PAGEMAPLVL4(Addr>>39) & PF_PRESENT) )     goto print_done;
-               Log_Warning("MMVirt", "PDP Ent    = %P", PAGEDIRPTR(Addr>>30));
-               if( !(PAGEDIRPTR(Addr>>30) & PF_PRESENT) )      goto print_done;
-               Log_Warning("MMVirt", "PDir Ent   = %P", PAGEDIR(Addr>>21));
-               if( !(PAGEDIR(Addr>>21) & PF_PRESENT) ) goto print_done;
-               Log_Warning("MMVirt", "PTable Ent = %P", PAGETABLE(Addr>>12));
-               if( !(PAGETABLE(Addr>>12) & PF_PRESENT) )       goto print_done;
-       print_done:
-               
-               for(;;);
-       }
-
-       // TODO: Implement Copy-on-Write
-       #if 1
-       if( PAGEMAPLVL4(Addr>>39) & PF_PRESENT
-        && PAGEDIRPTR (Addr>>30) & PF_PRESENT
-        && PAGEDIR    (Addr>>21) & PF_PRESENT
-        && PAGETABLE  (Addr>>12) & PF_PRESENT )
-       {
-               // PML4 Entry
-               if( PAGEMAPLVL4(Addr>>39) & PF_COW )
-               {
-                       tPAddr  *dp = &PAGEDIRPTR((Addr>>39)*512);
-                       MM_int_ClonePageEnt( &PAGEMAPLVL4(Addr>>39), dp, Addr, 1 );
-//                     MM_DumpTables(Addr>>39 << 39, (((Addr>>39) + 1) << 39) - 1);
-               }
-               // PDP Entry
-               if( PAGEDIRPTR(Addr>>30) & PF_COW )
-               {
-                       tPAddr  *dp = &PAGEDIR( (Addr>>30)*512 );
-                       MM_int_ClonePageEnt( &PAGEDIRPTR(Addr>>30), dp, Addr, 1 );
-//                     MM_DumpTables(Addr>>30 << 30, (((Addr>>30) + 1) << 30) - 1);
-               }
-               // PD Entry
-               if( PAGEDIR(Addr>>21) & PF_COW )
-               {
-                       tPAddr  *dp = &PAGETABLE( (Addr>>21)*512 );
-                       MM_int_ClonePageEnt( &PAGEDIR(Addr>>21), dp, Addr, 1 );
-//                     MM_DumpTables(Addr>>21 << 21, (((Addr>>21) + 1) << 21) - 1);
-               }
-               // PT Entry
-               if( PAGETABLE(Addr>>12) & PF_COW )
-               {
-                       MM_int_ClonePageEnt( &PAGETABLE(Addr>>12), (void*)(Addr & ~0xFFF), Addr, 0 );
-                       INVLPG( Addr & ~0xFFF );
-                       return 0;
-               }
-       }
-       #endif
-       
-       // If it was a user, tell the thread handler
-       if(ErrorCode & 4) {
-               Warning("User %s %s memory%s",
-                       (ErrorCode&2?"write to":"read from"),
-                       (ErrorCode&1?"bad/locked":"non-present"),
-                       (ErrorCode&16?" (Instruction Fetch)":"")
-                       );
-               Warning("User Pagefault: Instruction at %04x:%p accessed %p",
-                       Regs->CS, Regs->RIP, Addr);
-               __asm__ __volatile__ ("sti");   // Restart IRQs
-               Error_Backtrace(Regs->RIP, Regs->RBP);
-               Threads_SegFault(Addr);
-               return 0;
-       }
-       
-       // Kernel #PF
-       Debug_KernelPanic();
-       // -- Check Error Code --
-       if(ErrorCode & 8)
-               Warning("Reserved Bits Trashed!");
-       else
-       {
-               Warning("Kernel %s %s memory%s",
-                       (ErrorCode&2?"write to":"read from"),
-                       (ErrorCode&1?"bad/locked":"non-present"),
-                       (ErrorCode&16?" (Instruction Fetch)":"")
-                       );
-       }
-       
-       Log("Thread %i - Code at %p accessed %p", Threads_GetTID(), Regs->RIP, Addr);
-       // Print Stack Backtrace
-       Error_Backtrace(Regs->RIP, Regs->RBP);
-       
-       MM_DumpTables(0, -1);
-
-       return 1;       
-}
-
-void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected)
-{
-       #define CANOICAL(addr)  ((addr)&0x800000000000?(addr)|0xFFFF000000000000:(addr))
-       LogF("%016llx => ", CANOICAL(RangeStart));
-//     LogF("%6llx %6llx %6llx %016llx => ",
-//             MM_GetPhysAddr( (tVAddr)&PAGEDIRPTR(RangeStart>>30) ),
-//             MM_GetPhysAddr( (tVAddr)&PAGEDIR(RangeStart>>21) ),
-//             MM_GetPhysAddr( (tVAddr)&PAGETABLE(RangeStart>>12) ),
-//             CANOICAL(RangeStart)
-//             );
-       if( gMM_ZeroPage && (PAGETABLE(RangeStart>>12) & PADDR_MASK) == gMM_ZeroPage )
-               LogF("%13s", "zero" );
-       else
-               LogF("%13llx", PAGETABLE(RangeStart>>12) & PADDR_MASK );
-       LogF(" : 0x%6llx (%c%c%c%c%c%c)\r\n",
-               Length,
-               (Expected & PF_GLOBAL ? 'G' : '-'),
-               (Expected & PF_NX ? '-' : 'x'),
-               (Expected & PF_PAGED ? 'p' : '-'),
-               (Expected & PF_COW ? 'C' : '-'),
-               (Expected & PF_USER ? 'U' : '-'),
-               (Expected & PF_WRITE ? 'W' : '-')
-               );
-       #undef CANOICAL
-}
-
-/**
- * \brief Dumps the layout of the page tables
- */
-void MM_DumpTables(tVAddr Start, tVAddr End)
-{
-       const tPAddr    FIXED_BITS = PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED|PF_NX|PF_GLOBAL;
-       const tPAddr    CHANGEABLE_BITS = ~FIXED_BITS & 0xFFF;
-       const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
-       tVAddr  rangeStart = 0;
-       tPAddr  expected = CHANGEABLE_BITS;     // CHANGEABLE_BITS is used because it's not a vaild value
-       tVAddr  curPos;
-       Uint    page;
-       tPAddr  expected_pml4 = PF_WRITE|PF_USER;       
-       tPAddr  expected_pdp = PF_WRITE|PF_USER;        
-       tPAddr  expected_pd = PF_WRITE|PF_USER; 
-
-       Log("Table Entries: (%p to %p)", Start, End);
-       
-       End &= (1L << 48) - 1;
-       
-       Start >>= 12;   End >>= 12;
-       
-       for(page = Start, curPos = Start<<12;
-               page < End;
-               curPos += 0x1000, page++)
-       {
-               //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27));
-               //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18));
-               //Debug("&PAGEDIR(%i page>>9) = %p", page>>9, &PAGEDIR(page>>9));
-               //Debug("&PAGETABLE(%i page) = %p", page, &PAGETABLE(page));
-               
-               // End of a range
-               if(!(PAGEMAPLVL4(page>>27) & PF_PRESENT)
-               ||  (PAGEMAPLVL4(page>>27) & FIXED_BITS) != expected_pml4
-               || !(PAGEDIRPTR(page>>18) & PF_PRESENT)
-               ||  (PAGEDIRPTR(page>>18) & FIXED_BITS) != expected_pdp
-               || !(PAGEDIR(page>>9) & PF_PRESENT)
-               ||  (PAGEDIR(page>>9) & FIXED_BITS) != expected_pd
-               || !(PAGETABLE(page) & PF_PRESENT)
-               ||  (PAGETABLE(page) & MASK) != expected)
-               {                       
-                       if(expected != CHANGEABLE_BITS)
-                       {
-                               // Merge
-                               expected &= expected_pml4 | ~(PF_WRITE|PF_USER);
-                               expected &= expected_pdp  | ~(PF_WRITE|PF_USER);
-                               expected &= expected_pd   | ~(PF_WRITE|PF_USER);
-                               expected |= expected_pml4 & PF_NX;
-                               expected |= expected_pdp  & PF_NX;
-                               expected |= expected_pd   & PF_NX;
-                               Log("expected (pml4 = %x, pdp = %x, pd = %x)",
-                                       expected_pml4, expected_pdp, expected_pd);
-                               // Dump
-                               MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
-                               expected = CHANGEABLE_BITS;
-                       }
-                       
-                       if( curPos == 0x800000000000L )
-                               curPos = 0xFFFF800000000000L;
-               
-                       if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) ) {
-                               page += (1 << 27) - 1;
-                               curPos += (1L << 39) - 0x1000;
-                               continue;
-                       }
-                       if( !(PAGEDIRPTR(page>>18) & PF_PRESENT) ) {
-                               page += (1 << 18) - 1;
-                               curPos += (1L << 30) - 0x1000;
-                               continue;
-                       }
-                       if( !(PAGEDIR(page>>9) & PF_PRESENT) ) {
-                               page += (1 << 9) - 1;
-                               curPos += (1L << 21) - 0x1000;
-                               continue;
-                       }
-                       if( !(PAGETABLE(page) & PF_PRESENT) )   continue;
-                       
-                       expected = (PAGETABLE(page) & MASK);
-                       expected_pml4 = (PAGEMAPLVL4(page>>27) & FIXED_BITS);
-                       expected_pdp  = (PAGEDIRPTR (page>>18) & FIXED_BITS);
-                       expected_pd   = (PAGEDIR    (page>> 9) & FIXED_BITS);
-                       rangeStart = curPos;
-               }
-               if(gMM_ZeroPage && (expected & PADDR_MASK) == gMM_ZeroPage )
-                       expected = expected;
-               else if(expected != CHANGEABLE_BITS)
-                       expected += 0x1000;
-       }
-       
-       if(expected != CHANGEABLE_BITS) {
-               // Merge
-               
-               // Dump
-               MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
-               expected = 0;
-       }
-}
-
-/**
- * \brief Get a pointer to a page entry
- * \param Addr Virtual Address
- * \param bTemp        Use the Temporary fractal mapping
- * \param bAllocate    Allocate entries
- * \param bLargePage   Request a large page
- * \param Pointer      Location to place the calculated pointer
- * \return Page size, or -ve on error
- */
-int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer)
-{
-       tPAddr  *pmlevels[4];
-       tPAddr  tmp;
-        int    i, size;
-       
-       #define BITMASK(bits)   ( (1LL << (bits))-1 )
-
-       if( bTemp )
-       {
-               pmlevels[3] = &TMPTABLE(0);     // Page Table
-               pmlevels[2] = &TMPDIR(0);       // PDIR
-               pmlevels[1] = &TMPDIRPTR(0);    // PDPT
-               pmlevels[0] = &TMPMAPLVL4(0);   // PML4
-       }
-       else
-       {
-               pmlevels[3] = (void*)MM_FRACTAL_BASE;   // Page Table
-               pmlevels[2] = &pmlevels[3][(MM_FRACTAL_BASE>>12)&BITMASK(VIRT_BITS-12)];        // PDIR
-               pmlevels[1] = &pmlevels[2][(MM_FRACTAL_BASE>>21)&BITMASK(VIRT_BITS-21)];        // PDPT
-               pmlevels[0] = &pmlevels[1][(MM_FRACTAL_BASE>>30)&BITMASK(VIRT_BITS-30)];        // PML4
-       }
-       
-       // Mask address
-       Addr &= (1ULL << 48)-1;
-       
-       for( size = 39, i = 0; size > 12; size -= 9, i ++ )
-       {
-               Uint64  *ent = &pmlevels[i][Addr >> size];
-//             INVLPG( &pmlevels[i][ (Addr >> ADDR_SIZES[i]) & 
-               
-               // Check for a free large page slot
-               // TODO: Better support with selectable levels
-               if( (Addr & ((1ULL << size)-1)) == 0 && bLargePage )
-               {
-                       if(Pointer)     *Pointer = ent;
-                       return size;
-               }
-               // Allocate an entry if required
-               if( !(*ent & PF_PRESENT) )
-               {
-                       if( !bAllocate )        return -4;      // If allocation is not requested, error
-                       if( !(tmp = MM_AllocPhys()) )   return -2;
-                       *ent = tmp | 3;
-                       if( Addr < 0x800000000000 )
-                               *ent |= PF_USER;
-                       INVLPG( &pmlevels[i+1][ (Addr>>size)*512 ] );
-                       memset( &pmlevels[i+1][ (Addr>>size)*512 ], 0, 0x1000 );
-                       LOG("Init PML%i ent 0x%x %p with %P (*ent = %P)", 4 - i,
-                               Addr>>size, (Addr>>size) << size, tmp, *ent);
-               }
-               // Catch large pages
-               else if( *ent & PF_LARGE )
-               {
-                       // Alignment
-                       if( (Addr & ((1ULL << size)-1)) != 0 )  return -3;
-                       if(Pointer)     *Pointer = ent;
-                       return size;    // Large page warning
-               }
-       }
-       
-       // And, set the page table entry
-       if(Pointer)     *Pointer = &pmlevels[i][Addr >> size];
-       return size;
-}
-
-/**
- * \brief Map a physical page to a virtual one
- * \param VAddr        Target virtual address
- * \param PAddr        Physical address of page
- * \param bTemp        Use tempoary mappings
- * \param bLarge       Treat as a large page
- */
-int MM_MapEx(tVAddr VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge)
-{
-       tPAddr  *ent;
-        int    rv;
-       
-       ENTER("pVAddr PPAddr", VAddr, PAddr);
-       
-       // Get page pointer (Allow allocating)
-       rv = MM_GetPageEntryPtr(VAddr, bTemp, 1, bLarge, &ent);
-       if(rv < 0)      LEAVE_RET('i', 0);
-       
-       if( *ent & 1 )  LEAVE_RET('i', 0);
-       
-       *ent = PAddr | 3;
-
-       if( VAddr < 0x800000000000 )
-               *ent |= PF_USER;
-
-       INVLPG( VAddr );
-
-       LEAVE('i', 1);  
-       return 1;
-}
-
-/**
- * \brief Map a physical page to a virtual one
- * \param VAddr        Target virtual address
- * \param PAddr        Physical address of page
- */
-int MM_Map(tVAddr VAddr, tPAddr PAddr)
-{
-       return MM_MapEx(VAddr, PAddr, 0, 0);
-}
-
-/**
- * \brief Removed a mapped page
- */
-void MM_Unmap(tVAddr VAddr)
-{
-       // Check PML4
-       if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )   return ;
-       // Check PDP
-       if( !(PAGEDIRPTR(VAddr >> 30) & 1) )    return ;
-       // Check Page Dir
-       if( !(PAGEDIR(VAddr >> 21) & 1) )       return ;
-
-       PAGETABLE(VAddr >> PTAB_SHIFT) = 0;
-       INVLPG( VAddr );
-}
-
-/**
- * \brief Allocate a block of memory at the specified virtual address
- */
-tPAddr MM_Allocate(tVAddr VAddr)
-{
-       tPAddr  ret;
-       
-       ENTER("xVAddr", VAddr);
-       
-       // Ensure the tables are allocated before the page (keeps things neat)
-       MM_GetPageEntryPtr(VAddr, 0, 1, 0, NULL);
-       
-       // Allocate the page
-       ret = MM_AllocPhys();
-       LOG("ret = %x", ret);
-       if(!ret)        LEAVE_RET('i', 0);
-       
-       if( !MM_Map(VAddr, ret) )
-       {
-               Warning("MM_Allocate: Unable to map. Strange, we should have errored earlier");
-               MM_DerefPhys(ret);
-               LEAVE('i');
-               return 0;
-       }
-       
-       LEAVE('X', ret);
-       return ret;
-}
-
-tPAddr MM_AllocateZero(tVAddr VAddr)
-{
-       tPAddr  ret = gMM_ZeroPage;
-       
-       MM_GetPageEntryPtr(VAddr, 0, 1, 0, NULL);
-
-       if(!gMM_ZeroPage) {
-               ret = gMM_ZeroPage = MM_AllocPhys();
-               MM_RefPhys(ret);        // Don't free this please
-               MM_Map(VAddr, ret);
-               memset((void*)VAddr, 0, 0x1000);
-       }
-       else {
-               MM_Map(VAddr, ret);
-       }
-       MM_RefPhys(ret);        // Refernce for this map
-       MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
-       return ret;
-}
-
-/**
- * \brief Deallocate a page at a virtual address
- */
-void MM_Deallocate(tVAddr VAddr)
-{
-       tPAddr  phys;
-       
-       phys = MM_GetPhysAddr(VAddr);
-       if(!phys)       return ;
-       
-       MM_Unmap(VAddr);
-       
-       MM_DerefPhys(phys);
-}
-
-/**
- * \brief Get the page table entry of a virtual address
- * \param Addr Virtual Address
- * \param Phys Location to put the physical address
- * \param Flags        Flags on the entry (set to zero if unmapped)
- * \return Size of the entry (in address bits) - 12 = 4KiB page
- */
-int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags)
-{
-       tPAddr  *ptr;
-        int    ret;
-       
-       if(!Phys || !Flags)     return 0;
-       
-       ret = MM_GetPageEntryPtr(Addr, 0, 0, 0, &ptr);
-       if( ret < 0 )   return 0;
-       
-       *Phys = *ptr & PADDR_MASK;
-       *Flags = *ptr & 0xFFF;
-       return ret;
-}
-
-/**
- * \brief Get the physical address of a virtual location
- */
-tPAddr MM_GetPhysAddr(tVAddr Addr)
-{
-       tPAddr  *ptr;
-        int    ret;
-       
-       ret = MM_GetPageEntryPtr(Addr, 0, 0, 0, &ptr);
-       if( ret < 0 )   return 0;
-       
-       if( !(*ptr & 1) )       return 0;
-       
-       return (*ptr & PADDR_MASK) | (Addr & 0xFFF);
-}
-
-/**
- * \brief Sets the flags on a page
- */
-void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
-{
-       tPAddr  *ent;
-        int    rv;
-       
-       // Get pointer
-       rv = MM_GetPageEntryPtr(VAddr, 0, 0, 0, &ent);
-       if(rv < 0)      return ;
-       
-       // Ensure the entry is valid
-       if( !(*ent & 1) )       return ;
-       
-       // Read-Only
-       if( Mask & MM_PFLAG_RO )
-       {
-               if( Flags & MM_PFLAG_RO ) {
-                       *ent &= ~PF_WRITE;
-               }
-               else {
-                       *ent |= PF_WRITE;
-               }
-       }
-       
-       // Kernel
-       if( Mask & MM_PFLAG_KERNEL )
-       {
-               if( Flags & MM_PFLAG_KERNEL ) {
-                       *ent &= ~PF_USER;
-               }
-               else {
-                       *ent |= PF_USER;
-               }
-       }
-       
-       // Copy-On-Write
-       if( Mask & MM_PFLAG_COW )
-       {
-               if( Flags & MM_PFLAG_COW ) {
-                       *ent &= ~PF_WRITE;
-                       *ent |= PF_COW;
-       INVLPG_ALL();
-               }
-               else {
-                       *ent &= ~PF_COW;
-                       *ent |= PF_WRITE;
-               }
-       }
-       
-       // Execute
-       if( Mask & MM_PFLAG_EXEC )
-       {
-               if( Flags & MM_PFLAG_EXEC ) {
-                       *ent &= ~PF_NX;
-               }
-               else {
-                       *ent |= PF_NX;
-               }
-       }
-}
-
-/**
- * \brief Get the flags applied to a page
- */
-Uint MM_GetFlags(tVAddr VAddr)
-{
-       tPAddr  *ent;
-        int    rv, ret = 0;
-       
-       rv = MM_GetPageEntryPtr(VAddr, 0, 0, 0, &ent);
-       if(rv < 0)      return 0;
-       
-       if( !(*ent & 1) )       return 0;
-       
-       // Read-Only
-       if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
-       // Kernel
-       if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
-       // Copy-On-Write
-       if( *ent & PF_COW )     ret |= MM_PFLAG_COW;    
-       // Execute
-       if( !(*ent & PF_NX) )   ret |= MM_PFLAG_EXEC;
-       
-       return ret;
-}
-
-/**
- * \brief Check if the provided buffer is valid
- * \return Boolean valid
- */
-int MM_IsValidBuffer(tVAddr Addr, size_t Size)
-{
-        int    bIsUser;
-       Uint64  pml4, pdp, dir, tab;
-
-       Size += Addr & (PAGE_SIZE-1);
-       Addr &= ~(PAGE_SIZE-1);
-       Addr &= ((1UL << 48)-1);        // Clap to address space
-
-       pml4 = Addr >> 39;
-       pdp = Addr >> 30;
-       dir = Addr >> 21;
-       tab = Addr >> 12;
-
-       if( !(PAGEMAPLVL4(pml4) & 1) )  return 0;
-       if( !(PAGEDIRPTR(pdp) & 1) )    return 0;
-       if( !(PAGEDIR(dir) & 1) )       return 0;
-       if( !(PAGETABLE(tab) & 1) )     return 0;
-       
-       bIsUser = !!(PAGETABLE(tab) & PF_USER);
-
-       while( Size >= PAGE_SIZE )
-       {
-               if( (tab & 511) == 0 )
-               {
-                       dir ++;
-                       if( ((dir >> 9) & 511) == 0 )
-                       {
-                               pdp ++;
-                               if( ((pdp >> 18) & 511) == 0 )
-                               {
-                                       pml4 ++;
-                                       if( !(PAGEMAPLVL4(pml4) & 1) )  return 0;
-                               }
-                               if( !(PAGEDIRPTR(pdp) & 1) )    return 0;
-                       }
-                       if( !(PAGEDIR(dir) & 1) )       return 0;
-               }
-               
-               if( !(PAGETABLE(tab) & 1) )   return 0;
-               if( bIsUser && !(PAGETABLE(tab) & PF_USER) )    return 0;
-
-               tab ++;
-               Size -= PAGE_SIZE;
-       }
-       return 1;
-}
-
-// --- Hardware Mappings ---
-/**
- * \brief Map a range of hardware pages
- */
-tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
-{
-       tVAddr  ret;
-        int    num;
-       
-       //TODO: Add speedups (memory of first possible free)
-       for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_TOP; ret += 0x1000 )
-       {
-               for( num = Number; num -- && ret < MM_HWMAP_TOP; ret += 0x1000 )
-               {
-                       if( MM_GetPhysAddr(ret) != 0 )  break;
-               }
-               if( num >= 0 )  continue;
-               
-//             Log_Debug("MMVirt", "Mapping %i pages to %p (base %P)", Number, ret-Number*0x1000, PAddr);
-
-               PAddr += 0x1000 * Number;
-               
-               while( Number -- )
-               {
-                       ret -= 0x1000;
-                       PAddr -= 0x1000;
-                       MM_Map(ret, PAddr);
-                       MM_RefPhys(PAddr);
-               }
-               
-               return ret;
-       }
-       
-       Log_Error("MM", "MM_MapHWPages - No space for %i pages", Number);
-       return 0;
-}
-
-/**
- * \brief Free a range of hardware pages
- */
-void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
-{
-//     Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
-       while( Number -- )
-       {
-               MM_DerefPhys( MM_GetPhysAddr(VAddr) );
-               MM_Unmap(VAddr);
-               VAddr += 0x1000;
-       }
-}
-
-
-/**
- * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
- * \brief Allocates DMA physical memory
- * \param Pages        Number of pages required
- * \param MaxBits      Maximum number of bits the physical address can have
- * \param PhysAddr     Pointer to the location to place the physical address allocated
- * \return Virtual address allocate
- */
-tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
-{
-       tPAddr  phys;
-       tVAddr  ret;
-       
-       // Sanity Check
-       if(MaxBits < 12 || !PhysAddr)   return 0;
-       
-       // Fast Allocate
-       if(Pages == 1 && MaxBits >= PHYS_BITS)
-       {
-               phys = MM_AllocPhys();
-               *PhysAddr = phys;
-               ret = MM_MapHWPages(phys, 1);
-               MM_DerefPhys(phys);
-               return ret;
-       }
-       
-       // Slow Allocate
-       phys = MM_AllocPhysRange(Pages, MaxBits);
-       // - Was it allocated?
-       if(phys == 0)   return 0;
-       
-       // Allocated successfully, now map
-       ret = MM_MapHWPages(phys, Pages);
-       // MapHWPages references the pages, so deref them back down to 1
-       for(;Pages--;phys+=0x1000)
-               MM_DerefPhys(phys);
-       if( ret == 0 ) {
-               // If it didn't map, free then return 0
-               return 0;
-       }
-       
-       *PhysAddr = phys;
-       return ret;
-}
-
-// --- Tempory Mappings ---
-tVAddr MM_MapTemp(tPAddr PAddr)
-{
-       const int max_slots = (MM_TMPMAP_END - MM_TMPMAP_BASE) / PAGE_SIZE;
-       tVAddr  ret = MM_TMPMAP_BASE;
-        int    i;
-       
-       for( i = 0; i < max_slots; i ++, ret += PAGE_SIZE )
-       {
-               tPAddr  *ent;
-               if( MM_GetPageEntryPtr( ret, 0, 1, 0, &ent) < 0 ) {
-                       continue ;
-               }
-
-               if( *ent & 1 )
-                       continue ;
-
-               *ent = PAddr | 3;
-               MM_RefPhys(PAddr);
-               INVLPG(ret);
-               return ret;
-       }
-       return 0;
-}
-
-void MM_FreeTemp(tVAddr VAddr)
-{
-       MM_Deallocate(VAddr);
-       return ;
-}
-
-
-// --- Address Space Clone --
-tPAddr MM_Clone(void)
-{
-       tPAddr  ret;
-        int    i;
-       tVAddr  kstackbase;
-
-       // #1 Create a copy of the PML4
-       ret = MM_AllocPhys();
-       if(!ret)        return 0;
-       
-       // #2 Alter the fractal pointer
-       Mutex_Acquire(&glMM_TempFractalLock);
-       TMPCR3() = ret | 3;
-       INVLPG_ALL();
-       
-       // #3 Set Copy-On-Write to all user pages
-       if( Threads_GetPID() != 0 )
-       {
-               for( i = 0; i < 256; i ++)
-               {
-                       if( PAGEMAPLVL4(i) & PF_WRITE ) {
-                               PAGEMAPLVL4(i) |= PF_COW;
-                               PAGEMAPLVL4(i) &= ~PF_WRITE;
-                       }
-       
-                       TMPMAPLVL4(i) = PAGEMAPLVL4(i);
-//                     Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i));
-                       if( !(TMPMAPLVL4(i) & PF_PRESENT) )     continue ;
-                       
-                       MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
-               }
-       }
-       else
-       {
-               for( i = 0; i < 256; i ++ )
-               {
-                       TMPMAPLVL4(i) = 0;
-               }
-       }
-       
-       // #4 Map in kernel pages
-       for( i = 256; i < 512; i ++ )
-       {
-               // Skip addresses:
-               // 320 0xFFFFA....      - Kernel Stacks
-               if( i == MM_KSTACK_BASE>>39 )   continue;
-               // 509 0xFFFFFE0..      - Fractal mapping
-               if( i == MM_FRACTAL_BASE>>39 )  continue;
-               // 510 0xFFFFFE8..      - Temp fractal mapping
-               if( i == MM_TMPFRAC_BASE>>39 )  continue;
-               
-               TMPMAPLVL4(i) = PAGEMAPLVL4(i);
-               if( TMPMAPLVL4(i) & 1 )
-                       MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
-       }
-
-       // Mark Per-Process data as COW
-       TMPMAPLVL4(MM_PPD_BASE>>39) |= PF_COW;
-       TMPMAPLVL4(MM_PPD_BASE>>39) &= ~PF_WRITE;
-       
-       // #5 Set fractal mapping
-       TMPMAPLVL4(MM_FRACTAL_BASE>>39) = ret | 3;      // Main
-       TMPMAPLVL4(MM_TMPFRAC_BASE>>39) = 0;    // Temp
-       
-       // #6 Create kernel stack
-       //  tThread->KernelStack is the top
-       //  There is 1 guard page below the stack
-       kstackbase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE;
-
-       // Clone stack
-       TMPMAPLVL4(MM_KSTACK_BASE >> PML4_SHIFT) = 0;
-       for( i = 1; i < KERNEL_STACK_SIZE/0x1000; i ++ )
-       {
-               tPAddr  phys = MM_AllocPhys();
-               tVAddr  tmpmapping;
-               MM_MapEx(kstackbase+i*0x1000, phys, 1, 0);
-               
-               tmpmapping = MM_MapTemp(phys);
-               if( MM_GetPhysAddr( kstackbase+i*0x1000 ) )
-                       memcpy((void*)tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
-               else
-                       memset((void*)tmpmapping, 0, 0x1000);
-//             if( i == 0xF )
-//                     Debug_HexDump("MM_Clone: *tmpmapping = ", (void*)tmpmapping, 0x1000);
-               MM_FreeTemp(tmpmapping);
-       }
-       
-//     MAGIC_BREAK();
-
-       // #7 Return
-       TMPCR3() = 0;
-       INVLPG_ALL();
-       Mutex_Release(&glMM_TempFractalLock);
-//     Log("MM_Clone: RETURN %P", ret);
-       return ret;
-}
-
-void MM_int_ClearTableLevel(tVAddr VAddr, int LevelBits, int MaxEnts)
-{
-       Uint64  * const table_bases[] = {&PAGETABLE(0), &PAGEDIR(0), &PAGEDIRPTR(0), &PAGEMAPLVL4(0)};
-       Uint64  *table = table_bases[(LevelBits-12)/9] + (VAddr >> LevelBits);
-        int    i;
-//     Log("MM_int_ClearTableLevel: (VAddr=%p, LevelBits=%i, MaxEnts=%i)", VAddr, LevelBits, MaxEnts);
-       for( i = 0; i < MaxEnts; i ++ )
-       {
-               // Skip non-present tables
-               if( !(table[i] & PF_PRESENT) ) {
-                       table[i] = 0;
-                       continue ;
-               }
-       
-               if( (table[i] & PF_COW) && MM_GetRefCount(table[i] & PADDR_MASK) > 1 ) {
-                       MM_DerefPhys(table[i] & PADDR_MASK);
-                       table[i] = 0;
-                       continue ;
-               }
-               // Clear table contents (if it is a table)
-               if( LevelBits > 12 )
-                       MM_int_ClearTableLevel(VAddr + ((tVAddr)i << LevelBits), LevelBits-9, 512);
-               MM_DerefPhys(table[i] & PADDR_MASK);
-               table[i] = 0;
-       }
-}
-
-void MM_ClearUser(void)
-{
-       MM_int_ClearTableLevel(0, 39, 256);     
-}
-
-tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize)
-{
-       tVAddr  ret;
-       tPAddr  phys;
-        int    i;
-       
-       // #1 Set temp fractal to PID0
-       Mutex_Acquire(&glMM_TempFractalLock);
-       TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3;
-       INVLPG_ALL();
-       
-       // #2 Scan for a free stack addresss < 2^47
-       for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE)
-       {
-               tPAddr  *ptr;
-               if( MM_GetPageEntryPtr(ret, 1, 0, 0, &ptr) <= 0 )       break;
-               if( !(*ptr & 1) )       break;
-       }
-       if( ret >= (1ULL << 47) ) {
-               Mutex_Release(&glMM_TempFractalLock);
-               return 0;
-       }
-       
-       // #3 Map all save the last page in the range
-       //  - This acts as as guard page
-       MM_GetPageEntryPtr(ret, 1, 1, 0, NULL); // Make sure tree is allocated
-       for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ )
-       {
-               phys = MM_AllocPhys();
-               if(!phys) {
-                       // TODO: Clean up
-                       Log_Error("MM", "MM_NewWorkerStack - Unable to allocate page");
-                       return 0;
-               }
-               MM_MapEx(ret + i*0x1000, phys, 1, 0);
-               MM_SetFlags(ret + i*0x1000, MM_PFLAG_KERNEL|MM_PFLAG_RO, MM_PFLAG_KERNEL);
-       }
-
-       // Copy data
-       if( StackSize > 0x1000 ) {
-               Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize);
-       }
-       else {
-               tVAddr  tmp_addr, dest;
-               tmp_addr = MM_MapTemp(phys);
-               dest = tmp_addr + (0x1000 - StackSize);
-               memcpy( (void*)dest, StackData, StackSize );
-               Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i);
-               Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret);
-               MM_FreeTemp(tmp_addr);
-       }
-
-       TMPCR3() = 0;
-       Mutex_Release(&glMM_TempFractalLock);
-       
-       return ret + i*0x1000;
-}
-
-/**
- * \brief Allocate a new kernel stack
- */
-tVAddr MM_NewKStack(void)
-{
-       tVAddr  base = MM_KSTACK_BASE;
-       Uint    i;
-       for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
-       {
-               if(MM_GetPhysAddr(base+KERNEL_STACK_SIZE-0x1000) != 0)
-                       continue;
-               
-               //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
-               for( i = 0x1000; i < KERNEL_STACK_SIZE; i += 0x1000)
-               {
-                       if( !MM_Allocate(base+i) )
-                       {
-                               Log_Warning("MM", "MM_NewKStack - Allocation failed");
-                               for( i -= 0x1000; i; i -= 0x1000)
-                                       MM_Deallocate(base+i);
-                               return 0;
-                       }
-               }
-               
-               return base + KERNEL_STACK_SIZE;
-       }
-       Log_Warning("MM", "MM_NewKStack - No address space left\n");
-       return 0;
-}
diff --git a/Kernel/arch/x86_64/pci.c b/Kernel/arch/x86_64/pci.c
deleted file mode 120000 (symlink)
index cac29a8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../x86/pci.c
\ No newline at end of file
diff --git a/Kernel/arch/x86_64/proc.asm b/Kernel/arch/x86_64/proc.asm
deleted file mode 100644 (file)
index f540b3b..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-;
-;
-;
-%include "arch/x86_64/include/common.inc.asm"
-[BITS 64]
-[section .text]
-
-[extern Threads_Exit]
-
-[global GetRIP]
-GetRIP:
-       mov rax, [rsp]
-       ret
-
-[global NewTaskHeader]
-NewTaskHeader:
-       ; [rsp+0x00]: Thread
-       ; [rsp+0x08]: Function
-       ; [rsp+0x10]: Argument
-
-       mov rdi, [rsp+0x10]
-       mov rax, [rsp+0x8]
-       add rsp, 0x10   ; Reclaim stack space (thread/fcn)
-       xchg bx, bx
-       call rax
-       
-       ; Quit thread with RAX as the return code
-       xor rdi, rdi
-       mov rsi, rax
-       call Threads_Exit
-
-.hlt:
-       jmp .hlt
-
-[extern MM_Clone]
-[extern MM_DumpTables]
-[global Proc_CloneInt]
-Proc_CloneInt:
-       PUSH_GPR
-       ; Save RSP
-       mov [rdi], rsp
-       call MM_Clone
-       ; Save CR3
-       mov rsi, [rsp+0x30]     ; Saved version of RSI
-       mov [rsi], rax
-       ; Undo the PUSH_GPR
-       add rsp, 0x80
-       mov rax, .newTask
-       ret
-.newTask:
-;      mov rdi, 0
-;      mov rsi, 0x800000000000
-;      call MM_DumpTables
-       POP_GPR
-       xor eax, eax
-       ret
-
-[global SaveState]
-SaveState:
-       ; Save regs to RSI
-       add rsi, 0x80
-       SAVE_GPR rsi
-       ; Save return addr
-       mov rax, [rsp]
-       mov [rsi], rax
-       ; Return RSI as the RSP value
-       sub rsi, 0x80
-       mov [rdi], rsi
-       ; Check for 
-       mov rax, .restore
-       ret
-.restore:
-       ; RSP = RSI now
-       POP_GPR
-       mov rax, [rsp]
-       mov rsp, [rsp-0x60]     ; Restore RSP from the saved value
-       mov [rsp], rax  ; Restore return address
-       xor eax, eax
-       ret
-
-[global SwitchTasks]
-; rdi = New RSP
-; rsi = Old RSP save loc
-; rdx = New RIP
-; rcx = Old RIP save loc
-; r8 = CR3
-SwitchTasks:
-       PUSH_GPR
-       
-       ; Save state RIP and RSP
-       lea rax, [rel .restore]
-       mov [rcx], rax
-       mov [rsi], rsp
-
-       ; Change CR3 if requested
-       test r8, r8
-       jz .setState
-       mov cr3, r8
-       
-       ; Make sure the stack is valid before jumping
-       invlpg [rdi-0x1000]
-       invlpg [rdi]
-       invlpg [rdi+0x1000]
-       
-       ; Go to new state
-.setState:
-       mov rsp, rdi
-       jmp rdx
-
-       ; Restore point for saved state
-.restore:
-       POP_GPR
-       xor eax, eax    ; Return zero
-       ret
-
-[global Proc_InitialiseSSE]
-Proc_InitialiseSSE:
-       mov rax, cr4
-       or ax, (1 << 9)|(1 << 10)       ; Set OSFXSR and OSXMMEXCPT
-       mov cr4, rax
-       mov rax, cr0
-       and ax, ~(1 << 2)       ; Clear EM
-       or rax, (1 << 1)        ; Set MP
-       mov rax, cr0
-       ret
-[global Proc_DisableSSE]
-Proc_DisableSSE:
-       mov rax, cr0
-       or ax, 1 << 3   ; Set TS
-       mov cr0, rax
-       ret
-[global Proc_EnableSSE]
-Proc_EnableSSE:
-       mov rax, cr0
-       and ax, ~(1 << 3)       ; Clear TS
-       mov cr0, rax
-       ret
-
-[global Proc_SaveSSE]
-Proc_SaveSSE:
-       fxsave [rdi]
-       ret
-[global Proc_RestoreSSE]
-Proc_RestoreSSE:
-       fxrstor [rdi]
-       ret
-
-; vim: ft=nasm
diff --git a/Kernel/arch/x86_64/proc.c b/Kernel/arch/x86_64/proc.c
deleted file mode 100644 (file)
index 5f71a45..0000000
+++ /dev/null
@@ -1,827 +0,0 @@
-/*
- * Acess2 x86_64 port
- * proc.c
- */
-#include <acess.h>
-#include <proc.h>
-#include <threads.h>
-#include <threads_int.h>
-#include <desctab.h>
-#include <mm_virt.h>
-#include <errno.h>
-#if USE_MP
-# include <mp.h>
-#endif
-#include <arch_config.h>
-#include <hal_proc.h>
-
-// === FLAGS ===
-#define DEBUG_TRACE_SWITCH     0
-#define BREAK_ON_SWITCH        0       // Break into bochs debugger on a task switch
-
-// === CONSTANTS ===
-
-// === TYPES ===
-typedef struct sCPU
-{
-       Uint8   APICID;
-       Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
-       Uint16  Resvd;
-       tThread *Current;
-       tThread *IdleThread;
-}      tCPU;
-
-// === IMPORTS ===
-extern tGDT    gGDT[];
-extern void    APStartup(void);        // 16-bit AP startup code
-
-extern Uint    GetRIP(void);   // start.asm
-extern Uint    SaveState(Uint *RSP, Uint *Regs);
-extern Uint    Proc_CloneInt(Uint *RSP, Uint *CR3);
-extern void    NewTaskHeader(void);    // Actually takes cdecl args
-extern void    Proc_InitialiseSSE(void);
-extern void    Proc_SaveSSE(Uint DestPtr);
-extern void    Proc_DisableSSE(void);
-
-extern Uint64  gInitialPML4[512];      // start.asm
-extern int     giNumCPUs;
-extern int     giNextTID;
-extern int     giTotalTickets;
-extern int     giNumActiveThreads;
-extern tThread gThreadZero;
-extern tProcess        gProcessZero;
-extern void    Threads_Dump(void);
-extern void    Proc_ReturnToUser(tVAddr Handler, tVAddr KStackTop, int Argument);
-extern void    Time_UpdateTimestamp(void);
-extern void    SwitchTasks(Uint NewSP, Uint *OldSP, Uint NewIP, Uint *OldIO, Uint CR3);
-
-// === PROTOTYPES ===
-//void ArchThreads_Init(void);
-#if USE_MP
-void   MP_StartAP(int CPU);
-void   MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
-#endif
-void   Proc_IdleTask(void *unused);
-//void Proc_Start(void);
-//tThread      *Proc_GetCurThread(void);
-// int Proc_NewKThread(void (*Fcn)(void*), void *Data);
-// int Proc_Clone(Uint *Err, Uint Flags);
-// int Proc_SpawnWorker(void);
-Uint   Proc_MakeUserStack(void);
-//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
-void   Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NORETURN;
- int   Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
-//void Proc_CallFaultHandler(tThread *Thread);
-//void Proc_DumpThreadCPUState(tThread *Thread);
-//void Proc_Reschedule(void);
-void   Proc_Scheduler(int CPU, Uint RSP, Uint RIP);
-
-// === GLOBALS ===
-//!\brief Used by desctab.asm in SyscallStub
-const int ci_offsetof_tThread_KernelStack = offsetof(tThread, KernelStack);
-// --- Multiprocessing ---
-#if USE_MP
-volatile int   giNumInitingCPUs = 0;
-tMPInfo        *gMPFloatPtr = NULL;
-tAPIC  *gpMP_LocalAPIC = NULL;
-Uint8  gaAPIC_to_CPU[256] = {0};
-#endif
-tCPU   gaCPUs[MAX_CPUS];
-tTSS   *gTSSs = NULL;
-tTSS   gTSS0 = {0};
-// --- Error Recovery ---
-Uint32 gaDoubleFaultStack[1024];
-
-// === CODE ===
-/**
- * \fn void ArchThreads_Init(void)
- * \brief Starts the process scheduler
- */
-void ArchThreads_Init(void)
-{
-       Uint    pos = 0;
-       
-       #if USE_MP
-       tMPTable        *mptable;
-       
-       // Mark BSP as active
-       gaCPUs[0].State = 2;
-       
-       // -- Initialise Multiprocessing
-       // Find MP Floating Table
-       // - EBDA/Last 1Kib (640KiB)
-       for(pos = KERNEL_BASE|0x9F000; pos < (KERNEL_BASE|0xA0000); pos += 16) {
-               if( *(Uint*)(pos) == MPPTR_IDENT ) {
-                       Log("Possible %p", pos);
-                       if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
-                       gMPFloatPtr = (void*)pos;
-                       break;
-               }
-       }
-       // - Last KiB (512KiB base mem)
-       if(!gMPFloatPtr) {
-               for(pos = KERNEL_BASE|0x7F000; pos < (KERNEL_BASE|0x80000); pos += 16) {
-                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
-                               Log("Possible %p", pos);
-                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
-                               gMPFloatPtr = (void*)pos;
-                               break;
-                       }
-               }
-       }
-       // - BIOS ROM
-       if(!gMPFloatPtr) {
-               for(pos = KERNEL_BASE|0xE0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
-                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
-                               Log("Possible %p", pos);
-                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
-                               gMPFloatPtr = (void*)pos;
-                               break;
-                       }
-               }
-       }
-       
-       // If the MP Table Exists, parse it
-       if(gMPFloatPtr)
-       {
-                int    i;
-               tMPTable_Ent    *ents;
-               Log("gMPFloatPtr = %p", gMPFloatPtr);
-               Log("*gMPFloatPtr = {");
-               Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig);
-               Log("\t.MPConfig = 0x%08x", gMPFloatPtr->MPConfig);
-               Log("\t.Length = 0x%02x", gMPFloatPtr->Length);
-               Log("\t.Version = 0x%02x", gMPFloatPtr->Version);
-               Log("\t.Checksum = 0x%02x", gMPFloatPtr->Checksum);
-               Log("\t.Features = [0x%02x,0x%02x,0x%02x,0x%02x,0x%02x]",
-                       gMPFloatPtr->Features[0],       gMPFloatPtr->Features[1],
-                       gMPFloatPtr->Features[2],       gMPFloatPtr->Features[3],
-                       gMPFloatPtr->Features[4]
-                       );
-               Log("}");
-               
-               mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig );
-               Log("mptable = %p", mptable);
-               Log("*mptable = {");
-               Log("\t.Sig = 0x%08x", mptable->Sig);
-               Log("\t.BaseTableLength = 0x%04x", mptable->BaseTableLength);
-               Log("\t.SpecRev = 0x%02x", mptable->SpecRev);
-               Log("\t.Checksum = 0x%02x", mptable->Checksum);
-               Log("\t.OEMID = '%8c'", mptable->OemID);
-               Log("\t.ProductID = '%8c'", mptable->ProductID);
-               Log("\t.OEMTablePtr = %p'", mptable->OEMTablePtr);
-               Log("\t.OEMTableSize = 0x%04x", mptable->OEMTableSize);
-               Log("\t.EntryCount = 0x%04x", mptable->EntryCount);
-               Log("\t.LocalAPICMemMap = 0x%08x", mptable->LocalAPICMemMap);
-               Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen);
-               Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum);
-               Log("}");
-               
-               gpMP_LocalAPIC = (void*)MM_MapHWPage(mptable->LocalAPICMemMap, 1);
-               
-               ents = mptable->Entries;
-               giNumCPUs = 0;
-               
-               for( i = 0; i < mptable->EntryCount; i ++ )
-               {
-                        int    entSize = 0;
-                       switch( ents->Type )
-                       {
-                       case 0: // Processor
-                               entSize = 20;
-                               Log("%i: Processor", i);
-                               Log("\t.APICID = %i", ents->Proc.APICID);
-                               Log("\t.APICVer = 0x%02x", ents->Proc.APICVer);
-                               Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags);
-                               Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature);
-                               Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags);
-                               
-                               
-                               if( !(ents->Proc.CPUFlags & 1) ) {
-                                       Log("DISABLED");
-                                       break;
-                               }
-                               
-                               // Check if there is too many processors
-                               if(giNumCPUs >= MAX_CPUS) {
-                                       giNumCPUs ++;   // If `giNumCPUs` > MAX_CPUS later, it will be clipped
-                                       break;
-                               }
-                               
-                               // Initialise CPU Info
-                               gaAPIC_to_CPU[ents->Proc.APICID] = giNumCPUs;
-                               gaCPUs[giNumCPUs].APICID = ents->Proc.APICID;
-                               gaCPUs[giNumCPUs].State = 0;
-                               giNumCPUs ++;
-                               
-                               // Send IPI
-                               if( !(ents->Proc.CPUFlags & 2) )
-                               {
-                                       MP_StartAP( giNumCPUs-1 );
-                               }
-                               
-                               break;
-                       case 1: // Bus
-                               entSize = 8;
-                               Log("%i: Bus", i);
-                               Log("\t.ID = %i", ents->Bus.ID);
-                               Log("\t.TypeString = '%6c'", ents->Bus.TypeString);
-                               break;
-                       case 2: // I/O APIC
-                               entSize = 8;
-                               Log("%i: I/O APIC", i);
-                               Log("\t.ID = %i", ents->IOAPIC.ID);
-                               Log("\t.Version = 0x%02x", ents->IOAPIC.Version);
-                               Log("\t.Flags = 0x%02x", ents->IOAPIC.Flags);
-                               Log("\t.Addr = 0x%08x", ents->IOAPIC.Addr);
-                               break;
-                       case 3: // I/O Interrupt Assignment
-                               entSize = 8;
-                               Log("%i: I/O Interrupt Assignment", i);
-                               Log("\t.IntType = %i", ents->IOInt.IntType);
-                               Log("\t.Flags = 0x%04x", ents->IOInt.Flags);
-                               Log("\t.SourceBusID = 0x%02x", ents->IOInt.SourceBusID);
-                               Log("\t.SourceBusIRQ = 0x%02x", ents->IOInt.SourceBusIRQ);
-                               Log("\t.DestAPICID = 0x%02x", ents->IOInt.DestAPICID);
-                               Log("\t.DestAPICIRQ = 0x%02x", ents->IOInt.DestAPICIRQ);
-                               break;
-                       case 4: // Local Interrupt Assignment
-                               entSize = 8;
-                               Log("%i: Local Interrupt Assignment", i);
-                               Log("\t.IntType = %i", ents->LocalInt.IntType);
-                               Log("\t.Flags = 0x%04x", ents->LocalInt.Flags);
-                               Log("\t.SourceBusID = 0x%02x", ents->LocalInt.SourceBusID);
-                               Log("\t.SourceBusIRQ = 0x%02x", ents->LocalInt.SourceBusIRQ);
-                               Log("\t.DestLocalAPICID = 0x%02x", ents->LocalInt.DestLocalAPICID);
-                               Log("\t.DestLocalAPICIRQ = 0x%02x", ents->LocalInt.DestLocalAPICIRQ);
-                               break;
-                       default:
-                               Log("%i: Unknown (%i)", i, ents->Type);
-                               break;
-                       }
-                       ents = (void*)( (Uint)ents + entSize );
-               }
-               
-               if( giNumCPUs > MAX_CPUS ) {
-                       Warning("Too many CPUs detected (%i), only using %i of them", giNumCPUs, MAX_CPUS);
-                       giNumCPUs = MAX_CPUS;
-               }
-       
-               while( giNumInitingCPUs )
-                       MM_FinishVirtualInit();
-               
-               Panic("Uh oh... MP Table Parsing is unimplemented\n");
-       }
-       else {
-               Log("No MP Table was found, assuming uniprocessor\n");
-               giNumCPUs = 1;
-               gTSSs = &gTSS0;
-       }
-       #else
-       giNumCPUs = 1;
-       gTSSs = &gTSS0;
-       MM_FinishVirtualInit();
-       #endif
-       
-       #if USE_MP
-       // Initialise Normal TSS(s)
-       for(pos=0;pos<giNumCPUs;pos++)
-       {
-       #else
-       pos = 0;
-       #endif
-               gTSSs[pos].RSP0 = 0;    // Set properly by scheduler
-               gGDT[7+pos*2].LimitLow = sizeof(tTSS) & 0xFFFF;
-               gGDT[7+pos*2].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
-               gGDT[7+pos*2].BaseMid = ((Uint)(&gTSSs[pos])) >> 16;
-               gGDT[7+pos*2].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
-               gGDT[7+pos*2+1].DWord[0] = ((Uint)(&gTSSs[pos])) >> 32;
-       #if USE_MP
-       }
-       for(pos=0;pos<giNumCPUs;pos++) {
-               __asm__ __volatile__ ("ltr %%ax"::"a"(0x38+pos*16));
-       }
-       #else
-       __asm__ __volatile__ ("ltr %%ax"::"a"(0x38));
-       #endif
-       
-       // Set Debug registers
-       __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
-       __asm__ __volatile__ ("mov %%rax, %%db1" : : "a"(0));
-       
-       gaCPUs[0].Current = &gThreadZero;
-       
-       gProcessZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
-       gThreadZero.CurCPU = 0;
-       gThreadZero.KernelStack = 0xFFFFA00000000000 + KERNEL_STACK_SIZE;
-       
-       // Set timer frequency
-       outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
-       outb(0x40, PIT_TIMER_DIVISOR&0xFF);     // Low Byte of Divisor
-       outb(0x40, (PIT_TIMER_DIVISOR>>8)&0xFF);        // High Byte
-       
-       // Create Per-Process Data Block
-       if( !MM_Allocate(MM_PPD_CFG) )
-       {
-               Warning("Oh, hell, Unable to allocate PPD for Thread#0");
-       }
-
-       Proc_InitialiseSSE();
-
-       Log_Log("Proc", "Multithreading initialised");
-}
-
-#if USE_MP
-void MP_StartAP(int CPU)
-{
-       Log("Starting AP %i (APIC %i)", CPU, gaCPUs[CPU].APICID);
-       // Set location of AP startup code and mark for a warm restart
-       *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0);
-       *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
-       outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Warm Reset
-       MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);
-       giNumInitingCPUs ++;
-}
-
-void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
-{
-       Uint32  addr = (Uint)gpMP_LocalAPIC + 0x300;
-       Uint32  val;
-       
-       // High
-       val = (Uint)APICID << 24;
-       Log("*%p = 0x%08x", addr+0x10, val);
-       *(Uint32*)(addr+0x10) = val;
-       // Low (and send)
-       val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
-       Log("*%p = 0x%08x", addr, val);
-       *(Uint32*)addr = val;
-}
-#endif
-
-/**
- * \brief Idle task
- */
-void Proc_IdleTask(void *ptr)
-{
-       tCPU    *cpu = ptr;
-       cpu->IdleThread = Proc_GetCurThread();
-       cpu->IdleThread->ThreadName = (char*)"Idle Thread";
-       Threads_SetPriority( cpu->IdleThread, -1 );     // Never called randomly
-       cpu->IdleThread->Quantum = 1;   // 1 slice quantum
-       for(;;) {
-               HALT(); // Just yeilds
-               Threads_Yield();
-       }
-}
-
-/**
- * \fn void Proc_Start(void)
- * \brief Start process scheduler
- */
-void Proc_Start(void)
-{
-       #if USE_MP
-        int    i;
-       #endif
-       
-       #if USE_MP
-       // Start APs
-       for( i = 0; i < giNumCPUs; i ++ )
-       {
-                int    tid;
-               if(i)   gaCPUs[i].Current = NULL;
-               
-               Proc_NewKThread(Proc_IdleTask, &gaCPUs[i]);             
-
-               // Create Idle Task
-               gaCPUs[i].IdleThread = Threads_GetThread(tid);
-               
-               
-               // Start the AP
-               if( i != giProc_BootProcessorID ) {
-                       MP_StartAP( i );
-               }
-       }
-       
-       // BSP still should run the current task
-       gaCPUs[0].Current = &gThreadZero;
-       __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
-       
-       // Start interrupts and wait for APs to come up
-       Log("Waiting for APs to come up\n");
-       __asm__ __volatile__ ("sti");
-       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
-       #else
-       Proc_NewKThread(Proc_IdleTask, &gaCPUs[0]);
-       
-       // Start Interrupts (and hence scheduler)
-       __asm__ __volatile__("sti");
-       #endif
-       MM_FinishVirtualInit();
-       Log_Log("Proc", "Multithreading started");
-}
-
-/**
- * \fn tThread *Proc_GetCurThread(void)
- * \brief Gets the current thread
- */
-tThread *Proc_GetCurThread(void)
-{
-       #if USE_MP
-       tThread *ret;
-       __asm__ __volatile__ ("mov %%db0, %0" : "=r"(thread));
-       return ret;     // gaCPUs[ GetCPUNum() ].Current;
-       #else
-       return gaCPUs[ 0 ].Current;
-       #endif
-}
-
-void Proc_ClearProcess(tProcess *Process)
-{
-       Log_Warning("Proc", "TODO: Nuke address space etc");
-}
-
-/*
- * 
- */
-void Proc_ClearThread(tThread *Thread)
-{
-}
-
-/**
- * \brief Create a new kernel thread
- */
-tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
-{
-       Uint    rsp;
-       tThread *newThread, *cur;
-       
-       cur = Proc_GetCurThread();
-       newThread = Threads_CloneTCB(0);
-       if(!newThread)  return -1;
-       
-       // Create new KStack
-       newThread->KernelStack = MM_NewKStack();
-       // Check for errors
-       if(newThread->KernelStack == 0) {
-               free(newThread);
-               return -1;
-       }
-
-       rsp = newThread->KernelStack;
-       *(Uint*)(rsp-=8) = (Uint)Data;  // Data (shadowed)
-       *(Uint*)(rsp-=8) = (Uint)Fcn;   // Function to call
-       *(Uint*)(rsp-=8) = (Uint)newThread;     // Thread ID
-       
-       newThread->SavedState.RSP = rsp;
-       newThread->SavedState.RIP = (Uint)&NewTaskHeader;
-       newThread->SavedState.SSE = NULL;
-//     Log("New (KThread) %p, rsp = %p\n", newThread->SavedState.RIP, newThread->SavedState.RSP);
-       
-//     MAGIC_BREAK();  
-       Threads_AddActive(newThread);
-
-       return newThread->TID;
-}
-
-/**
- * \fn int Proc_Clone(Uint Flags)
- * \brief Clone the current process
- */
-tTID Proc_Clone(Uint Flags)
-{
-       tThread *newThread, *cur = Proc_GetCurThread();
-       Uint    rip;
-
-       // Sanity check 
-       if( !(Flags & CLONE_VM) ) {
-               Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
-               return -1;
-       }
-
-       // Create new TCB
-       newThread = Threads_CloneTCB(Flags);
-       if(!newThread)  return -1;
-       
-       // Save core machine state
-       rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->Process->MemState.CR3);
-       if(rip == 0)    return 0;       // Child
-       newThread->KernelStack = cur->KernelStack;
-       newThread->SavedState.RIP = rip;
-       newThread->SavedState.SSE = NULL;
-
-       // DEBUG
-       #if 0
-       Log("New (Clone) %p, rsp = %p, cr3 = %p", rip, newThread->SavedState.RSP, newThread->MemState.CR3);
-       {
-               Uint cr3;
-               __asm__ __volatile__ ("mov %%cr3, %0" : "=r" (cr3));
-               Log("Current CR3 = 0x%x, PADDR(RSP) = 0x%x", cr3, MM_GetPhysAddr(newThread->SavedState.RSP));
-       }
-       #endif
-       // /DEBUG
-       
-       // Lock list and add to active
-       Threads_AddActive(newThread);
-       
-       return newThread->TID;
-}
-
-/**
- * \fn int Proc_SpawnWorker(void)
- * \brief Spawns a new worker thread
- */
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
-{
-       tThread *new, *cur;
-       Uint    stack_contents[3];
-
-       cur = Proc_GetCurThread();
-       
-       // Create new thread
-       new = Threads_CloneThreadZero();
-       if(!new) {
-               Warning("Proc_SpawnWorker - Out of heap space!\n");
-               return -1;
-       }
-
-       // Create the stack contents
-       stack_contents[2] = (Uint)Data;
-       stack_contents[1] = (Uint)Fcn;
-       stack_contents[0] = (Uint)new;
-       
-       // Create a new worker stack (in PID0's address space)
-       // - The stack is built by this code using stack_contents
-       new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
-
-       new->SavedState.RSP = new->KernelStack - sizeof(stack_contents);
-       new->SavedState.RIP = (Uint)&NewTaskHeader;
-       new->SavedState.SSE = NULL;
-       
-//     Log("New (Worker) %p, rsp = %p\n", new->SavedState.RIP, new->SavedState.RSP);
-       
-       // Mark as active
-       new->Status = THREAD_STAT_PREINIT;
-       Threads_AddActive( new );
-       
-       return new->TID;
-}
-
-/**
- * \brief Creates a new user stack
- */
-Uint Proc_MakeUserStack(void)
-{
-        int    i;
-       Uint    base = USER_STACK_TOP - USER_STACK_SZ;
-       
-       // Check Prospective Space
-       for( i = USER_STACK_SZ >> 12; i--; )
-       {
-               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
-                       break;
-       }
-       
-       if(i != -1)     return 0;
-       
-       // Allocate Stack - Allocate incrementally to clean up MM_Dump output
-       // - Most of the user stack is the zero page
-       for( i = 0; i < (USER_STACK_SZ-USER_STACK_PREALLOC)/0x1000; i++ )
-       {
-               MM_AllocateZero( base + (i<<12) );
-       }
-       // - but the top USER_STACK_PREALLOC pages are actually allocated
-       for( ; i < USER_STACK_SZ/0x1000; i++ )
-       {
-               tPAddr  alloc = MM_Allocate( base + (i<<12) );
-               if( !alloc )
-               {
-                       // Error
-                       Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
-                       while( i -- )
-                               MM_Deallocate( base + (i<<12) );
-                       return 0;
-               }
-       }
-       
-       return base + USER_STACK_SZ;
-}
-
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
-{
-       Uint    *stack;
-        int    i;
-       const char      **envp = NULL;
-       Uint16  ss, cs;
-       
-       
-       // Copy Arguments
-       stack = (void*)Proc_MakeUserStack();
-       if(!stack) {
-               Log_Error("Proc", "Unable to create user stack!");
-               Threads_Exit(0, -1);
-       }
-       stack -= (DataSize+7)/8;
-       memcpy( stack, ArgV, DataSize );
-       free(ArgV);
-       
-       // Adjust Arguments and environment
-       if(DataSize)
-       {
-               Uint    delta = (Uint)stack - (Uint)ArgV;
-               ArgV = (const char**)stack;
-               for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
-               envp = &ArgV[i+1];
-               for( i = 0; envp[i]; i++ )      envp[i] += delta;
-       }
-       
-       // User Mode Segments
-       // 0x2B = 64-bit
-       ss = 0x23;      cs = 0x2B;
-       
-       // Arguments
-       *--stack = (Uint)envp;
-       *--stack = (Uint)ArgV;
-       *--stack = (Uint)ArgC;
-       *--stack = Base;
-       
-       Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
-}
-
-void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
-{
-       if( !(CS == 0x1B || CS == 0x2B) || SS != 0x23 ) {
-               Log_Error("Proc", "Proc_StartProcess: CS / SS are not valid (%x, %x)",
-                       CS, SS);
-               Threads_Exit(0, -1);
-       }
-//     Log("Proc_StartProcess: (SS=%x, Stack=%p, Flags=%x, CS=%x, IP=%p)", SS, Stack, Flags, CS, IP);
-//     MM_DumpTables(0, USER_MAX);
-       if(CS == 0x1B)
-       {
-               // 32-bit return
-               __asm__ __volatile__ (
-                       "mov %0, %%rsp;\n\t"    // Set stack pointer
-                       "mov %2, %%r11;\n\t"    // Set RFLAGS
-                       "sysret;\n\t"
-                       : : "r" (Stack), "c" (IP), "r" (Flags)
-                       );
-       }
-       else
-       {
-               // 64-bit return
-               __asm__ __volatile__ (
-                       "mov %0, %%rsp;\n\t"    // Set stack pointer
-                       "mov %2, %%r11;\n\t"    // Set RFLAGS
-                       "sysretq;\n\t"
-                       : : "r" (Stack), "c" (IP), "r" (Flags)
-                       );
-       }
-       for(;;);
-}
-
-/**
- * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
- * \brief Demotes a process to a lower permission level
- * \param Err  Pointer to user's errno
- * \param Dest New Permission Level
- * \param Regs Pointer to user's register structure
- */
-int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
-{
-        int    cpl = Regs->CS & 3;
-       // Sanity Check
-       if(Dest > 3 || Dest < 0) {
-               *Err = -EINVAL;
-               return -1;
-       }
-       
-       // Permission Check
-       if(cpl > Dest) {
-               *Err = -EACCES;
-               return -1;
-       }
-       
-       // Change the Segment Registers
-       Regs->CS = (((Dest+1)<<4) | Dest) - 8;
-       Regs->SS = ((Dest+1)<<4) | Dest;
-       
-       return 0;
-}
-
-/**
- * \brief Calls a signal handler in user mode
- * \note Used for signals
- */
-void Proc_CallFaultHandler(tThread *Thread)
-{
-       // Never returns
-       Proc_ReturnToUser(Thread->FaultHandler, Thread->KernelStack, Thread->CurFaultNum);
-       for(;;);
-}
-
-void Proc_DumpThreadCPUState(tThread *Thread)
-{
-       Log("  At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
-}
-
-void Proc_Reschedule(void)
-{
-       tThread *nextthread, *curthread;
-        int    cpu = GetCPUNum();
-
-       // TODO: Wait for it?
-       if(IS_LOCKED(&glThreadListLock))        return;
-       
-       curthread = gaCPUs[cpu].Current;
-
-       nextthread = Threads_GetNextToRun(cpu, curthread);
-
-       if(nextthread == curthread)     return ;
-       if(!nextthread)
-               nextthread = gaCPUs[cpu].IdleThread;
-       if(!nextthread)
-               return ;
-
-       #if DEBUG_TRACE_SWITCH
-       LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n",
-               nextthread->Process->MemState.CR3,
-               nextthread->SavedState.RIP,
-               nextthread->SavedState.RSP,
-               nextthread->TID,
-               nextthread->ThreadName
-               );
-       #endif
-
-       // Update CPU state
-       gaCPUs[cpu].Current = nextthread;
-       gTSSs[cpu].RSP0 = nextthread->KernelStack-4;
-       __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread));
-
-       if( curthread )
-       {
-               // Save FPU/MMX/XMM/SSE state
-               if( curthread->SavedState.SSE )
-               {
-                       Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
-                       curthread->SavedState.bSSEModified = 0;
-                       Proc_DisableSSE();
-               }
-               SwitchTasks(
-                       nextthread->SavedState.RSP, &curthread->SavedState.RSP,
-                       nextthread->SavedState.RIP, &curthread->SavedState.RIP,
-                       nextthread->Process->MemState.CR3
-                       );
-       }
-       else
-       {
-               Uint    tmp;
-               SwitchTasks(
-                       nextthread->SavedState.RSP, &tmp,
-                       nextthread->SavedState.RIP, &tmp,
-                       nextthread->Process->MemState.CR3
-                       );
-       }
-       return ;
-}
-
-/**
- * \fn void Proc_Scheduler(int CPU)
- * \brief Swap current thread and clears dead threads
- */
-void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
-{
-#if 0
-       tThread *thread;
-
-       // If the spinlock is set, let it complete
-       if(IS_LOCKED(&glThreadListLock))        return;
-       
-       // Get current thread
-       thread = gaCPUs[CPU].Current;
-
-       if( thread )
-       {
-               tRegs   *regs;
-               // Reduce remaining quantum and continue timeslice if non-zero
-               if(thread->Remaining--) return;
-               // Reset quantum for next call
-               thread->Remaining = thread->Quantum;
-               
-               // TODO: Make this more stable somehow
-               {
-                       regs = (tRegs*)(RSP+(1)*8);     // CurThread
-                       thread->SavedState.UserCS = regs->CS;
-                       thread->SavedState.UserRIP = regs->RIP;
-               }
-       }
-
-       // ACK Timer here?
-
-       Proc_Reschedule();
-#endif
-}
-
-// === EXPORTS ===
-EXPORT(Proc_SpawnWorker);
diff --git a/Kernel/arch/x86_64/rme.c b/Kernel/arch/x86_64/rme.c
deleted file mode 120000 (symlink)
index 330f4f5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/home/tpg/Projects/RealmodeEmulator/src/rme.c
\ No newline at end of file
diff --git a/Kernel/arch/x86_64/rme.h b/Kernel/arch/x86_64/rme.h
deleted file mode 120000 (symlink)
index 98b2739..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/home/tpg/Projects/RealmodeEmulator/src/rme.h
\ No newline at end of file
diff --git a/Kernel/arch/x86_64/start32.asm b/Kernel/arch/x86_64/start32.asm
deleted file mode 100644 (file)
index 52b133c..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-;
-; Acess2 x86_64 port
-;
-
-%include "arch/x86_64/include/common.inc.asm"
-
-[BITS 32]
-
-;KERNEL_BASE   equ     0xFFFF800000000000
-KERNEL_BASE    equ     0xFFFFFFFF80000000
-
-[section .multiboot]
-mboot:
-       ; Multiboot macros to make a few lines later more readable
-       MULTIBOOT_PAGE_ALIGN    equ 1<<0
-       MULTIBOOT_MEMORY_INFO   equ 1<<1
-       MULTIBOOT_AOUT_KLUDGE   equ 1<<16
-       MULTIBOOT_HEADER_MAGIC  equ 0x1BADB002
-       MULTIBOOT_HEADER_FLAGS  equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO; | MULTIBOOT_AOUT_KLUDGE
-       MULTIBOOT_CHECKSUM      equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
-       
-       ; This is the GRUB Multiboot header. A boot signature
-       dd MULTIBOOT_HEADER_MAGIC
-       dd MULTIBOOT_HEADER_FLAGS
-       dd MULTIBOOT_CHECKSUM
-       [extern __load_addr]
-       [extern __bss_start]
-       [extern gKernelEnd]
-       ; a.out kludge
-       dd mboot        ; Location of Multiboot Header
-       dd __load_addr  ; Load address
-       dd __bss_start - KERNEL_BASE    ; End of .data
-       dd gKernelEnd - KERNEL_BASE     ; End of .bss (and kernel)
-       dd start - KERNEL_BASE  ; Entrypoint
-
-[extern start64]
-
-[section .text]
-[global start]
-start:
-       mov [gMultibootMagic - KERNEL_BASE], eax
-       mov [gMultibootPtr - KERNEL_BASE], ebx
-
-       ; Check for Long Mode support
-       mov eax, 0x80000000
-       cpuid
-       cmp eax, 0x80000001     ; Compare the A-register with 0x80000001.
-       mov eax, 0x80000001
-       cpuid
-       jb .not64bitCapable
-       test edx, 1<<29
-       jz .not64bitCapable
-
-       ; Enable PGE (Page Global Enable)
-       ; + PAE (Physical Address Extension)
-       ; + PSE (Page Size Extensions)
-       mov eax, cr4
-       or eax, 0x80|0x20|0x10
-       mov cr4, eax
-
-       ; Load PDP4
-       mov eax, gInitialPML4 - KERNEL_BASE
-       mov cr3, eax
-
-       ; Enable IA-32e mode
-       ; (Also enables SYSCALL and NX)
-       mov ecx, 0xC0000080
-       rdmsr
-       or eax, (1 << 11)|(1 << 8)|(1 << 0)     ; NXE, LME, SCE
-       wrmsr
-
-       ; Enable paging
-       mov eax, cr0
-       or eax, 0x80010000      ; PG & WP
-       mov cr0, eax
-
-       ; Load GDT
-       lgdt [gGDTPtr - KERNEL_BASE]
-       jmp 0x08:start64 - KERNEL_BASE
-
-.not64bitCapable:
-       mov ah, 0x0F
-       mov edi, 0xB8000
-       mov esi, csNot64BitCapable - KERNEL_BASE
-
-.loop:
-       lodsb
-       test al, al
-       jz .hlt
-       stosw
-       jmp .loop
-       
-.hlt:
-       cli
-       hlt
-       jmp .hlt
-
-[section .data]
-[global gGDT]
-[global gGDTPtr]
-gGDT:
-       dd      0,0
-       dd      0x00000000, 0x00209A00  ; 0x08: 64-bit Code
-       dd      0x00000000, 0x00009200  ; 0x10: 64-bit Data
-       dd      0x00000000, 0x0040FA00  ; 0x18: 32-bit User Code
-       dd      0x00000000, 0x0040F200  ; 0x20: User Data
-       dd      0x00000000, 0x0020FA00  ; 0x28: 64-bit User Code
-       dd      0x00000000, 0x0000F200  ; 0x30: User Data (64 version)
-       times MAX_CPUS  dd      0, 0x00008900, 0, 0     ; 0x38+16*n: TSS 0
-gGDTPtr:
-       dw      $-gGDT-1
-       dd      gGDT-KERNEL_BASE
-       dd      0
-[global gMultibootPtr]
-[global gMultibootMagic]
-gMultibootMagic:
-       dd      0
-gMultibootPtr:
-       dd      0
-
-[section .padata]
-[global gInitialPML4]
-gInitialPML4:  ; Covers 256 TiB (Full 48-bit Virtual Address Space)
-       dd      gInitialPDP - KERNEL_BASE + 3, 0        ; Identity Map Low 4Mb
-       times 0xA0*2-1  dq      0
-       dd      gStackPDP - KERNEL_BASE + 3, 0
-       times 512-4-($-gInitialPML4)/8  dq      0
-       dd      gInitialPML4 - KERNEL_BASE + 3, 0       ; Fractal Mapping
-       dq      0
-       dq      0
-       dd      gHighPDP - KERNEL_BASE + 3, 0   ; Map Low 4Mb to kernel base
-
-gInitialPDP:   ; Covers 512 GiB
-       dd      gInitialPD - KERNEL_BASE + 3, 0
-       times 511       dq      0
-
-gStackPDP:
-       dd      gStackPD - KERNEL_BASE + 3, 0
-       times 511       dq      0
-
-gHighPDP:      ; Covers 512 GiB
-       times 510       dq      0
-       ;dq     0 + 0x143       ; 1 GiB Page from zero
-       dd      gInitialPD - KERNEL_BASE + 3, 0
-       dq      0
-
-gInitialPD:    ; Covers 1 GiB
-;      dq      0 + 0x143       ; 1 GiB Page from zero
-       dd      gInitialPT1 - KERNEL_BASE + 3, 0
-       dd      gInitialPT2 - KERNEL_BASE + 3, 0
-       times 510       dq      0
-
-gStackPD:
-       dd      gKStackPT - KERNEL_BASE + 3, 0
-       times 511       dq      0
-
-gKStackPT:     ; Covers 2 MiB
-       ; Initial stack - 64KiB
-       dq      0
-       %assign i 0
-       %rep INITIAL_KSTACK_SIZE-1
-       dd      gInitialKernelStack - KERNEL_BASE + i*0x1000 + 0x103, 0
-       %assign i i+1
-       %endrep
-       times 512-INITIAL_KSTACK_SIZE   dq 0
-gInitialPT1:   ; 2 MiB
-       %assign i 0
-       %rep 512
-       dq      i*4096+0x103
-       %assign i i+1
-       %endrep
-gInitialPT2:   ; 2 MiB
-       %assign i 512
-       %rep 512
-       dq      i*4096+0x103
-       %assign i i+1
-       %endrep
-
-[section .padata]
-[global gInitialKernelStack]
-gInitialKernelStack:
-       times 0x1000*(INITIAL_KSTACK_SIZE-1)    db 0    ; 8 Pages
-
-[section .rodata]
-csNot64BitCapable:
-       db "Not 64-bit Capable",0
-
-; vim: ft=nasm
diff --git a/Kernel/arch/x86_64/start64.asm b/Kernel/arch/x86_64/start64.asm
deleted file mode 100644 (file)
index c8e7f9a..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-;
-; Acess2 x86_64 Port
-;
-%include "arch/x86_64/include/common.inc.asm"
-[bits 64]
-;KERNEL_BASE   equ     0xFFFF800000000000
-KERNEL_BASE    equ     0xFFFFFFFF80000000
-
-[extern kmain]
-
-[extern gMultibootPtr]
-[extern gMultibootMagic]
-
-[section .text]
-[global start64]
-start64:
-       ; Load Registers
-       mov ax, 0x10
-       mov ds, ax
-       mov es, ax
-       mov fs, ax
-       mov gs, ax
-       
-       ; Go to high memory
-       mov rax, start64.himem
-       jmp rax
-.himem:
-       
-       xor rax, rax
-       mov dr0, rax    ; Set CPU0
-       
-       ; Clear the screen
-       mov rax, 0x1F201F201F201F20     ; Set the screen to White on blue, space (4 characters)
-       mov edi, 0xB8000
-       mov ecx, 80*25*2/8
-       rep stosq
-       
-       ; Set kernel stack
-       mov rsp, 0xFFFFA00000000000 + INITIAL_KSTACK_SIZE*0x1000
-       
-       ; Call main
-       mov edi, [gMultibootMagic - KERNEL_BASE]
-       mov esi, [gMultibootPtr - KERNEL_BASE]
-       call kmain
-       
-       cli
-.hlt:
-       hlt
-       jmp .hlt
-
-[global GetCPUNum]
-GetCPUNum:
-       mov rax, dr1
-       ret
-
-KSTACK_USERSTATE_SIZE  equ     (5+2+16+2)*8    ; IRET, ErrorNum, ErrorCode, GPRs, FS&GS
-[global Proc_ReturnToUser]
-Proc_ReturnToUser:
-       ; RDI - Handler
-       ; RSI - Kernel Stack
-       ; RDX - Signal num
-       
-       ;
-       ; NOTE: This can cause corruption if the signal happens while the user
-       ;       has called a kernel operation.
-       ; Good thing this can only be called on a user fault.
-       ;
-
-       xchg bx, bx     
-       ; Get and alter User SP
-       mov rcx, [rsi-0x20]     ; Get user SP
-       xor eax, eax
-       mov [rcx-16], rax
-       sub rcx, 16
-       
-       ; Drop down to user mode
-       cli
-       mov rsp, rcx    ; Set SP
-       mov rcx, rdi    ; SYSRET IP
-       
-       mov rdi, rdx    ; Argument for handler
-       mov r11, 0x202  ; RFlags
-       db 0x48
-       sysret
-
-; int CallWithArgArray(void *Ptr, int NArgs, Uint *Args)
-; Call a function passing the array as arguments
-[global CallWithArgArray]
-CallWithArgArray:
-       push rbp
-       mov rbp, rsp
-       push r10
-       push r11
-       
-       mov [rbp+2*8], rdi      ; Save Ptr to stack
-       
-       mov r11, rsi    ; NArgs
-       mov r10, rdx    ; Args
-
-       ; Arg 1: RDI
-       mov rdi, [r10]
-       add r10, 8
-       dec r11
-       jz .call
-       ; Arg 2: RSI
-       mov rsi, [r10]
-       add r10, 8
-       dec r11
-       jz .call
-       ; Arg 3: RDX
-       mov rdx, [r10]
-       add r10, 8
-       dec r11
-       jz .call
-       ; Arg 4: RCX
-       mov rcx, [r10]
-       add r10, 8
-       dec r11
-       jz .call
-       ; Arg 5: R8
-       mov r8, [r10]
-       add r10, 8
-       dec r11
-       jz .call
-       ; Arg 6: R9
-       mov r9, [r10]
-       add r10, 8
-       dec r11
-       jz .call
-       ; No support for more
-
-.call:
-       mov rax, [rbp+2*8]      ; Ptr
-       call rax
-       
-       pop r11
-       pop r10
-       
-       lea rsp, [rbp]
-       pop rbp
-       ret
-
-; vim: ft=nasm
diff --git a/Kernel/arch/x86_64/time.c b/Kernel/arch/x86_64/time.c
deleted file mode 100644 (file)
index 03c889f..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Acess2 Kernel
- * Timekeeping
- * arch/x86_64/time.c
- */
-#include <acess.h>
-#include <arch_config.h>
-
-// === MACROS ===
-#define        TIMER_QUANTUM   100
-#define TIMER_FREQ     PIT_TIMER_BASE_N/(PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR)
-#define MS_PER_TICK_WHOLE      (1000*(PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR)/PIT_TIMER_BASE_N)
-#define MS_PER_TICK_FRACT      ((0x80000000ULL*1000ULL*PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR/PIT_TIMER_BASE_N)&0x7FFFFFFF)
-
-// === IMPORTS ===
-extern volatile Sint64 giTimestamp;
-extern volatile Uint64 giTicks;
-extern volatile Uint64 giPartMiliseconds;
-extern void    Timer_CallTimers(void);
-
-// === GLOBALS ===
-volatile Uint64        giTime_TSCAtLastTick = 0;
-volatile Uint64        giTime_TSCPerTick = 0;
-
-// === PROTOTYPES ===
-//Sint64       now(void);
- int   Time_Setup(void);
-void   Time_UpdateTimestamp(void);
-Uint64 Time_ReadTSC(void);
-
-// === CODE ===
-/**
- * \fn Sint64 now()
- * \brief Return the current timestamp
- */
-Sint64 now(void)
-{
-       Uint64  tsc = Time_ReadTSC();
-       tsc -= giTime_TSCAtLastTick;
-       tsc *= MS_PER_TICK_WHOLE;
-       if( giTime_TSCPerTick ) {
-               tsc /= giTime_TSCPerTick;
-       }
-       else
-               tsc = 0;
-       return giTimestamp + tsc;
-}
-
-/**
- * \fn int Time_Setup(void)
- * \brief Sets the system time from the Realtime-Clock
- */
-int Time_Setup(void)
-{
-       Log_Log("Timer", "PIT Timer firing at %iHz, %i.0x%08x miliseconds per tick",
-               TIMER_FREQ, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
-
-       // TODO: Read time from RTC
-       
-       return 0;
-}
-
-/**
- * \brief Called on the timekeeping IRQ
- */
-void Time_UpdateTimestamp(void)
-{
-       Uint64  curTSC = Time_ReadTSC();
-       
-       if( giTime_TSCAtLastTick )
-       {
-               giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
-       }
-       giTime_TSCAtLastTick = curTSC;
-       
-       giTicks ++;
-       giTimestamp += MS_PER_TICK_WHOLE;
-       giPartMiliseconds += MS_PER_TICK_FRACT;
-       if(giPartMiliseconds > 0x80000000) {
-               giTimestamp ++;
-               giPartMiliseconds -= 0x80000000;
-       }
-       
-       Timer_CallTimers();
-}
-
-#if 0
-/**
- * \fn void Time_TimerThread(void)
- */
-void Time_TimerThread(void)
-{
-       Sint64  next;
-       Threads_SetName("TIMER");
-       
-       next = giTimestamp + TIMER_QUANTUM;
-       for(;;)
-       {
-               while(giTimestamp < next)       Threads_Yield();
-               next = giTimestamp + TIMER_QUANTUM;     
-               Timer_CallTimers();
-       }
-}
-#endif
-
-Uint64 Time_ReadTSC(void)
-{
-       Uint32  a, d;
-       __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
-       return ((Uint64)d << 32) | a;
-}
diff --git a/Kernel/arch/x86_64/vm8086.c b/Kernel/arch/x86_64/vm8086.c
deleted file mode 100644 (file)
index 4251570..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- */
-#include <acess.h>
-#include <vm8086.h>
-#include <modules.h>
-//#include "rme.h"
-
-// === CONSTANTS ===
-#define VM8086_STACK_SEG       0x9F00
-#define VM8086_STACK_OFS       0x0AFE
-#define VM8086_PAGES_PER_INST  4
-
-// === PROTOTYPES ===
- int   VM8086_Install(char **Arguments);
-//tVM8086      *VM8086_Init(void);
-//void VM8086_Free(tVM8086 *State);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL);
-tMutex glVM8086_Process;
-//tRME_State   *gpVM8086_State;
-tPID   gVM8086_WorkerPID;
-tTID   gVM8086_CallingThread;
-tVM8086        volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions
-
-// === CODE ===
-int VM8086_Install(char **Arguments)
-{
-       //gpVM8086_State = RME_CreateState();
-       return MODULE_ERR_OK;
-}
-
-tVM8086 *VM8086_Init(void)
-{
-       return NULL;
-}
-
-void VM8086_Free(tVM8086 *State)
-{
-       
-}
-
-void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset)
-{
-       return NULL;
-}
-
-void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset)
-{
-       return NULL;
-}
-
-void VM8086_Int(tVM8086 *State, Uint8 Interrupt)
-{
-       
-}
diff --git a/Kernel/bin/README b/Kernel/bin/README
deleted file mode 100644 (file)
index 63d64bb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Acess2 Binary File Loader Specifcation
---------------------------------------
-
-Binary file loaders are defined by creating a \a tBinaryType variable that
-is registered with the kernel.
-
-\a tBinaryType contains seven fields.
--#     \a Next
-       This field is used internally by the kernel and should be set to NULL
-       when the definition is initialise and not changed by the driver.
--#     \a Ident
-       This field tells the kernel how to recognise this file format. If the
-       first 32-bits of the file (ANDed with the \a Mask field) match this
-       value, the file will be passed to this loader.
--#     \a Mask
-       Determines what bits in the first 32-bits of the file matter for the
-       identifcation.
--#     \a Name
-       This is a C string that uniquely identifies this binary format.
--#     \a Load
-       This field is a pointer to a function that takes a VFS Handle of the
-       source exectuable file as an argument and returns a \a tBinary
-       pointer that defines the location and attributes of the exectable's
-       segments. (See \a tBinary for more information)
diff --git a/Kernel/bin/elf.c b/Kernel/bin/elf.c
deleted file mode 100644 (file)
index 8f51290..0000000
+++ /dev/null
@@ -1,643 +0,0 @@
-/*\r
- * Acess v0.1\r
- * ELF Executable Loader Code\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <binary.h>\r
-#include "elf.h"\r
-\r
-#define DEBUG_WARN     1\r
-\r
-// === PROTOTYPES ===\r
-tBinary        *Elf_Load(int fp);\r
-tBinary        *Elf_Load64(int fp, Elf64_Ehdr *hdr);\r
-tBinary        *Elf_Load32(int fp, Elf32_Ehdr *hdr);\r
- int   Elf_Relocate(void *Base);\r
- int   Elf_Relocate32(void *Base);\r
- int   Elf_GetSymbol(void *Base, const char *Name, Uint *ret);\r
- int   Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base);\r
-Uint   Elf_Int_HashString(const char *str);\r
-\r
-// === GLOBALS ===\r
-tBinaryType    gELF_Info = {\r
-       NULL,\r
-       0x464C457F, 0xFFFFFFFF, // '\x7FELF'\r
-       "ELF",\r
-       Elf_Load, Elf_Relocate, Elf_GetSymbol\r
-       };\r
-\r
-// === CODE ===\r
-tBinary *Elf_Load(int fp)\r
-{\r
-       Elf64_Ehdr      hdr;\r
-       \r
-       // Read ELF Header\r
-       VFS_Read(fp, sizeof(hdr), &hdr);\r
-       \r
-       // Check the file type\r
-       if(hdr.e_ident[0] != 0x7F || hdr.e_ident[1] != 'E' || hdr.e_ident[2] != 'L' || hdr.e_ident[3] != 'F') {\r
-               Log_Warning("ELF", "Non-ELF File was passed to the ELF loader");\r
-               return NULL;\r
-       }\r
-\r
-       switch(hdr.e_ident[4])  // EI_CLASS\r
-       {\r
-       case ELFCLASS32:\r
-               return Elf_Load32(fp, (Elf32_Ehdr*)&hdr);\r
-       case ELFCLASS64:\r
-               return Elf_Load64(fp, &hdr);\r
-       default:\r
-               Log_Warning("ELF", "Unknown EI_CLASS value %i", hdr.e_ident[4]);\r
-               return NULL;\r
-       }\r
-}\r
-\r
-tBinary *Elf_Load64(int FD, Elf64_Ehdr *Header)\r
-{\r
-       tBinary *ret;\r
-       Elf64_Phdr      phtab[Header->e_phnum];\r
-        int    nLoadSegments;\r
-        int    i, j;\r
-       \r
-       // Sanity check\r
-       if( Header->e_phoff == 0 )\r
-       {\r
-               Log_Warning("ELF", "No program header, panic!");\r
-               return NULL;\r
-       }\r
-       if( Header->e_shentsize != sizeof(Elf64_Shdr) ) {\r
-               Log_Warning("ELF", "Header gives shentsize as %i, my type is %i",\r
-                       Header->e_shentsize, sizeof(Elf64_Shdr) );\r
-       }\r
-       if( Header->e_phentsize != sizeof(Elf64_Phdr) ) {\r
-               Log_Warning("ELF", "Header gives phentsize as %i, my type is %i",\r
-                       Header->e_phentsize, sizeof(Elf64_Phdr) );\r
-       }\r
-\r
-       LOG("Header = {");\r
-       LOG("  e_ident = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",\r
-               Header->e_ident[0], Header->e_ident[1], Header->e_ident[2], Header->e_ident[3],\r
-               Header->e_ident[4], Header->e_ident[5], Header->e_ident[6], Header->e_ident[7],\r
-               Header->e_ident[8], Header->e_ident[9], Header->e_ident[10], Header->e_ident[11],\r
-               Header->e_ident[12], Header->e_ident[13], Header->e_ident[14], Header->e_ident[15]\r
-               );\r
-       LOG("  e_type = %i", Header->e_type);\r
-       LOG("  e_machine = %i", Header->e_machine);\r
-       LOG("  e_version = %i", Header->e_version);\r
-       LOG("  e_entry   = 0x%llx", Header->e_entry);\r
-       LOG("  e_phoff   = 0x%llx", Header->e_phoff);\r
-       LOG("  e_shoff   = 0x%llx", Header->e_shoff);\r
-       LOG("  e_flags   = 0x%x", Header->e_flags);\r
-       LOG("  e_ehsize  = %i", Header->e_ehsize);\r
-       LOG("  e_phentsize = %i", Header->e_phentsize);\r
-       LOG("  e_phnum   = %i", Header->e_phnum);\r
-       LOG("  e_shentsize = %i", Header->e_shentsize);\r
-       LOG("  e_shnum   = %i", Header->e_shnum);\r
-       LOG("  e_shstrndx = %i", Header->e_shstrndx);\r
-       LOG("}");\r
-\r
-       // Load Program Header table\r
-       VFS_Seek(FD, Header->e_phoff, SEEK_SET);\r
-       VFS_Read(FD, sizeof(Elf64_Phdr)*Header->e_phnum, phtab);\r
-\r
-       // Count load segments\r
-       nLoadSegments = 0;\r
-       for( i = 0; i < Header->e_phnum; i ++ )\r
-       {\r
-               if( phtab[i].p_type != PT_LOAD )        continue ;\r
-               nLoadSegments ++;\r
-       }\r
-       \r
-       // Allocate Information Structure\r
-       ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*nLoadSegments );\r
-       // Fill Info Struct\r
-       ret->Entry = Header->e_entry;\r
-       ret->Base = -1;         // Set Base to maximum value\r
-       ret->NumSections = nLoadSegments;\r
-       ret->Interpreter = NULL;\r
-\r
-       j = 0;  // LoadSections[] index\r
-       for( i = 0; i < Header->e_phnum; i ++ )\r
-       {\r
-               LOG("phtab[%i] = {", i);\r
-               LOG("  .p_type   = %i", phtab[i].p_type);\r
-               LOG("  .p_flags  = 0x%x", phtab[i].p_flags);\r
-               LOG("  .p_offset = 0x%llx", phtab[i].p_offset);\r
-               LOG("  .p_vaddr  = 0x%llx", phtab[i].p_vaddr);\r
-               LOG("  .p_paddr  = 0x%llx", phtab[i].p_paddr);\r
-               LOG("  .p_filesz = 0x%llx", phtab[i].p_filesz);\r
-               LOG("  .p_memsz  = 0x%llx", phtab[i].p_memsz);\r
-               LOG("  .p_align  = 0x%llx", phtab[i].p_align);\r
-               LOG("}");\r
-\r
-               // Get Interpreter Name\r
-               if( phtab[i].p_type == PT_INTERP )\r
-               {\r
-                       char *tmp;\r
-                       if(ret->Interpreter)    continue;\r
-                       tmp = malloc(phtab[i].p_filesz);\r
-                       VFS_Seek(FD, phtab[i].p_offset, 1);\r
-                       VFS_Read(FD, phtab[i].p_filesz, tmp);\r
-                       ret->Interpreter = Binary_RegInterp(tmp);\r
-                       LOG("Interpreter '%s'", tmp);\r
-                       free(tmp);\r
-                       continue;\r
-               }\r
-               \r
-               if( phtab[i].p_type != PT_LOAD )        continue ;\r
-               \r
-               // Find the executable base\r
-               if( phtab[i].p_vaddr < ret->Base )      ret->Base = phtab[i].p_vaddr;\r
-\r
-               ret->LoadSections[j].Offset = phtab[i].p_offset;\r
-               ret->LoadSections[j].Virtual = phtab[i].p_vaddr;\r
-               ret->LoadSections[j].FileSize = phtab[i].p_filesz;\r
-               ret->LoadSections[j].MemSize = phtab[i].p_memsz;\r
-               \r
-               ret->LoadSections[j].Flags = 0;\r
-               if( !(phtab[i].p_flags & PF_W) )\r
-                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
-               if( phtab[i].p_flags & PF_X )\r
-                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
-               j ++;\r
-       }\r
-\r
-       return ret;\r
-}\r
-\r
-tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header)\r
-{\r
-       tBinary *ret;\r
-       Elf32_Phdr      *phtab;\r
-        int    i, j;\r
-        int    iLoadCount;\r
-\r
-       ENTER("xFD", FD);\r
-\r
-       // Check architecture with current CPU\r
-       // - TODO: Support kernel level emulation\r
-       #if ARCH_IS_x86\r
-       if( Header->machine != EM_386 )\r
-       {\r
-               Log_Warning("ELF", "Unknown architecure on ELF-32");\r
-               LEAVE_RET('n');\r
-               return NULL;\r
-       }\r
-       #endif\r
-\r
-       // Check for a program header\r
-       if(Header->phoff == 0) {\r
-               #if DEBUG_WARN\r
-               Log_Warning("ELF", "File does not contain a program header (phoff == 0)");\r
-               #endif\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Read Program Header Table\r
-       phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount );\r
-       if( !phtab ) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       LOG("hdr.phoff = 0x%08x", Header->phoff);\r
-       VFS_Seek(FD, Header->phoff, SEEK_SET);\r
-       VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab);\r
-       \r
-       // Count Pages\r
-       iLoadCount = 0;\r
-       LOG("Header->phentcount = %i", Header->phentcount);\r
-       for( i = 0; i < Header->phentcount; i++ )\r
-       {\r
-               // Ignore Non-LOAD types\r
-               if(phtab[i].Type != PT_LOAD)\r
-                       continue;\r
-               iLoadCount ++;\r
-               LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
-       }\r
-       \r
-       LOG("iLoadCount = %i", iLoadCount);\r
-       \r
-       // Allocate Information Structure\r
-       ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount );\r
-       // Fill Info Struct\r
-       ret->Entry = Header->entrypoint;\r
-       ret->Base = -1;         // Set Base to maximum value\r
-       ret->NumSections = iLoadCount;\r
-       ret->Interpreter = NULL;\r
-       \r
-       // Load Pages\r
-       j = 0;\r
-       for( i = 0; i < Header->phentcount; i++ )\r
-       {\r
-               //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
-               LOG("phtab[%i] = {", i);\r
-               LOG(" .Type = 0x%08x", phtab[i].Type);\r
-               LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
-               LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
-               LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
-               LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
-               LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
-               LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
-               LOG(" .Align = 0x%08x", phtab[i].Align);\r
-               LOG(" }");\r
-               // Get Interpreter Name\r
-               if( phtab[i].Type == PT_INTERP )\r
-               {\r
-                       char *tmp;\r
-                       if(ret->Interpreter)    continue;\r
-                       tmp = malloc(phtab[i].FileSize);\r
-                       VFS_Seek(FD, phtab[i].Offset, 1);\r
-                       VFS_Read(FD, phtab[i].FileSize, tmp);\r
-                       ret->Interpreter = Binary_RegInterp(tmp);\r
-                       LOG("Interpreter '%s'", tmp);\r
-                       free(tmp);\r
-                       continue;\r
-               }\r
-               // Ignore non-LOAD types\r
-               if(phtab[i].Type != PT_LOAD)    continue;\r
-               \r
-               // Find Base\r
-               if(phtab[i].VAddr < ret->Base)  ret->Base = phtab[i].VAddr;\r
-               \r
-               LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",\r
-                       i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);\r
-               \r
-               ret->LoadSections[j].Offset = phtab[i].Offset;\r
-               ret->LoadSections[j].FileSize = phtab[i].FileSize;\r
-               ret->LoadSections[j].Virtual = phtab[i].VAddr;\r
-               ret->LoadSections[j].MemSize = phtab[i].MemSize;\r
-               ret->LoadSections[j].Flags = 0;\r
-               if( !(phtab[i].Flags & PF_W) )\r
-                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
-               if( phtab[i].Flags & PF_X )\r
-                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
-               j ++;\r
-       }\r
-       \r
-       // Clean Up\r
-       free(phtab);\r
-       // Return\r
-       LEAVE('p', ret);\r
-       return ret;\r
-}\r
-\r
-// --- ELF RELOCATION ---\r
-int Elf_Relocate(void *Base)\r
-{\r
-       Elf64_Ehdr      *hdr = Base;\r
-       \r
-       switch( hdr->e_ident[EI_CLASS] )\r
-       {\r
-       case ELFCLASS32:\r
-               return Elf_Relocate32(Base);\r
-       case ELFCLASS64:\r
-               return 0;\r
-       default:\r
-               return 1;\r
-       }\r
-}\r
-\r
-\r
-/**\r
- * \brief Relocates a loaded ELF Executable\r
- */\r
-int Elf_Relocate32(void *Base)\r
-{\r
-       Elf32_Ehdr      *hdr = Base;\r
-       Elf32_Phdr      *phtab;\r
-        int    i, j;   // Counters\r
-       char    *libPath;\r
-       Uint    iRealBase = -1;\r
-       Uint    iBaseDiff;\r
-        int    iSegmentCount;\r
-        int    iSymCount = 0;\r
-       Elf32_Rel       *rel = NULL;\r
-       Elf32_Rela      *rela = NULL;\r
-       Uint32  *pltgot = NULL;\r
-       void    *plt = NULL;\r
-       Uint32  *ptr;\r
-        int    relSz=0, relEntSz=8;\r
-        int    relaSz=0, relaEntSz=8;\r
-        int    pltSz=0, pltType=0;\r
-       Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer\r
-       char    *dynstrtab = NULL;      // .dynamic String Table\r
-       Elf32_Sym       *dynsymtab = NULL;\r
-        int    bFailed = 0;\r
-       \r
-       ENTER("pBase", Base);\r
-       \r
-       // Parse Program Header to get Dynamic Table\r
-       phtab = (void *)( (tVAddr)Base + hdr->phoff );\r
-       iSegmentCount = hdr->phentcount;\r
-       for(i = 0; i < iSegmentCount; i ++ )\r
-       {\r
-               // Determine linked base address\r
-               if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)\r
-                       iRealBase = phtab[i].VAddr;\r
-               \r
-               // Find Dynamic Section\r
-               if(phtab[i].Type == PT_DYNAMIC) {\r
-                       if(dynamicTab) {\r
-                               Log_Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
-                               continue;\r
-                       }\r
-                       dynamicTab = (void *) (tVAddr) phtab[i].VAddr;\r
-                       j = i;  // Save Dynamic Table ID\r
-                       break;\r
-               }\r
-       }\r
-       \r
-       // Check if a PT_DYNAMIC segement was found\r
-       if(!dynamicTab) {\r
-               Log_Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
-               LEAVE('x', 0);\r
-               return 0;\r
-       }\r
-       \r
-       // Page Align real base\r
-       iRealBase &= ~0xFFF;\r
-       \r
-       // Adjust "Real" Base\r
-       iBaseDiff = (Uint)Base - iRealBase;\r
-       // Adjust Dynamic Table\r
-       dynamicTab = (void *) ((Uint)dynamicTab + iBaseDiff);\r
-       \r
-       // === Get Symbol table and String Table ===\r
-       for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
-       {\r
-               switch(dynamicTab[j].d_tag)\r
-               {\r
-               // --- Symbol Table ---\r
-               case DT_SYMTAB:\r
-                       dynamicTab[j].d_val += iBaseDiff;\r
-                       dynsymtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
-                       hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident\r
-                       break;\r
-               \r
-               // --- String Table ---\r
-               case DT_STRTAB:\r
-                       dynamicTab[j].d_val += iBaseDiff;\r
-                       dynstrtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
-                       break;\r
-               \r
-               // --- Hash Table --\r
-               case DT_HASH:\r
-                       dynamicTab[j].d_val += iBaseDiff;\r
-                       iSymCount = ((Uint*)((tVAddr)dynamicTab[j].d_val))[1];\r
-                       hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident\r
-                       break;\r
-               }\r
-       }\r
-\r
-       if( !dynsymtab && iSymCount > 0 ) {\r
-               Log_Warning("ELF", "Elf_Relocate: No Dynamic symbol table, but count >0");\r
-               return 0;\r
-       }\r
-\r
-       // Alter Symbols to true base\r
-       for(i = 0; i < iSymCount; i ++)\r
-       {\r
-               dynsymtab[i].value += iBaseDiff;\r
-               dynsymtab[i].nameOfs += (Uint)dynstrtab;\r
-               //LOG("Sym '%s' = 0x%x (relocated)\n", dynsymtab[i].name, dynsymtab[i].value);\r
-       }\r
-       \r
-       // === Add to loaded list (can be imported now) ===\r
-       //Binary_AddLoaded( (Uint)Base );\r
-\r
-       // === Parse Relocation Data ===\r
-       for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
-       {\r
-               switch(dynamicTab[j].d_tag)\r
-               {\r
-               // --- Shared Library Name ---\r
-               case DT_SONAME:\r
-                       LOG(".so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);\r
-                       break;\r
-               // --- Needed Library ---\r
-               case DT_NEEDED:\r
-                       libPath = dynstrtab + dynamicTab[j].d_val;\r
-                       Log_Notice("ELF", "%p - Required Library '%s' (Ignored in kernel mode)\n", Base, libPath);\r
-                       break;\r
-               // --- PLT/GOT ---\r
-               case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val);        break;\r
-               case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val);   break;\r
-               case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;\r
-               case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;\r
-               \r
-               // --- Relocation ---\r
-               case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
-               case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;\r
-               case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;\r
-               \r
-               case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;\r
-               case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;\r
-               case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;\r
-               }\r
-       }\r
-       \r
-       // Parse Relocation Entries\r
-       if(rel && relSz)\r
-       {\r
-               j = relSz / relEntSz;\r
-               for( i = 0; i < j; i++ )\r
-               {\r
-                       ptr = (void*)(iBaseDiff + rel[i].r_offset);\r
-                       if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {\r
-                               bFailed = 1;\r
-                       }\r
-               }\r
-       }\r
-       // Parse Relocation Entries\r
-       if(rela && relaSz)\r
-       {\r
-               j = relaSz / relaEntSz;\r
-               for( i = 0; i < j; i++ )\r
-               {\r
-                       ptr = (void*)(iBaseDiff + rela[i].r_offset);\r
-                       if( !Elf_Int_DoRelocate(rela[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
-                               bFailed = 1;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       // === Process PLT (Procedure Linkage Table) ===\r
-       if(plt && pltSz)\r
-       {\r
-               if(pltType == DT_REL)\r
-               {\r
-                       Elf32_Rel       *pltRel = plt;\r
-                       j = pltSz / sizeof(Elf32_Rel);\r
-                       LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
-                       for(i = 0; i < j; i++)\r
-                       {\r
-                               ptr = (void*)(iBaseDiff + pltRel[i].r_offset);\r
-                               if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {\r
-                                       bFailed = 1;\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       Elf32_Rela      *pltRela = plt;\r
-                       j = pltSz / sizeof(Elf32_Rela);\r
-                       LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
-                       for(i=0;i<j;i++)\r
-                       {\r
-                               ptr = (void*)(iBaseDiff + pltRela[i].r_offset);\r
-                               if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
-                                       bFailed = 1;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       if(bFailed) {\r
-               LEAVE('i', 0);\r
-               return 0;\r
-       }\r
-       \r
-       LEAVE('x', 1);\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn void Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)\r
- * \brief Performs a relocation\r
- * \param r_info       Field from relocation entry\r
- * \param ptr  Pointer to location of relocation\r
- * \param addend       Value to add to symbol\r
- * \param symtab       Symbol Table\r
- * \param base Base of loaded binary\r
- */\r
-int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)\r
-{\r
-       Uint    val;\r
-        int    type = ELF32_R_TYPE(r_info);\r
-        int    sym = ELF32_R_SYM(r_info);\r
-       char    *sSymName = symtab[sym].name;\r
-       \r
-       //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",\r
-       //      r_info, ptr, addend, base);\r
-       \r
-       switch( type )\r
-       {\r
-       // Standard 32 Bit Relocation (S+A)\r
-       case R_386_32:\r
-               if( !Elf_GetSymbol((void*)base, sSymName, &val) )       // Search this binary first\r
-                       if( !Binary_GetSymbol( sSymName, &val ) )\r
-                               return 0;\r
-               LOG("%08x R_386_32 *0x%x += 0x%x('%s')", r_info, ptr, val, sSymName);\r
-               *ptr = val + addend;\r
-               break;\r
-               \r
-       // 32 Bit Relocation wrt. Offset (S+A-P)\r
-       case R_386_PC32:\r
-               if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
-                       if( !Binary_GetSymbol( sSymName, &val ) )\r
-                               return 0;\r
-               LOG("%08x R_386_PC32 *0x%x = 0x%x + 0x%x('%s') - 0x%x", r_info, ptr, *ptr, val, sSymName, (Uint)ptr );\r
-               // TODO: Check if it needs the true value of ptr or the compiled value\r
-               // NOTE: Testing using true value\r
-               *ptr = val + addend - (Uint)ptr;\r
-               break;\r
-\r
-       // Absolute Value of a symbol (S)\r
-       case R_386_GLOB_DAT:\r
-               if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
-                       if( !Binary_GetSymbol( sSymName, &val ) )\r
-                               return 0;\r
-               LOG("%08x R_386_GLOB_DAT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
-               *ptr = val;\r
-               break;\r
-       \r
-       // Absolute Value of a symbol (S)\r
-       case R_386_JMP_SLOT:\r
-               if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
-                       if( !Binary_GetSymbol( sSymName, &val ) )\r
-                               return 0;\r
-               LOG("%08x R_386_JMP_SLOT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
-               *ptr = val;\r
-               break;\r
-\r
-       // Base Address (B+A)\r
-       case R_386_RELATIVE:\r
-               LOG("%08x R_386_RELATIVE *0x%x = 0x%x + 0x%x", r_info, ptr, base, addend);\r
-               *ptr = base + addend;\r
-               break;\r
-               \r
-       default:\r
-               LOG("Rel 0x%x: 0x%x,%i", ptr, sym, type);\r
-               break;\r
-       }\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn int Elf_GetSymbol(void *Base, const char *name, Uint *ret)\r
- * \brief Get a symbol from the loaded binary\r
- */\r
-int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)\r
-{\r
-       Elf32_Ehdr      *hdr = (void*)Base;\r
-       Elf32_Sym       *symtab;\r
-        int    nbuckets = 0;\r
-        int    iSymCount = 0;\r
-        int    i;\r
-       Uint    *pBuckets;\r
-       Uint    *pChains;\r
-       Uint    iNameHash;\r
-\r
-       if(!Base)       return 0;\r
-\r
-       pBuckets = (void *) hdr->misc.HashTable;\r
-       symtab = (void *) hdr->misc.SymTable;\r
-       \r
-       nbuckets = pBuckets[0];\r
-       iSymCount = pBuckets[1];\r
-       pBuckets = &pBuckets[2];\r
-       pChains = &pBuckets[ nbuckets ];\r
-       \r
-       // Get hash\r
-       iNameHash = Elf_Int_HashString(Name);\r
-       iNameHash %= nbuckets;\r
-\r
-       // Check Bucket\r
-       i = pBuckets[ iNameHash ];\r
-       if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[i].name, Name) == 0) {\r
-               if(ret) *ret = symtab[ i ].value;\r
-               return 1;\r
-       }\r
-       \r
-       // Walk Chain\r
-       while(pChains[i] != STN_UNDEF)\r
-       {\r
-               i = pChains[i];\r
-               if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {\r
-                       if(ret) *ret = symtab[ i ].value;\r
-                       return 1;\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn Uint Elf_Int_HashString(char *str)\r
- * \brief Hash a string in the ELF format\r
- * \param str  String to hash\r
- * \return Hash value\r
- */\r
-Uint Elf_Int_HashString(const char *str)\r
-{\r
-       Uint    h = 0, g;\r
-       while(*str)\r
-       {\r
-               h = (h << 4) + *str++;\r
-               if( (g = h & 0xf0000000) )\r
-                       h ^= g >> 24;\r
-               h &= ~g;\r
-       }\r
-       return h;\r
-}\r
diff --git a/Kernel/bin/elf.h b/Kernel/bin/elf.h
deleted file mode 100644 (file)
index 13b5373..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/**\r
- * \file elf.h\r
- * \brief ELF Exeutable Loader\r
- */\r
-#ifndef _BIN_ELF_H\r
-#define _BIN_ELF_H\r
-\r
-typedef Uint16 Elf64_Half;\r
-typedef Uint32 Elf64_Word;\r
-typedef Uint64 Elf64_Addr;\r
-typedef Uint64 Elf64_Off;\r
-typedef Uint64 Elf64_Xword;\r
-\r
-enum e_ident_values\r
-{\r
-       EI_MAG0,\r
-       EI_MAG1,\r
-       EI_MAG2,\r
-       EI_MAG3,\r
-       EI_CLASS,\r
-       EI_DATA,\r
-       EI_VERSION,\r
-       EI_OSABI,\r
-       EI_ABIVERSION,\r
-       EI_PAD,\r
-       EI_NIDENT = 16,\r
-};\r
-\r
-#define ELFCLASS32     1\r
-#define ELFCLASS64     2\r
-\r
-/**\r
- * \brief ELF File Header\r
- */\r
-struct sElf32_Ehdr\r
-{\r
-       union {\r
-               char    ident[16];      //!< Identifier Bytes\r
-               struct {\r
-                       Uint    Ident1;\r
-                       Uint    Ident2;\r
-                       Uint    HashTable;\r
-                       Uint    SymTable;\r
-               } misc;\r
-       };\r
-       Uint16  filetype;       //!< File Type\r
-       Uint16  machine;        //!< Machine / Arch\r
-       Uint32  version;        //!< Version (File?)\r
-       Uint32  entrypoint;     //!< Entry Point\r
-       Uint32  phoff;  //!< Program Header Offset\r
-       Uint32  shoff;  //!< Section Header Offset\r
-       Uint32  flags;  //!< Flags\r
-       Uint16  headersize;     //!< Header Size\r
-       Uint16  phentsize;      //!< Program Header Entry Size\r
-       Uint16  phentcount;     //!< Program Header Entry Count\r
-       Uint16  shentsize;      //!< Section Header Entry Size\r
-       Uint16  shentcount;     //!< Section Header Entry Count\r
-       Uint16  shstrindex;     //!< Section Header String Table Index\r
-} __attribute__ ((packed));\r
-\r
-typedef struct\r
-{\r
-       unsigned char   e_ident[16];\r
-       Elf64_Half      e_type;\r
-       Elf64_Half      e_machine;\r
-       Elf64_Word      e_version;\r
-       Elf64_Addr      e_entry;\r
-       Elf64_Off       e_phoff;\r
-       Elf64_Off       e_shoff;\r
-       Elf64_Word      e_flags;\r
-       Elf64_Half      e_ehsize;\r
-       Elf64_Half      e_phentsize;\r
-       Elf64_Half      e_phnum;\r
-       Elf64_Half      e_shentsize;\r
-       Elf64_Half      e_shnum;\r
-       Elf64_Half      e_shstrndx;\r
-} Elf64_Ehdr;\r
-\r
-/**\r
- * \brief Executable Types\r
- */\r
-enum eElf32_ExecTypes\r
-{\r
-       ET_NONE = 0,    //!< NULL Type\r
-       ET_REL  = 1,    //!< Relocatable (Object)\r
-       ET_EXEC = 2,    //!< Executable\r
-       ET_DYN  = 3,    //!< Dynamic Library\r
-       ET_CORE = 4,    //!< Core?\r
-       ET_LOPROC = 0xFF00,     //!< Low Impl Defined\r
-       ET_HIPROC = 0xFFFF      //!< High Impl Defined\r
-};\r
-\r
-/**\r
- \name Section IDs\r
- \{\r
-*/\r
-#define SHN_UNDEF              0       //!< Undefined Section\r
-#define SHN_LORESERVE  0xFF00  //!< Low Reserved\r
-#define SHN_LOPROC     0xFF00  //!< Low Impl Defined\r
-#define SHN_HIPROC     0xFF1F  //!< High Impl Defined\r
-#define SHN_ABS        0xFFF1  //!< Absolute Address (Base: 0, Size: -1)\r
-#define SHN_COMMON     0xFFF2  //!< Common\r
-#define SHN_HIRESERVE  0xFFFF  //!< High Reserved\r
-//! \}\r
-\r
-/**\r
- \enum eElfSectionTypes\r
- \brief ELF Section Types\r
-*/\r
-enum eElfSectionTypes {\r
-       SHT_NULL,       //0\r
-       SHT_PROGBITS,   //1\r
-       SHT_SYMTAB,     //2\r
-       SHT_STRTAB,     //3\r
-       SHT_RELA,       //4\r
-       SHT_HASH,       //5\r
-       SHT_DYNAMIC,    //6\r
-       SHT_NOTE,       //7\r
-       SHT_NOBITS,     //8\r
-       SHT_REL,        //9\r
-       SHT_SHLIB,      //A\r
-       SHT_DYNSYM,     //B\r
-       SHT_LAST,       //C\r
-       SHT_LOPROC = 0x70000000,\r
-       SHT_HIPROC = 0x7fffffff,\r
-       SHT_LOUSER = 0x80000000,\r
-       SHT_HIUSER = 0xffffffff\r
-};\r
-\r
-#define SHF_WRITE      0x1\r
-#define SHF_ALLOC      0x2\r
-#define SHF_EXECINSTR  0x4\r
-#define SHF_MASKPROC   0xf0000000\r
-\r
-struct sElf32_Shent {\r
-       Uint32  name;\r
-       Uint32  type;\r
-       Uint32  flags;\r
-       Uint32  address;\r
-       Uint32  offset;\r
-       Uint32  size;\r
-       Uint32  link;\r
-       Uint32  info;\r
-       Uint32  addralign;\r
-       Uint32  entsize;\r
-} __attribute__ ((packed));    //sizeof = 40\r
-\r
-typedef struct\r
-{\r
-       Elf64_Word      sh_name;\r
-       Elf64_Word      sh_type;\r
-       Elf64_Xword     sh_flags;\r
-       Elf64_Addr      sh_addr;\r
-       Elf64_Off       sh_offset;\r
-       Elf64_Xword     sh_size;\r
-       Elf64_Word      sh_link;\r
-       Elf64_Word      sh_info;\r
-       Elf64_Xword     sh_addralign;\r
-       Elf64_Xword     sh_entsize;\r
-} Elf64_Shdr;\r
-\r
-struct elf_sym_s {\r
-       union {\r
-               Uint32  nameOfs;\r
-               char    *name;\r
-       };\r
-       Uint32  value;  //Address\r
-       Uint32  size;\r
-       Uint8   info;\r
-       Uint8   other;\r
-       Uint16  shndx;\r
-} __attribute__ ((packed));\r
-#define        STN_UNDEF       0       // Undefined Symbol\r
-\r
-enum {\r
-       PT_NULL,        //0\r
-       PT_LOAD,        //1\r
-       PT_DYNAMIC,     //2\r
-       PT_INTERP,      //3\r
-       PT_NOTE,        //4\r
-       PT_SHLIB,       //5\r
-       PT_PHDR,        //6\r
-       PT_LOPROC = 0x70000000,\r
-       PT_HIPROC = 0x7fffffff\r
-};\r
-\r
-struct sElf32_Phdr {\r
-       Uint32  Type;\r
-       Uint32  Offset;\r
-       Uint32  VAddr;\r
-       Uint32  PAddr;\r
-       Uint32  FileSize;\r
-       Uint32  MemSize;\r
-       Uint32  Flags;\r
-       Uint32  Align;\r
-} __attribute__ ((packed));\r
-\r
-typedef struct\r
-{\r
-       Elf64_Word      p_type;\r
-       Elf64_Word      p_flags;\r
-       Elf64_Off       p_offset;\r
-       Elf64_Addr      p_vaddr;\r
-       Elf64_Addr      p_paddr;\r
-       Elf64_Xword     p_filesz;\r
-       Elf64_Xword     p_memsz;\r
-       Elf64_Xword     p_align;\r
-} Elf64_Phdr;\r
-\r
-#define PF_X   1\r
-#define PF_W   2\r
-#define PF_R   4\r
-\r
-struct elf32_rel_s {\r
-       Uint32  r_offset;\r
-       Uint32  r_info;\r
-} __attribute__ ((packed));\r
-\r
-struct elf32_rela_s {\r
-       Uint32  r_offset;\r
-       Uint32  r_info;\r
-       Sint32  r_addend;\r
-} __attribute__ ((packed));\r
-\r
-enum {\r
-       R_386_NONE = 0, // none\r
-       R_386_32,       // S+A\r
-       R_386_PC32,     // S+A-P\r
-       R_386_GOT32,    // G+A-P\r
-       R_386_PLT32,    // L+A-P\r
-       R_386_COPY,     // none\r
-       R_386_GLOB_DAT, // S\r
-       R_386_JMP_SLOT, // S\r
-       R_386_RELATIVE, // B+A\r
-       R_386_GOTOFF,   // S+A-GOT\r
-       R_386_GOTPC,    // GOT+A-P\r
-       R_386_LAST      // none\r
-};\r
-\r
-#define        ELF32_R_SYM(i)  ((i)>>8)        // Takes an info value and returns a symbol index\r
-#define        ELF32_R_TYPE(i) ((i)&0xFF)      // Takes an info value and returns a type\r
-#define        ELF32_R_INFO(s,t)       (((s)<<8)+((t)&0xFF))   // Takes a type and symbol index and returns an info value\r
-\r
-struct elf32_dyn_s {\r
-       Uint32  d_tag;\r
-       Uint32  d_val;  //Also d_ptr\r
-} __attribute__ ((packed));\r
-\r
-enum {\r
-       DT_NULL,        //!< Marks End of list\r
-       DT_NEEDED,      //!< Offset in strtab to needed library\r
-       DT_PLTRELSZ,    //!< Size in bytes of PLT\r
-       DT_PLTGOT,      //!< Address of PLT/GOT\r
-       DT_HASH,        //!< Address of symbol hash table\r
-       DT_STRTAB,      //!< String Table address\r
-       DT_SYMTAB,      //!< Symbol Table address\r
-       DT_RELA,        //!< Relocation table address\r
-       DT_RELASZ,      //!< Size of relocation table\r
-       DT_RELAENT,     //!< Size of entry in relocation table\r
-       DT_STRSZ,       //!< Size of string table\r
-       DT_SYMENT,      //!< Size of symbol table entry\r
-       DT_INIT,        //!< Address of initialisation function\r
-       DT_FINI,        //!< Address of termination function\r
-       DT_SONAME,      //!< String table offset of so name\r
-       DT_RPATH,       //!< String table offset of library path\r
-       DT_SYMBOLIC,//!< Reverse order of symbol searching for library, search libs first then executable\r
-       DT_REL,         //!< Relocation Entries (Elf32_Rel instead of Elf32_Rela)\r
-       DT_RELSZ,       //!< Size of above table (bytes)\r
-       DT_RELENT,      //!< Size of entry in above table\r
-       DT_PLTREL,      //!< Relocation entry of PLT\r
-       DT_DEBUG,       //!< Debugging Entry - Unknown contents\r
-       DT_TEXTREL,     //!< Indicates that modifcations to a non-writeable segment may occur\r
-       DT_JMPREL,      //!< Address of PLT only relocation entries\r
-       DT_LOPROC = 0x70000000, //!< Low Definable\r
-       DT_HIPROC = 0x7FFFFFFF  //!< High Definable\r
-};\r
-\r
-typedef struct sElf32_Ehdr     Elf32_Ehdr;\r
-typedef struct sElf32_Phdr     Elf32_Phdr;\r
-typedef struct sElf32_Shent    Elf32_Shent;\r
-typedef struct elf_sym_s       elf_symtab;\r
-typedef struct elf_sym_s       Elf32_Sym;\r
-typedef struct elf32_rel_s     Elf32_Rel;\r
-typedef struct elf32_rela_s    Elf32_Rela;\r
-typedef struct elf32_dyn_s     Elf32_Dyn;\r
-\r
-#endif // defined(_EXE_ELF_H)\r
diff --git a/Kernel/bin/pe.c b/Kernel/bin/pe.c
deleted file mode 100644 (file)
index 0e7d1ac..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/*\r
- * Acess v1\r
- * Portable Executable Loader\r
- */\r
-#define DEBUG  1\r
-#include <acess.h>\r
-#include <binary.h>\r
-#include <modules.h>\r
-#include "pe.h"\r
-\r
-// === PROTOTYPES ===\r
- int   PE_Install(char **Arguments);\r
-tBinary        *PE_Load(int fp);\r
-tBinary        *MZ_Open(int fp);\r
- int   PE_Relocate(void *Base);\r
- int   PE_GetSymbol(void *Base, const char *Name, Uint *Ret);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, 0x0032, BinPE, PE_Install, NULL, NULL);\r
-const char     *gsPE_DefaultInterpreter = "/Acess/Libs/ld-acess.so";\r
-tBinaryType    gPE_Loader = {\r
-       NULL,\r
-       ('M'|('Z'<<8)), 0xFFFF, // 'MZ'\r
-       "PE/DOS",\r
-       PE_Load, PE_Relocate, PE_GetSymbol\r
-       };\r
-\r
-// === CODE ===\r
-int PE_Install(char **Arguments)\r
-{\r
-       Binary_RegisterType(&gPE_Loader);\r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \brief Loads a PE Binary\r
- */\r
-tBinary *PE_Load(int FP)\r
-{\r
-        int    count, i, j;\r
-        int    iSectCount;\r
-       tBinary *ret;\r
-       tPE_DOS_HEADER          dosHdr;\r
-       tPE_IMAGE_HEADERS       peHeaders;\r
-       tPE_SECTION_HEADER      *peSections;\r
-       char    namebuf[9] = {0};\r
-       Uint    iFlags, iVA;\r
-       \r
-       ENTER("xFP", FP);\r
-       \r
-       // Read DOS header and check\r
-       VFS_Read(FP, sizeof(tPE_DOS_HEADER), &dosHdr);\r
-       if( dosHdr.Ident != ('M'|('Z'<<8)) ) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // - Read PE Header\r
-       VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET);\r
-       if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) {\r
-               ret = MZ_Open(FP);\r
-               LEAVE('p', ret);\r
-               return ret;\r
-       }\r
-       VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders);\r
-       \r
-       // - Check PE Signature and pass on to the MZ Loader if invalid\r
-       if( peHeaders.Signature != (('P')|('E'<<8)) ) {\r
-               ret = MZ_Open(FP);\r
-               LEAVE('p', ret);\r
-               return ret;\r
-       }\r
-       \r
-       // Read Sections (Uses `count` as a temp variable)\r
-       count = sizeof(tPE_SECTION_HEADER) * peHeaders.FileHeader.SectionCount;\r
-       peSections = malloc( count );\r
-       if(!peSections)\r
-       {\r
-               Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count);\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       VFS_Read(FP, count, peSections);\r
-       \r
-       // Count Pages\r
-       iSectCount = 1; // 1st page is headers\r
-       for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
-       {\r
-               // Check if the section is loadable\r
-               // (VA is zero in non-loadable sections)\r
-               if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0)              continue;\r
-               \r
-               // Moar pages\r
-               iSectCount ++;\r
-       }\r
-       \r
-       LOG("%i Sections", iSectCount);\r
-       \r
-       // Initialise Executable Information\r
-       ret = malloc(sizeof(tBinary) + sizeof(tBinarySection)*iSectCount);\r
-       \r
-       ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase;\r
-       ret->Base = peHeaders.OptHeader.ImageBase;\r
-       ret->Interpreter = gsPE_DefaultInterpreter;\r
-       ret->NumSections = iSectCount;\r
-       \r
-       LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base);\r
-       \r
-       ret->LoadSections[0].Virtual = peHeaders.OptHeader.ImageBase;\r
-       ret->LoadSections[0].Offset = 0;\r
-       ret->LoadSections[0].FileSize = 4096;\r
-       ret->LoadSections[0].MemSize = 4096;\r
-       ret->LoadSections[0].Flags = 0;\r
-       \r
-       // Parse Sections\r
-       j = 1;  // Page Index\r
-       for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
-       {\r
-               tBinarySection  *sect = &ret->LoadSections[j];\r
-               iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase;\r
-               \r
-               // Skip non-loadable sections\r
-               if(iVA == 0)    continue;\r
-               \r
-               // Create Name Buffer\r
-               memcpy(namebuf, peSections[i].Name, 8);\r
-               LOG("Section %i '%s', iVA = %p", i, namebuf, iVA);\r
-               \r
-               // Create Flags\r
-               iFlags = 0;\r
-               if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE)\r
-                       iFlags |= BIN_SECTFLAG_EXEC;\r
-               if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) )\r
-                       iFlags |= BIN_SECTFLAG_RO;\r
-               \r
-               sect->Virtual = iVA;\r
-               sect->Offset = peSections[i].RawOffs;\r
-               sect->FileSize = peSections[i].RawSize;\r
-               sect->MemSize = peSections[i].VirtualSize;\r
-               sect->Flags = iFlags;\r
-               j ++;\r
-               \r
-               LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x",\r
-                       i, namebuf, \r
-                       iVA,\r
-                       peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs,\r
-                       peSections[i].Flags\r
-                       );\r
-               \r
-       }\r
-       // Free Executable Memory\r
-       free(peSections);\r
-       \r
-       LEAVE('p', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- */\r
-tBinary *MZ_Open(int FP)\r
-{\r
-       ENTER("xFP", FP);\r
-       UNIMPLEMENTED();\r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-int PE_Relocate(void *Base)\r
-{\r
-       tPE_DOS_HEADER          *dosHdr;\r
-       tPE_IMAGE_HEADERS       *peHeaders;\r
-       tPE_SECTION_HEADER      *peSections;\r
-       tPE_DATA_DIR    *directory;\r
-       tPE_IMPORT_DIR  *impDir;\r
-        int    i;\r
-       Uint    iBase = (Uint)Base;\r
-       #if 0\r
-       void    *hLibrary;\r
-       char    *libPath;\r
-       #endif\r
-       \r
-       ENTER("pBase", Base);\r
-       dosHdr = Base;\r
-       peHeaders = (void*)( iBase + dosHdr->PeHdrOffs );\r
-       LOG("Prefered Base %p", peHeaders->OptHeader.ImageBase);\r
-       peSections = (void*)( iBase + sizeof(tPE_IMAGE_HEADERS) );\r
-       \r
-       directory = (void*)(peSections[0].RVA + iBase);\r
-       \r
-       // === Load Import Tables\r
-       impDir = (void*)( directory[PE_DIR_IMPORT].RVA + iBase );\r
-       for( i = 0; impDir[i].DLLName != NULL; i++ )\r
-       {\r
-               impDir[i].DLLName += iBase;\r
-               impDir[i].ImportLookupTable += iBase/4;\r
-               impDir[i].ImportAddressTable += iBase/4;\r
-               LOG("DLL Required '%s'(0x%x)", impDir[i].DLLName, impDir[i].DLLName);\r
-               #if 0\r
-               libPath = FindLibrary(impDir[i].DLLName);\r
-               if(libPath == NULL)\r
-               {\r
-                       Warning("PE_Relocate - Unable to find library '%s'");\r
-                       LEAVE('i', -1);\r
-                       return -1;\r
-               }\r
-               LOG("DLL Path = '%s'", libPath);\r
-               hLibrary = DynLib_Load(libPath, 0);\r
-               #endif\r
-       }\r
-       \r
-       for(i=0;i<PE_DIR_LAST;i++)\r
-               LOG("directory[%i] = {RVA=0x%x,Size=0x%x}", i, directory[i].RVA, directory[i].Size);\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-\r
-int PE_GetSymbol(void *Base, const char *Name, Uint *Ret)\r
-{\r
-       return 0;\r
-}\r
diff --git a/Kernel/bin/pe.h b/Kernel/bin/pe.h
deleted file mode 100644 (file)
index 4e85cf9..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*\r
-AcessOS/AcessBasic v1\r
-PE Loader\r
-HEADER\r
-*/\r
-#ifndef _EXE_PE_H\r
-#define _EXE_PE_H\r
-\r
-enum ePE_MACHINES {\r
-       PE_MACHINE_I386 = 0x14c,        // Intel 386+\r
-       PE_MACHINE_IA64 = 0x200         // Intel-64\r
-};\r
-\r
-enum ePE_DIR_INDX {\r
-       PE_DIR_EXPORT,          // 0\r
-       PE_DIR_IMPORT,          // 1\r
-       PE_DIR_RESOURCE,        // 2\r
-       PE_DIR_EXCEPTION,       // 3\r
-       PE_DIR_SECRURITY,       // 4\r
-       PE_DIR_RELOC,           // 5\r
-       PE_DIR_DEBUG,           // 6\r
-       PE_DIR_COPYRIGHT,       // 7\r
-       PE_DIR_ARCHITECTURE,// 8\r
-       PE_DIR_GLOBALPTR,       // 9\r
-       PE_DIR_TLS,                     // 10\r
-       PE_DIR_LOAD_CFG,        // 11\r
-       PE_DIR_BOUND_IMPORT,// 12\r
-       PE_DIR_IAT,                     // 13\r
-       PE_DIR_DELAY_IMPORT,// 14\r
-       PE_DIR_COM_DESCRIPTOR,  //15\r
-       PE_DIR_LAST\r
-};\r
-\r
-typedef struct {\r
-       Uint32  RVA;\r
-       Uint32  Size;\r
-} tPE_DATA_DIR;\r
-\r
-typedef struct {\r
-       Uint32  *ImportLookupTable;     //0x80000000 is Ordninal Flag\r
-       Uint32  TimeStamp;\r
-       Uint32  FowarderChain;\r
-       char    *DLLName;\r
-       Uint32  *ImportAddressTable;    // Array of Addresses - To be edited by loader\r
-} tPE_IMPORT_DIR;\r
-\r
-typedef struct {\r
-       Uint16  Hint;\r
-       char    Name[]; // Zero Term String\r
-} tPE_HINT_NAME;\r
-\r
-typedef struct {\r
-       char    Name[8];\r
-       Uint32  VirtualSize;\r
-       Uint32  RVA;\r
-       Uint32  RawSize;\r
-       Uint32  RawOffs;\r
-       Uint32  RelocationsPtr; //Set to 0 in executables\r
-       Uint32  LineNumberPtr;  //Pointer to Line Numbers\r
-       Uint16  RelocationCount;        // Set to 0 in executables\r
-       Uint16  LineNumberCount;\r
-       Uint32  Flags;\r
-} tPE_SECTION_HEADER;\r
-\r
-#define PE_SECTION_FLAG_CODE   0x00000020      // Section contains executable code.\r
-#define PE_SECTION_FLAG_IDATA  0x00000040      // Section contains initialized data.\r
-#define PE_SECTION_FLAG_UDATA  0x00000080      // Section contains uninitialized data.\r
-#define PE_SECTION_FLAG_DISCARDABLE    0x02000000      // Section can be discarded as needed.\r
-#define PE_SECTION_FLAG_MEM_NOT_CACHED 0x04000000      // Section cannot be cached.\r
-#define PE_SECTION_FLAG_MEM_NOT_PAGED  0x08000000      // Section is not pageable.\r
-#define PE_SECTION_FLAG_MEM_SHARED     0x10000000      // Section can be shared in memory.\r
-#define PE_SECTION_FLAG_MEM_EXECUTE    0x20000000      // Section can be executed as code.\r
-#define PE_SECTION_FLAG_MEM_READ       0x40000000      // Section can be read.\r
-#define PE_SECTION_FLAG_MEM_WRITE      0x80000000      // Section can be written to.\r
-\r
-typedef struct {\r
-       Uint32  page;\r
-       Uint32  size;\r
-       Uint16  ents[];\r
-} tPE_FIXUP_BLOCK;\r
-\r
-//File Header\r
-typedef struct {\r
-       Uint16  Machine;\r
-       Uint16  SectionCount;\r
-       Uint32  CreationTimestamp;\r
-       Uint32  SymbolTableOffs;\r
-       Uint32  SymbolCount;\r
-       Uint16  OptHeaderSize;\r
-       Uint16  Flags;\r
-} tPE_FILE_HEADER;\r
-\r
-typedef struct {\r
-       Uint16  Magic;  //0x10b: 32Bit, 0x20b: 64Bit\r
-       Uint16  LinkerVersion;\r
-       Uint32  CodeSize;       //Sum of all Code Segment Sizes\r
-       Uint32  DataSize;       //Sum of all Intialised Data Segments\r
-       Uint32  BssSize;        //Sum of all Unintialised Data Segments\r
-       Uint32  EntryPoint;\r
-       Uint32  CodeRVA;\r
-       Uint32  DataRVA;\r
-       Uint32  ImageBase;      //Prefered Base Address\r
-       Uint32  SectionAlignment;\r
-       Uint32  FileAlignment;\r
-       Uint32  WindowsVersion; //Unused/Irrelevent\r
-       Uint32  ImageVersion;   //Unused/Irrelevent\r
-       Uint32  SubsystemVersion;       //Unused, Set to 4\r
-       Uint32  Win32Version;   //Unused\r
-       Uint32  ImageSize;\r
-       Uint32  HeaderSize;\r
-       Uint32  Checksum;       //Unknown Method, Can be set to 0\r
-       Uint16  Subsystem;      //Required Windows Subsystem (None, GUI, Console)\r
-       Uint16  DllFlags;\r
-       Uint32  MaxStackSize;           //Reserved Stack Size\r
-       Uint32  InitialStackSize;       //Commited Stack Size\r
-       Uint32  InitialReservedHeap;    // Reserved Heap Size\r
-       Uint32  InitialCommitedHeap;    // Commited Heap Size\r
-       Uint32  LoaderFlags;    // Obselete\r
-       Uint32  NumberOfDirEntries;\r
-       tPE_DATA_DIR    Directory[16];\r
-} tPE_OPT_HEADER;\r
-\r
-// Root Header\r
-typedef struct {\r
-       Uint32  Signature;\r
-       tPE_FILE_HEADER FileHeader;\r
-       tPE_OPT_HEADER  OptHeader;\r
-} tPE_IMAGE_HEADERS;\r
-\r
-typedef struct {\r
-       Uint16  Ident;\r
-       Uint16  Resvd[29];\r
-       Uint32  PeHdrOffs;              // File address of new exe header\r
-} tPE_DOS_HEADER;\r
-\r
-#endif\r
diff --git a/Kernel/binary.c b/Kernel/binary.c
deleted file mode 100644 (file)
index 5213bf2..0000000
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * Acess2
- * Common Binary Loader
- */
-#define DEBUG  0
-#include <acess.h>
-#include <binary.h>
-#include <mm_virt.h>
-#include <hal_proc.h>
-#include <vfs_threads.h>
-
-// === CONSTANTS ===
-#define BIN_LOWEST     MM_USER_MIN             // 1MiB
-#define BIN_GRANUALITY 0x10000         // 64KiB
-#define BIN_HIGHEST    (USER_LIB_MAX-BIN_GRANUALITY)           // Just below the kernel
-#define        KLIB_LOWEST     MM_MODULE_MIN
-#define KLIB_GRANUALITY        0x10000         // 32KiB
-#define        KLIB_HIGHEST    (MM_MODULE_MAX-KLIB_GRANUALITY)
-
-// === TYPES ===
-typedef struct sKernelBin {
-       struct sKernelBin       *Next;
-       void    *Base;
-       tBinary *Info;
-} tKernelBin;
-
-// === IMPORTS ===
-extern char    *Threads_GetName(int ID);
-extern tKernelSymbol   gKernelSymbols[];
-extern tKernelSymbol   gKernelSymbolsEnd[];
-extern tBinaryType     gELF_Info;
-
-// === PROTOTYPES ===
- int   Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
-tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
-tBinary        *Binary_GetInfo(tMount MountID, tInode InodeID);
-tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
-tVAddr Binary_IsMapped(tBinary *Binary);
-tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
-void   Binary_Dereference(tBinary *Info);
-#if 0
-Uint   Binary_Relocate(void *Base);
-#endif
-Uint   Binary_GetSymbolEx(const char *Name, Uint *Value);
-#if 0
-Uint   Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
-#endif
- int   Binary_int_CheckMemFree( tVAddr _start, size_t _len );
-
-// === GLOBALS ===
-tShortSpinlock glBinListLock;
-tBinary        *glLoadedBinaries = NULL;
-char   **gsaRegInterps = NULL;
- int   giRegInterps = 0;
-tShortSpinlock glKBinListLock;
-tKernelBin     *glLoadedKernelLibs;
-tBinaryType    *gRegBinTypes = &gELF_Info;
-// === FUNCTIONS ===
-/**
- * \brief Registers a binary type
- */
-int Binary_RegisterType(tBinaryType *Type)
-{
-       Type->Next = gRegBinTypes;
-       gRegBinTypes = Type;
-       return 1;
-}
-
-/**
- * \fn int Proc_Spawn(const char *Path)
- */
-int Proc_Spawn(const char *Path)
-{
-       char    stackPath[strlen(Path)+1];
-       ENTER("sPath", Path);
-       
-       strcpy(stackPath, Path);
-       
-       LOG("stackPath = '%s'", stackPath);
-       
-       if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
-       {
-               // CHILD
-               const char      *args[2] = {stackPath, NULL};
-               LOG("stackPath = '%s'", stackPath);
-               Proc_Execve(stackPath, args, &args[1], 0);
-               for(;;);
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \todo Document
- */
-int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
-{
-        int    size, argc=0, envc=0;
-        int    i;
-       char    *strbuf;
-       const char      **arrays;
-       
-       // Calculate size
-       size = 0;
-       if( ArgV && *ArgV )
-       {
-               const char      **argv = *ArgV;
-               for( argc = 0; argv[argc]; argc ++ )
-                       size += strlen( argv[argc] ) + 1;
-       }
-       if( EnvP && *EnvP )
-       {
-               const char      **envp = *EnvP;
-               for( envc = 0; envp[envc]; envc ++ )
-                       size += strlen( envp[envc] ) + 1;
-       }
-       size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1);   // Word align
-       size += (argc+1+envc+1)*sizeof(void*);  // Arrays
-       if( Path )
-       {
-               size += strlen( *Path ) + 1;
-       }
-
-       if( DestBuffer )        
-       {
-               arrays = DestBuffer;
-               strbuf = (void*)&arrays[argc+1+envc+1];
-       
-               // Fill ArgV
-               if( ArgV && *ArgV )
-               {
-                       const char      **argv = *ArgV;
-                       for( i = 0; argv[i]; i ++ )
-                       {
-                               arrays[i] = strbuf;
-                               strcpy(strbuf, argv[i]);
-                               strbuf += strlen( argv[i] ) + 1;
-                       }
-                       *ArgV = arrays;
-                       arrays += i;
-               }
-               *arrays++ = NULL;
-               // Fill EnvP
-               if( EnvP && *EnvP )
-               {
-                       const char      **envp = *EnvP;
-                       for( i = 0; envp[i]; i ++ )
-                       {
-                               arrays[i] = strbuf;
-                               strcpy(strbuf, envp[i]);
-                               strbuf += strlen( envp[i] ) + 1;
-                       }
-                       *EnvP = arrays;
-                       arrays += i;
-               }
-               *arrays++ = NULL;
-               // Fill path
-               if( Path )
-               {
-                       strcpy(strbuf, *Path);
-                       *Path = strbuf;
-               }
-       }
-       
-       return size;
-}
-
-/**
- * \brief Create a new process with the specified set of file descriptors
- */
-int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
-{
-       void    *handles;
-       void    *cachebuf;
-        int    size;
-       tPID    ret;
-       
-       // --- Save File, ArgV and EnvP
-       size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
-       cachebuf = malloc( size );
-       Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
-
-       // Cache the VFS handles        
-       handles = VFS_SaveHandles(nFD, FDs);
-
-       // Create new process   
-       ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
-       if( ret == 0 )
-       {
-               VFS_RestoreHandles(nFD, handles);
-               VFS_FreeSavedHandles(nFD, handles);
-               // Frees cachebuf
-               Proc_Execve(Binary, ArgV, EnvP, size);
-               for(;;);
-       }
-       if( ret < 0 )
-       {
-               VFS_FreeSavedHandles(nFD, handles);
-       }
-       
-       return ret;
-}
-
-/**
- * \brief Replace the current user image with another
- * \param File File to load as the next image
- * \param ArgV Arguments to pass to user
- * \param EnvP User's environment
- * \note Called Proc_ for historical reasons
- */
-int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
-{
-       void    *cachebuf;
-       tVAddr  entry;
-       Uint    base;   // Uint because Proc_StartUser wants it
-        int    argc;
-       
-       ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
-       
-       // --- Save File, ArgV and EnvP
-       if( DataSize == 0 )
-       {
-               DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
-               cachebuf = malloc( DataSize );
-               Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
-       }
-
-       // --- Get argc 
-       for( argc = 0; ArgV && ArgV[argc]; argc ++ );
-       
-       // --- Set Process Name
-       Threads_SetName(File);
-       
-       // --- Clear User Address space
-       // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
-       //       PPD area would be a better idea.
-       {
-                int    nfd = *Threads_GetMaxFD();
-               void    *handles;
-               handles = VFS_SaveHandles(nfd, NULL);
-               VFS_CloseAllUserHandles();
-               MM_ClearUser();
-               VFS_RestoreHandles(nfd, handles);
-               VFS_FreeSavedHandles(nfd, handles);
-       }
-       
-       // --- Load new binary
-       base = Binary_Load(File, &entry);
-       if(base == 0)
-       {
-               Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
-               LEAVE('-');
-               Threads_Exit(0, -10);
-               for(;;);
-       }
-       
-       LOG("entry = 0x%x, base = 0x%x", entry, base);
-       LEAVE('-');
-       // --- And... Jump to it
-       Proc_StartUser(entry, base, argc, ArgV, DataSize);
-       for(;;);        // Tell GCC that we never return
-}
-
-/**
- * \brief Load a binary into the current address space
- * \param Path Path to binary to load
- * \param EntryPoint   Pointer for exectuable entry point
- * \return Virtual address where the binary has been loaded
- */
-tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
-{
-       tMount  mount_id;
-       tInode  inode;
-       tBinary *pBinary;
-       tVAddr  base = -1;
-
-       ENTER("sPath pEntryPoint", Path, EntryPoint);
-       
-       // Sanity Check Argument
-       if(Path == NULL) {
-               LEAVE('x', 0);
-               return 0;
-       }
-
-       // Check if this path has been loaded before.
-       #if 0
-       // TODO: Implement a list of string/tBinary pairs for loaded bins
-       #endif
-
-       // Get Inode
-       {
-               int fd;
-               tFInfo  info;
-               fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
-               if( fd == -1 ) {
-                       LOG("%s does not exist", Path);
-                       LEAVE_RET('x', 0);
-               }
-               VFS_FInfo(fd, &info, 0);
-               VFS_Close(fd);
-               mount_id = info.mount;
-               inode = info.inode;
-               LOG("mount_id = %i, inode = %i", mount_id, inode);
-       }
-
-       // TODO: Also get modifcation time?
-
-       // Check if the binary has already been loaded
-       if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
-               pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
-       
-       // Error Check
-       if(pBinary == NULL) {
-               LEAVE('x', 0);
-               return 0;
-       }
-       
-       // Map into process space
-       base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
-       
-       // Check for errors
-       if(base == 0) {
-               LEAVE('x', 0);
-               return 0;
-       }
-       
-       // Interpret
-       if(pBinary->Interpreter) {
-               tVAddr  start;
-               if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
-                       LEAVE('x', 0);
-                       return 0;
-               }
-               *EntryPoint = start;
-       }
-       else
-               *EntryPoint = pBinary->Entry - pBinary->Base + base;
-       
-       // Return
-       LOG("*EntryPoint = 0x%x", *EntryPoint);
-       LEAVE('x', base);
-       return base;    // Pass the base as an argument to the user if there is an interpreter
-}
-
-/**
- * \brief Finds a matching binary entry
- * \param MountID      Mountpoint ID of binary file
- * \param InodeID      Inode ID of the file
- * \return Pointer to the binary definition (if already loaded)
- */
-tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
-{
-       tBinary *pBinary;
-       for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
-       {
-               if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
-                       return pBinary;
-       }
-       return NULL;
-}
-
-/**
- * \brief Maps an already-loaded binary into an address space.
- * \param Binary       Pointer to globally stored binary definition
- * \param Path Path to the binary's file (for debug)
- * \param LoadMin      Lowest location to map to
- * \param LoadMax      Highest location to map to
- * \return Base load address
- */
-tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
-{
-       tVAddr  base;
-        int    i, fd;
-
-       ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
-
-       // Reference Executable (Makes sure that it isn't unloaded)
-       Binary->ReferenceCount ++;
-       
-       // Get Binary Base
-       base = Binary->Base;
-       
-       // Check if base is free
-       if(base != 0)
-       {
-               LOG("Checking base %p", base);
-               for( i = 0; i < Binary->NumSections; i ++ )
-               {
-                       if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
-                       {
-                               base = 0;
-                               LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
-                               break;
-                       }
-               }
-       }
-       
-       // Check if the executable has no base or it is not free
-       if(base == 0)
-       {
-               // If so, give it a base
-               base = LoadMax;
-               while(base >= LoadMin)
-               {
-                       for( i = 0; i < Binary->NumSections; i ++ )
-                       {
-                               tVAddr  addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
-                               if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) )
-                                       break;
-                       }
-                       // If space was found, break
-                       if(i == Binary->NumSections)            break;
-                       // Else decrement pointer and try again
-                       base -= BIN_GRANUALITY;
-               }
-               LOG("Allocated base %p", base);
-       }
-       
-       // Error Check
-       if(base < LoadMin) {
-               Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Map Executable In
-       fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
-       for( i = 0; i < Binary->NumSections; i ++ )
-       {
-               tBinarySection  *sect = &Binary->LoadSections[i];
-               Uint    protflags, mapflags;
-               tVAddr  addr = sect->Virtual - Binary->Base + base;
-               LOG("%i - %p to offset 0x%llx (%x)", i, addr, sect->Offset, sect->Flags);
-
-               protflags = MMAP_PROT_READ;
-               mapflags = MMAP_MAP_FIXED;
-
-               if( sect->Flags & BIN_SECTFLAG_EXEC )
-                       protflags |= MMAP_PROT_EXEC;
-               // Read only pages are COW
-               if( sect->Flags & BIN_SECTFLAG_RO  ) {
-                       VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
-               }
-               else {
-                       protflags |= MMAP_PROT_WRITE;
-                       VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
-               }
-               
-               // Apply anonymous memory for BSS
-               if( sect->FileSize < sect->MemSize ) {
-                       mapflags |= MMAP_MAP_ANONYMOUS;
-                       VFS_MMap(
-                               (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
-                               protflags, MMAP_MAP_PRIVATE|mapflags,
-                               0, 0
-                               );
-               }
-       }
-       
-       Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
-       VFS_Close(fd);
-       
-       LEAVE('p', base);
-       return base;
-}
-
-#if 0
-/**
- * \fn Uint Binary_IsMapped(tBinary *binary)
- * \brief Check if a binary is already mapped into the address space
- * \param binary       Binary information to check
- * \return Current Base or 0
- */
-Uint Binary_IsMapped(tBinary *binary)
-{
-       Uint    iBase;
-       
-       // Check prefered base
-       iBase = binary->Base;
-       if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
-               return iBase;
-       
-       for(iBase = BIN_HIGHEST;
-               iBase >= BIN_LOWEST;
-               iBase -= BIN_GRANUALITY)
-       {
-               if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
-                       return iBase;
-       }
-       
-       return 0;
-}
-#endif
-
-/**
- * \fn tBinary *Binary_DoLoad(char *truePath)
- * \brief Loads a binary file into memory
- * \param truePath     Absolute filename of binary
- */
-tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
-{
-       tBinary *pBinary;
-        int    fp;
-       Uint32  ident;
-       tBinaryType     *bt = gRegBinTypes;
-       
-       ENTER("iMountID XInode sPath", MountID, Inode, Path);
-       
-       // Open File
-       fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
-       if(fp == -1) {
-               LOG("Unable to load file, access denied");
-               LEAVE('n');
-               return NULL;
-       }
-
-       LOG("fp = 0x%x", fp);
-       
-       // Read File Type
-       VFS_Read(fp, 4, &ident);
-       VFS_Seek(fp, 0, SEEK_SET);
-
-       LOG("ident = 0x%x", ident);
-
-       // Determine the type   
-       for(; bt; bt = bt->Next)
-       {
-               if( (ident & bt->Mask) != (Uint32)bt->Ident )
-                       continue;
-               LOG("bt = %p (%s)", bt, bt->Name);
-               pBinary = bt->Load(fp);
-               break;
-       }
-
-       // Close File
-       VFS_Close(fp);
-       
-       // Catch errors
-       if(!bt) {
-               Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
-                       Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
-               LEAVE('n');
-               return NULL;
-       }
-       
-       LOG("pBinary = %p", pBinary);
-       
-       // Error Check
-       if(pBinary == NULL) {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Initialise Structure
-       pBinary->ReferenceCount = 0;
-       pBinary->MountID = MountID;
-       pBinary->Inode = Inode;
-       
-       // Debug Information
-       LOG("Interpreter: '%s'", pBinary->Interpreter);
-       LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
-       LOG("NumSections: %i", pBinary->NumSections);
-       
-       // Add to the list
-       SHORTLOCK(&glBinListLock);
-       pBinary->Next = glLoadedBinaries;
-       glLoadedBinaries = pBinary;
-       SHORTREL(&glBinListLock);
-
-       // TODO: Register the path with the binary      
-
-       // Return
-       LEAVE('p', pBinary);
-       return pBinary;
-}
-
-/**
- * \fn void Binary_Unload(void *Base)
- * \brief Unload / Unmap a binary
- * \param Base Loaded Base
- * \note Currently used only for kernel libaries
- */
-void Binary_Unload(void *Base)
-{
-       tKernelBin      *pKBin;
-       tKernelBin      *prev = NULL;
-        int    i;
-       
-       if((Uint)Base < 0xC0000000)
-       {
-               // TODO: User Binaries
-               Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
-               return;
-       }
-       
-       // Kernel Libraries
-       for(pKBin = glLoadedKernelLibs;
-               pKBin;
-               prev = pKBin, pKBin = pKBin->Next)
-       {
-               // Check the base
-               if(pKBin->Base != Base) continue;
-               // Deallocate Memory
-               for(i = 0; i < pKBin->Info->NumSections; i++)
-               {
-                       // TODO: VFS_MUnmap();
-               }
-               // Dereference Binary
-               Binary_Dereference( pKBin->Info );
-               // Remove from list
-               if(prev)        prev->Next = pKBin->Next;
-               else            glLoadedKernelLibs = pKBin->Next;
-               // Free Kernel Lib
-               free(pKBin);
-               return;
-       }
-}
-
-/**
- * \fn void Binary_Dereference(tBinary *Info)
- * \brief Dereferences and if nessasary, deletes a binary
- * \param Info Binary information structure
- */
-void Binary_Dereference(tBinary *Info)
-{
-       // Decrement reference count
-       Info->ReferenceCount --;
-       
-       // Check if it is still in use
-       if(Info->ReferenceCount)        return;
-       
-       /// \todo Implement binary freeing
-}
-
-/**
- * \fn char *Binary_RegInterp(char *Path)
- * \brief Registers an Interpreter
- * \param Path Path to interpreter provided by executable
- */
-char *Binary_RegInterp(char *Path)
-{
-        int    i;
-       // NULL Check Argument
-       if(Path == NULL)        return NULL;
-       // NULL Check the array
-       if(gsaRegInterps == NULL)
-       {
-               giRegInterps = 1;
-               gsaRegInterps = malloc( sizeof(char*) );
-               gsaRegInterps[0] = malloc( strlen(Path) );
-               strcpy(gsaRegInterps[0], Path);
-               return gsaRegInterps[0];
-       }
-       
-       // Scan Array
-       for( i = 0; i < giRegInterps; i++ )
-       {
-               if(strcmp(gsaRegInterps[i], Path) == 0)
-                       return gsaRegInterps[i];
-       }
-       
-       // Interpreter is not in list
-       giRegInterps ++;
-       gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
-       gsaRegInterps[i] = malloc( strlen(Path) );
-       strcpy(gsaRegInterps[i], Path);
-       return gsaRegInterps[i];
-}
-
-// ============
-// Kernel Binary Handling
-// ============
-/**
- * \fn void *Binary_LoadKernel(const char *File)
- * \brief Load a binary into kernel space
- * \note This function shares much with #Binary_Load, but does it's own mapping
- * \param File File to load into the kernel
- */
-void *Binary_LoadKernel(const char *File)
-{
-       tBinary *pBinary;
-       tKernelBin      *pKBinary;
-       tVAddr  base = -1;
-       tMount  mount_id;
-       tInode  inode;
-
-       ENTER("sFile", File);
-       
-       // Sanity Check Argument
-       if(File == NULL) {
-               LEAVE('n');
-               return 0;
-       }
-
-       {
-               int fd = VFS_Open(File, VFS_OPENFLAG_READ);
-               tFInfo  info;
-               if(fd == -1) {
-                       LEAVE('n');
-                       return NULL;
-               }
-               VFS_FInfo(fd, &info, 0);
-               mount_id = info.mount;
-               inode = info.inode;
-               VFS_Close(fd);
-       }
-       
-       // Check if the binary has already been loaded
-       if( (pBinary = Binary_GetInfo(mount_id, inode)) )
-       {
-               for(pKBinary = glLoadedKernelLibs;
-                       pKBinary;
-                       pKBinary = pKBinary->Next )
-               {
-                       if(pKBinary->Info == pBinary) {
-                               LEAVE('p', pKBinary->Base);
-                               return pKBinary->Base;
-                       }
-               }
-       }
-       else
-               pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
-       
-       // Error Check
-       if(pBinary == NULL) {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // --------------
-       // Now pBinary is valid (either freshly loaded or only user mapped)
-       // So, map it into kernel space
-       // --------------
-       
-       // Reference Executable (Makes sure that it isn't unloaded)
-       pBinary->ReferenceCount ++;
-
-       Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
-
-       // Relocate Library
-       if( !Binary_Relocate( (void*)base ) )
-       {
-               Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
-               Binary_Unload( (void*)base );
-               Binary_Dereference( pBinary );
-               LEAVE('n');
-               return 0;
-       }
-       
-       // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
-       pKBinary = malloc(sizeof(*pKBinary));
-       pKBinary->Base = (void*)base;
-       pKBinary->Info = pBinary;
-       SHORTLOCK( &glKBinListLock );
-       pKBinary->Next = glLoadedKernelLibs;
-       glLoadedKernelLibs = pKBinary;
-       SHORTREL( &glKBinListLock );
-       
-       LEAVE('p', base);
-       return (void*)base;
-}
-
-/**
- * \fn Uint Binary_Relocate(void *Base)
- * \brief Relocates a loaded binary (used by kernel libraries)
- * \param Base Loaded base address of binary
- * \return Boolean Success
- */
-Uint Binary_Relocate(void *Base)
-{
-       Uint32  ident = *(Uint32*) Base;
-       tBinaryType     *bt = gRegBinTypes;
-       
-       for(; bt; bt = bt->Next)
-       {
-               if( (ident & bt->Mask) == (Uint)bt->Ident )
-                       return bt->Relocate( (void*)Base);
-       }
-       
-       Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
-               Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
-       return 0;
-}
-
-/**
- * \fn int Binary_GetSymbol(char *Name, Uint *Val)
- * \brief Get a symbol value
- * \return Value of symbol or -1 on error
- * 
- * Gets the value of a symbol from either the currently loaded
- * libraries or the kernel's exports.
- */
-int Binary_GetSymbol(const char *Name, Uint *Val)
-{
-       if( Binary_GetSymbolEx(Name, Val) )     return 1;
-       return 0;
-}
-
-/**
- * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
- * \brief Get a symbol value
- * 
- * Gets the value of a symbol from either the currently loaded
- * libraries or the kernel's exports.
- */
-Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
-{
-        int    i;
-       tKernelBin      *pKBin;
-        int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
-       
-       // Scan Kernel
-       for( i = 0; i < numKSyms; i++ )
-       {
-               if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
-                       *Value = gKernelSymbols[i].Value;
-                       return 1;
-               }
-       }
-       
-       // Scan Loaded Libraries
-       for(pKBin = glLoadedKernelLibs;
-               pKBin;
-               pKBin = pKBin->Next )
-       {
-               if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
-                       return 1;
-               }
-       }
-       
-       Log_Warning("BIN", "Unable to find symbol '%s'", Name);
-       return 0;
-}
-
-/**
- * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
- * \brief Get a symbol from the specified library
- * \param Base Base address
- * \param Name Name of symbol to find
- * \param Val  Pointer to place final value
- */
-Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
-{
-       Uint32  ident = *(Uint32*) Base;
-       tBinaryType     *bt = gRegBinTypes;
-       
-       for(; bt; bt = bt->Next)
-       {
-               if( (ident & bt->Mask) == (Uint)bt->Ident )
-                       return bt->GetSymbol(Base, Name, Val);
-       }
-       
-       Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
-               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
-       return 0;
-}
-
-/**
- * \brief Check if a range of memory is fully free
- * \return Inverse boolean free (0 if all pages are unmapped)
- */
-int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
-{
-       _len += _start & (PAGE_SIZE-1);
-       _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
-       _start &= ~(PAGE_SIZE-1);
-       for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
-               if( MM_GetPhysAddr(_start) != 0 )
-                       return 1;
-       }
-       if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 )
-               return 1;
-       return 0;
-}
-
-
-// === EXPORTS ===
-EXPORT(Binary_FindSymbol);
-EXPORT(Binary_Unload);
diff --git a/Kernel/debug.c b/Kernel/debug.c
deleted file mode 100644 (file)
index 355624d..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * debug.c
- * 
- * TODO: Move the Debug_putchar methods out to the arch/ tree
- */
-#include <acess.h>
-#include <stdarg.h>
-
-#define        DEBUG_MAX_LINE_LEN      256
-
-#define        LOCK_DEBUG_OUTPUT       1
-
-#define TRACE_TO_KTERM 0
-
-// === IMPORTS ===
-extern void    Threads_Dump(void);
-extern void    KernelPanic_SetMode(void);
-extern void    KernelPanic_PutChar(char Ch);
-
-// === PROTOTYPES ===
-static void    Debug_Putchar(char ch);
-static void    Debug_Puts(int bUseKTerm, const char *Str);
-void   Debug_DbgOnlyFmt(const char *format, va_list args);
-void   Debug_FmtS(int bUseKTerm, const char *format, ...);
-void   Debug_Fmt(int bUseKTerm, const char *format, va_list args);
-void   Debug_SetKTerminal(const char *File);
-
-// === GLOBALS ===
- int   gDebug_Level = 0;
- int   giDebug_KTerm = -1;
- int   gbDebug_IsKPanic = 0;
-volatile int   gbInPutChar = 0;
-#if LOCK_DEBUG_OUTPUT
-tShortSpinlock glDebug_Lock;
-#endif
-
-// === CODE ===
-static void Debug_Putchar(char ch)
-{
-       Debug_PutCharDebug(ch);
-       if( !gbDebug_IsKPanic )
-       {
-               if(gbInPutChar) return ;
-               gbInPutChar = 1;
-               if(giDebug_KTerm != -1)
-                       VFS_Write(giDebug_KTerm, 1, &ch);
-               gbInPutChar = 0;
-       }
-       else
-               KernelPanic_PutChar(ch);
-}
-
-static void Debug_Puts(int UseKTerm, const char *Str)
-{
-        int    len = 0;
-       
-       Debug_PutStringDebug(Str);
-       
-       if( gbDebug_IsKPanic )
-       {               
-               for( len = 0; Str[len]; len ++ )
-                       KernelPanic_PutChar( Str[len] );
-       }
-       else
-               for( len = 0; Str[len]; len ++ );
-       
-       // Output to the kernel terminal
-       if( UseKTerm && !gbDebug_IsKPanic && giDebug_KTerm != -1)
-       {
-               if(gbInPutChar) return ;
-               gbInPutChar = 1;
-               VFS_Write(giDebug_KTerm, len, Str);
-               gbInPutChar = 0;
-       }
-}
-
-void Debug_DbgOnlyFmt(const char *format, va_list args)
-{
-       Debug_Fmt(0, format, args);
-}
-
-void Debug_Fmt(int bUseKTerm, const char *format, va_list args)
-{
-       char    buf[DEBUG_MAX_LINE_LEN];
-        int    len;
-       buf[DEBUG_MAX_LINE_LEN-1] = 0;
-       len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
-       //if( len < DEBUG_MAX_LINE )
-               // do something
-       Debug_Puts(bUseKTerm, buf);
-       return ;
-}
-
-void Debug_FmtS(int bUseKTerm, const char *format, ...)
-{
-       va_list args;   
-       va_start(args, format);
-       Debug_Fmt(bUseKTerm, format, args);
-       va_end(args);
-}
-
-void Debug_KernelPanic(void)
-{
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-       gbDebug_IsKPanic = 1;
-       KernelPanic_SetMode();
-}
-
-/**
- * \fn void LogF(const char *Msg, ...)
- * \brief Raw debug log (no new line, no prefix)
- */
-void LogF(const char *Fmt, ...)
-{
-       va_list args;
-
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-       
-       va_start(args, Fmt);
-
-       Debug_Fmt(1, Fmt, args);
-
-       va_end(args);
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-/**
- * \fn void Debug(const char *Msg, ...)
- * \brief Print only to the debug channel (not KTerm)
- */
-void Debug(const char *Fmt, ...)
-{
-       va_list args;
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-
-       Debug_Puts(0, "Debug: ");
-       va_start(args, Fmt);
-       Debug_DbgOnlyFmt(Fmt, args);
-       va_end(args);
-       Debug_PutCharDebug('\r');
-       Debug_PutCharDebug('\n');
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-/**
- * \fn void Log(const char *Msg, ...)
- */
-void Log(const char *Fmt, ...)
-{
-       va_list args;
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-
-       Debug_Puts(1, "Log: ");
-       va_start(args, Fmt);
-       Debug_Fmt(1, Fmt, args);
-       va_end(args);
-       Debug_Puts(1, "\r\n");
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-void Warning(const char *Fmt, ...)
-{
-       va_list args;
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-       
-       Debug_Puts(1, "Warning: ");
-       va_start(args, Fmt);
-       Debug_Fmt(1, Fmt, args);
-       va_end(args);
-       Debug_Putchar('\r');
-       Debug_Putchar('\n');
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-void Panic(const char *Fmt, ...)
-{
-       va_list args;
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-       // And never SHORTREL
-       
-       Debug_KernelPanic();
-       
-       Debug_Puts(1, "Panic: ");
-       va_start(args, Fmt);
-       Debug_Fmt(1, Fmt, args);
-       va_end(args);
-       Debug_Putchar('\r');
-       Debug_Putchar('\n');
-
-       Threads_Dump();
-
-       for(;;) ;
-}
-
-void Debug_SetKTerminal(const char *File)
-{
-        int    tmp;
-       if(giDebug_KTerm != -1) {
-               tmp = giDebug_KTerm;
-               giDebug_KTerm = -1;
-               VFS_Close(tmp);
-       }
-       tmp = VFS_Open(File, VFS_OPENFLAG_WRITE);
-//     Log_Log("Debug", "Opened '%s' as 0x%x", File, tmp);
-       giDebug_KTerm = tmp;
-//     Log_Log("Debug", "Returning to %p", __builtin_return_address(0));
-}
-
-void Debug_Enter(const char *FuncName, const char *ArgTypes, ...)
-{
-       va_list args;
-        int    i;
-        int    pos;
-       tTID    tid = Threads_GetTID();
-        
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-
-       i = gDebug_Level ++;
-
-       va_start(args, ArgTypes);
-
-       Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
-       while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
-
-       Debug_Puts(TRACE_TO_KTERM, FuncName);
-       Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
-       Debug_Puts(TRACE_TO_KTERM, ": (");
-
-       while(*ArgTypes)
-       {
-               pos = strpos(ArgTypes, ' ');
-               if(pos == -1 || pos > 1) {
-                       if(pos == -1)
-                               Debug_Puts(TRACE_TO_KTERM, ArgTypes+1);
-                       else {
-                               Debug_FmtS(TRACE_TO_KTERM, "%.*s", pos-1, ArgTypes+1);
-                       }
-                       Debug_Puts(TRACE_TO_KTERM, "=");
-               }
-               switch(*ArgTypes)
-               {
-               case 'p':       Debug_FmtS(TRACE_TO_KTERM, "%p", va_arg(args, void*));  break;
-               case 'P':       Debug_FmtS(TRACE_TO_KTERM, "%P", va_arg(args, tPAddr)); break;
-               case 's':       Debug_FmtS(TRACE_TO_KTERM, "'%s'", va_arg(args, char*));        break;
-               case 'i':       Debug_FmtS(TRACE_TO_KTERM, "%i", va_arg(args, int));    break;
-               case 'u':       Debug_FmtS(TRACE_TO_KTERM, "%u", va_arg(args, Uint));   break;
-               case 'x':       Debug_FmtS(TRACE_TO_KTERM, "0x%x", va_arg(args, Uint)); break;
-               case 'b':       Debug_FmtS(TRACE_TO_KTERM, "0b%b", va_arg(args, Uint)); break;
-               case 'X':       Debug_FmtS(TRACE_TO_KTERM, "0x%llx", va_arg(args, Uint64));     break;  // Extended (64-Bit)
-               case 'B':       Debug_FmtS(TRACE_TO_KTERM, "0b%llb", va_arg(args, Uint64));     break;  // Extended (64-Bit)
-               }
-               if(pos != -1) {
-                       Debug_Puts(TRACE_TO_KTERM, ", ");
-               }
-
-               if(pos == -1)   break;
-               ArgTypes = &ArgTypes[pos+1];
-       }
-
-       va_end(args);
-       Debug_Puts(TRACE_TO_KTERM, ")\r\n");
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-
-void Debug_Log(const char *FuncName, const char *Fmt, ...)
-{
-       va_list args;
-        int    i = gDebug_Level;
-       tTID    tid = Threads_GetTID();
-
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-
-       Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
-       while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
-
-       Debug_Puts(TRACE_TO_KTERM, FuncName);
-       Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
-       Debug_Puts(TRACE_TO_KTERM, ": ");
-
-       va_start(args, Fmt);
-       Debug_Fmt(TRACE_TO_KTERM, Fmt, args);
-       va_end(args);
-
-       Debug_Puts(TRACE_TO_KTERM, "\r\n");
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-
-void Debug_Leave(const char *FuncName, char RetType, ...)
-{
-       va_list args;
-        int    i;
-       tTID    tid = Threads_GetTID();
-
-       #if LOCK_DEBUG_OUTPUT
-       SHORTLOCK(&glDebug_Lock);
-       #endif
-       
-       i = --gDebug_Level;
-
-       va_start(args, RetType);
-
-       if( i == -1 ) {
-               gDebug_Level = 0;
-               i = 0;
-       }
-       Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
-       // Indenting
-       while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
-
-       Debug_Puts(TRACE_TO_KTERM, FuncName);
-       Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
-       Debug_Puts(TRACE_TO_KTERM, ": RETURN");
-
-       // No Return
-       if(RetType == '-') {
-               Debug_Puts(TRACE_TO_KTERM, "\r\n");
-               #if LOCK_DEBUG_OUTPUT
-               SHORTREL(&glDebug_Lock);
-               #endif
-               return;
-       }
-
-       switch(RetType)
-       {
-       case 'n':       Debug_Puts(TRACE_TO_KTERM, " NULL");    break;
-       case 'p':       Debug_Fmt(TRACE_TO_KTERM, " %p", args); break;
-       case 'P':       Debug_Fmt(TRACE_TO_KTERM, " %P", args); break;  // PAddr
-       case 's':       Debug_Fmt(TRACE_TO_KTERM, " '%s'", args);       break;
-       case 'i':       Debug_Fmt(TRACE_TO_KTERM, " %i", args); break;
-       case 'u':       Debug_Fmt(TRACE_TO_KTERM, " %u", args); break;
-       case 'x':       Debug_Fmt(TRACE_TO_KTERM, " 0x%x", args);       break;
-       // Extended (64-Bit)
-       case 'X':       Debug_Fmt(TRACE_TO_KTERM, " 0x%llx", args);     break;
-       }
-       Debug_Puts(TRACE_TO_KTERM, "\r\n");
-
-       va_end(args);
-       
-       #if LOCK_DEBUG_OUTPUT
-       SHORTREL(&glDebug_Lock);
-       #endif
-}
-
-void Debug_HexDump(const char *Header, const void *Data, Uint Length)
-{
-       const Uint8     *cdat = Data;
-       Uint    pos = 0;
-       LogF("%014lli ", now());
-       Debug_Puts(1, Header);
-       LogF(" (Hexdump of %p)\r\n", Data);
-
-       #define CH(n)   ((' '<=cdat[(n)]&&cdat[(n)]<0x7F) ? cdat[(n)] : '.')
-
-       while(Length >= 16)
-       {
-               LogF("%014lli Log: %04x:"
-                       " %02x %02x %02x %02x %02x %02x %02x %02x"
-                       " %02x %02x %02x %02x %02x %02x %02x %02x"
-                       "  %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\r\n",
-                       now(),
-                       pos,
-                       cdat[ 0], cdat[ 1], cdat[ 2], cdat[ 3], cdat[ 4], cdat[ 5], cdat[ 6], cdat[ 7],
-                       cdat[ 8], cdat[ 9], cdat[10], cdat[11], cdat[12], cdat[13], cdat[14], cdat[15],
-                       CH(0),  CH(1),  CH(2),  CH(3),  CH(4),  CH(5),  CH(6),  CH(7),
-                       CH(8),  CH(9),  CH(10), CH(11), CH(12), CH(13), CH(14), CH(15)
-                       );
-               Length -= 16;
-               cdat += 16;
-               pos += 16;
-       }
-
-       {
-                int    i ;
-               LogF("%014lli Log: %04x: ", now(), pos);
-               for(i = 0; i < Length; i ++)
-               {
-                       LogF("%02x ", cdat[i]);
-               }
-               for( ; i < 16; i ++)    LogF("   ");
-               LogF(" ");
-               for(i = 0; i < Length; i ++)
-               {
-                       if( i == 8 )    LogF(" ");
-                       LogF("%c", CH(i));
-               }
-       
-               Debug_Putchar('\r');
-               Debug_Putchar('\n');
-       }
-}
-
-// --- EXPORTS ---
-EXPORT(Debug);
-EXPORT(Log);
-EXPORT(Warning);
-EXPORT(Debug_Enter);
-EXPORT(Debug_Log);
-EXPORT(Debug_Leave);
diff --git a/Kernel/drv/Makefile b/Kernel/drv/Makefile
deleted file mode 100644 (file)
index 44f17cd..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# Acess2 Module/Driver Templater Makefile
-# Makefile.tpl
-
--include ../../Makefile.cfg
-
-CPPFLAGS = -I../include -I../arch/$(ARCHDIR)/include -DARCH=$(ARCH) -DBUILD_MODULE
-CFLAGS = -Wall -Werror $(CPPFLAGS)
-
-.PHONY: all clean
-
-all: bochsvbe.kmd
-
-%.kmd: %.o
-       $(CC) -shared -nostdlib -o $@ $<
-
-%.o: %.c
-       $(CC) $(CFLAGS) -o $@ -c $<
-
-#ata_x86.kmd: ata_x86.o
-#bochsvbe.kmd: bochsvbe.o
diff --git a/Kernel/drv/fifo.c b/Kernel/drv/fifo.c
deleted file mode 100644 (file)
index 0779a60..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-/* AcessOS
- * FIFO Pipe Driver
- */
-#define DEBUG  0
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <semaphore.h>
-
-// === CONSTANTS ===
-#define DEFAULT_RING_SIZE      2048
-#define PF_BLOCKING            1
-
-// === TYPES ===
-typedef struct sPipe {
-       struct sPipe    *Next;
-       char    *Name;
-       tVFS_Node       Node;
-       Uint    Flags;
-        int    ReadPos;
-        int    WritePos;
-        int    BufSize;
-       char    *Buffer;
-} tPipe;
-
-// === PROTOTYPES ===
- int   FIFO_Install(char **Arguments);
- int   FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
-char   *FIFO_ReadDir(tVFS_Node *Node, int Id);
-tVFS_Node      *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
- int   FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
-void   FIFO_Reference(tVFS_Node *Node);
-void   FIFO_Close(tVFS_Node *Node);
- int   FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
-Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
-tPipe  *FIFO_Int_NewPipe(int Size, const char *Name);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
-tVFS_NodeType  gFIFO_DirNodeType = {
-       .TypeName = "FIFO Dir Node",
-       .ReadDir = FIFO_ReadDir,
-       .FindDir = FIFO_FindDir,
-       .MkNod = FIFO_MkNod,
-       .Relink = FIFO_Relink,
-       .IOCtl = FIFO_IOCtl
-};
-tVFS_NodeType  gFIFO_PipeNodeType = {
-       .TypeName = "FIFO Pipe Node",
-       .Read = FIFO_Read,
-       .Write = FIFO_Write,
-       .Close = FIFO_Close,
-       .Reference = FIFO_Reference
-};
-tDevFS_Driver  gFIFO_DriverInfo = {
-       NULL, "fifo",
-       {
-       .Size = 1,
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRW,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Type = &gFIFO_DirNodeType
-       }
-};
-tVFS_Node      gFIFO_AnonNode = {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRW,
-       };
-tPipe  *gFIFO_NamedPipes = NULL;
-
-// === CODE ===
-/**
- * \fn int FIFO_Install(char **Options)
- * \brief Installs the FIFO Driver
- */
-int FIFO_Install(char **Options)
-{
-       DevFS_AddDevice( &gFIFO_DriverInfo );
-       return MODULE_ERR_OK;
-}
-
-/**
- * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
- */
-int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
-       return 0;
-}
-
-/**
- * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
- * \brief Reads from the FIFO root
- */
-char *FIFO_ReadDir(tVFS_Node *Node, int Id)
-{
-       tPipe   *tmp = gFIFO_NamedPipes;
-       
-       // Entry 0 is Anon Pipes
-       if(Id == 0)     return strdup("anon");
-       
-       // Find the id'th node
-       while(--Id && tmp)      tmp = tmp->Next;
-       // If node found, return it
-       if(tmp) return strdup(tmp->Name);
-       // else error return
-       return NULL;
-}
-
-/**
- * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
- * \brief Find a file in the FIFO root
- * \note Creates an anon pipe if anon is requested
- */
-tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
-{
-       tPipe   *tmp;
-       if(!Filename)   return NULL;
-       
-       // NULL String Check
-       if(Filename[0] == '\0') return NULL;
-       
-       // Anon Pipe
-       if(Filename[0] == 'a' && Filename[1] == 'n'
-       && Filename[2] == 'o' && Filename[3] == 'n'
-       && Filename[4] == '\0') {
-               tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
-               return &tmp->Node;
-       }
-       
-       // Check Named List
-       tmp = gFIFO_NamedPipes;
-       while(tmp)
-       {
-               if(strcmp(tmp->Name, Filename) == 0)
-                       return &tmp->Node;
-               tmp = tmp->Next;
-       }
-       return NULL;
-}
-
-/**
- * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
- */
-int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
-{
-       return 0;
-}
-
-void FIFO_Reference(tVFS_Node *Node)
-{
-       if(!Node->ImplPtr)      return ;
-       
-       Node->ReferenceCount ++;
-}
-
-/**
- * \fn void FIFO_Close(tVFS_Node *Node)
- * \brief Close a FIFO end
- */
-void FIFO_Close(tVFS_Node *Node)
-{
-       tPipe   *pipe;
-       if(!Node->ImplPtr)      return ;
-       
-       Node->ReferenceCount --;
-       if(Node->ReferenceCount)        return ;
-       
-       pipe = Node->ImplPtr;
-       
-       if(strcmp(pipe->Name, "anon") == 0) {
-               Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr);
-               free(Node->ImplPtr);
-               return ;
-       }
-       
-       return ;
-}
-
-/**
- * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
- * \brief Relink a file (Deletes named pipes)
- */
-int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
-{
-       tPipe   *pipe, *tmp;
-       
-       if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
-       
-       // Can't relink anon
-       if(strcmp(OldName, "anon"))     return 0;
-       
-       // Find node
-       for(pipe = gFIFO_NamedPipes;
-               pipe;
-               pipe = pipe->Next)
-       {
-               if(strcmp(pipe->Name, OldName) == 0)
-                       break;
-       }
-       if(!pipe)       return 0;
-       
-       // Relink a named pipe
-       if(NewName) {
-               // Check new name
-               for(tmp = gFIFO_NamedPipes;
-                       tmp;
-                       tmp = tmp->Next)
-               {
-                       if(strcmp(tmp->Name, NewName) == 0)     return 0;
-               }
-               // Create new name
-               free(pipe->Name);
-               pipe->Name = malloc(strlen(NewName)+1);
-               strcpy(pipe->Name, NewName);
-               return 1;
-       }
-       
-       // Unlink the pipe
-       if(Node->ImplPtr) {
-               free(Node->ImplPtr);
-               return 1;
-       }
-       
-       return 0;
-}
-
-/**
- * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from a fifo pipe
- */
-Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tPipe   *pipe = Node->ImplPtr;
-       Uint    len;
-       Uint    remaining = Length;
-
-       if(!pipe)       return 0;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       while(remaining)
-       {
-               // Wait for buffer to fill
-               if(pipe->Flags & PF_BLOCKING)
-               {
-                       if( pipe->ReadPos == pipe->WritePos )
-                               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
-                       
-               }
-               else
-               {
-                       if(pipe->ReadPos == pipe->WritePos)
-                       {
-                               VFS_MarkAvaliable(Node, 0);
-                               LEAVE('i', 0);
-                               return 0;
-                       }
-               }
-       
-               len = remaining;
-               if( pipe->ReadPos < pipe->WritePos )
-               {
-                        int    avail_bytes = pipe->WritePos - pipe->ReadPos;
-                       if( avail_bytes < remaining )   len = avail_bytes;
-               }
-               else
-               {
-                        int    avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
-                       if( avail_bytes < remaining )   len = avail_bytes;
-               }
-
-               LOG("len = %i, remaining = %i", len, remaining);                
-
-               // Check if read overflows buffer
-               if(len > pipe->BufSize - pipe->ReadPos)
-               {
-                       int ofs = pipe->BufSize - pipe->ReadPos;
-                       memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
-                       memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
-               }
-               else
-               {
-                       memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
-               }
-               
-               // Increment read position
-               pipe->ReadPos += len;
-               pipe->ReadPos %= pipe->BufSize;
-               
-               // Mark some flags
-               if( pipe->ReadPos == pipe->WritePos ) {
-                       VFS_MarkAvaliable(Node, 0);
-               }
-               VFS_MarkFull(Node, 0);  // Buffer can't still be full
-               
-               // Decrement Remaining Bytes
-               remaining -= len;
-               // Increment Buffer address
-               Buffer = (Uint8*)Buffer + len;
-               
-               // TODO: Option to read differently
-               LEAVE('i', len);
-               return len;
-       }
-
-       LEAVE('i', Length);
-       return Length;
-
-}
-
-/**
- * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Write to a fifo pipe
- */
-Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tPipe   *pipe = Node->ImplPtr;
-       Uint    len;
-       Uint    remaining = Length;
-       
-       if(!pipe)       return 0;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       while(remaining)
-       {
-               // Wait for buffer to empty
-               if(pipe->Flags & PF_BLOCKING) {
-                       if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
-                               VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
-
-                       len = remaining;
-                       if( pipe->ReadPos > pipe->WritePos )
-                       {
-                                int    rem_space = pipe->ReadPos - pipe->WritePos;
-                               if(rem_space < remaining)       len = rem_space;
-                       }
-                       else
-                       {
-                                int    rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
-                               if(rem_space < remaining)       len = rem_space;
-                       }
-               }
-               else
-               {
-                       if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
-                       {
-                               LEAVE('i', 0);
-                               return 0;
-                       }
-                       // Write buffer
-                       if(pipe->ReadPos - pipe->WritePos < remaining)
-                               len = pipe->ReadPos - pipe->WritePos;
-                       else
-                               len = remaining;
-               }
-               
-               // Check if write overflows buffer
-               if(len > pipe->BufSize - pipe->WritePos)
-               {
-                       int ofs = pipe->BufSize - pipe->WritePos;
-                       memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
-                       memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
-               }
-               else
-               {
-                       memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
-               }
-               
-               // Increment read position
-               pipe->WritePos += len;
-               pipe->WritePos %= pipe->BufSize;
-               
-               // Mark some flags
-               if( pipe->ReadPos == pipe->WritePos ) {
-                       VFS_MarkFull(Node, 1);  // Buffer full
-               }
-               VFS_MarkAvaliable(Node, 1);
-               
-               // Decrement Remaining Bytes
-               remaining -= len;
-               // Increment Buffer address
-               Buffer = (Uint8*)Buffer + len;
-       }
-
-       LEAVE('i', Length);
-       return Length;
-}
-
-// --- HELPERS ---
-/**
- * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
- * \brief Create a new pipe
- */
-tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
-{
-       tPipe   *ret;
-        int    namelen = strlen(Name) + 1;
-        int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
-       
-       ret = calloc(1, allocsize);
-       if(!ret)        return NULL;
-       
-       // Clear Return
-       ret->Flags = PF_BLOCKING;
-       
-       // Allocate Buffer
-       ret->BufSize = Size;
-       ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
-       
-       // Set name (and FIFO name)
-       ret->Name = ret->Buffer + Size;
-       strcpy(ret->Name, Name);
-       // - Start empty, max of `Size`
-       //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
-       
-       // Set Node
-       ret->Node.ReferenceCount = 1;
-       ret->Node.Size = 0;
-       ret->Node.ImplPtr = ret;
-       ret->Node.UID = Threads_GetUID();
-       ret->Node.GID = Threads_GetGID();
-       ret->Node.NumACLs = 1;
-       ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
-               ret->Node.ACLs->Group = 0;
-               ret->Node.ACLs->ID = ret->Node.UID;
-               ret->Node.ACLs->Inv = 0;
-               ret->Node.ACLs->Perms = -1;
-       ret->Node.CTime
-               = ret->Node.MTime
-               = ret->Node.ATime = now();
-       ret->Node.Type = &gFIFO_PipeNodeType;
-       
-       return ret;
-}
diff --git a/Kernel/drv/iocache.c b/Kernel/drv/iocache.c
deleted file mode 100644 (file)
index 8f73541..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Acess2 Kernel
- * - IO Cache
- * 
- * By thePowersGang (John Hodge)
- * 
- * TODO: Convert to use spare physical pages instead
- */
-#define DEBUG  0
-#include <acess.h>
-#include <iocache.h>
-
-// === TYPES ===
-typedef struct sIOCache_Ent    tIOCache_Ent;
-typedef struct sIOCache_PageInfo       tIOCache_PageInfo;
-
-// === STRUCTURES ===
-struct sIOCache_Ent
-{
-       tIOCache_Ent    *Next;
-       Uint64  Num;
-       Sint64  LastAccess;
-       Sint64  LastWrite;
-       Uint8   Data[];
-};
-
-struct sIOCache_PageInfo
-{
-       tIOCache_PageInfo       *GlobalNext;
-       tIOCache_PageInfo       *CacheNext;
-       tIOCache        *Owner;
-       tPAddr  BasePhys;
-       Uint64  BaseOffset;
-};
-
-struct sIOCache
-{
-       tIOCache        *Next;
-        int    SectorSize;
-       tMutex  Lock;
-        int    Mode;
-       Uint32  ID;
-       tIOCache_WriteCallback  Write;
-        int    CacheSize;
-        int    CacheUsed;
-       tIOCache_Ent    *Entries;
-};
-
-// === GLOBALS ===
-tShortSpinlock glIOCache_Caches;
-tIOCache       *gIOCache_Caches = NULL;
- int   giIOCache_NumCaches = 0;
-tIOCache_PageInfo      *gIOCache_GlobalPages;
-
-// === CODE ===
-/**
- * \fn tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
- * \brief Creates a new IO Cache
- */
-tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
-{
-       tIOCache        *ret = calloc( 1, sizeof(tIOCache) );
-       
-       // Sanity Check
-       if(!ret)        return NULL;
-       
-       // Fill Structure
-       ret->SectorSize = SectorSize;
-       ret->Mode = IOCACHE_WRITEBACK;
-       ret->ID = ID;
-       ret->Write = Write;
-       ret->CacheSize = CacheSize;
-       
-       // Append to list
-       SHORTLOCK( &glIOCache_Caches );
-       ret->Next = gIOCache_Caches;
-       gIOCache_Caches = ret;
-       SHORTREL( &glIOCache_Caches );
-       
-       // Return
-       return ret;
-}
-
-/**
- * \fn int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
- * \brief Read from a cached sector
- */
-int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
-{
-       
-       ENTER("pCache XSector pBuffer", Cache, Sector, Buffer);
-       
-       // Sanity Check!
-       if(!Cache || !Buffer) {
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       // Lock
-       Mutex_Acquire( &Cache->Lock );
-       if(Cache->CacheSize == 0) {
-               Mutex_Release( &Cache->Lock );
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       #if IOCACHE_USE_PAGES
-       tIOCache_PageInfo       *page;
-       size_t  offset = (Sector*Cache->SectorSize) % PAGE_SIZE;
-       Uint64  wanted_base = (Sector*Cache->SectorSize) & ~(PAGE_SIZE-1);
-       for( page = Cache->Pages; page; page = page->CacheNext )
-       {
-               void    *tmp;
-               if(page->BaseOffset < WantedBase)       continue;
-               if(page->BaseOffset > WantedBase)       break;
-               tmp = MM_MapTemp( page->BasePhys );
-               memcpy( Buffer, tmp + offset, Cache->SectorSize ); 
-               MM_FreeTemp( tmp );
-       }
-       #else   
-       tIOCache_Ent    *ent;
-       // Search the list
-       for( ent = Cache->Entries; ent; ent = ent->Next )
-       {
-               // Have we found what we are looking for?
-               if( ent->Num == Sector ) {
-                       memcpy(Buffer, ent->Data, Cache->SectorSize);
-                       ent->LastAccess = now();
-                       Mutex_Release( &Cache->Lock );
-                       LEAVE('i', 1);
-                       return 1;
-               }
-               // It's a sorted list, so as soon as we go past `Sector` we know
-               // it's not there
-               if(ent->Num > Sector)   break;
-       }
-       #endif
-       
-       Mutex_Release( &Cache->Lock );
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \fn int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
- * \brief Cache a sector
- */
-int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
-{
-       tIOCache_Ent    *ent, *prev;
-       tIOCache_Ent    *new;
-       tIOCache_Ent    *oldest = NULL, *oldestPrev;
-       
-       // Sanity Check!
-       if(!Cache || !Buffer)
-               return -1;
-       
-       // Lock
-       Mutex_Acquire( &Cache->Lock );
-       if(Cache->CacheSize == 0) {
-               Mutex_Release( &Cache->Lock );
-               return -1;
-       }
-       
-       // Search the list
-       prev = (tIOCache_Ent*)&Cache->Entries;
-       for( ent = Cache->Entries; ent; prev = ent, ent = ent->Next )
-       {
-               // Is it already here?
-               if( ent->Num == Sector ) {
-                       Mutex_Release( &Cache->Lock );
-                       return 0;
-               }
-               
-               // Check if we have found the oldest entry
-               if( !oldest || oldest->LastAccess > ent->LastAccess ) {
-                       oldest = ent;
-                       oldestPrev = prev;
-               }
-               
-               // Here we go!
-               if(ent->Num > Sector)
-                       break;
-       }
-       
-       // Create the new entry
-       new = malloc( sizeof(tIOCache_Ent) + Cache->SectorSize );
-       new->Next = ent;
-       new->Num = Sector;
-       new->LastAccess = now();
-       new->LastWrite = 0;     // Zero is special, it means unmodified
-       memcpy(new->Data, Buffer, Cache->SectorSize);
-       
-       // Have we reached the maximum cached entries?
-       if( Cache->CacheUsed == Cache->CacheSize )
-       {
-               tIOCache_Ent    *savedPrev = prev;
-               oldestPrev = (tIOCache_Ent*)&Cache->Entries;
-               // If so, search for the least recently accessed entry
-               for( ; ent; prev = ent, ent = ent->Next )
-               {       
-                       // Check if we have found the oldest entry
-                       if( !oldest || oldest->LastAccess > ent->LastAccess ) {
-                               oldest = ent;
-                               oldestPrev = prev;
-                       }
-               }
-               if( !oldest ) {
-                       Log_Error("IOCache", "Cache full, but also empty");
-                       return -1;
-               }
-               // Remove from list, write back and free
-               oldestPrev->Next = oldest->Next;
-               if(oldest->LastWrite && Cache->Mode != IOCACHE_VIRTUAL)
-                       Cache->Write(Cache->ID, oldest->Num, oldest->Data);
-               free(oldest);
-               
-               // Decrement the used count
-               Cache->CacheUsed --;
-               
-               // Restore `prev`
-               prev = savedPrev;
-       }
-       
-       // Append to list
-       prev->Next = new;
-       Cache->CacheUsed ++;
-       
-       // Release Spinlock
-       Mutex_Release( &Cache->Lock );
-       
-       // Return success
-       return 1;
-}
-
-/**
- * \fn int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
- * \brief Read from a cached sector
- */
-int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
-{
-       tIOCache_Ent    *ent;
-       
-       // Sanity Check!
-       if(!Cache || !Buffer)
-               return -1;
-       // Lock
-       Mutex_Acquire( &Cache->Lock );
-       if(Cache->CacheSize == 0) {
-               Mutex_Release( &Cache->Lock );
-               return -1;
-       }
-       
-       // Search the list
-       for( ent = Cache->Entries; ent; ent = ent->Next )
-       {
-               // Have we found what we are looking for?
-               if( ent->Num == Sector ) {
-                       memcpy(ent->Data, Buffer, Cache->SectorSize);
-                       ent->LastAccess = ent->LastWrite = now();
-                       
-                       if(Cache->Mode == IOCACHE_WRITEBACK) {
-                               Cache->Write(Cache->ID, Sector, Buffer);
-                               ent->LastWrite = 0;
-                       }
-                       
-                       Mutex_Release( &Cache->Lock );
-                       return 1;
-               }
-               // It's a sorted list, so as soon as we go past `Sector` we know
-               // it's not there
-               if(ent->Num > Sector)   break;
-       }
-       
-       Mutex_Release( &Cache->Lock );
-       return 0;
-}
-
-/**
- * \fn void IOCache_Flush( tIOCache *Cache )
- * \brief Flush a cache
- */
-void IOCache_Flush( tIOCache *Cache )
-{
-       tIOCache_Ent    *ent;
-       
-       if( Cache->Mode == IOCACHE_VIRTUAL )    return;
-       
-       // Lock
-       Mutex_Acquire( &Cache->Lock );
-       if(Cache->CacheSize == 0) {
-               Mutex_Release( &Cache->Lock );
-               return;
-       }
-       
-       // Write All
-       for( ent = Cache->Entries; ent; ent = ent->Next )
-       {
-               Cache->Write(Cache->ID, ent->Num, ent->Data);
-               ent->LastWrite = 0;
-       }
-       
-       Mutex_Release( &Cache->Lock );
-}
-
-/**
- * \fn void IOCache_Destroy( tIOCache *Cache )
- * \brief Destroy a cache
- */
-void IOCache_Destroy( tIOCache *Cache )
-{
-       tIOCache_Ent    *ent, *prev = NULL;
-       
-       // Lock
-       Mutex_Acquire( &Cache->Lock );
-       if(Cache->CacheSize == 0) {
-               Mutex_Release( &Cache->Lock );
-               return;
-       }
-       
-       // Free All
-       for(ent = Cache->Entries;
-               ent;
-               prev = ent, ent = ent->Next, free(prev) )
-       {
-               if( Cache->Mode != IOCACHE_VIRTUAL )
-               {
-                       Cache->Write(Cache->ID, ent->Num, ent->Data);
-                       ent->LastWrite = 0;
-               }
-       }
-       
-       Cache->CacheSize = 0;
-       
-       Mutex_Release( &Cache->Lock );
-       
-       // Remove from list
-       SHORTLOCK( &glIOCache_Caches );
-       {
-               tIOCache        *cache;
-               tIOCache        *prev_cache = (tIOCache*)&gIOCache_Caches;
-               for(cache = gIOCache_Caches;
-                       cache;
-                       prev_cache = cache, cache = cache->Next )
-               {
-                       if(cache == Cache) {
-                               prev_cache->Next = cache->Next;
-                               break;
-                       }
-               }
-       }
-       SHORTREL( &glIOCache_Caches );
-       
-       free(Cache);
-}
diff --git a/Kernel/drv/pci.c b/Kernel/drv/pci.c
deleted file mode 100644 (file)
index 8745080..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-/*\r
- * AcessOS/AcessBasic v0.1\r
- * PCI Bus Driver\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include <fs_devfs.h>\r
-#include <drv_pci.h>\r
-#include <drv_pci_int.h>\r
-\r
-#define        LIST_DEVICES    1\r
-\r
-// === STRUCTURES ===\r
-typedef struct sPCIDevice\r
-{\r
-       Uint16  bus, slot, fcn;\r
-       Uint16  vendor, device;\r
-       Uint32  class;  // Class:Subclass:ProgIf\r
-       Uint8   revision;\r
-       Uint32  ConfigCache[256/4];\r
-       char    Name[8];\r
-       tVFS_Node       Node;\r
-} tPCIDevice;\r
-\r
-// === CONSTANTS ===\r
-#define SPACE_STEP     5\r
-#define MAX_RESERVED_PORT      0xD00\r
-\r
-// === PROTOTYPES ===\r
- int   PCI_Install(char **Arguments);\r
- int   PCI_ScanBus(int ID, int bFill);\r
\r
-char   *PCI_int_ReadDirRoot(tVFS_Node *node, int pos);\r
-tVFS_Node      *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename);\r
-Uint32 PCI_int_GetBusAddr(Uint16 Bus, Uint16 Slot, Uint16 Fcn, Uint8 Offset);\r
-Uint64 PCI_int_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);\r
- int   PCI_int_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
- int   giPCI_BusCount = 1;\r
- int   giPCI_InodeHandle = -1;\r
- int   giPCI_DeviceCount = 0;\r
-tPCIDevice     *gPCI_Devices = NULL;\r
-tVFS_NodeType  gPCI_RootNodeType = {\r
-       .TypeName = "PCI Root Node",\r
-       .ReadDir = PCI_int_ReadDirRoot,\r
-       .FindDir = PCI_int_FindDirRoot\r
-};\r
-tVFS_NodeType  gPCI_DevNodeType = {\r
-       .TypeName = "PCI Dev Node",\r
-       .Read = PCI_int_ReadDevice\r
-};\r
-tDevFS_Driver  gPCI_DriverStruct = {\r
-       NULL, "pci",\r
-       {\r
-       .Flags = VFS_FFLAG_DIRECTORY,\r
-       .Size = -1,\r
-       .NumACLs = 1,\r
-       .ACLs = &gVFS_ACL_EveryoneRX,\r
-       .Type = &gPCI_RootNodeType\r
-       }\r
-};\r
-Uint32 *gaPCI_PortBitmap = NULL;\r
-Uint32 gaPCI_BusBitmap[256/32];\r
\r
-// === CODE ===\r
-/**\r
- * \brief Scan the PCI Bus for devices\r
- * \param Arguments    Boot-time parameters\r
- */\r
-int PCI_Install(char **Arguments)\r
-{\r
-        int    i;\r
-       void    *tmpPtr;\r
-       \r
-       // Build Portmap\r
-       gaPCI_PortBitmap = malloc( 1 << 13 );\r
-       if( !gaPCI_PortBitmap ) {\r
-               Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);\r
-               return MODULE_ERR_MALLOC;\r
-       }\r
-       memset( gaPCI_PortBitmap, 0, 1 << 13 );\r
-       for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )\r
-               gaPCI_PortBitmap[i] = -1;\r
-       for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
-               gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
-       \r
-       // Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
-       i = PCI_ScanBus(0, 0);\r
-       if(i != MODULE_ERR_OK)  return i;\r
-               \r
-       if(giPCI_DeviceCount == 0) {\r
-               Log_Notice("PCI", "No devices were found");\r
-               return MODULE_ERR_NOTNEEDED;\r
-       }\r
-       \r
-       // Allocate device buffer\r
-       tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));\r
-       if(tmpPtr == NULL) {\r
-               Log_Warning("PCI", "Malloc ERROR");\r
-               return MODULE_ERR_MALLOC;\r
-       }\r
-       gPCI_Devices = tmpPtr;\r
-       \r
-       Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);\r
-       \r
-       // Reset counts\r
-       giPCI_DeviceCount = 0;\r
-       giPCI_BusCount = 0;\r
-       memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));\r
-       // Rescan, filling the PCI device array\r
-       PCI_ScanBus(0, 1);\r
-       \r
-       // Complete Driver Structure\r
-       gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;\r
-       \r
-       // And add to DevFS\r
-       DevFS_AddDevice(&gPCI_DriverStruct);\r
-       \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \brief Scans a specific PCI Bus\r
- * \param BusID        PCI Bus ID to scan\r
- * \param bFill        Fill the \a gPCI_Devices array?\r
- */\r
-int PCI_ScanBus(int BusID, int bFill)\r
-{\r
-        int    dev, fcn;\r
-       tPCIDevice      devInfo;\r
-       \r
-       if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )\r
-               return MODULE_ERR_OK;\r
-       \r
-       gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));\r
-       \r
-       for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus\r
-       {\r
-               for( fcn = 0; fcn < 8; fcn++ )  // Max 8 functions per device\r
-               {\r
-                       // Check if the device/function exists\r
-                       if(!PCI_int_EnumDevice(BusID, dev, fcn, &devInfo))\r
-                               continue;\r
-                       \r
-                       if(devInfo.class == PCI_OC_PCIBRIDGE)\r
-                       {\r
-                               #if LIST_DEVICES\r
-                               if( !bFill )\r
-                                       Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
-                                               BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
-                               #endif\r
-                               //TODO: Handle PCI-PCI Bridges\r
-                               //PCI_ScanBus(devInfo.???, bFill);\r
-                               giPCI_BusCount ++;\r
-                       }\r
-                       else\r
-                       {\r
-                               #if LIST_DEVICES\r
-                               if( !bFill )\r
-                                       Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x",\r
-                                               BusID, dev, fcn, devInfo.class, devInfo.vendor, devInfo.device);\r
-                               #endif\r
-                       }\r
-                       \r
-                       if( bFill ) {\r
-                               devInfo.Node.Inode = giPCI_DeviceCount;\r
-                               memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));\r
-                       }\r
-                       giPCI_DeviceCount ++;\r
-                       \r
-                       // If bit 23 of (soemthing) is set, there are sub-functions\r
-                       if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )\r
-                               break;\r
-               }\r
-       }\r
-       \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \brief Read from Root of PCI Driver\r
-*/\r
-char *PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos)\r
-{\r
-       ENTER("pNode iPos", Node, Pos);\r
-       if(Pos < 0 || Pos >= giPCI_DeviceCount) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       LEAVE('s', gPCI_Devices[Pos].Name);\r
-       return strdup( gPCI_Devices[Pos].Name );\r
-}\r
-/**\r
- */\r
-tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename)\r
-{\r
-        int    bus,slot,fcn;\r
-        int    i;\r
-       // Validate Filename (Pointer and length)\r
-       if(!filename || strlen(filename) != 7)\r
-               return NULL;\r
-       // Check for spacers\r
-       if(filename[2] != '.' || filename[5] != ':')\r
-               return NULL;\r
-       \r
-       // Get Information\r
-       if(filename[0] < '0' || filename[0] > '9')      return NULL;\r
-       bus = (filename[0] - '0')*10;\r
-       if(filename[1] < '0' || filename[1] > '9')      return NULL;\r
-       bus += filename[1] - '0';\r
-       if(filename[3] < '0' || filename[3] > '9')      return NULL;\r
-       slot = (filename[3] - '0')*10;\r
-       if(filename[4] < '0' || filename[4] > '9')      return NULL;\r
-       slot += filename[4] - '0';\r
-       if(filename[6] < '0' || filename[6] > '9')      return NULL;\r
-       fcn = filename[6] - '0';\r
-       \r
-       // Find Match\r
-       for(i=0;i<giPCI_DeviceCount;i++)\r
-       {\r
-               if(gPCI_Devices[i].bus != bus)          continue;\r
-               if(gPCI_Devices[i].slot != slot)        continue;\r
-               if(gPCI_Devices[i].fcn != fcn)  continue;\r
-               \r
-               return &gPCI_Devices[i].Node;\r
-       }\r
-       \r
-       // Error Return\r
-       return NULL;\r
-}\r
-\r
-/**\r
- */\r
-Uint64 PCI_int_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
-{      \r
-       if( pos + length > 256 )        return 0;\r
-       \r
-       memcpy(\r
-               buffer,\r
-               (char*)gPCI_Devices[node->Inode].ConfigCache + pos,\r
-               length);\r
-       \r
-       return length;\r
-}\r
-\r
-// --- Kernel Code Interface ---\r
-/**\r
- * \brief Counts the devices with the specified codes\r
- * \param vendor       Vendor ID\r
- * \param device       Device ID\r
- */\r
-int PCI_CountDevices(Uint16 vendor, Uint16 device)\r
-{\r
-       int i, ret=0;\r
-       for(i=0;i<giPCI_DeviceCount;i++)\r
-       {\r
-               if(gPCI_Devices[i].vendor != vendor)    continue;\r
-               if(gPCI_Devices[i].device != device)    continue;\r
-               ret ++;\r
-       }\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \brief Gets the ID of the specified PCI device\r
- * \param vendor       Vendor ID\r
- * \param device       Device ID\r
- * \param idx  Number of matching entry wanted\r
- */\r
-tPCIDev PCI_GetDevice(Uint16 vendor, Uint16 device, int idx)\r
-{\r
-        int    i, j=0;\r
-       for( i = 0; i < giPCI_DeviceCount; i ++ )\r
-       {\r
-               if(gPCI_Devices[i].vendor != vendor)    continue;\r
-               if(gPCI_Devices[i].device != device)    continue;\r
-               if(j == idx)    return i;\r
-               j ++;\r
-       }\r
-       return -1;\r
-}\r
-\r
-/**\r
- * \brief Gets the ID of a device by it's class code\r
- * \param class        Class Code\r
- * \param mask Mask for class comparison\r
- * \param prev ID of previous device (-1 for no previous)\r
- */\r
-tPCIDev PCI_GetDeviceByClass(Uint32 class, Uint32 mask, tPCIDev prev)\r
-{\r
-        int    i;\r
-       // Check if prev is negative (meaning get first)\r
-       if(prev < 0)    i = 0;\r
-       else    i = prev+1;\r
-       \r
-       for( ; i < giPCI_DeviceCount; i++ )\r
-       {\r
-               if((gPCI_Devices[i].class & mask) == class)\r
-                       return i;\r
-       }\r
-       return -1;\r
-}\r
-\r
-int PCI_GetDeviceInfo(tPCIDev ID, Uint16 *Vendor, Uint16 *Device, Uint32 *Class)\r
-{\r
-       tPCIDevice      *dev = &gPCI_Devices[ID];\r
-       if(ID < 0 || ID >= giPCI_DeviceCount)   return 1;\r
-       \r
-       if(Vendor)      *Vendor = dev->vendor;\r
-       if(Device)      *Device = dev->device;\r
-       if(Class)       *Class = dev->class;\r
-       return 0;\r
-}\r
-\r
-int PCI_GetDeviceVersion(tPCIDev ID, Uint8 *Revision)\r
-{\r
-       tPCIDevice      *dev = &gPCI_Devices[ID];\r
-       if(ID < 0 || ID >= giPCI_DeviceCount)   return 1;\r
-       \r
-       if(Revision)    *Revision = dev->revision;\r
-       return 0;\r
-}\r
-\r
-int PCI_GetDeviceSubsys(tPCIDev ID, Uint16 *SubsystemVendor, Uint16 *SubsystemID)\r
-{\r
-       tPCIDevice      *dev = &gPCI_Devices[ID];\r
-       if(ID < 0 || ID >= giPCI_DeviceCount)   return 1;\r
-       \r
-       if(SubsystemVendor)     *SubsystemVendor = dev->ConfigCache[0x2c/4] & 0xFFFF;\r
-       if(SubsystemID) *SubsystemID = dev->ConfigCache[0x2c/4] >> 16;\r
-\r
-       return 0;\r
-}\r
-\r
-Uint32 PCI_int_GetBusAddr(Uint16 Bus, Uint16 Slot, Uint16 Fcn, Uint8 Offset)\r
-{\r
-       Bus &= 0xFF;\r
-       Slot &= 0x1F;\r
-       Fcn &= 7;\r
-       Offset &= 0xFC;\r
-       return ((Uint32)Bus << 16) | (Slot << 11) | (Fcn << 8) | (Offset & 0xFC);\r
-}\r
-\r
-Uint32 PCI_ConfigRead(tPCIDev ID, int Offset, int Size)\r
-{\r
-       tPCIDevice      *dev;\r
-       Uint32  dword, addr;\r
-       \r
-       if( ID < 0 || ID >= giPCI_DeviceCount ) return 0;\r
-       if( Offset < 0 || Offset > 256 )        return 0;\r
-\r
-       // TODO: Should I support non-aligned reads?\r
-       if( Offset & (Size - 1) )       return 0;\r
-\r
-       dev = &gPCI_Devices[ID];\r
-       addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
-\r
-       dword = PCI_CfgReadDWord(addr);\r
-       gPCI_Devices[ID].ConfigCache[Offset/4] = dword;\r
-       switch( Size )\r
-       {\r
-       case 1: return (dword >> (8 * (Offset&3))) & 0xFF;\r
-       case 2: return (dword >> (8 * (Offset&2))) & 0xFFFF;\r
-       case 4: return dword;\r
-       default:\r
-               return 0;\r
-       }\r
-}\r
-\r
-void PCI_ConfigWrite(tPCIDev ID, int Offset, int Size, Uint32 Value)\r
-{\r
-       tPCIDevice      *dev;\r
-       Uint32  dword, addr;\r
-        int    shift;\r
-       if( ID < 0 || ID >= giPCI_DeviceCount ) return ;\r
-       if( Offset < 0 || Offset > 256 )        return ;\r
-       \r
-       dev = &gPCI_Devices[ID];\r
-       addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
-\r
-       if(Size != 4)\r
-               dword = PCI_CfgReadDWord(addr);\r
-       switch(Size)\r
-       {\r
-       case 1:\r
-               shift = (Offset&3)*8;\r
-               dword &= ~(0xFF << shift);\r
-               dword |= Value << shift;\r
-               break;\r
-       case 2:\r
-               shift = (Offset&2)*8;\r
-               dword &= ~(0xFFFF << shift);\r
-               dword |= Value << shift;\r
-               break;\r
-       case 4:\r
-               dword = Value;\r
-               break;\r
-       default:\r
-               return;\r
-       }\r
-       PCI_CfgWriteDWord(addr, dword);\r
-}\r
-\r
-/**\r
- * \brief Get the IRQ assigned to a device\r
- */\r
-Uint8 PCI_GetIRQ(tPCIDev id)\r
-{\r
-       if(id < 0 || id >= giPCI_DeviceCount)\r
-               return 0;\r
-       return gPCI_Devices[id].ConfigCache[15] & 0xFF;\r
-       //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);\r
-}\r
-\r
-/**\r
- * \brief Read the a BAR (base address register) from the PCI config space\r
- */\r
-Uint32 PCI_GetBAR(tPCIDev id, int BARNum)\r
-{\r
-       if(id < 0 || id >= giPCI_DeviceCount)\r
-               return 0;\r
-       if(BARNum < 0 || BARNum >= 6)\r
-               return 0;\r
-       return gPCI_Devices[id].ConfigCache[4+BARNum];\r
-}\r
-\r
-/**\r
- * \brief Get device information for a slot/function\r
- */\r
-int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
-{\r
-       Uint32  vendor_dev, tmp;\r
-        int    i;\r
-       Uint32  addr;\r
-       addr = PCI_int_GetBusAddr(bus, slot, fcn, 0);   \r
-\r
-       vendor_dev = PCI_CfgReadDWord( addr );\r
-       if((vendor_dev & 0xFFFF) == 0xFFFF)     // Invalid Device\r
-               return 0;\r
-\r
-       info->ConfigCache[0] = vendor_dev;\r
-       for( i = 1, addr += 4; i < 256/4; i ++, addr += 4 )\r
-       {\r
-               info->ConfigCache[i] = PCI_CfgReadDWord(addr);\r
-       }       \r
-\r
-       info->bus = bus;\r
-       info->slot = slot;\r
-       info->fcn = fcn;\r
-       info->vendor = vendor_dev & 0xFFFF;\r
-       info->device = vendor_dev >> 16;\r
-       tmp = info->ConfigCache[2];\r
-       info->revision = tmp & 0xFF;\r
-       info->class = tmp >> 8;\r
-       \r
-//     #if LIST_DEVICES\r
-//     Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);\r
-//     Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);\r
-//     Log("Class: 0x%06x", info->class);\r
-//     #endif\r
-       \r
-       // Make node name\r
-       info->Name[0] = '0' + bus/10;\r
-       info->Name[1] = '0' + bus%10;\r
-       info->Name[2] = '.';\r
-       info->Name[3] = '0' + slot/10;\r
-       info->Name[4] = '0' + slot%10;\r
-       info->Name[5] = ':';\r
-       info->Name[6] = '0' + fcn;\r
-       info->Name[7] = '\0';\r
-       \r
-       // Create VFS Node\r
-       memset( &info->Node, 0, sizeof(tVFS_Node) );\r
-       info->Node.Size = 256;\r
-       \r
-       info->Node.NumACLs = 1;\r
-       info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
-       \r
-       info->Node.Type = &gPCI_RootNodeType;\r
-       \r
-       return 1;\r
-}\r
-\r
-// === EXPORTS ===\r
-//*\r
-EXPORT(PCI_CountDevices);\r
-EXPORT(PCI_GetDevice);\r
-EXPORT(PCI_GetDeviceByClass);\r
-EXPORT(PCI_GetDeviceInfo);\r
-EXPORT(PCI_GetDeviceVersion);\r
-EXPORT(PCI_GetDeviceSubsys);\r
-//EXPORT(PCI_AssignPort);\r
-EXPORT(PCI_GetBAR);\r
-EXPORT(PCI_GetIRQ);\r
-//*/\r
diff --git a/Kernel/drv/proc.c b/Kernel/drv/proc.c
deleted file mode 100644 (file)
index 73f4535..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Acess2
- * - Kernel Status Driver
- */
-#define DEBUG  1
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <fs_sysfs.h>
-
-// === CONSTANTS ===
-#define        VERSION ((0 << 8) | (1))        // 0.01
-
-// === TYPES ===
-typedef struct sSysFS_Ent
-{
-       struct sSysFS_Ent       *Next;
-       struct sSysFS_Ent       *ListNext;
-       struct sSysFS_Ent       *Parent;
-       tVFS_Node       Node;
-       char    Name[];
-} tSysFS_Ent;
-
-// === PROTOTYPES ===
- int   SysFS_Install(char **Arguments);
- int   SysFS_IOCtl(tVFS_Node *Node, int Id, void *Data);
-
-#if 0
- int   SysFS_RegisterFile(const char *Path, const char *Data, int Length);
- int   SysFS_UpdateFile(int ID, const char *Data, int Length);
- int   SysFS_RemoveFile(int ID);
-#endif
-
-char   *SysFS_Comm_ReadDir(tVFS_Node *Node, int Id);
-tVFS_Node      *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename);
-Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-void   SysFS_Comm_CloseFile(tVFS_Node *Node);
-
-// === GLOBALS ===
-extern tSysFS_Ent      gSysFS_Version; // Defined Later
-extern tSysFS_Ent      gSysFS_Root;    // Defined Later
-MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
-tVFS_NodeType  gSysFS_FileNodeType = {
-       .TypeName = "SysFS File",
-       .Read = SysFS_Comm_ReadFile
-       };
-tVFS_NodeType  gSysFS_DirNodeType = {
-       .TypeName = "SysFS Dir",
-       .ReadDir = SysFS_Comm_ReadDir,
-       .FindDir = SysFS_Comm_FindDir
-       };
-tSysFS_Ent     gSysFS_Version_Kernel = {
-       NULL, NULL,     // Nexts
-       &gSysFS_Version,        // Parent
-       {
-               .Inode = 1,     // File #1
-               .ImplPtr = NULL,
-               .ImplInt = (Uint)&gSysFS_Version_Kernel,        // Self-Link
-               .Size = 0,
-               .NumACLs = 1,
-               .ACLs = &gVFS_ACL_EveryoneRO,
-               .Type = &gSysFS_FileNodeType
-       },
-       "Kernel"
-};
-tSysFS_Ent     gSysFS_Version = {
-       NULL, NULL,
-       &gSysFS_Root,
-       {
-               .Size = 1,
-               .ImplPtr = &gSysFS_Version_Kernel,
-               .ImplInt = (Uint)&gSysFS_Version,       // Self-Link
-               .NumACLs = 1,
-               .ACLs = &gVFS_ACL_EveryoneRX,
-               .Flags = VFS_FFLAG_DIRECTORY,
-               .Type = &gSysFS_DirNodeType
-       },
-       "Version"
-};
-// Root of the SysFS tree (just used to keep the code clean)
-tSysFS_Ent     gSysFS_Root = {
-       NULL, NULL,
-       NULL,
-       {
-               .Size = 1,
-               .ImplPtr = &gSysFS_Version,
-               .ImplInt = (Uint)&gSysFS_Root   // Self-Link
-       },
-       "/"
-};
-tDevFS_Driver  gSysFS_DriverInfo = {
-       NULL, "system",
-       {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .ImplPtr = &gSysFS_Version,
-       .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
-       .Type = &gSysFS_DirNodeType
-       }
-};
- int   giSysFS_NextFileID = 2;
-tSysFS_Ent     *gSysFS_FileList;
-
-// === CODE ===
-/**
- * \fn int SysFS_Install(char **Options)
- * \brief Installs the SysFS Driver
- */
-int SysFS_Install(char **Options)
-{
-       {
-               const char      *fmt = "Acess2 "EXPAND_STR(KERNEL_VERSION)" "EXPAND_STR(ARCHDIR)" build %i, hash %s";
-               gSysFS_Version_Kernel.Node.Size = sprintf(NULL, fmt, BUILD_NUM, gsGitHash);
-               gSysFS_Version_Kernel.Node.ImplPtr = malloc( gSysFS_Version_Kernel.Node.Size + 1 );
-               sprintf(gSysFS_Version_Kernel.Node.ImplPtr, fmt, BUILD_NUM, gsGitHash);
-       }
-
-       DevFS_AddDevice( &gSysFS_DriverInfo );
-       return MODULE_ERR_OK;
-}
-
-/**
- * \fn int SysFS_RegisterFile(char *Path, char *Data, int Length)
- * \brief Registers a file (buffer) for the user to be able to read from
- * \param Path Path for the file to be accessable from (relative to SysFS root)
- * \param Data Pointer to the data buffer (must be non-volatile)
- * \param Length       Length of the data buffer
- * \return The file's identifier
- */
-int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
-{
-        int    start = 0;
-        int    tmp;
-       tSysFS_Ent      *ent = NULL;
-       tSysFS_Ent      *child, *prev;
-       
-       // Find parent directory
-       while( (tmp = strpos(&Path[start], '/')) != -1 )
-       {
-               prev = NULL;
-               
-               if(ent)
-                       child = ent->Node.ImplPtr;
-               else
-                       child = gSysFS_DriverInfo.RootNode.ImplPtr;
-               for( ; child; prev = child, child = child->Next )
-               {
-                       if( strncmp( &Path[start], child->Name, tmp+1 ) == '/' )
-                               break;
-               }
-               
-               // Need a new directory?
-               if( !child )
-               {
-                       child = calloc( 1, sizeof(tSysFS_Ent)+tmp+1 );
-                       child->Next = NULL;
-                       memcpy(child->Name, &Path[start], tmp);
-                       child->Name[tmp] = '\0';
-                       child->Parent = ent;
-                       child->Node.Inode = 0;
-                       child->Node.ImplPtr = NULL;
-                       child->Node.ImplInt = (Uint)child;      // Uplink
-                       child->Node.NumACLs = 1;
-                       child->Node.ACLs = &gVFS_ACL_EveryoneRX;
-                       child->Node.Flags = VFS_FFLAG_DIRECTORY;
-                       child->Node.Type = &gSysFS_DirNodeType;
-                       if( !prev ) {
-                               if(ent)
-                                       ent->Node.ImplPtr = child;
-                               else
-                                       gSysFS_DriverInfo.RootNode.ImplPtr = child;
-                               // ^^^ Impossible (There is already /Version)
-                       }
-                       else
-                               prev->Next = child;
-                       if(ent)
-                               ent->Node.Size ++;
-                       else
-                               gSysFS_DriverInfo.RootNode.Size ++;
-                       Log_Log("SysFS", "Added directory '%s'", child->Name);
-               }
-               
-               ent = child;
-               
-               start = tmp+1;
-       }
-       
-       // ent: Parent tSysFS_Ent or NULL
-       // start: beginning of last path element
-       
-       // Check if the name is taken
-       prev = NULL;
-       if(ent)
-               child = ent->Node.ImplPtr;
-       else
-               child = gSysFS_DriverInfo.RootNode.ImplPtr;
-       for( ; child; child = child->Next )
-       {
-               if( strcmp( &Path[start], child->Name ) == 0 )
-                       break;
-       }
-       if( child ) {
-               Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
-               return 0;
-       }
-       
-       // Create new node
-       child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
-       child->Next = NULL;
-       strcpy(child->Name, &Path[start]);
-       child->Parent = ent;
-       
-       child->Node.Inode = giSysFS_NextFileID++;
-       child->Node.ImplPtr = (void*)Data;
-       child->Node.ImplInt = (Uint)child;      // Uplink
-       child->Node.Size = Length;
-       child->Node.NumACLs = 1;
-       child->Node.ACLs = &gVFS_ACL_EveryoneRO;
-       child->Node.Type = &gSysFS_FileNodeType;
-       
-       // Add to parent's child list
-       if(ent) {
-               ent->Node.Size ++;
-               child->Next = ent->Node.ImplPtr;
-               ent->Node.ImplPtr = child;
-       }
-       else {
-               gSysFS_DriverInfo.RootNode.Size ++;
-               child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
-               gSysFS_DriverInfo.RootNode.ImplPtr = child;
-       }
-       // Add to global file list
-       child->ListNext = gSysFS_FileList;
-       gSysFS_FileList = child;
-       
-       Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
-       
-       return child->Node.Inode;
-}
-
-/**
- * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
- * \brief Updates a file
- * \param ID   Identifier returned by ::SysFS_RegisterFile
- * \param Data Pointer to the data buffer
- * \param Length       Length of the data buffer
- * \return Boolean Success
- */
-int SysFS_UpdateFile(int ID, const char *Data, int Length)
-{
-       tSysFS_Ent      *ent;
-       
-       for( ent = gSysFS_FileList; ent; ent = ent->Next )
-       {
-               // It's a reverse sorted list
-               if(ent->Node.Inode < ID)        return 0;
-               if(ent->Node.Inode == ID)
-               {
-                       ent->Node.ImplPtr = (void*)Data;
-                       ent->Node.Size = Length;
-                       return 1;
-               }
-       }
-       
-       return 0;
-}
-
-/**
- * \fn int SysFS_RemoveFile(int ID)
- * \brief Removes a file from user access
- * \param ID   Identifier returned by ::SysFS_RegisterFile
- * \return Boolean Success
- * \note If a handle is still open to the file, it will be invalidated
- */
-int SysFS_RemoveFile(int ID)
-{
-       tSysFS_Ent      *file;
-       tSysFS_Ent      *ent, *parent, *prev;
-       
-       prev = NULL;
-       for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
-       {
-               // It's a reverse sorted list
-               if(ent->Node.Inode < ID)        return 0;
-               if(ent->Node.Inode == ID)       break;
-       }
-       
-       if(!ent)        return 0;
-       
-       // Set up for next part
-       file = ent;
-       parent = file->Parent;
-       
-       // Remove from file list
-       if(prev)
-               prev->ListNext = file->ListNext;
-       else
-               gSysFS_FileList = file->ListNext;
-       file->Node.Size = 0;
-       file->Node.ImplPtr = NULL;
-       
-       // Search parent directory
-       for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
-       {
-               if( ent == file )       break;
-       }
-       if(!ent) {
-               Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
-               return 0;
-       }
-       
-       // Remove from parent directory
-       if(prev)
-               prev->Next = ent->Next;
-       else
-               parent->Node.ImplPtr = ent->Next;
-       
-       // Free if not in use
-       if(file->Node.ReferenceCount == 0)
-               free(file);
-       
-       return 1;
-}
-
-/**
- * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
- * \brief Reads from a SysFS directory
- */
-char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
-       if(Pos < 0 || Pos >= Node->Size)        return NULL;
-       
-       for( ; child; child = child->Next, Pos-- )
-       {
-               if( Pos == 0 )  return strdup(child->Name);
-       }
-       return NULL;
-}
-
-/**
- * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
- * \brief Find a file in a SysFS directory
- */
-tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
-{
-       tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
-       
-       for( ; child; child = child->Next )
-       {
-               if( strcmp(child->Name, Filename) == 0 )
-                       return &child->Node;
-       }
-       
-       return NULL;
-}
-
-/**
- * \fn Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from an exposed buffer
- */
-Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       if( Offset > Node->Size )       return -1;
-       if( Length > Node->Size )       Length = Node->Size;
-       if( Offset + Length > Node->Size)       Length = Node->Size - Offset;
-       
-       if( Node->ImplPtr )
-               memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
-       else
-               return -1;
-       
-       return Length;
-}
-
-/**
- * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
- * \brief Closes an open file
- * \param Node Node to close
- */
-void SysFS_Comm_CloseFile(tVFS_Node *Node)
-{
-       // Dereference
-       Node->ReferenceCount --;
-       if( Node->ReferenceCount > 0 )  return;
-       
-       // Check if it is still valid
-       if( Node->ImplPtr )     return;
-       
-       // Delete
-       free( (void*)Node->ImplInt );
-}
diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c
deleted file mode 100644 (file)
index 2ae38ee..0000000
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * Acess2 Virtual Terminal Driver
- */
-#define DEBUG  0
-#include "vterm.h"
-#include <fs_devfs.h>
-#include <modules.h>
-#include <api_drv_keyboard.h>
-#include <api_drv_video.h>
-#include <errno.h>
-#include <semaphore.h>
-
-// === CONSTANTS ===
-#define VERSION        ((0<<8)|(50))
-
-#define        NUM_VTS 8
-//#define DEFAULT_OUTPUT       "BochsGA"
-#define DEFAULT_OUTPUT "Vesa"
-#define FALLBACK_OUTPUT        "x86_VGAText"
-#define DEFAULT_INPUT  "PS2Keyboard"
-#define        DEFAULT_WIDTH   640
-#define        DEFAULT_HEIGHT  480
-#define DEFAULT_SCROLLBACK     2       // 2 Screens of text + current screen
-//#define DEFAULT_SCROLLBACK   0
-
-// === TYPES ===
-
-// === IMPORTS ===
-extern void    Debug_SetKTerminal(const char *File);
-
-// === PROTOTYPES ===
- int   VT_Install(char **Arguments);
-char   *VT_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *VT_FindDir(tVFS_Node *Node, const char *Name);
- int   VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
-Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
- int   VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data);
-
-// === CONSTANTS ===
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_INPUT, NULL);
-tVFS_NodeType  gVT_RootNodeType = {
-       .TypeName = "VTerm Root",
-       .ReadDir = VT_ReadDir,
-       .FindDir = VT_FindDir,
-       .IOCtl = VT_Root_IOCtl
-       };
-tVFS_NodeType  gVT_TermNodeType = {
-       .TypeName = "VTerm",
-       .Read = VT_Read,
-       .Write = VT_Write,
-       .IOCtl = VT_Terminal_IOCtl
-       };
-tDevFS_Driver  gVT_DrvInfo = {
-       NULL, "VTerm",
-       {
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Size = NUM_VTS,
-       .Inode = -1,
-       .NumACLs = 0,
-       .Type = &gVT_RootNodeType
-       }
-};
-// --- Terminals ---
-tVTerm gVT_Terminals[NUM_VTS];
- int   giVT_CurrentTerminal = 0;
-tVTerm *gpVT_CurTerm = &gVT_Terminals[0];
-// --- Video State ---
-short  giVT_RealWidth  = DEFAULT_WIDTH;        //!< Screen Width
-short  giVT_RealHeight = DEFAULT_HEIGHT;       //!< Screen Height
- int   giVT_Scrollback = DEFAULT_SCROLLBACK;
-// --- Driver Handles ---
-char   *gsVT_OutputDevice = NULL;
-char   *gsVT_InputDevice = NULL;
- int   giVT_OutputDevHandle = -2;
- int   giVT_InputDevHandle = -2;
-
-// === CODE ===
-/**
- * \fn int VT_Install(char **Arguments)
- * \brief Installs the Virtual Terminal Driver
- */
-int VT_Install(char **Arguments)
-{
-        int    i;
-       
-       // Scan Arguments
-       if(Arguments)
-       {
-               char    **args;
-               const char      *arg;
-               for(args = Arguments; (arg = *args); args++ )
-               {
-                       char    data[strlen(arg)+1];
-                       char    *opt = data;
-                       char    *val;
-                       
-                       val = strchr(arg, '=');
-                       strcpy(data, arg);
-                       if( val ) {
-                               data[ val - arg ] = '\0';
-                               val ++;
-                       }
-                       Log_Debug("VTerm", "Argument '%s'", arg);
-                       
-                       if( strcmp(opt, "Video") == 0 ) {
-                               if( !gsVT_OutputDevice )
-                                       gsVT_OutputDevice = strdup(val);
-                       }
-                       else if( strcmp(opt, "Input") == 0 ) {
-                               if( !gsVT_InputDevice )
-                                       gsVT_InputDevice = strdup(val);
-                       }
-                       else if( strcmp(opt, "Width") == 0 ) {
-                               giVT_RealWidth = atoi( val );
-                       }
-                       else if( strcmp(opt, "Height") == 0 ) {
-                               giVT_RealHeight = atoi( val );
-                       }
-                       else if( strcmp(opt, "Scrollback") == 0 ) {
-                               giVT_Scrollback = atoi( val );
-                       }
-               }
-       }
-       
-       // Apply Defaults
-       if(!gsVT_OutputDevice)  gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
-       else if( Module_EnsureLoaded( gsVT_OutputDevice ) )     gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
-       if( Module_EnsureLoaded( gsVT_OutputDevice ) )  gsVT_OutputDevice = (char*)FALLBACK_OUTPUT;
-       if( Module_EnsureLoaded( gsVT_OutputDevice ) ) {
-               Log_Error("VTerm", "Fallback video '%s' is not avaliable, giving up", FALLBACK_OUTPUT);
-               return MODULE_ERR_MISC;
-       }
-       
-       if(!gsVT_InputDevice)   gsVT_InputDevice = (char*)DEFAULT_INPUT;
-       else if( Module_EnsureLoaded( gsVT_InputDevice ) )      gsVT_InputDevice = (char*)DEFAULT_INPUT;
-       
-       // Create device paths
-       {
-               char    *tmp;
-               tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 );
-               strcpy(tmp, "/Devices/");
-               strcpy(&tmp[9], gsVT_OutputDevice);
-               gsVT_OutputDevice = tmp;
-
-               tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 );
-               strcpy(tmp, "/Devices/");
-               strcpy(&tmp[9], gsVT_InputDevice);
-               gsVT_InputDevice = tmp;
-       }
-       
-       Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice);
-       Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice);
-       
-       VT_InitOutput();
-       VT_InitInput();
-       
-       // Create Nodes
-       for( i = 0; i < NUM_VTS; i++ )
-       {
-               gVT_Terminals[i].Mode = TERM_MODE_TEXT;
-               gVT_Terminals[i].Flags = 0;
-//             gVT_Terminals[i].Flags = VT_FLAG_HIDECSR;       //HACK - Stop all those memcpy calls
-               gVT_Terminals[i].CurColour = DEFAULT_COLOUR;
-               gVT_Terminals[i].WritePos = 0;
-               gVT_Terminals[i].AltWritePos = 0;
-               gVT_Terminals[i].ViewPos = 0;
-               gVT_Terminals[i].ReadingThread = -1;
-               gVT_Terminals[i].ScrollHeight = 0;
-               
-               // Initialise
-               VT_int_ChangeMode( &gVT_Terminals[i],
-                       TERM_MODE_TEXT, giVT_RealWidth, giVT_RealHeight );
-               
-               gVT_Terminals[i].Name[0] = '0'+i;
-               gVT_Terminals[i].Name[1] = '\0';
-               gVT_Terminals[i].Node.Inode = i;
-               gVT_Terminals[i].Node.ImplPtr = &gVT_Terminals[i];
-               gVT_Terminals[i].Node.NumACLs = 0;      // Only root can open virtual terminals
-       
-               gVT_Terminals[i].Node.Type = &gVT_TermNodeType; 
-//             Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
-       }
-       
-       // Add to DevFS
-       DevFS_AddDevice( &gVT_DrvInfo );
-       
-       // Set kernel output to VT0
-       Debug_SetKTerminal("/Devices/VTerm/0");
-       
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Set the video resolution
- * \param Width        New screen width
- * \param Height       New screen height
- */
-void VT_SetResolution(int Width, int Height)
-{
-       tVideo_IOCtl_Mode       mode = {0};
-        int    tmp;
-        int    i;
-       
-       // Create the video mode
-       mode.width = Width;
-       mode.height = Height;
-       mode.bpp = 32;
-       mode.flags = 0;
-       
-       // Set video mode
-       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode );
-       tmp = mode.id;
-       if( Width != mode.width || Height != mode.height )
-       {
-               Log_Warning("VTerm",
-                       "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)",
-                       giVT_RealWidth, giVT_RealHeight,
-                       mode.width, mode.height
-                       );
-               giVT_RealWidth = mode.width;
-               giVT_RealHeight = mode.height;
-       }
-       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp );
-       
-       // Resize text terminals if needed
-       if( gVT_Terminals[0].Text && (giVT_RealWidth != mode.width || giVT_RealHeight != mode.height) )
-       {
-                int    newBufSize = (giVT_RealWidth/giVT_CharWidth)
-                                       *(giVT_RealHeight/giVT_CharHeight)
-                                       *(giVT_Scrollback+1);
-               //tVT_Char      *tmp;
-               // Resize the text terminals
-               Log_Debug("VTerm", "Resizing terminals to %ix%i",
-                       giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight);
-               for( i = 0; i < NUM_VTS; i ++ )
-               {
-                       if( gVT_Terminals[i].Mode != TERM_MODE_TEXT )   continue;
-                       
-                       gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth;
-                       gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight;
-                       gVT_Terminals[i].ScrollHeight = gVT_Terminals[i].TextHeight;
-                       
-                       gVT_Terminals[i].Text = realloc(
-                               gVT_Terminals[i].Text,
-                               newBufSize*sizeof(tVT_Char)
-                               );
-               }
-       }
-}
-
-/**
- * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
- * \brief Read from the VTerm Directory
- */
-char *VT_ReadDir(tVFS_Node *Node, int Pos)
-{
-       if(Pos < 0)     return NULL;
-       if(Pos >= NUM_VTS)      return NULL;
-       return strdup( gVT_Terminals[Pos].Name );
-}
-
-/**
- * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name)
- * \brief Find an item in the VTerm directory
- * \param Node Root node
- * \param Name Name (number) of the terminal
- */
-tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name)
-{
-        int    num;
-       
-       ENTER("pNode sName", Node, Name);
-       
-       // Open the input and output files if needed
-       if(giVT_OutputDevHandle == -2)  VT_InitOutput();
-       if(giVT_InputDevHandle == -2)   VT_InitInput();
-       
-       // Sanity check name
-       if(Name[0] < '0' || Name[0] > '9' || Name[1] != '\0') {
-               LEAVE('n');
-               return NULL;
-       }
-       // Get index
-       num = Name[0] - '0';
-       if(num >= NUM_VTS) {
-               LEAVE('n');
-               return NULL;
-       }
-       // Return node
-       LEAVE('p', &gVT_Terminals[num].Node);
-       return &gVT_Terminals[num].Node;
-}
-
-/**
- * \fn int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief Control the VTerm Driver
- */
-int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
-        int    len;
-       switch(Id)
-       {
-       case DRV_IOCTL_TYPE:    return DRV_TYPE_MISC;
-       case DRV_IOCTL_IDENT:   memcpy(Data, "VT\0\0", 4);      return 0;
-       case DRV_IOCTL_VERSION: return VERSION;
-       case DRV_IOCTL_LOOKUP:  return 0;
-       
-       case 4: // Get Video Driver
-               if(Data)        strcpy(Data, gsVT_OutputDevice);
-               return strlen(gsVT_OutputDevice);
-       
-       case 5: // Set Video Driver
-               if(!Data)       return -EINVAL;
-               if(Threads_GetUID() != 0)       return -EACCES;
-               
-               len = strlen(Data);
-               
-               // TODO: Check if the string used is a heap string
-               
-               free(gsVT_OutputDevice);
-               
-               gsVT_OutputDevice = malloc(len+1);
-               strcpy(gsVT_OutputDevice, Data);
-               
-               VFS_Close(giVT_OutputDevHandle);
-               giVT_OutputDevHandle = -1;
-               
-               VT_InitOutput();
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * \brief Read from a virtual terminal
- */
-Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-        int    pos = 0;
-        int    avail;
-       tVTerm  *term = &gVT_Terminals[ Node->Inode ];
-       Uint32  *codepoint_buf = Buffer;
-       Uint32  *codepoint_in;
-       
-       Mutex_Acquire( &term->ReadingLock );
-       
-       // Check current mode
-       switch(term->Mode)
-       {
-       // Text Mode (UTF-8)
-       case TERM_MODE_TEXT:
-               VT_int_UpdateCursor(term, 1);
-       
-               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UTF-8)");
-               
-               avail = term->InputWrite - term->InputRead;
-               if(avail < 0)
-                       avail += MAX_INPUT_CHARS8;
-               if(avail > Length - pos)
-                       avail = Length - pos;
-               
-               while( avail -- )
-               {
-                       ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead];
-                       pos ++;
-                       term->InputRead ++;
-                       while(term->InputRead >= MAX_INPUT_CHARS8)
-                               term->InputRead -= MAX_INPUT_CHARS8;
-               }
-               break;
-       
-       //case TERM_MODE_FB:
-       // Other - UCS-4
-       default:
-               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)");
-               
-               avail = term->InputWrite - term->InputRead;
-               if(avail < 0)
-                       avail += MAX_INPUT_CHARS32;
-               Length /= 4;
-               if(avail > Length - pos)
-                       avail = Length - pos;
-               
-               codepoint_in = (void*)term->InputBuffer;
-               codepoint_buf = Buffer;
-               
-               while( avail -- )
-               {
-                       codepoint_buf[pos] = codepoint_in[term->InputRead];
-                       pos ++;
-                       term->InputRead ++;
-                       while(term->InputRead >= MAX_INPUT_CHARS32)
-                               term->InputRead -= MAX_INPUT_CHARS32;
-               }
-               pos *= 4;
-               break;
-       }
-       
-       // Mark none avaliable if buffer empty
-       if( term->InputRead == term->InputWrite )
-               VFS_MarkAvaliable(&term->Node, 0);
-       
-       term->ReadingThread = -1;
-
-//     VT_int_UpdateCursor(term, term->Mode == TERM_MODE_TEXT);
-
-       Mutex_Release( &term->ReadingLock );
-       
-       return pos;
-}
-
-/**
- * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
- * \brief Write to a virtual terminal
- */
-Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tVTerm  *term = &gVT_Terminals[ Node->Inode ];
-        int    size;
-       
-       // Write
-       switch( term->Mode )
-       {
-       // Print Text
-       case TERM_MODE_TEXT:
-               VT_int_PutString(term, Buffer, Length);
-               break;
-       
-       // Framebuffer :)
-       case TERM_MODE_FB:
-               // - Sanity Checking
-               size = term->Width*term->Height*4;
-               if( Offset > size ) {
-                       Log_Notice("VTerm", "VT_Write: Offset (0x%llx) > FBSize (0x%x)",
-                               Offset, size);
-                       return 0;
-               }
-               if( Offset + Length > size ) {
-                       Log_Notice("VTerm", "VT_Write: Offset+Length (0x%llx) > FBSize (0x%x)",
-                               Offset+Length, size);
-                       Length = size - Offset;
-               }
-               
-               // Update screen if needed
-               if( Node->Inode == giVT_CurrentTerminal )
-               {
-                       if( giVT_RealHeight > term->Height )
-                               Offset += (giVT_RealHeight - term->Height) / 2 * term->Width * 4;
-                       // Handle undersized virtual terminals
-                       if( giVT_RealWidth > term->Width )
-                       {
-                               // No? :( Well, just center it
-                                int    x, y, w, h;
-                               Uint    dst_ofs;
-                               // TODO: Fix to handle the final line correctly?
-                               x = Offset/4;   y = x / term->Width;    x %= term->Width;
-                               w = Length/4+x; h = w / term->Width;    w %= term->Width;
-                               
-                               // Center
-                               x += (giVT_RealWidth - term->Width) / 2;
-                               dst_ofs = (x + y * giVT_RealWidth) * 4;
-                               while(h--)
-                               {
-                                       VFS_WriteAt( giVT_OutputDevHandle,
-                                               dst_ofs,
-                                               term->Width * 4,
-                                               Buffer
-                                               );
-                                       Buffer = (void*)( (Uint)Buffer + term->Width*4 );
-                                       dst_ofs += giVT_RealWidth * 4;
-                               }
-                               return 0;
-                       }
-                       else
-                       {
-                               return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer );
-                       }
-               }
-               else
-               {
-                       if( !term->Buffer )
-                               term->Buffer = malloc( term->Width * term->Height * 4 );
-                       // Copy to the local cache
-                       memcpy( (char*)term->Buffer + (Uint)Offset, Buffer, Length );
-               }
-               break;
-       // Just pass on (for now)
-       // TODO: Handle locally too to ensure no information is lost on
-       //       VT Switch (and to isolate terminals from each other)
-       case TERM_MODE_2DACCEL:
-       //case TERM_MODE_3DACCEL:
-               if( Node->Inode == giVT_CurrentTerminal )
-               {
-                       VFS_Write( giVT_OutputDevHandle, Length, Buffer );
-               }
-               break;
-       }
-       
-       return 0;
-}
-
-/**
- * \fn int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief Call an IO Control on a virtual terminal
- */
-int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
-        int    *iData = Data;
-        int    ret;
-       tVTerm  *term = Node->ImplPtr;
-       ENTER("pNode iId pData", Node, Id, Data);
-       
-       if(Id >= DRV_IOCTL_LOOKUP) {
-               // Only root can fiddle with graphics modes
-               // TODO: Remove this and replace with user ownership
-               if( Threads_GetUID() != 0 )     return -1;
-       }
-       
-       switch(Id)
-       {
-       // --- Core Defined
-       case DRV_IOCTL_TYPE:
-               LEAVE('i', DRV_TYPE_TERMINAL);
-               return DRV_TYPE_TERMINAL;
-       case DRV_IOCTL_IDENT:
-               memcpy(Data, "VT\0\0", 4);
-               LEAVE('i', 0);
-               return 0;
-       case DRV_IOCTL_VERSION:
-               LEAVE('x', VERSION);
-               return VERSION;
-       case DRV_IOCTL_LOOKUP:
-               LEAVE('i', 0);
-               return 0;
-       
-       // Get/Set the mode (and apply any changes)
-       case TERM_IOCTL_MODETYPE:
-               if(Data != NULL)
-               {
-                       if( CheckMem(Data, sizeof(int)) == 0 ) {
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-                       Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData);
-                       
-                       // Update mode if needed
-                       if( term->Mode != *iData || term->NewWidth || term->NewHeight)
-                       {
-                               // Adjust for text mode
-                               if( *iData == TERM_MODE_TEXT ) {
-                                       term->NewHeight *= giVT_CharHeight;
-                                       term->NewWidth *= giVT_CharWidth;
-                               }
-                               // Fill unchanged dimensions
-                               if(term->NewHeight == 0)        term->NewHeight = term->Height;
-                               if(term->NewWidth == 0) term->NewWidth = term->Width;
-                               // Set new mode
-                               VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight);
-                               // Clear unapplied dimensions
-                               term->NewWidth = 0;
-                               term->NewHeight = 0;
-                       }
-                       
-                       // Update the screen dimensions
-                       if(Node->Inode == giVT_CurrentTerminal)
-                               VT_SetTerminal( giVT_CurrentTerminal );
-               }
-               LEAVE('i', term->Mode);
-               return term->Mode;
-       
-       // Get/set the terminal width
-       case TERM_IOCTL_WIDTH:
-               if(Data != NULL) {
-                       if( CheckMem(Data, sizeof(int)) == 0 ) {
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-                       term->NewWidth = *iData;
-               }
-               if( term->NewWidth )
-                       ret = term->NewWidth;
-               else if( term->Mode == TERM_MODE_TEXT )
-                       ret = term->TextWidth;
-               else
-                       ret = term->Width;
-               LEAVE('i', ret);
-               return ret;
-       
-       // Get/set the terminal height
-       case TERM_IOCTL_HEIGHT:
-               if(Data != NULL) {
-                       if( CheckMem(Data, sizeof(int)) == 0 ) {
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-                       term->NewHeight = *iData;
-               }
-               if( term->NewHeight )
-                       ret = term->NewHeight;
-               else if( term->Mode == TERM_MODE_TEXT )
-                       ret = term->TextHeight;
-               else
-                       ret = term->Height;
-               LEAVE('i', ret);
-               return ret;
-       
-       case TERM_IOCTL_FORCESHOW:
-               Log_Log("VTerm", "Thread %i forced VTerm %i to be shown",
-                       Threads_GetTID(), (int)Node->Inode);
-               VT_SetTerminal( Node->Inode );
-               LEAVE('i', 1);
-               return 1;
-       
-       case TERM_IOCTL_GETSETCURSOR:
-               if(Data != NULL)
-               {
-                       tVideo_IOCtl_Pos        *pos = Data;
-                       if( !CheckMem(Data, sizeof(*pos)) ) {
-                               errno = -EINVAL;
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-               
-                       if( term->Mode == TERM_MODE_TEXT )
-                       {
-                               if(term->Flags & VT_FLAG_ALTBUF)
-                                       term->AltWritePos = pos->x + pos->y * term->TextWidth;
-                               else
-                                       term->WritePos = pos->x + pos->y * term->TextWidth + term->ViewPos;
-                               VT_int_UpdateCursor(term, 0);
-                       }
-                       else
-                       {
-                               term->VideoCursorX = pos->x;
-                               term->VideoCursorY = pos->y;
-                               VT_int_UpdateCursor(term, 1);
-                       }
-               }
-               ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos;
-               LEAVE('i', ret);
-               return ret;
-
-       case TERM_IOCTL_SETCURSORBITMAP: {
-               tVideo_IOCtl_Bitmap     *bmp = Data;
-               if( Data == NULL )
-               {
-                       free( term->VideoCursor );
-                       term->VideoCursor = NULL;
-                       LEAVE('i', 0);
-                       return 0;
-               }
-
-               // Sanity check bitmap
-               if( !CheckMem(bmp, sizeof(tVideo_IOCtl_Bitmap)) ) {
-                       Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
-                       errno = -EINVAL;
-                       LEAVE_RET('i', -1);
-               }
-               if( !CheckMem(bmp->Data, bmp->W*bmp->H*sizeof(Uint32)) ) {
-                       Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
-                       errno = -EINVAL;
-                       LEAVE_RET('i', -1);
-               }
-
-               // Reallocate if needed
-               if(term->VideoCursor)
-               {
-                       if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) {
-                               free(term->VideoCursor);
-                               term->VideoCursor = NULL;
-                       }
-               }
-               if(!term->VideoCursor) {
-                       term->VideoCursor = malloc(sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
-                       if(!term->VideoCursor) {
-                               Log_Error("VTerm", "Unable to allocate memory for cursor");
-                               errno = -ENOMEM;
-                               LEAVE_RET('i', -1);
-                       }
-               }
-               
-               memcpy(term->VideoCursor, bmp, sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
-       
-               Log_Debug("VTerm", "Set VT%i's cursor to %p %ix%i",
-                       (int)term->Node.Inode, bmp, bmp->W, bmp->H);
-
-               if(gpVT_CurTerm == term)
-                       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, term->VideoCursor);
-       
-               LEAVE('i', 0);
-               return 0; }
-       }
-       LEAVE('i', -1);
-       return -1;
-}
-
-/**
- * \fn void VT_SetTerminal(int ID)
- * \brief Set the current terminal
- */
-void VT_SetTerminal(int ID)
-{
-       // Copy the screen state
-       if( ID != giVT_CurrentTerminal && gpVT_CurTerm->Mode != TERM_MODE_TEXT )
-       {
-               if( !gpVT_CurTerm->Buffer )
-                       gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 );
-               if( gpVT_CurTerm->Width < giVT_RealWidth )
-               {
-                        int    line;
-                       Uint    ofs = 0;
-                       Uint32  *dest = gpVT_CurTerm->Buffer;
-                       // Slower scanline copy
-                       for( line = 0; line < gpVT_CurTerm->Height; line ++ )
-                       {
-                               VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest);
-                               ofs += giVT_RealWidth * 4;
-                               dest += gpVT_CurTerm->Width;
-                       }
-               }
-               else
-               {
-                       VFS_ReadAt(giVT_OutputDevHandle,
-                               0, gpVT_CurTerm->Height*giVT_RealWidth*4,
-                               gpVT_CurTerm->Buffer
-                               );
-               }
-       }
-
-       // Update current terminal ID
-       Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID);
-       giVT_CurrentTerminal = ID;
-       gpVT_CurTerm = &gVT_Terminals[ID];
-       
-       if( gpVT_CurTerm->Mode == TERM_MODE_TEXT )
-       {
-               VT_SetMode( VIDEO_BUFFMT_TEXT );
-       }
-       else
-       {
-               // Update the cursor image
-               if(gpVT_CurTerm->VideoCursor)
-                       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor);
-               VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER );
-       }
-       
-       if(gpVT_CurTerm->Buffer)
-       {
-               // TODO: Handle non equal sized
-               VFS_WriteAt(
-                       giVT_OutputDevHandle,
-                       0,
-                       gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32),
-                       gpVT_CurTerm->Buffer
-                       );
-       }
-       
-       VT_int_UpdateCursor(gpVT_CurTerm, 1);
-       // Update the screen
-       VT_int_UpdateScreen(gpVT_CurTerm, 1);
-}
diff --git a/Kernel/drv/vterm.h b/Kernel/drv/vterm.h
deleted file mode 100644 (file)
index cd37ebd..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv/vterm.h
- * - Virtual Terminal - Common
- */
-#ifndef _VTERM_H_
-#define _VTERM_H_
-
-#include <acess.h>
-#include <api_drv_video.h>     // tVT_Char
-#include <api_drv_terminal.h>
-#include <vfs.h>
-
-// === CONSTANTS ===
-#define MAX_INPUT_CHARS32      64
-#define MAX_INPUT_CHARS8       (MAX_INPUT_CHARS32*4)
-#define        DEFAULT_COLOUR  (VT_COL_BLACK|(0xAAA<<16))
-
-/**
- * \{
- */
-#define        VT_FLAG_HIDECSR 0x01    //!< Hide the cursor
-#define        VT_FLAG_ALTBUF  0x02    //!< Alternate screen buffer
-#define VT_FLAG_RAWIN  0x04    //!< Don't handle ^Z/^C/^V
-#define        VT_FLAG_HASFB   0x10    //!< Set if the VTerm has requested the Framebuffer
-#define VT_FLAG_SHOWCSR        0x20    //!< Always show the text cursor
-/**
- * \}
- */
-
-enum eVT_InModes {
-       VT_INMODE_TEXT8,        // UTF-8 Text Mode (VT100/xterm Emulation)
-       VT_INMODE_TEXT32,       // UTF-32 Text Mode (Acess Native)
-       NUM_VT_INMODES
-};
-
-
-// === TYPES ==
-typedef struct sVTerm  tVTerm;
-
-// === STRUCTURES ===
-struct sVTerm
-{
-        int    Mode;   //!< Current Mode (see ::eTplTerminal_Modes)
-        int    Flags;  //!< Flags (see VT_FLAG_*)
-       
-       short   NewWidth;       //!< Un-applied dimensions (Width)
-       short   NewHeight;      //!< Un-applied dimensions (Height)
-       short   Width;  //!< Virtual Width
-       short   Height; //!< Virtual Height
-       short   TextWidth;      //!< Text Virtual Width
-       short   TextHeight;     //!< Text Virtual Height
-       
-       Uint32  CurColour;      //!< Current Text Colour
-       
-        int    ViewPos;        //!< View Buffer Offset (Text Only)
-        int    WritePos;       //!< Write Buffer Offset (Text Only)
-       tVT_Char        *Text;
-       
-       tVT_Char        *AltBuf;        //!< Alternate Screen Buffer
-        int    AltWritePos;    //!< Alternate write position
-       short   ScrollTop;      //!< Top of scrolling region (smallest)
-       short   ScrollHeight;   //!< Length of scrolling region
-
-        int    VideoCursorX;
-        int    VideoCursorY;
-       
-       tMutex  ReadingLock;    //!< Lock the VTerm when a process is reading from it
-       tTID    ReadingThread;  //!< Owner of the lock
-        int    InputRead;      //!< Input buffer read position
-        int    InputWrite;     //!< Input buffer write position
-       char    InputBuffer[MAX_INPUT_CHARS8];
-//     tSemaphore      InputSemaphore;
-       
-       Uint32          *Buffer;
-
-       // TODO: Do I need to keep this about?
-       // When should it be deallocated? on move to text mode, or some other time
-       // Call set again, it's freed, and if NULL it doesn't get reallocated.
-       tVideo_IOCtl_Bitmap     *VideoCursor;
-       
-       char    Name[2];        //!< Name of the terminal
-       tVFS_Node       Node;
-};
-
-// === GOBALS ===
-extern tVTerm  *gpVT_CurTerm;
-extern int     giVT_Scrollback;
-extern short   giVT_RealWidth; //!< Screen Width
-extern short   giVT_RealHeight;        //!< Screen Width
-extern char    *gsVT_OutputDevice;
-extern char    *gsVT_InputDevice;
-extern int     giVT_OutputDevHandle;
-extern int     giVT_InputDevHandle;
-
-// === FUNCTIONS ===
-extern void    VT_SetResolution(int Width, int Height);
-extern void    VT_SetTerminal(int ID);
-// --- Output ---
-extern void    VT_InitOutput(void);
-extern void    VT_SetMode(int Mode);
-extern void    VT_int_ScrollFramebuffer( tVTerm *Term, int Count );
-extern void    VT_int_UpdateCursor( tVTerm *Term, int bShow );
-extern void    VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
-// --- Input ---
-extern void    VT_InitInput(void);
-extern void    VT_KBCallBack(Uint32 Codepoint);
-// --- VT100 Emulation ---
-extern void    VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args);
-extern int     VT_int_ParseEscape(tVTerm *Term, const char *Buffer);
-// --- Terminal Buffer ---
-extern void    VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count);
-extern void    VT_int_PutChar(tVTerm *Term, Uint32 Ch);
-extern void    VT_int_ScrollText(tVTerm *Term, int Count);
-extern void    VT_int_ClearLine(tVTerm *Term, int Num);
-extern void    VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight);
-extern void    VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
-
-#endif
-
diff --git a/Kernel/drv/vterm_font.c b/Kernel/drv/vterm_font.c
deleted file mode 100644 (file)
index 841ea50..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv/vterm_font.c
- * - Virtual Terminal - Font rendering code
- */
-#include "vterm.h"
-#include <api_drv_terminal.h>
-
-// ---
-// Font Render
-// ---
-#define MONOSPACE_FONT 10816
-
-#if MONOSPACE_FONT == 10808    // 8x8
-# include "vterm_font_8x8.h"
-#elif MONOSPACE_FONT == 10816  // 8x16
-# include "vterm_font_8x16.h"
-#endif
-
-// === PROTOTYPES ===
-Uint8  *VT_Font_GetChar(Uint32 Codepoint);
-
-// === GLOBALS ===
-int    giVT_CharWidth = FONT_WIDTH;
-int    giVT_CharHeight = FONT_HEIGHT;
-
-// === CODE ===
-/**
- * \brief Render a font character
- */
-void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC)
-{
-       Uint8   *font;
-        int    x, y;
-       
-       // 8-bpp and below
-       if( Depth <= 8 )
-       {
-               Uint8   *buf = Buffer;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               if(*font & (1 << (FONT_WIDTH-x-1)))
-                                       buf[x] = FGC;
-                               else
-                                       buf[x] = BGC;
-                       }
-                       buf = (void*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-       // 16-bpp and below
-       else if( Depth <= 16 )
-       {
-               Uint16  *buf = Buffer;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               if(*font & (1 << (FONT_WIDTH-x-1)))
-                                       buf[x] = FGC;
-                               else
-                                       buf[x] = BGC;
-                       }
-                       buf = (void*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-       // 24-bpp colour
-       // - Special handling to not overwrite the next pixel
-       //TODO: Endian issues here
-       else if( Depth == 24 )
-       {
-               Uint8   *buf = Buffer;
-               Uint8   bg_r = (BGC >> 16) & 0xFF;
-               Uint8   bg_g = (BGC >>  8) & 0xFF;
-               Uint8   bg_b = (BGC >>  0) & 0xFF;
-               Uint8   fg_r = (FGC >> 16) & 0xFF;
-               Uint8   fg_g = (FGC >>  8) & 0xFF;
-               Uint8   fg_b = (FGC >>  0) & 0xFF;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               Uint8   r, g, b;
-                               
-                               if(*font & (1 << (FONT_WIDTH-x-1))) {
-                                       r = fg_r;       g = fg_g;       b = fg_b;
-                               }
-                               else {
-                                       r = bg_r;       g = bg_g;       b = bg_b;
-                               }
-                               buf[x*3+0] = b;
-                               buf[x*3+1] = g;
-                               buf[x*3+2] = r;
-                       }
-                       buf = (void*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-       // 32-bpp colour (nice and easy)
-       else if( Depth == 32 )
-       {
-               Uint32  *buf = Buffer;
-               
-               font = VT_Font_GetChar(Codepoint);
-               
-               for(y = 0; y < FONT_HEIGHT; y ++)
-               {
-                       for(x = 0; x < FONT_WIDTH; x ++)
-                       {
-                               if(*font & (1 << (FONT_WIDTH-x-1)))
-                                       buf[x] = FGC;
-                               else
-                                       buf[x] = BGC;
-                       }
-                       buf = (Uint32*)( (tVAddr)buf + Pitch );
-                       font ++;
-               }
-       }
-}
-
-/**
- * \fn Uint32 VT_Colour12to24(Uint16 Col12)
- * \brief Converts a 12-bit colour into 24 bits
- */
-Uint32 VT_Colour12to24(Uint16 Col12)
-{
-       Uint32  ret;
-        int    tmp;
-       tmp = Col12 & 0xF;
-       ret  = (tmp << 0) | (tmp << 4);
-       tmp = (Col12 & 0xF0) >> 4;
-       ret |= (tmp << 8) | (tmp << 12);
-       tmp = (Col12 & 0xF00) >> 8;
-       ret |= (tmp << 16) | (tmp << 20);
-       return ret;
-}
-/**
- * \brief Converts a 12-bit colour into 15 bits
- */
-Uint16 VT_Colour12to15(Uint16 Col12)
-{
-       Uint32  ret;
-        int    tmp;
-       tmp = Col12 & 0xF;
-       ret  = (tmp << 1) | (tmp & 1);
-       tmp = (Col12 & 0xF0) >> 4;
-       ret |= ( (tmp << 1) | (tmp & 1) ) << 5;
-       tmp = (Col12 & 0xF00) >> 8;
-       ret |= ( (tmp << 1) | (tmp & 1) ) << 10;
-       return ret;
-}
-
-/**
- * \brief Converts a 12-bit colour into any other depth
- * \param Col12        12-bit source colour
- * \param Depth        Desired bit deptj
- * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5)
- */
-Uint32 VT_Colour12toN(Uint16 Col12, int Depth)
-{
-       Uint32  ret;
-       Uint32  r, g, b;
-        int    rSize, gSize, bSize;
-       
-       // Fast returns
-       if( Depth == 24 )       return VT_Colour12to24(Col12);
-       if( Depth == 15 )       return VT_Colour12to15(Col12);
-       // - 32 is a special case, it's usually 24-bit colour with an unused byte
-       if( Depth == 32 )       return VT_Colour12to24(Col12);
-       
-       // Bounds checks
-       if( Depth < 8 ) return 0;
-       if( Depth > 32 )        return 0;
-       
-       r = Col12 & 0xF;
-       g = (Col12 & 0xF0) >> 4;
-       b = (Col12 & 0xF00) >> 8;
-       
-       rSize = gSize = bSize = Depth / 3;
-       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 1
-               gSize ++;
-       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 2
-               bSize ++;
-       
-       // Expand
-       r <<= rSize - 4;        g <<= gSize - 4;        b <<= bSize - 4;
-       // Fill with the lowest bit
-       if( Col12 & 0x001 )     r |= (1 << (rSize - 4)) - 1;
-       if( Col12 & 0x010 )     r |= (1 << (gSize - 4)) - 1;
-       if( Col12 & 0x100 )     r |= (1 << (bSize - 4)) - 1;
-       
-       // Create output
-       ret  = r;
-       ret |= g << rSize;
-       ret |= b << (rSize + gSize);
-       
-       return ret;
-}
-
-/**
- * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)
- * \brief Gets an index into the font array given a Unicode Codepoint
- * \note See http://en.wikipedia.org/wiki/CP437
- */
-Uint8 *VT_Font_GetChar(Uint32 Codepoint)
-{
-        int    index = 0;
-       if(Codepoint < 128)
-               return &VTermFont[Codepoint*FONT_HEIGHT];
-       switch(Codepoint)
-       {
-       case 0xC7:      index = 128;    break;  // Ã‡
-       case 0xFC:      index = 129;    break;  // Ã¼
-       case 0xE9:      index = 130;    break;  // Ã©
-       case 0xE2:      index = 131;    break;  // Ã¢
-       case 0xE4:      index = 132;    break;  // Ã¤
-       case 0xE0:      index = 133;    break;  // Ã 
-       case 0xE5:      index = 134;    break;  // Ã¥
-       case 0xE7:      index = 135;    break;  // Ã§
-       case 0xEA:      index = 136;    break;  // Ãª
-       case 0xEB:      index = 137;    break;  // Ã«
-       case 0xE8:      index = 138;    break;  // Ã¨
-       case 0xEF:      index = 139;    break;  // Ã¯
-       case 0xEE:      index = 140;    break;  // Ã®
-       case 0xEC:      index = 141;    break;  // Ã¬
-       case 0xC4:      index = 142;    break;  // Ã„
-       case 0xC5:      index = 143;    break;  // Ã…
-       }
-       
-       return &VTermFont[index*FONT_HEIGHT];
-}
-
-EXPORTAS(&giVT_CharWidth, giVT_CharWidth);
-EXPORTAS(&giVT_CharHeight, giVT_CharHeight);
-EXPORT(VT_Font_Render);
-EXPORT(VT_Colour12to24);
diff --git a/Kernel/drv/vterm_font_8x16.h b/Kernel/drv/vterm_font_8x16.h
deleted file mode 100644 (file)
index 7c61332..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
- * Altered for Acess2
- */
-#define FONT_WIDTH     8
-#define FONT_HEIGHT    16
-static Uint8 VTermFont[256*16]=
-{
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
-       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
-       0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
-       0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
-       0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
-       0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
-       0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
-       0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
-       0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-       0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-       0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
diff --git a/Kernel/drv/vterm_font_8x8.h b/Kernel/drv/vterm_font_8x8.h
deleted file mode 100644 (file)
index 2a5311d..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
- * Altered for Acess2
- */
-#define FONT_WIDTH     8
-#define FONT_HEIGHT    8
-static Uint8 VTermFont[256*8]=
-{
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
-       0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
-       0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
-       0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
-       0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
-       0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
-       0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
-       0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
-       0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
-       0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
-       0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
-       0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
-       0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
-       0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
-       0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
-       0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
-       0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
-       0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
-       0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-       0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
-       0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
-       0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
-       0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
-       0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
-       0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
-       0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
-       0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
-       0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
-       0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
-       0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
-       0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
-       0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
-       0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
-       0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
-       0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-       0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-       0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
-       0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
-       0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
-       0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
-       0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
-       0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
-       0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
-       0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
-       0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
-       0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
-       0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
-       0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
-       0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
-       0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
-       0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
-       0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
-       0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
-       0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
-       0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
-       0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
-       0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
-       0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
-       0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
-       0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
-       0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
-       0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
-       0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
-       0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
-       0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
-       0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
-       0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
-       0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
-       0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
-       0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
-       0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
-       0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
-       0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
-       0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
-       0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
-       0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
-       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
-       0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
-       0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
-       0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
-       0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
-       0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-       0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
-       0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-       0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-       0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
-       0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
-       0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
-       0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
-       0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
-       0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
-       0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
-       0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
-       0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
-       0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
-       0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
-       0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
-       0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
-       0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
-       0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
-       0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
-       0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
-       0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
-       0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
-       0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
-       0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
-       0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
-       0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
-       0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
-       0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
-       0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-       0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
-       0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
-       0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
-       0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
-       0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
-       0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
-       0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
-       0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
-       0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
-       0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
-       0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
-       0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
-       0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
-       0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
-       0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
-       0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
-       0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
-       0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
-       0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
-       0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
-       0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
-       0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
-       0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
-       0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
-       0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
-       0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
-       0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
-       0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
-       0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
-       0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
-       0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
-       0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
-       0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
-       0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-       0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
-       0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
-       0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
-       0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
-       0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
-       0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
-       0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
-       0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
-       0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
-       0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
-       0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
-       0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
-       0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
-       0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
-       0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-       0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
-       0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
-       0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-       0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
-       0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
-       0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
-       0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
-       0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
-       0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
-       0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
-       0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
-       0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
-       0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
-       0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
-       0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
-       0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
-       0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
-       0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
-       0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
-       0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
-       0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
-       0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
-       0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
-       0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
-       0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
-       0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
-       0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-       0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
-       0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
-       0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
diff --git a/Kernel/drv/vterm_input.c b/Kernel/drv/vterm_input.c
deleted file mode 100644 (file)
index d83cede..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv/vterm_input.c
- * - Virtual Terminal - Input code
- */
-#include "vterm.h"
-#include <api_drv_keyboard.h>
-
-// === GLOBALS ===
-// --- Key States --- (Used for VT Switching/Magic Combos)
- int   gbVT_CtrlDown = 0;
- int   gbVT_AltDown = 0;
- int   gbVT_SysrqDown = 0;
-
-// === CODE ===
-/**
- * \fn void VT_InitInput()
- * \brief Initialises the input
- */
-void VT_InitInput()
-{
-       giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
-       if(giVT_InputDevHandle == -1) {
-               Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice);
-               return ;
-       }
-       VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
-}
-
-/**
- * \fn void VT_KBCallBack(Uint32 Codepoint)
- * \brief Called on keyboard interrupt
- * \param Codepoint    Pseudo-UTF32 character
- * 
- * Handles a key press and sends the key code to the user's buffer.
- * If the code creates a kernel-magic sequence, it is not passed to the
- * user and is handled in-kernel.
- */
-void VT_KBCallBack(Uint32 Codepoint)
-{
-       tVTerm  *term = gpVT_CurTerm;
-
-       // Catch VT binds
-       switch( Codepoint & KEY_ACTION_MASK )
-       {
-       case KEY_ACTION_RELEASE:
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               case KEY_LALT:  gbVT_AltDown &= ~1;     break;
-               case KEY_RALT:  gbVT_AltDown &= ~2;     break;
-               case KEY_LCTRL: gbVT_CtrlDown &= ~1;    break;
-               case KEY_RCTRL: gbVT_CtrlDown &= ~2;    break;
-               }
-               break;
-       
-       case KEY_ACTION_PRESS:
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               case KEY_LALT:  gbVT_AltDown |= 1;      break;
-               case KEY_RALT:  gbVT_AltDown |= 2;      break;
-               case KEY_LCTRL: gbVT_CtrlDown |= 1;     break;
-               case KEY_RCTRL: gbVT_CtrlDown |= 2;     break;
-               }
-               
-               if(!gbVT_AltDown || !gbVT_CtrlDown)
-                       break;
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               case KEY_F1:    VT_SetTerminal(0);      return;
-               case KEY_F2:    VT_SetTerminal(1);      return;
-               case KEY_F3:    VT_SetTerminal(2);      return;
-               case KEY_F4:    VT_SetTerminal(3);      return;
-               case KEY_F5:    VT_SetTerminal(4);      return;
-               case KEY_F6:    VT_SetTerminal(5);      return;
-               case KEY_F7:    VT_SetTerminal(6);      return;
-               case KEY_F8:    VT_SetTerminal(7);      return;
-               case KEY_F9:    VT_SetTerminal(8);      return;
-               case KEY_F10:   VT_SetTerminal(9);      return;
-               case KEY_F11:   VT_SetTerminal(10);     return;
-               case KEY_F12:   VT_SetTerminal(11);     return;
-               }
-               
-               // Scrolling is only valid in text mode
-               if(gpVT_CurTerm->Mode != TERM_MODE_TEXT)
-                       break;
-               
-               switch(Codepoint & KEY_CODEPOINT_MASK)
-               {
-               // Scrolling
-               case KEY_PGUP:
-                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
-                               return ;
-                       gpVT_CurTerm->ViewPos = MAX(
-                               0,
-                               gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width
-                               );
-                       return;
-               case KEY_PGDOWN:
-                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
-                               return ;
-                       gpVT_CurTerm->ViewPos = MIN(
-                               gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width,
-                               gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback
-                               );
-                       return;
-               }
-               break;
-       }
-       
-       // Encode key
-       if(term->Mode == TERM_MODE_TEXT)
-       {
-               Uint8   buf[6] = {0};
-                int    len = 0;
-       
-               // Ignore anything that isn't a press or refire
-               if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
-                && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
-                   )
-               {
-                       return ;
-               }
-       
-               Codepoint &= KEY_CODEPOINT_MASK;
-
-               // Ignore Modifer Keys
-               if(Codepoint > KEY_MODIFIERS)   return;
-               
-               // Get UTF-8/ANSI Encoding
-               switch(Codepoint)
-               {
-               // 0: No translation, don't send to user
-               case 0: break;
-               case KEY_LEFT:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
-                       len = 3;
-                       break;
-               case KEY_RIGHT:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
-                       len = 3;
-                       break;
-               case KEY_UP:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
-                       len = 3;
-                       break;
-               case KEY_DOWN:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
-                       len = 3;
-                       break;
-               
-               case KEY_PGUP:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
-                       len = 4;
-                       break;
-               case KEY_PGDOWN:
-                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
-                       len = 4;
-                       break;
-               
-               // Attempt to encode in UTF-8
-               default:
-                       len = WriteUTF8( buf, Codepoint );
-                       if(len == 0) {
-                               Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
-                       }
-                       break;
-               }
-               
-               if(len == 0) {
-                       // Unprintable / Don't Pass
-                       return;
-               }
-
-#if 0
-               // Handle meta characters
-               if( !(term->Flags & VT_FLAG_RAWIN) )
-               {
-                       switch(buf[0])
-                       {
-                       case '\3':      // ^C
-                               
-                               break;
-                       }
-               }
-#endif
-               
-               // Write
-               if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
-                       memcpy( &term->InputBuffer[term->InputWrite], buf, len );
-               else {
-                       memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
-                       memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
-               }
-               // Roll the buffer over
-               term->InputWrite += len;
-               term->InputWrite %= MAX_INPUT_CHARS8;
-               if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
-                       term->InputRead = term->InputWrite + 1;
-                       term->InputRead %= MAX_INPUT_CHARS8;
-               }
-       }
-       else
-       {
-               // Encode the raw key event
-               Uint32  *raw_in = (void*)term->InputBuffer;
-       
-               #if 0
-               // Drop new keys
-               if( term->InputWrite == term->InputRead )
-                       return ;                
-               #endif
-
-               raw_in[ term->InputWrite ] = Codepoint;
-               term->InputWrite ++;
-               if(term->InputWrite >= MAX_INPUT_CHARS32)
-                       term->InputWrite -= MAX_INPUT_CHARS32;
-               
-               #if 1
-               // TODO: Should old or new be dropped?
-               if(term->InputRead == term->InputWrite) {
-                       term->InputRead ++;
-                       if( term->InputRead >= MAX_INPUT_CHARS32 )
-                               term->InputRead -= MAX_INPUT_CHARS32;
-               }
-               #endif
-       }
-       
-       VFS_MarkAvaliable(&term->Node, 1);
-}
-
diff --git a/Kernel/drv/vterm_output.c b/Kernel/drv/vterm_output.c
deleted file mode 100644 (file)
index 95a2bce..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv/vterm_input.c
- * - Virtual Terminal - Input code
- */
-#include "vterm.h"
-#include <api_drv_video.h>
-
-// === CODE ===
-/**
- * \fn void VT_InitOutput()
- * \brief Initialise Video Output
- */
-void VT_InitOutput()
-{
-       giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
-       if(giVT_OutputDevHandle == -1) {
-               Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
-               return ;
-       }
-       VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
-       VT_SetTerminal( 0 );
-       VT_SetMode( VIDEO_BUFFMT_TEXT );
-}
-
-/**
- * \brief Set video output buffer mode
- */
-void VT_SetMode(int Mode)
-{
-       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode );
-}
-
-/**
- * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
- * \note Scrolls the framebuffer down by \a Count text lines
- */
-void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
-{
-        int    tmp;
-       struct {
-               Uint8   Op;
-               Uint16  DstX, DstY;
-               Uint16  SrcX, SrcY;
-               Uint16  W, H;
-       } PACKED        buf;
-       
-       // Only update if this is the current terminal
-       if( Term != gpVT_CurTerm )      return;
-       
-       if( Count > Term->ScrollHeight )        Count = Term->ScrollHeight;
-       if( Count < -Term->ScrollHeight )       Count = -Term->ScrollHeight;
-       
-       // Switch to 2D Command Stream
-       tmp = VIDEO_BUFFMT_2DSTREAM;
-       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
-       
-       // BLIT to 0,0 from 0,giVT_CharHeight
-       buf.Op = VIDEO_2DOP_BLIT;
-       buf.SrcX = 0;   buf.DstX = 0;
-       // TODO: Don't assume character dimensions
-       buf.W = Term->TextWidth * giVT_CharWidth;
-       if( Count > 0 )
-       {
-               buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
-               buf.DstY = Term->ScrollTop * giVT_CharHeight;
-       }
-       else    // Scroll up, move text down
-       {
-               Count = -Count;
-               buf.SrcY = Term->ScrollTop * giVT_CharHeight;
-               buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
-       }
-       buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
-       VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
-       
-       // Restore old mode (this function is only called during text mode)
-       tmp = VIDEO_BUFFMT_TEXT;
-       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
-}
-
-void VT_int_UpdateCursor( tVTerm *Term, int bShow )
-{
-       tVideo_IOCtl_Pos        csr_pos;
-
-       if( Term != gpVT_CurTerm )      return ;
-
-       if( !bShow )
-       {
-               csr_pos.x = -1; 
-               csr_pos.y = -1; 
-       }
-       else if( Term->Mode == TERM_MODE_TEXT )
-       {
-                int    offset;
-               
-//             if( !(Term->Flags & VT_FLAG_SHOWCSR)
-//              && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads)
-//               )
-               if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR )
-               {
-                       csr_pos.x = -1;
-                       csr_pos.y = -1;
-               }
-               else
-               {
-                       if(Term->Flags & VT_FLAG_ALTBUF)
-                               offset = Term->AltWritePos;
-                       else
-                               offset = Term->WritePos - Term->ViewPos;
-                                       
-                       csr_pos.x = offset % Term->TextWidth;
-                       csr_pos.y = offset / Term->TextWidth;
-                       if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight )
-                               csr_pos.y = -1, csr_pos.x = -1;
-               }
-       }
-       else
-       {
-               csr_pos.x = Term->VideoCursorX;
-               csr_pos.y = Term->VideoCursorY;
-       }
-       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
-}      
-
-/**
- * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
- * \brief Updates the video framebuffer
- */
-void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
-{
-       tVT_Char        *buffer;
-        int    view_pos, write_pos;
-       // Only update if this is the current terminal
-       if( Term != gpVT_CurTerm )      return;
-       
-       switch( Term->Mode )
-       {
-       case TERM_MODE_TEXT:
-               view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos;
-               write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
-               buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
-               // Re copy the entire screen?
-               if(UpdateAll) {
-                       VFS_WriteAt(
-                               giVT_OutputDevHandle,
-                               0,
-                               Term->TextWidth*Term->TextHeight*sizeof(tVT_Char),
-                               &buffer[view_pos]
-                               );
-               }
-               // Only copy the current line
-               else {
-                        int    ofs = write_pos - write_pos % Term->TextWidth;
-                       VFS_WriteAt(
-                               giVT_OutputDevHandle,
-                               (ofs - view_pos)*sizeof(tVT_Char),
-                               Term->TextWidth*sizeof(tVT_Char),
-                               &buffer[ofs]
-                               );
-               }
-               break;
-       case TERM_MODE_FB:
-               break;
-       }
-       
-       VT_int_UpdateCursor(Term, 1);
-}
-
diff --git a/Kernel/drv/vterm_termbuf.c b/Kernel/drv/vterm_termbuf.c
deleted file mode 100644 (file)
index 2511048..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv/vterm_termbuf.c
- * - Virtual Terminal - Terminal buffer manipulation
- */
-#include "vterm.h"
-
-// === CODE ===
-
-/**
- * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
- * \brief Print a string to the Virtual Terminal
- */
-void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
-{
-       Uint32  val;
-        int    i;
-       
-       // Iterate
-       for( i = 0; i < Count; i++ )
-       {
-               // Handle escape sequences
-               if( Buffer[i] == 0x1B )
-               {
-                       i ++;
-                       i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
-                       continue;
-               }
-               
-               // Fast check for non UTF-8
-               if( Buffer[i] < 128 )   // Plain ASCII
-                       VT_int_PutChar(Term, Buffer[i]);
-               else {  // UTF-8
-                       i += ReadUTF8(&Buffer[i], &val) - 1;
-                       VT_int_PutChar(Term, val);
-               }
-       }
-       // Update Screen
-       VT_int_UpdateScreen( Term, 0 );
-}
-
-/**
- * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
- * \brief Write a single character to a VTerm
- */
-void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
-{
-        int    i;
-       tVT_Char        *buffer;
-        int    write_pos;
-       
-       if(Term->Flags & VT_FLAG_ALTBUF) {
-               buffer = Term->AltBuf;
-               write_pos = Term->AltWritePos;
-       }
-       else {
-               buffer = Term->Text;
-               write_pos = Term->WritePos;
-       }
-       
-       switch(Ch)
-       {
-       case '\0':      return; // Ignore NULL byte
-       case '\n':
-               VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
-               write_pos += Term->TextWidth;
-       case '\r':
-               write_pos -= write_pos % Term->TextWidth;
-               break;
-       
-       case '\t': { int tmp = write_pos / Term->TextWidth;
-               write_pos %= Term->TextWidth;
-               do {
-                       buffer[ write_pos ].Ch = '\0';
-                       buffer[ write_pos ].Colour = Term->CurColour;
-                       write_pos ++;
-               } while(write_pos & 7);
-               write_pos += tmp * Term->TextWidth;
-               break; }
-       
-       case '\b':
-               // Backspace is invalid at Offset 0
-               if(write_pos == 0)      break;
-               
-               write_pos --;
-               // Singe Character
-               if(buffer[ write_pos ].Ch != '\0') {
-                       buffer[ write_pos ].Ch = 0;
-                       buffer[ write_pos ].Colour = Term->CurColour;
-                       break;
-               }
-               // Tab
-               i = 7;  // Limit it to 8
-               do {
-                       buffer[ write_pos ].Ch = 0;
-                       buffer[ write_pos ].Colour = Term->CurColour;
-                       write_pos --;
-               } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
-               if(buffer[ write_pos ].Ch != '\0')
-                       write_pos ++;
-               break;
-       
-       default:
-               buffer[ write_pos ].Ch = Ch;
-               buffer[ write_pos ].Colour = Term->CurColour;
-               // Update the line before wrapping
-               if( (write_pos + 1) % Term->TextWidth == 0 )
-                       VT_int_UpdateScreen( Term, 0 );
-               write_pos ++;
-               break;
-       }
-       
-       if(Term->Flags & VT_FLAG_ALTBUF)
-       {
-               Term->AltBuf = buffer;
-               Term->AltWritePos = write_pos;
-               
-               if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
-               {
-                       Term->AltWritePos -= Term->TextWidth;
-                       VT_int_ScrollText(Term, 1);
-               }
-               
-       }
-       else
-       {
-               Term->Text = buffer;
-               Term->WritePos = write_pos;
-               // Move Screen
-               // - Check if we need to scroll the entire scrollback buffer
-               if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
-               {
-                        int    base;
-                       
-                       // Update previous line
-                       Term->WritePos -= Term->TextWidth;
-                       VT_int_UpdateScreen( Term, 0 );
-                       
-                       // Update view position
-                       base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
-                       if(Term->ViewPos < base)
-                               Term->ViewPos += Term->Width;
-                       if(Term->ViewPos > base)
-                               Term->ViewPos = base;
-                       
-                       VT_int_ScrollText(Term, 1);
-               }
-               // Ok, so we only need to scroll the screen
-               else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
-               {
-                       // Update the last line
-                       Term->WritePos -= Term->TextWidth;
-                       VT_int_UpdateScreen( Term, 0 );
-                       Term->WritePos += Term->TextWidth;
-                       
-                       VT_int_ScrollText(Term, 1);
-                       
-                       Term->ViewPos += Term->TextWidth;
-               }
-       }
-       
-       //LEAVE('-');
-}
-
-void VT_int_ScrollText(tVTerm *Term, int Count)
-{
-       tVT_Char        *buf;
-        int    height, init_write_pos;
-        int    len, i;
-        int    scroll_top, scroll_height;
-
-       // Get buffer pointer and attributes    
-       if( Term->Flags & VT_FLAG_ALTBUF )
-       {
-               buf = Term->AltBuf;
-               height = Term->TextHeight;
-               init_write_pos = Term->AltWritePos;
-               scroll_top = Term->ScrollTop;
-               scroll_height = Term->ScrollHeight;
-       }
-       else
-       {
-               buf = Term->Text;
-               height = Term->TextHeight*(giVT_Scrollback+1);
-               init_write_pos = Term->WritePos;
-               scroll_top = 0;
-               scroll_height = height;
-       }
-
-       // Scroll text downwards        
-       if( Count > 0 )
-       {
-                int    base;
-       
-               // Set up
-               if(Count > scroll_height)       Count = scroll_height;
-               base = Term->TextWidth*(scroll_top + scroll_height - Count);
-               len = Term->TextWidth*(scroll_height - Count);
-               
-               // Scroll terminal cache
-               memmove(
-                       &buf[Term->TextWidth*scroll_top],
-                       &buf[Term->TextWidth*(scroll_top+Count)],
-                       len*sizeof(tVT_Char)
-                       );
-               // Clear last rows
-               for( i = 0; i < Term->TextWidth*Count; i ++ )
-               {
-                       buf[ base + i ].Ch = 0;
-                       buf[ base + i ].Colour = Term->CurColour;
-               }
-               
-               // Update Screen
-               VT_int_ScrollFramebuffer( Term, Count );
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = base;
-               else
-                       Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
-               for( i = 0; i < Count; i ++ )
-               {
-                       VT_int_UpdateScreen( Term, 0 );
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                               Term->AltWritePos += Term->TextWidth;
-                       else
-                               Term->WritePos += Term->TextWidth;
-               }
-       }
-       else
-       {
-               Count = -Count;
-               if(Count > scroll_height)       Count = scroll_height;
-               
-               len = Term->TextWidth*(scroll_height - Count);
-               
-               // Scroll terminal cache
-               memmove(
-                       &buf[Term->TextWidth*(scroll_top+Count)],
-                       &buf[Term->TextWidth*scroll_top],
-                       len*sizeof(tVT_Char)
-                       );
-               // Clear preceding rows
-               for( i = 0; i < Term->TextWidth*Count; i ++ )
-               {
-                       buf[ i ].Ch = 0;
-                       buf[ i ].Colour = Term->CurColour;
-               }
-               
-               VT_int_ScrollFramebuffer( Term, -Count );
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = Term->TextWidth*scroll_top;
-               else
-                       Term->WritePos = Term->ViewPos;
-               for( i = 0; i < Count; i ++ )
-               {
-                       VT_int_UpdateScreen( Term, 0 );
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                               Term->AltWritePos += Term->TextWidth;
-                       else
-                               Term->WritePos += Term->TextWidth;
-               }
-       }
-       
-       if( Term->Flags & VT_FLAG_ALTBUF )
-               Term->AltWritePos = init_write_pos;
-       else
-               Term->WritePos = init_write_pos;
-}
-
-/**
- * \brief Clears a line in a virtual terminal
- * \param Term Terminal to modify
- * \param Num  Line number to clear
- */
-void VT_int_ClearLine(tVTerm *Term, int Num)
-{
-        int    i;
-       tVT_Char        *cell;
-       
-       if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
-       
-       cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
-       cell = &cell[ Num*Term->TextWidth ];
-       
-       for( i = Term->TextWidth; i--; )
-       {
-               cell[ i ].Ch = 0;
-               cell[ i ].Colour = Term->CurColour;
-       }
-}
-
-/**
- * \brief Update the screen mode
- * \param Term Terminal to update
- * \param NewMode      New mode to set
- * \param NewWidth     New framebuffer width
- * \param NewHeight    New framebuffer height
- */
-void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
-{
-        int    oldW = Term->Width;
-        int    oldTW = Term->TextWidth;
-        int    oldH = Term->Height;
-        int    oldTH = Term->TextHeight;
-       tVT_Char        *oldTBuf = Term->Text;
-       Uint32  *oldFB = Term->Buffer;
-        int    w, h, i;
-       
-       // TODO: Increase RealWidth/RealHeight when this happens
-       if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
-       if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
-       
-       Term->Mode = NewMode;
-
-       // Fast exit if no resolution change
-       if(NewWidth == Term->Width && NewHeight == Term->Height)
-               return ;
-       
-       // Calculate new dimensions
-       Term->Width = NewWidth;
-       Term->Height = NewHeight;
-       Term->TextWidth = NewWidth / giVT_CharWidth;
-       Term->TextHeight = NewHeight / giVT_CharHeight;
-       Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
-       
-       // Allocate new buffers
-       // - Text
-       Term->Text = calloc(
-               Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
-               sizeof(tVT_Char)
-               );
-       if(oldTBuf) {
-               // Copy old buffer
-               w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
-               h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
-               h *= giVT_Scrollback + 1;
-               for( i = 0; i < h; i ++ )
-               {
-                       memcpy(
-                               &Term->Text[i*Term->TextWidth],
-                               &oldTBuf[i*oldTW],
-                               w*sizeof(tVT_Char)
-                               );      
-               }
-               free(oldTBuf);
-       }
-       
-       // - Alternate Text
-       Term->AltBuf = realloc(
-               Term->AltBuf,
-               Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
-               );
-       
-       // - Framebuffer
-       if(oldFB) {
-               Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
-               // Copy old buffer
-               w = (oldW > Term->Width) ? Term->Width : oldW;
-               h = (oldH > Term->Height) ? Term->Height : oldH;
-               for( i = 0; i < h; i ++ )
-               {
-                       memcpy(
-                               &Term->Buffer[i*Term->Width],
-                               &oldFB[i*oldW],
-                               w*sizeof(Uint32)
-                               );
-               }
-               free(oldFB);
-       }
-       
-       // Debug
-       switch(NewMode)
-       {
-       case TERM_MODE_TEXT:
-               Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
-                       Term, Term->TextWidth, Term->TextHeight);
-               break;
-       case TERM_MODE_FB:
-               Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
-                       Term, Term->Width, Term->Height);
-               break;
-       //case TERM_MODE_2DACCEL:
-       //case TERM_MODE_3DACCEL:
-       //      return;
-       }
-}
-
-
-void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
-{      
-       if(Enabled)
-               Term->Flags |= VT_FLAG_ALTBUF;
-       else
-               Term->Flags &= ~VT_FLAG_ALTBUF;
-       VT_int_UpdateScreen(Term, 1);
-}
-
diff --git a/Kernel/drv/vterm_vt100.c b/Kernel/drv/vterm_vt100.c
deleted file mode 100644 (file)
index fb152a3..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv/vterm_vt100.c
- * - Virtual Terminal - VT100 (Kinda) Emulation
- */
-#include "vterm.h"
-
-// === CONSTANTS ===
-const Uint16   caVT100Colours[] = {
-               // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
-               // Same again, but bright
-               VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
-               VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
-       };
-
-// === CODE ===
-/**
- * \brief Handle a standard large escape code
- * 
- * Handles any escape code of the form \x1B[n,...A where n is an integer
- * and A is any letter.
- */
-void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
-{
-        int    tmp = 1;
-       switch(CmdChar)
-       {
-       // Left
-       case 'D':
-               tmp = -1;
-       // Right
-       case 'C':
-               if(argc == 1)   tmp *= args[0];
-               if( Term->Flags & VT_FLAG_ALTBUF )
-               {
-                       if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
-                               Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
-                               Term->AltWritePos += Term->TextWidth - 1;
-                       }
-                       else
-                               Term->AltWritePos += tmp;
-               }
-               else
-               {
-                       if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
-                               Term->WritePos -= Term->WritePos % Term->TextWidth;
-                               Term->WritePos += Term->TextWidth - 1;
-                       }
-                       else
-                               Term->WritePos += tmp;
-               }
-               break;
-       
-       // Erase
-       case 'J':
-               switch(args[0])
-               {
-               case 0: // Erase below
-                       break;
-               case 1: // Erase above
-                       break;
-               case 2: // Erase all
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                                int    i = Term->TextHeight;
-                               while( i-- )    VT_int_ClearLine(Term, i);
-                               Term->AltWritePos = 0;
-                               VT_int_UpdateScreen(Term, 1);
-                       }
-                       else
-                       {
-                                int    i = Term->TextHeight * (giVT_Scrollback + 1);
-                               while( i-- )    VT_int_ClearLine(Term, i);
-                               Term->WritePos = 0;
-                               Term->ViewPos = 0;
-                               VT_int_UpdateScreen(Term, 1);
-                       }
-                       break;
-               }
-               break;
-       
-       // Erase in line
-       case 'K':
-               switch(args[0])
-               {
-               case 0: // Erase to right
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                                int    i, max;
-                               max = Term->Width - Term->AltWritePos % Term->Width;
-                               for( i = 0; i < max; i ++ )
-                                       Term->AltBuf[Term->AltWritePos+i].Ch = 0;
-                       }
-                       else
-                       {
-                                int    i, max;
-                               max = Term->Width - Term->WritePos % Term->Width;
-                               for( i = 0; i < max; i ++ )
-                                       Term->Text[Term->WritePos+i].Ch = 0;
-                       }
-                       VT_int_UpdateScreen(Term, 0);
-                       break;
-               case 1: // Erase to left
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                                int    i = Term->AltWritePos % Term->Width;
-                               while( i -- )
-                                       Term->AltBuf[Term->AltWritePos++].Ch = 0;
-                       }
-                       else
-                       {
-                                int    i = Term->WritePos % Term->Width;
-                               while( i -- )
-                                       Term->Text[Term->WritePos++].Ch = 0;
-                       }
-                       VT_int_UpdateScreen(Term, 0);
-                       break;
-               case 2: // Erase all
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                       {
-                               VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
-                       }
-                       else
-                       {
-                               VT_int_ClearLine(Term, Term->WritePos / Term->Width);
-                       }
-                       VT_int_UpdateScreen(Term, 0);
-                       break;
-               }
-               break;
-       
-       // Set cursor position
-       case 'H':
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
-               else
-                       Term->WritePos = args[0] + args[1]*Term->TextWidth;
-               //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
-               break;
-       
-       // Scroll up `n` lines
-       case 'S':
-               tmp = -1;
-       // Scroll down `n` lines
-       case 'T':
-               if(argc == 1)   tmp *= args[0];
-               if( Term->Flags & VT_FLAG_ALTBUF )
-                       VT_int_ScrollText(Term, tmp);
-               else
-               {
-                       if(Term->ViewPos/Term->TextWidth + tmp < 0)
-                               break;
-                       if(Term->ViewPos/Term->TextWidth + tmp  > Term->TextHeight * (giVT_Scrollback + 1))
-                               break;
-                       
-                       Term->ViewPos += Term->TextWidth*tmp;
-               }
-               break;
-       
-       // Set Font flags
-       case 'm':
-               for( ; argc--; )
-               {
-                        int    colour_idx;
-                       // Flags
-                       if( 0 <= args[argc] && args[argc] <= 8)
-                       {
-                               switch(args[argc])
-                               {
-                               case 0: Term->CurColour = DEFAULT_COLOUR;       break;  // Reset
-                               case 1: Term->CurColour |= 0x80000000;  break;  // Bright
-                               case 2: Term->CurColour &= ~0x80000000; break;  // Dim
-                               }
-                       }
-                       // Foreground Colour
-                       else if(30 <= args[argc] && args[argc] <= 37) {
-                               // Get colour index, accounting for bright bit
-                               colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
-                               Term->CurColour &= 0x8000FFFF;
-                               Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
-                       }
-                       // Background Colour
-                       else if(40 <= args[argc] && args[argc] <= 47) {
-                               // Get colour index, accounting for bright bit
-                               colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
-                               Term->CurColour &= 0xFFFF8000;
-                               Term->CurColour |= caVT100Colours[ colour_idx ];
-                       }
-                       else {
-                               Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
-                       }
-               }
-               break;
-       
-       // Set scrolling region
-       case 'r':
-               if( argc != 2 ) break;
-               Term->ScrollTop = args[0];
-               Term->ScrollHeight = args[1] - args[0];
-               break;
-       
-       default:
-               Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
-               break;
-       }
-}
-
-/**
- * \fn int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
- * \brief Parses a VT100 Escape code
- */
-int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
-{
-       char    c;
-        int    argc = 0, j = 1;
-        int    args[6] = {0,0,0,0};
-        int    bQuestionMark = 0;
-       
-       switch(Buffer[0])
-       {
-       //Large Code
-       case '[':
-               // Get Arguments
-               c = Buffer[j++];
-               if(c == '?') {
-                       bQuestionMark = 1;
-                       c = Buffer[j++];
-               }
-               if( '0' <= c && c <= '9' )
-               {
-                       do {
-                               if(c == ';')    c = Buffer[j++];
-                               while('0' <= c && c <= '9') {
-                                       args[argc] *= 10;
-                                       args[argc] += c-'0';
-                                       c = Buffer[j++];
-                               }
-                               argc ++;
-                       } while(c == ';');
-               }
-               
-               // Get Command
-               if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
-               {
-                       if( bQuestionMark )
-                       {
-                               switch(c)
-                               {
-                               // DEC Private Mode Set
-                               case 'h':
-                                       if(argc != 1)   break;
-                                       switch(args[0])
-                                       {
-                                       case 25:
-                                               Term->Flags &= ~VT_FLAG_HIDECSR;
-                                               break;
-                                       case 1047:
-                                               VT_int_ToggleAltBuffer(Term, 1);
-                                               break;
-                                       }
-                                       break;
-                               case 'l':
-                                       if(argc != 1)   break;
-                                       switch(args[0])
-                                       {
-                                       case 25:
-                                               Term->Flags |= VT_FLAG_HIDECSR;
-                                               break;
-                                       case 1047:
-                                               VT_int_ToggleAltBuffer(Term, 0);
-                                               break;
-                                       }
-                                       break;
-                               default:
-                                       Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
-                                       break;
-                               }
-                       }
-                       else
-                       {
-                               VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
-                       }
-               }
-               break;
-               
-       default:
-               Log_Notice("VTerm", "TODO: Handle short escape codes");
-               break;
-       }
-       
-       //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
-       return j;
-}
diff --git a/Kernel/drvutil.c b/Kernel/drvutil.c
deleted file mode 100644 (file)
index d19a050..0000000
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge
- *
- * drvutil.c
- * - Common Driver/Filesystem Helper Functions
- */
-#define DEBUG  0
-#include <acess.h>
-#include <api_drv_disk.h>
-#include <api_drv_video.h>
-
-// === TYPES ===
-
-// === PROTOTYPES ===
-//int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
-//size_t       DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
-//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
-//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
-void   DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
-//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
-void   DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
-void   DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
-
-// === GLOBALS ===
-tDrvUtil_Video_2DHandlers      gDrvUtil_Stub_2DFunctions = {
-       NULL,
-       DrvUtil_Video_2D_Fill,
-       DrvUtil_Video_2D_Blit
-};
-tVideo_IOCtl_Bitmap    gDrvUtil_TextModeCursor = {
-       8, 16,
-       0, 0,
-       {
-               0, 0, 0         , 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0, 0, 0         , 0, 0, 0, 0, 0,
-               0, 0, 0         , 0, 0, 0, 0, 0
-       }
-};
-
-// === CODE ===
-// --- Video Driver Helpers ---
-int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
-       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
-{
-       const Uint8     *stream = Buffer;
-        int    rem = Length;
-        int    op;
-       while( rem )
-       {
-               rem --;
-               op = *stream;
-               stream ++;
-               
-               if(op > NUM_VIDEO_2DOPS) {
-                       Log_Warning("DrvUtil",
-                               "DrvUtil_Video_2DStream: Unknown operation %i",
-                               op);
-                       return Length-rem;
-               }
-               
-               if(op*sizeof(void*) > SizeofHandlers) {
-                       Log_Warning("DrvUtil",
-                               "DrvUtil_Video_2DStream: Driver does not support op %i",
-                               op);
-                       return Length-rem;
-               }
-               
-               switch(op)
-               {
-               case VIDEO_2DOP_NOP:    break;
-               
-               case VIDEO_2DOP_FILL:
-                       if(rem < 10)    return Length-rem;
-                       
-                       if(!Handlers->Fill) {
-                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
-                                       " does not support VIDEO_2DOP_FILL");
-                               return Length-rem;
-                       }
-                       
-                       Handlers->Fill(
-                               Ent,
-                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
-                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
-                               ((const Uint32*)stream)[4]
-                               );
-                       
-                       rem -= 10;
-                       stream += 10;
-                       break;
-               
-               case VIDEO_2DOP_BLIT:
-                       if(rem < 12)    return Length-rem;
-                       
-                       if(!Handlers->Blit) {
-                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
-                                       " does not support VIDEO_2DOP_BLIT");
-                               return Length-rem;
-                       }
-                       
-                       Handlers->Blit(
-                               Ent,
-                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
-                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
-                               ((const Uint16*)stream)[4], ((const Uint16*)stream)[5]
-                               );
-                       
-                       rem -= 12;
-                       stream += 12;
-                       break;
-               
-               }
-       }
-       return 0;
-}
-
-int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
-{
-       Uint8   *dest;
-       const Uint32    *src = Buffer;
-        int    csr_x, csr_y;
-        int    x, y;
-        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
-       ENTER("pFBInfo xOffset xLength pBuffer",
-               Mode, FBInfo, Offset, Length, Buffer);
-
-       csr_x = FBInfo->CursorX;
-       csr_y = FBInfo->CursorY;
-
-       DrvUtil_Video_RemoveCursor(FBInfo);
-
-       switch( FBInfo->BufferFormat )
-       {
-       case VIDEO_BUFFMT_TEXT:
-               {
-               const tVT_Char  *chars = Buffer;
-                int    widthInChars = FBInfo->Width/giVT_CharWidth;
-                int    heightInChars = FBInfo->Height/giVT_CharHeight;
-                int    i;
-       
-               LOG("bytes_per_px = %i", bytes_per_px);
-               LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
-       
-               Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
-               
-               x = Offset % widthInChars;      y = Offset / widthInChars;
-               LOG("x = %i, y = %i", x, y);    
-       
-               // Sanity Check
-               if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
-               if(y >= heightInChars)  LEAVE_RET('i', 0);
-               
-               if( Offset + Length > heightInChars*widthInChars )
-               {
-                       Length = heightInChars*widthInChars - Offset;
-               }
-               
-               dest = FBInfo->Framebuffer;
-               LOG("dest = %p", dest);
-               dest += y * giVT_CharHeight * FBInfo->Pitch;
-               LOG("dest = %p", dest);
-               
-               for( i = 0; i < Length; i++ )
-               {
-                       if( y >= heightInChars )
-                       {
-                               Log_Notice("DrvUtil", "Stopped at %i", i);
-                               break;
-                       }
-
-                       VT_Font_Render(
-                               chars->Ch,
-                               dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
-                               VT_Colour12toN(chars->BGCol, FBInfo->Depth),
-                               VT_Colour12toN(chars->FGCol, FBInfo->Depth)
-                               );
-                       
-                       chars ++;
-                       x ++;
-                       if( x >= widthInChars )
-                       {
-                               x = 0;
-                               y ++;
-                               dest += FBInfo->Pitch*giVT_CharHeight;
-                               LOG("dest = %p", dest);
-                       }
-               }
-               Length = i * sizeof(tVT_Char);
-               }
-               break;
-       
-       case VIDEO_BUFFMT_FRAMEBUFFER:
-               if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
-               {
-                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
-                       return 0;
-               }
-               
-               switch(FBInfo->Depth)
-               {
-               case 15:
-               case 16:
-                       Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
-                       break;
-               case 24:
-                       x = Offset % FBInfo->Width;
-                       y = Offset / FBInfo->Width;
-                       dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
-                       for( ; Length >= 4; Length -= 4 )
-                       {
-                               dest[x*3+0] = *src & 0xFF;
-                               dest[x*3+1] = (*src >> 8) & 0xFF;
-                               dest[x*3+2] = (*src >> 16) & 0xFF;
-                               x ++;
-                               if(x == FBInfo->Width) {
-                                       dest += FBInfo->Pitch;
-                                       x = 0;
-                               }
-                       }
-                       break;
-               case 32:
-                       // Copy to Frambuffer
-                       if( FBInfo->Pitch != FBInfo->Width*4 )
-                       {
-                               Uint32  *px;
-                               // Pitch isn't 4*Width
-                               x = Offset % FBInfo->Width;
-                               y = Offset / FBInfo->Height;
-                               
-                               px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
-
-                               for( ; Length >= 4; Length -= 4, x )
-                               {
-                                       px[x++] = *src ++;
-                                       if( x == FBInfo->Width ) {
-                                               x = 0;
-                                               px += FBInfo->Pitch;
-                                       }
-                               }
-                       }
-                       else
-                       {
-                               dest = (Uint8 *)FBInfo->Framebuffer + Offset;
-                               memcpy(dest, Buffer, Length);
-                       }
-                       break;
-               default:
-                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
-                       break;
-               }
-               break;
-       
-       case VIDEO_BUFFMT_2DSTREAM:
-               Length = DrvUtil_Video_2DStream(
-                       FBInfo, Buffer, Length,
-                       &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
-                       );
-               break;
-       
-       default:
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
-
-       LEAVE('x', Length);
-       return Length;
-}
-
-int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
-{
-        int    csrX = Buf->CursorX, csrY = Buf->CursorY;
-       size_t  size;
-
-       // Clear old bitmap
-       if( Buf->CursorBitmap )
-       {
-               DrvUtil_Video_RemoveCursor(Buf);
-               if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
-               {
-                       free( Buf->CursorSaveBuf );
-                       Buf->CursorSaveBuf = NULL;
-               }
-               if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
-                       free(Buf->CursorBitmap);
-               Buf->CursorBitmap = NULL;
-       }
-       
-       // If the new bitmap is null, disable drawing
-       if( !Bitmap )
-       {
-               Buf->CursorX = -1;
-               Buf->CursorY = -1;
-               return 0;
-       }
-
-       // Sanity check the bitmap
-       if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
-       {
-               Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
-               errno = -EINVAL;
-               return -1;
-       }
-
-       // Don't take a copy of the DrvUtil provided cursor
-       if( Bitmap == &gDrvUtil_TextModeCursor )
-       {
-               Buf->CursorBitmap = Bitmap;
-       }
-       else
-       {
-               size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
-               
-               // Take a copy
-               Buf->CursorBitmap = malloc( size );
-               memcpy(Buf->CursorBitmap, Bitmap, size);
-       }
-       
-       // Restore cursor position
-       DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
-       return 0;
-}
-
-void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
-{
-        int    render_ox=0, render_oy=0, render_w, render_h;
-
-       DrvUtil_Video_RemoveCursor(Buf);
-
-       // X < 0 disables the cursor
-       if( X < 0 ) {
-               Buf->CursorX = -1;
-               return ;
-       }
-
-       // Sanity checking
-       if( X < 0 || Y < 0 )    return;
-       if( X >= Buf->Width || Y >= Buf->Height )       return;
-
-       // Ensure the cursor is enabled
-       if( !Buf->CursorBitmap )        return ;
-       
-       // Save cursor position (for changing the bitmap)
-       Buf->CursorX = X;       Buf->CursorY = Y;
-
-       // Apply cursor's center offset
-       X -= Buf->CursorBitmap->XOfs;
-       Y -= Buf->CursorBitmap->YOfs;
-       
-       // Get the width of the cursor on screen (clipping to right/bottom edges)
-       render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
-       render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
-
-       // Clipp to left/top edges
-       if(X < 0) {     render_ox = -X; X = 0;  }
-       if(Y < 0) {     render_oy = -Y; Y = 0;  }
-
-       // Save values
-       Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
-       Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
-       Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
-
-       // Call render routine
-       DrvUtil_Video_RenderCursor(Buf);
-}
-
-void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
-{
-        int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
-        int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
-        int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
-        int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       void    *dest;
-       Uint32  *src;
-        int    x, y;
-
-       dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
-       src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
-       
-       // Allocate save buffer if not already
-       if( !Buf->CursorSaveBuf )
-               Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
-
-       // Save behind the cursor
-       for( y = 0; y < render_h; y ++ )
-               memcpy(
-                       (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
-                       (Uint8*)dest + y*Buf->Pitch,
-                       render_w*bytes_per_px
-                       );
-
-       // Draw the cursor
-       switch(Buf->Depth)
-       {
-       case 15:
-       case 16:
-               Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
-               break;
-       case 24:
-               for( y = 0; y < render_h; y ++ )
-               {
-                       Uint8   *px;
-                       px = dest;
-                       for(x = 0; x < render_w; x ++, px += 3)
-                       {
-                               Uint32  value = src[x];
-                               // TODO: Should I implement alpha blending?
-                               if(value & 0xFF000000)
-                               {
-                                       px[0] = value & 0xFF;
-                                       px[1] = (value >> 8) & 0xFF;
-                                       px[2] = (value >> 16) & 0xFF;
-                               }
-                               else
-                                       ;
-                       }
-                       src += Buf->CursorBitmap->W;
-                       dest = (Uint8*)dest + Buf->Pitch;
-               }
-               break;
-       case 32:
-               for( y = 0; y < render_h; y ++ )
-               {
-                       Uint32  *px;
-                       px = dest;
-                       for(x = 0; x < render_w; x ++, px ++)
-                       {
-                               Uint32  value = src[x];
-                               // TODO: Should I implement alpha blending?
-                               if(value & 0xFF000000)
-                                       *px = value;
-                               else
-                                       ;       // NOP, completely transparent
-                       }
-                       src += Buf->CursorBitmap->W;
-                       dest = (Uint8*)dest + Buf->Pitch;
-               }
-               break;
-       default:
-               Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
-               Buf->CursorX = -1;
-               break;
-       }
-}
-
-void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
-{
-        int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    y, save_pitch;
-       Uint8   *dest, *src;
-
-       // Just a little sanity
-       if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
-       if( !Buf->CursorSaveBuf )       return ;
-
-//     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
-
-       // Set up
-       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
-       src = Buf->CursorSaveBuf;
-       
-       // Copy each line back
-       for( y = 0; y < Buf->CursorRenderH; y ++ )
-       {
-               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
-               src += save_pitch;
-               dest += Buf->Pitch;
-       }
-       
-       // Set the cursor as removed
-       Buf->CursorX = -1;
-}
-
-void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
-{
-       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
-
-       // TODO: Handle non-32bit modes
-       if( FBInfo->Depth != 32 )       return;
-
-       // TODO: Be less hacky
-        int    pitch = FBInfo->Pitch/4;
-       Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
-       while( H -- ) {
-               Uint32 *tmp;
-                int    i;
-               tmp = buf;
-               for(i=W;i--;tmp++)      *tmp = Colour;
-               buf += pitch;
-       }
-}
-
-void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
-{
-       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
-        int    scrnpitch = FBInfo->Pitch;
-        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
-        int    dst = DstY*scrnpitch + DstX;
-        int    src = SrcY*scrnpitch + SrcX;
-        int    tmp;
-       
-       //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
-       //      Ent, DstX, DstY, SrcX, SrcY, W, H);
-       
-       if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
-       if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
-       if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
-       if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
-       
-       //Debug("W = %i, H = %i", W, H);
-       
-       if( dst > src ) {
-               // Reverse copy
-               dst += H*scrnpitch;
-               src += H*scrnpitch;
-               while( H -- ) {
-                       dst -= scrnpitch;
-                       src -= scrnpitch;
-                       tmp = W*bytes_per_px;
-                       for( tmp = W; tmp --; ) {
-                               *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
-                       }
-               }
-       }
-       else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
-               memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
-       }
-       else {
-               // Normal copy is OK
-               while( H -- ) {
-                       memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
-                       dst += scrnpitch;
-                       src += scrnpitch;
-               }
-       }
-       //Log("Vesa_2D_Blit: RETURN");
-}
-       
-
-// --- Disk Driver Helpers ---
-Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
-       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
-{
-       Uint8   tmp[BlockSize]; // C99
-       Uint64  block = Start / BlockSize;
-        int    offset = Start - block * BlockSize;
-        int    leading = BlockSize - offset;
-       Uint64  num;
-        int    tailings;
-       Uint64  ret;
-       
-       ENTER("XStart XLength pBuffer pReadBlocks XBlockSize xArgument",
-               Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
-       
-       // Non aligned start, let's fix that!
-       if(offset != 0)
-       {
-               if(leading > Length)    leading = Length;
-               LOG("Reading %i bytes from Block1+%i", leading, offset);
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               memcpy( Buffer, &tmp[offset], leading );
-               
-               if(leading == Length) {
-                       LEAVE('i', leading);
-                       return leading;
-               }
-               
-               Buffer = (Uint8*)Buffer + leading;
-               block ++;
-               num = ( Length - leading ) / BlockSize;
-               tailings = Length - num * BlockSize - leading;
-       }
-       else {
-               num = Length / BlockSize;
-               tailings = Length % BlockSize;
-       }
-       
-       // Read central blocks
-       if(num)
-       {
-               LOG("Reading %i blocks", num);
-               ret = ReadBlocks(block, num, Buffer, Argument);
-               if(ret != num ) {
-                       LEAVE('X', leading + ret * BlockSize);
-                       return leading + ret * BlockSize;
-               }
-       }
-       
-       // Read last tailing block
-       if(tailings != 0)
-       {
-               LOG("Reading %i bytes from last block", tailings);
-               block += num;
-               Buffer = (Uint8*)Buffer + num * BlockSize;
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               memcpy( Buffer, tmp, tailings );
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
-
-Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
-       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
-       Uint64 BlockSize, Uint Argument)
-{
-       Uint8   tmp[BlockSize]; // C99
-       Uint64  block = Start / BlockSize;
-        int    offset = Start - block * BlockSize;
-        int    leading = BlockSize - offset;
-       Uint64  num;
-        int    tailings;
-       Uint64  ret;
-       
-       ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize xArgument",
-               Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
-       
-       // Non aligned start, let's fix that!
-       if(offset != 0)
-       {
-               if(leading > Length)    leading = Length;
-               LOG("Writing %i bytes to Block1+%i", leading, offset);
-               // Read a copy of the block
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               // Modify
-               memcpy( &tmp[offset], Buffer, leading );
-               // Write Back
-               ret = WriteBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               
-               if(leading == Length) {
-                       LEAVE('i', leading);
-                       return leading;
-               }
-               
-               Buffer = (Uint8*)Buffer + leading;
-               block ++;
-               num = ( Length - leading ) / BlockSize;
-               tailings = Length - num * BlockSize - leading;
-       }
-       else {
-               num = Length / BlockSize;
-               tailings = Length % BlockSize;
-       }
-       
-       // Read central blocks
-       if(num)
-       {
-               LOG("Writing %i blocks", num);
-               ret = WriteBlocks(block, num, Buffer, Argument);
-               if(ret != num ) {
-                       LEAVE('X', leading + ret * BlockSize);
-                       return leading + ret * BlockSize;
-               }
-       }
-       
-       // Read last tailing block
-       if(tailings != 0)
-       {
-               LOG("Writing %i bytes to last block", tailings);
-               block += num;
-               Buffer = (Uint8*)Buffer + num * BlockSize;
-               // Read
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               // Modify
-               memcpy( tmp, Buffer, tailings );
-               // Write
-               ret = WriteBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
diff --git a/Kernel/events.c b/Kernel/events.c
deleted file mode 100644 (file)
index a9eab78..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * events.c
- * - Thread level event handling
- */
-#define DEBUG  0
-#include <acess.h>
-#include <threads_int.h>
-#include <events.h>
-
-// === CODE ===
-void Threads_PostEvent(tThread *Thread, Uint32 EventMask)
-{
-       // Sanity checking
-       if( !Thread )   return ;
-       if( EventMask == 0 )    return ;
-       // TODO: Check that only one bit is set?
-       
-       ENTER("pThread xEventMask", Thread, EventMask);
-
-       SHORTLOCK( &Thread->IsLocked );
-
-       Thread->EventState |= EventMask;
-       LOG("Thread->EventState = 0x%x", Thread->EventState);
-       
-       // Currently sleeping on an event?
-       if( Thread->Status == THREAD_STAT_EVENTSLEEP )
-       {
-               // Waiting on this event?
-               if( (Uint32)Thread->RetStatus & EventMask )
-               {
-                       // Wake up
-                       LOG("Waking thread %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
-                       Threads_AddActive(Thread);
-               }
-       }
-       
-       SHORTREL( &Thread->IsLocked );
-       LEAVE('-');
-}
-
-/**
- * \brief Wait for an event to occur
- */
-Uint32 Threads_WaitEvents(Uint32 EventMask)
-{
-       Uint32  rv;
-       tThread *us = Proc_GetCurThread();
-
-       ENTER("xEventMask", EventMask);
-
-       // Early return check
-       if( EventMask == 0 )
-       {
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       LOG("us = %p(%i %s)", us, us->TID, us->ThreadName);
-
-       // Check if a wait is needed
-       SHORTLOCK( &us->IsLocked );
-       while( !(us->EventState & EventMask) )
-       {
-               LOG("Locked and preparing for wait");
-               // Wait
-               us->RetStatus = EventMask;      // HACK: Store EventMask in RetStatus
-               SHORTLOCK( &glThreadListLock );
-               us = Threads_RemActive();
-               us->Status = THREAD_STAT_EVENTSLEEP;
-               // Note stored anywhere because we're woken using other means
-               SHORTREL( &glThreadListLock );
-               SHORTREL( &us->IsLocked );
-               while(us->Status == THREAD_STAT_EVENTSLEEP)     Threads_Yield();
-               // Woken when lock is acquired
-               SHORTLOCK( &us->IsLocked );
-       }
-       
-       // Get return value and clear changed event bits
-       rv = us->EventState & EventMask;
-       us->EventState &= ~EventMask;
-       
-       SHORTREL( &us->IsLocked );
-       
-       LEAVE('x', rv);
-       return rv;
-}
-
diff --git a/Kernel/heap.c b/Kernel/heap.c
deleted file mode 100644 (file)
index eefd13c..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * heap.c
- */
-#include <acess.h>
-#include <mm_virt.h>
-#include <heap_int.h>
-
-#define WARNINGS       1
-#define        DEBUG_TRACE     0
-#define        VERBOSE_DUMP    0
-
-// === CONSTANTS ===
-#define        HEAP_INIT_SIZE  0x8000  // 32 KiB
-#define        MIN_SIZE        (sizeof(void*))*8       // 8 Machine Words
-#define        POW2_SIZES      0
-#define        COMPACT_HEAP    0       // Use 4 byte header?
-#define        FIRST_FIT       0
-
-//#define      MAGIC_FOOT      0x2ACE5505
-//#define      MAGIC_FREE      0xACE55000
-//#define      MAGIC_USED      0x862B0505      // MAGIC_FOOT ^ MAGIC_FREE
-#define        MAGIC_FOOT      0x544F4F46      // 'FOOT'
-#define        MAGIC_FREE      0x45455246      // 'FREE'
-#define        MAGIC_USED      0x44455355      // 'USED'
-
-// === PROTOTYPES ===
-void   Heap_Install(void);
-void   *Heap_Extend(int Bytes);
-void   *Heap_Merge(tHeapHead *Head);
-//void *Heap_Allocate(const char *File, int Line, size_t Bytes);
-//void *Heap_AllocateZero(const char *File, int Line, size_t Bytes);
-//void *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes);
-//void Heap_Deallocate(void *Ptr);
-void   Heap_Dump(void);
-void   Heap_Stats(void);
-
-// === GLOBALS ===
-tMutex glHeap;
-void   *gHeapStart;
-void   *gHeapEnd;
-
-// === CODE ===
-void Heap_Install(void)
-{
-       gHeapStart      = (void*)MM_KHEAP_BASE;
-       gHeapEnd        = (void*)MM_KHEAP_BASE;
-       Heap_Extend(HEAP_INIT_SIZE);
-}
-
-/**
- * \brief Extend the size of the heap
- */
-void *Heap_Extend(int Bytes)
-{
-       Uint    i;
-       tHeapHead       *head = gHeapEnd;
-       tHeapFoot       *foot;
-       
-       // Bounds Check
-       if( (tVAddr)gHeapEnd == MM_KHEAP_MAX )
-               return NULL;
-       
-       if( Bytes == 0 ) {
-               Log_Warning("Heap", "Heap_Extend called with Bytes=%i", Bytes);
-               return NULL;
-       }
-       
-       // Bounds Check
-       if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
-//             Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
-               return NULL;
-       }
-       
-       // Heap expands in pages
-       for( i = 0; i < (Bytes+0xFFF) >> 12; i ++ )
-       {
-               if( !MM_Allocate( (tVAddr)gHeapEnd+(i<<12) ) )
-               {
-                       Warning("OOM - Heap_Extend");
-                       return NULL;
-               }
-       }
-       
-       // Increas heap end
-       gHeapEnd = (Uint8*)gHeapEnd + (i << 12);
-       
-       // Create Block
-       head->Size = (Bytes+0xFFF)&~0xFFF;
-       head->Magic = MAGIC_FREE;
-       foot = (void*)( (Uint)gHeapEnd - sizeof(tHeapFoot) );
-       foot->Head = head;
-       foot->Magic = MAGIC_FOOT;
-       
-       return Heap_Merge(head);        // Merge with previous block
-}
-
-/**
- * \brief Merges two ajacent heap blocks
- */
-void *Heap_Merge(tHeapHead *Head)
-{
-       tHeapFoot       *foot;
-       tHeapFoot       *thisFoot;
-       tHeapHead       *head;
-       
-       //Log("Heap_Merge: (Head=%p)", Head);
-       
-       thisFoot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
-       if((Uint)thisFoot > (Uint)gHeapEnd)     return NULL;
-       
-       // Merge Left (Down)
-       foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
-       if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
-       && foot->Head->Magic == MAGIC_FREE) {
-               foot->Head->Size += Head->Size; // Increase size
-               thisFoot->Head = foot->Head;    // Change backlink
-               Head->Magic = 0;        // Clear old head
-               Head->Size = 0;
-               Head = foot->Head;      // Save new head address
-               foot->Head = NULL;      // Clear central footer
-               foot->Magic = 0;
-       }
-       
-       // Merge Right (Upwards)
-       head = (void*)( (Uint)Head + Head->Size );
-       if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
-       {
-               Head->Size += head->Size;
-               foot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
-               foot->Head = Head;      // Update Backlink
-               thisFoot->Head = NULL;  // Clear old footer
-               thisFoot->Magic = 0;
-               head->Size = 0;         // Clear old header
-               head->Magic = 0;
-       }
-       
-       // Return new address
-       return Head;
-}
-
-/**
- * \param File Allocating source file
- * \param Line Source line
- * \param __Bytes      Size of region to allocate
- */
-void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
-{
-       tHeapHead       *head, *newhead;
-       tHeapFoot       *foot, *newfoot;
-       tHeapHead       *best = NULL;
-       Uint    bestSize = 0;   // Speed hack
-       size_t  Bytes;
-
-       if( __Bytes == 0 ) {
-               //return NULL;  // TODO: Return a known un-mapped range.
-               return INVLPTR;
-       }
-       
-       // Get required size
-       #if POW2_SIZES
-       Bytes = __Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot);
-       Bytes = 1UUL << LOG2(__Bytes);
-       #else
-       Bytes = (__Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + MIN_SIZE-1) & ~(MIN_SIZE-1);
-       #endif
-       
-       // Lock Heap
-       Mutex_Acquire(&glHeap);
-       
-       // Traverse Heap
-       for( head = gHeapStart;
-               (Uint)head < (Uint)gHeapEnd;
-               head = (void*)((Uint)head + head->Size)
-               )
-       {
-               // Alignment Check
-               #if POW2_SIZES
-               if( head->Size != 1UUL << LOG2(head->Size) ) {
-               #else
-               if( head->Size & (MIN_SIZE-1) ) {
-               #endif
-                       Mutex_Release(&glHeap); // Release spinlock
-                       #if WARNINGS
-                       Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
-                       Heap_Dump();
-                       #endif
-                       return NULL;
-               }
-               
-               // Check if allocated
-               if(head->Magic == MAGIC_USED)   continue;
-               // Error check
-               if(head->Magic != MAGIC_FREE)   {
-                       Mutex_Release(&glHeap); // Release spinlock
-                       #if WARNINGS
-                       Log_Warning("Heap", "Magic of heap address %p is invalid (%p = 0x%x)",
-                               head, &head->Magic, head->Magic);
-                       Heap_Dump();
-                       #endif
-                       return NULL;
-               }
-               
-               // Size check
-               if(head->Size < Bytes)  continue;
-               
-               // Perfect fit
-               if(head->Size == Bytes) {
-                       head->Magic = MAGIC_USED;
-                       head->File = File;
-                       head->Line = Line;
-                       head->ValidSize = __Bytes;
-                       head->AllocateTime = now();
-                       Mutex_Release(&glHeap); // Release spinlock
-                       #if DEBUG_TRACE
-                       Debug("[Heap   ] Malloc'd %p (%i bytes), returning to %p",
-                               head->Data, head->Size,  __builtin_return_address(0));
-                       #endif
-                       return head->Data;
-               }
-               
-               // Break out of loop
-               #if FIRST_FIT
-               best = head;
-               bestSize = head->Size;
-               break;
-               #else
-               // or check if the block is the best size
-               if(bestSize > head->Size) {
-                       best = head;
-                       bestSize = head->Size;
-               }
-               #endif
-       }
-       
-       // If no block large enough is found, create one
-       if(!best)
-       {
-               best = Heap_Extend( Bytes );
-               // Check for errors
-               if(!best) {
-                       Mutex_Release(&glHeap); // Release spinlock
-                       return NULL;
-               }
-               // Check size
-               if(best->Size == Bytes) {
-                       best->Magic = MAGIC_USED;       // Mark block as used
-                       best->File = File;
-                       best->Line = Line;
-                       best->ValidSize = __Bytes;
-                       best->AllocateTime = now();
-                       Mutex_Release(&glHeap); // Release spinlock
-                       #if DEBUG_TRACE
-                       Debug("[Heap   ] Malloc'd %p (%i bytes), returning to %s:%i", best->Data, best->Size, File, Line);
-                       #endif
-                       return best->Data;
-               }
-       }
-       
-       // Split Block
-       newhead = (void*)( (Uint)best + Bytes );
-       newfoot = (void*)( (Uint)best + Bytes - sizeof(tHeapFoot) );
-       foot = (void*)( (Uint)best + best->Size - sizeof(tHeapFoot) );
-       
-       newfoot->Head = best;   // Create new footer
-       newfoot->Magic = MAGIC_FOOT;
-       newhead->Size = best->Size - Bytes;     // Create new header
-       newhead->Magic = MAGIC_FREE;
-       foot->Head = newhead;   // Update backlink in old footer
-       best->Size = Bytes;             // Update size in old header
-       best->ValidSize = __Bytes;
-       best->Magic = MAGIC_USED;       // Mark block as used
-       best->File = File;
-       best->Line = Line;
-       best->AllocateTime = now();
-       
-       Mutex_Release(&glHeap); // Release spinlock
-       #if DEBUG_TRACE
-       Debug("[Heap   ] Malloc'd %p (0x%x bytes), returning to %s:%i",
-               best->Data, best->Size, File, Line);
-       #endif
-       return best->Data;
-}
-
-/**
- * \brief Free an allocated memory block
- */
-void Heap_Deallocate(void *Ptr)
-{
-       tHeapHead       *head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
-       tHeapFoot       *foot;
-       
-       // INVLPTR is returned from Heap_Allocate when the allocation
-       // size is zero.
-       if( Ptr == INVLPTR )    return;
-       
-       #if DEBUG_TRACE
-       Debug("[Heap   ] free: %p freed by %p (%i old)", Ptr, __builtin_return_address(0), now()-head->AllocateTime);
-       #endif
-       
-       // Alignment Check
-       if( (Uint)Ptr & (sizeof(Uint)-1) ) {
-               Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
-               return;
-       }
-       
-       // Sanity check
-       if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
-       {
-               Log_Warning("Heap", "free - Passed a non-heap address by %p (%p < %p < %p)\n",
-                       __builtin_return_address(0), gHeapStart, Ptr, gHeapEnd);
-               return;
-       }
-       
-       // Check memory block - Header
-       head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
-       if(head->Magic == MAGIC_FREE) {
-               Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
-               return;
-       }
-       if(head->Magic != MAGIC_USED) {
-               Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)", head, head->Magic);
-               Log_Notice("Heap", "Allocated by %s:%i", head->File, head->Line);
-               return;
-       }
-       
-       // Check memory block - Footer
-       foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
-       if(foot->Head != head) {
-               Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)", head, foot->Head);
-               Log_Notice("Heap", "Allocated by %s:%i", head->File, head->Line);
-               return;
-       }
-       if(foot->Magic != MAGIC_FOOT) {
-               Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)", head, &foot->Magic, foot->Magic);
-               Log_Notice("Heap", "Allocated by %s:%i", head->File, head->Line);
-               return;
-       }
-       
-       // Lock
-       Mutex_Acquire( &glHeap );
-       
-       // Mark as free
-       head->Magic = MAGIC_FREE;
-       //head->File = NULL;
-       //head->Line = 0;
-       head->ValidSize = 0;
-       // Merge blocks
-       Heap_Merge( head );
-       
-       // Release
-       Mutex_Release( &glHeap );
-}
-
-/**
- * \brief Increase/Decrease the size of an allocation
- * \param File Calling File
- * \param Line Calling Line
- * \param __ptr        Old memory
- * \param __size       New Size
- */
-void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
-{
-       tHeapHead       *head = (void*)( (Uint)__ptr-sizeof(tHeapHead) );
-       tHeapHead       *nextHead;
-       tHeapFoot       *foot;
-       Uint    newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+MIN_SIZE-1)&~(MIN_SIZE-1);
-       
-       // Check for reallocating NULL
-       if(__ptr == NULL)       return Heap_Allocate(File, Line, __size);
-       
-       // Check if resize is needed
-       if(newSize <= head->Size)       return __ptr;
-       
-       // Check if next block is free
-       nextHead = (void*)( (Uint)head + head->Size );
-       
-       // Extend into next block
-       if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
-       {
-               Uint    size = nextHead->Size + head->Size;
-               foot = (void*)( (Uint)nextHead + nextHead->Size - sizeof(tHeapFoot) );
-               // Exact Fit
-               if(size == newSize) {
-                       head->Size = newSize;
-                       head->ValidSize = __size;
-                       head->File = File;
-                       head->Line = Line;
-                       foot->Head = head;
-                       nextHead->Magic = 0;
-                       nextHead->Size = 0;
-                       return __ptr;
-               }
-               // Create a new heap block
-               nextHead = (void*)( (Uint)head + newSize );
-               nextHead->Size = size - newSize;
-               nextHead->Magic = MAGIC_FREE;
-               foot->Head = nextHead;  // Edit 2nd footer
-               head->Size = newSize;   // Edit first header
-               head->File = File;
-               head->Line = Line;
-               head->ValidSize = __size;
-               // Create new footer
-               foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) );
-               foot->Head = head;
-               foot->Magic = MAGIC_FOOT;
-               return __ptr;
-       }
-       
-       // Extend downwards?
-       foot = (void*)( (Uint)head - sizeof(tHeapFoot) );
-       nextHead = foot->Head;
-       if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
-       {
-               Uint    size = nextHead->Size + head->Size;
-               // Inexact fit, split things up
-               if(size > newSize)
-               {
-                       // TODO
-                       Warning("[Heap   ] TODO: Space efficient realloc when new size is smaller");
-               }
-               
-               // Exact fit
-               if(size >= newSize)
-               {
-                       Uint    oldDataSize;
-                       // Set 1st (new/lower) header
-                       nextHead->Magic = MAGIC_USED;
-                       nextHead->Size = newSize;
-                       nextHead->File = File;
-                       nextHead->Line = Line;
-                       nextHead->ValidSize = __size;
-                       // Get 2nd (old) footer
-                       foot = (void*)( (Uint)nextHead + newSize );
-                       foot->Head = nextHead;
-                       // Save old data size
-                       oldDataSize = head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead);
-                       // Clear old header
-                       head->Size = 0;
-                       head->Magic = 0;
-                       // Copy data
-                       memcpy(nextHead->Data, __ptr, oldDataSize);
-                       // Return
-                       return nextHead->Data;
-               }
-               // On to the expensive then
-       }
-       
-       // Well, darn
-       nextHead = Heap_Allocate( File, Line, __size );
-       nextHead -= 1;
-       nextHead->File = File;
-       nextHead->Line = Line;
-       nextHead->ValidSize = __size;
-       
-       memcpy(
-               nextHead->Data,
-               __ptr,
-               head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead)
-               );
-       
-       free(__ptr);
-       
-       return nextHead->Data;
-}
-
-/**
- * \fn void *Heap_AllocateZero(const char *File, int Line, size_t Bytes)
- * \brief Allocate and Zero a buffer in memory
- * \param File Allocating file
- * \param Line Line of allocation
- * \param Bytes        Size of the allocation
- */
-void *Heap_AllocateZero(const char *File, int Line, size_t Bytes)
-{
-       void    *ret = Heap_Allocate(File, Line, Bytes);
-       if(ret == NULL) return NULL;
-       
-       memset( ret, 0, Bytes );
-       
-       return ret;
-}
-
-/**
- * \fn int Heap_IsHeapAddr(void *Ptr)
- * \brief Checks if an address is a heap pointer
- */
-int Heap_IsHeapAddr(void *Ptr)
-{
-       tHeapHead       *head;
-       if((Uint)Ptr < (Uint)gHeapStart)        return 0;
-       if((Uint)Ptr > (Uint)gHeapEnd)  return 0;
-       if((Uint)Ptr & (sizeof(Uint)-1))        return 0;
-       
-       head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
-       if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
-               return 0;
-       
-       return 1;
-}
-
-/**
- */
-void Heap_Validate(void)
-{
-       Heap_Dump();
-}
-
-#if WARNINGS
-void Heap_Dump(void)
-{
-       tHeapHead       *head, *badHead;
-       tHeapFoot       *foot = NULL;
-       
-       head = gHeapStart;
-       while( (Uint)head < (Uint)gHeapEnd )
-       {               
-               foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
-               #if VERBOSE_DUMP
-               Log_Log("Heap", "%p (0x%P): 0x%08x (%i) %4C",
-                       head, MM_GetPhysAddr((tVAddr)head), head->Size, head->ValidSize, &head->Magic);
-               Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
-               if(head->File) {
-                       Log_Log("Heap", "%sowned by %s:%i",
-                               (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line);
-               }
-               #endif
-               
-               // Sanity Check Header
-               if(head->Size == 0) {
-                       Log_Warning("Heap", "HALTED - Size is zero");
-                       break;
-               }
-               if(head->Size & (MIN_SIZE-1)) {
-                       Log_Warning("Heap", "HALTED - Size is malaligned");
-                       break;
-               }
-               if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
-                       Log_Warning("Heap", "HALTED - Head Magic is Bad");
-                       break;
-               }
-               
-               // Check footer
-               if(foot->Magic != MAGIC_FOOT) {
-                       Log_Warning("Heap", "HALTED - Foot Magic is Bad");
-                       break;
-               }
-               if(head != foot->Head) {
-                       Log_Warning("Heap", "HALTED - Footer backlink is invalid");
-                       break;
-               }
-               
-               #if VERBOSE_DUMP
-               Log_Log("Heap", "");
-               #endif
-               
-               // All OK? Go to next
-               head = foot->NextHead;
-       }
-       
-       // If the heap is valid, ok!
-       if( (tVAddr)head == (tVAddr)gHeapEnd )
-               return ;
-       
-       // Check for a bad return
-       if( (tVAddr)head >= (tVAddr)gHeapEnd )
-               return ;
-
-       #if !VERBOSE_DUMP
-       Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
-               head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
-       if(foot)
-               Log_Log("Heap", "Foot %p = {Head:%p,Magic:%4C}", foot, foot->Head, &foot->Magic);
-       if(head->File) {
-               Log_Log("Heap", "%sowned by %s:%i",
-                       (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line);
-       }
-       Log_Log("Heap", "");
-       #endif
-       
-       
-       badHead = head;
-       
-       // Work backwards
-       foot = (void*)( (tVAddr)gHeapEnd - sizeof(tHeapFoot) );
-       Log_Log("Heap", "==== Going Backwards ==== (from %p)", foot);
-       head = foot->Head;
-       while( (tVAddr)head >= (tVAddr)badHead )
-       {
-               Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
-                       head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
-               Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
-               if(head->File)
-                       Log_Log("Heap", "%sowned by %s:%i",
-                               (head->Magic!=MAGIC_USED?"was ":""),
-                               head->File, head->Line);
-               Log_Log("Heap", "");
-               
-               // Sanity Check Header
-               if(head->Size == 0) {
-                       Log_Warning("Heap", "HALTED - Size is zero");
-                       break;
-               }
-               if(head->Size & (MIN_SIZE-1)) {
-                       Log_Warning("Heap", " - Size is malaligned (&0x%x)", ~(MIN_SIZE-1));
-                       break ;
-               }
-               if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
-                       Log_Warning("Heap", "HALTED - Head Magic is Bad");
-                       break;
-               }
-               
-               // Check footer
-               if(foot->Magic != MAGIC_FOOT) {
-                       Log_Warning("Heap", "HALTED - Foot Magic is Bad");
-                       break;
-               }
-               if(head != foot->Head) {
-                       Log_Warning("Heap", "HALTED - Footer backlink is invalid");
-                       break;
-               }
-               
-               if(head == badHead)     break;
-               
-               foot = (void*)( (tVAddr)head - sizeof(tHeapFoot) );
-               head = foot->Head;
-               Log_Debug("Heap", "head=%p", head);
-       }
-       
-       Panic("Heap_Dump - Heap is corrupted, kernel panic!");
-}
-#endif
-
-#if 1
-void Heap_Stats(void)
-{
-       tHeapHead       *head;
-        int    nBlocks = 0;
-        int    nFree = 0;
-        int    totalBytes = 0;
-        int    freeBytes = 0;
-        int    maxAlloc=0, minAlloc=-1;
-        int    avgAlloc, frag, overhead;
-       
-       for(head = gHeapStart;
-               (Uint)head < (Uint)gHeapEnd;
-               head = (void*)( (Uint)head + head->Size )
-               )
-       {       
-               nBlocks ++;
-               totalBytes += head->Size;
-               if( head->Magic == MAGIC_FREE )
-               {
-                       nFree ++;
-                       freeBytes += head->Size;
-               }
-               else if( head->Magic == MAGIC_USED) {
-                       if(maxAlloc < head->Size)       maxAlloc = head->Size;
-                       if(minAlloc == -1 || minAlloc > head->Size)
-                               minAlloc = head->Size;
-               }
-               else {
-                       Log_Warning("Heap", "Magic on %p invalid, skipping remainder of heap", head);
-                       break;
-               }
-               
-               // Print the block info?
-               #if 1
-               if( head->Magic == MAGIC_FREE )
-                       Log_Debug("Heap", "%p (%P) - 0x%x free",
-                               head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size);
-               else
-                       Log_Debug("Heap", "%p (%P) - 0x%x (%i) Owned by %s:%i (%lli ms old)",
-                               head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size, head->ValidSize, head->File, head->Line,
-                               now() - head->AllocateTime
-                               );
-               #endif
-       }
-
-       Log_Log("Heap", "%i blocks (0x%x bytes)", nBlocks, totalBytes);
-       Log_Log("Heap", "%i free blocks (0x%x bytes)", nFree, freeBytes);
-       if(nBlocks != 0)
-               frag = (nFree-1)*10000/nBlocks;
-       else
-               frag = 0;
-       Log_Log("Heap", "%i.%02i%% Heap Fragmentation", frag/100, frag%100);
-       if(nBlocks <= nFree)
-               avgAlloc = 0;
-       else
-               avgAlloc = (totalBytes-freeBytes)/(nBlocks-nFree);
-       if(avgAlloc != 0)
-               overhead = (sizeof(tHeapFoot)+sizeof(tHeapHead))*10000/avgAlloc;
-       else
-               overhead = 0;
-       Log_Log("Heap", "Average allocation: %i bytes, Average Overhead: %i.%02i%%",
-               avgAlloc, overhead/100, overhead%100
-               );
-       Log_Log("Heap", "Smallest Block: %i bytes, Largest: %i bytes", 
-               minAlloc, maxAlloc);
-       
-       // Scan and get distribution
-       #if 1
-       if(nBlocks > 0)
-       {
-               struct {
-                       Uint    Size;
-                       Uint    Count;
-               }       sizeCounts[nBlocks];
-                int    i;
-               
-               memset(sizeCounts, 0, nBlocks*sizeof(sizeCounts[0]));
-               
-               for(head = gHeapStart;
-                       (Uint)head < (Uint)gHeapEnd;
-                       head = (void*)( (Uint)head + head->Size )
-                       )
-               {
-                       for( i = 0; i < nBlocks; i ++ ) {
-                               if( sizeCounts[i].Size == 0 )
-                                       break;
-                               if( sizeCounts[i].Size == head->Size )
-                                       break;
-                       }
-                       // Should never reach this part (in a non-concurrent case)
-                       if( i == nBlocks )      continue;
-                       sizeCounts[i].Size = head->Size;
-                       sizeCounts[i].Count ++;
-                       #if 1
-                       //Log("Heap_Stats: %i %p - 0x%x bytes (%s) (%i)", nBlocks, head,
-                       //      head->Size, (head->Magic==MAGIC_FREE?"FREE":"used"), i
-                       //      );
-                       //Log("Heap_Stats: sizeCounts[%i] = {Size:0x%x, Count: %i}", i,
-                       //      sizeCounts[i].Size, sizeCounts[i].Count);
-                       #endif
-               }
-               
-               for( i = 0; i < nBlocks && sizeCounts[i].Count; i ++ )
-               {
-                       Log("Heap_Stats: 0x%x - %i blocks",
-                               sizeCounts[i].Size, sizeCounts[i].Count
-                               );
-               }
-       }
-       #endif
-}
-#endif
-
-// === EXPORTS ===
-EXPORT(Heap_Allocate);
-EXPORT(Heap_AllocateZero);
-EXPORT(Heap_Reallocate);
-EXPORT(Heap_Deallocate);
-EXPORT(Heap_IsHeapAddr);
diff --git a/Kernel/include/acess.h b/Kernel/include/acess.h
deleted file mode 100644 (file)
index 2cd2cff..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * acess.h
- */
-#ifndef _ACESS_H
-#define _ACESS_H
-/**
- * \file acess.h
- * \brief Acess2 Kernel API Core
- */
-
-//! NULL Pointer
-#define NULL   ((void*)0)
-//! Pack a structure
-#define PACKED __attribute__((packed))
-//! Mark a function as not returning
-#define NORETURN       __attribute__((noreturn))
-//! Mark a parameter as unused
-#define UNUSED(x)      UNUSED_##x __attribute__((unused))
-//! Get the offset of a member in a structure
-#define offsetof(st, m) ((Uint)((char *)&((st *)(0))->m - (char *)0 ))
-
-/**
- * \name Boolean constants
- * \{
- */
-#define TRUE   1
-#define FALSE  0
-/**
- * \}
- */
-
-#include <arch.h>
-#include <stdarg.h>
-#include "errno.h"
-
-// --- Types ---
-typedef Uint32 tPID;   //!< Process ID type
-typedef Uint32 tTID;   //!< Thread ID Type
-typedef Uint32 tUID;   //!< User ID Type
-typedef Uint32 tGID;   //!< Group ID Type
-typedef Sint64 tTimestamp;     //!< Timestamp (miliseconds since 00:00 1 Jan 1970)
-typedef Sint64 tTime;  //!< Same again
-typedef struct sShortSpinlock  tShortSpinlock; //!< Opaque (kinda) spinlock
-typedef int    bool;   //!< Boolean type
-
-// --- Helper Macros ---
-/**
- * \name Helper Macros
- * \{
- */
-#define        CONCAT(x,y) x ## y
-#define EXPAND_CONCAT(x,y) CONCAT(x,y)
-#define STR(x) #x
-#define EXPAND_STR(x) STR(x)
-
-extern char    __buildnum[];
-#define BUILD_NUM      ((int)(Uint)&__buildnum)
-extern const char gsGitHash[];
-
-#define VER2(major,minor)      ((((major)&0xFF)<<8)|((minor)&0xFF))
-/**
- * \}
- */
-
-//! \brief Error number
-#define errno  (*Threads_GetErrno())
-
-// === CONSTANTS ===
-// --- Memory Flags --
-/**
- * \name Memory Flags
- * \{
- * \todo Move to mm_virt.h
- */
-#define        MM_PFLAG_RO             0x01    // Writes disallowed
-#define        MM_PFLAG_EXEC   0x02    // Allow execution
-#define        MM_PFLAG_NOPAGE 0x04    // Prevent from being paged out
-#define        MM_PFLAG_COW    0x08    // Copy-On-Write
-#define        MM_PFLAG_KERNEL 0x10    // Kernel-Only (Ring0)
-/**
- * \}
- */
-// --- Interface Flags & Macros
-/**
- * \name Flags for Proc_Clone
- * \{
- */
-//! Clone the entire process
-#define CLONE_VM       0x10
-//! Don't copy user pages
-#define CLONE_NOUSER   0x20
-/**
- * \}
- */
-
-// === Types ===
-/**
- * \brief Thread root function
- * 
- * Function pointer prototype of a thread entrypoint. When it
- * returns, Threads_Exit is called
- */
-typedef void (*tThreadFunction)(void*);
-
-// === Kernel Export Macros ===
-/**
- * \name Kernel exports
- * \{
- */
-//! Kernel symbol definition
-typedef struct sKernelSymbol {
-       const char      *Name;  //!< Symbolic name
-       tVAddr  Value;  //!< Value of the symbol
-} tKernelSymbol;
-//! Export a pointer symbol (function/array)
-#define        EXPORT(_name)   tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (tVAddr)_name}
-//! Export a variable
-#define        EXPORTV(_name)  tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (tVAddr)&_name}
-//! Export a symbol under another name
-#define        EXPORTAS(_sym,_name)    tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (tVAddr)_sym}
-/**
- * \}
- */
-
-// === FUNCTIONS ===
-// --- IRQs ---
-/**
- * \name IRQ hander registration
- * \{
- */
-extern int     IRQ_AddHandler(int Num, void (*Callback)(int, void*), void *Ptr);
-extern void    IRQ_RemHandler(int Handle);
-/**
- * \}
- */
-
-// --- Logging ---
-/**
- * \name Logging to kernel ring buffer
- * \{
- */
-extern void    Log_KernelPanic(const char *Ident, const char *Message, ...);
-extern void    Log_Panic(const char *Ident, const char *Message, ...);
-extern void    Log_Error(const char *Ident, const char *Message, ...);
-extern void    Log_Warning(const char *Ident, const char *Message, ...);
-extern void    Log_Notice(const char *Ident, const char *Message, ...);
-extern void    Log_Log(const char *Ident, const char *Message, ...);
-extern void    Log_Debug(const char *Ident, const char *Message, ...);
-/**
- * \}
- */
-
-// --- Debug ---
-/**
- * \name Debugging and Errors
- * \{
- */
-extern void    Debug_KernelPanic(void);        //!< Initiate a kernel panic
-extern void    Panic(const char *Msg, ...);    //!< Print a panic message (initiates a kernel panic)
-extern void    Warning(const char *Msg, ...);  //!< Print a warning message
-extern void    LogF(const char *Fmt, ...);     //!< Print a log message without a trailing newline
-extern void    Log(const char *Fmt, ...);      //!< Print a log message
-extern void    Debug(const char *Fmt, ...);    //!< Print a debug message (doesn't go to KTerm)
-extern void    LogV(const char *Fmt, va_list Args);    //!< va_list Log message
-extern void    Debug_Enter(const char *FuncName, const char *ArgTypes, ...);
-extern void    Debug_Log(const char *FuncName, const char *Fmt, ...);
-extern void    Debug_Leave(const char *FuncName, char RetType, ...);
-extern void    Debug_HexDump(const char *Header, const void *Data, Uint Length);
-#define UNIMPLEMENTED()        Warning("'%s' unimplemented", __func__)
-#if DEBUG
-# define ENTER(_types...)      Debug_Enter((char*)__func__, _types)
-# define LOG(_fmt...)  Debug_Log((char*)__func__, _fmt)
-# define LEAVE(_t...)  Debug_Leave((char*)__func__, _t)
-# define LEAVE_RET(_t,_v...)   do{LEAVE(_t,_v);return _v;}while(0)
-# define LEAVE_RET0()  do{LEAVE('-');return;}while(0)
-#else
-# define ENTER(...)
-# define LOG(...)
-# define LEAVE(...)
-# define LEAVE_RET(_t,_v...)   return (_v)
-# define LEAVE_RET0()  return
-#endif
-#if SANITY
-# define ASSERT(expr) do{if(!(expr))Panic("%s: Assertion '"#expr"' failed",(char*)__func__);}while(0)
-#else
-# define ASSERT(expr)
-#endif
-/**
- * \}
- */
-
-// --- IO ---
-#if NO_IO_BUS
-#define inb(a) (Log_Panic("Arch", STR(ARCHDIR)" does not support in*/out* (%s:%i)", __FILE__, __LINE__),0)
-#define inw(a) inb(a)
-#define ind(a) inb(a)
-#define inq(a) inb(a)
-#define outb(a,b)      inb(a)
-#define outw(a,b)      inb(a)
-#define outd(a,b)      inb(a)
-#define outq(a,b)      inb(a)
-#else
-/**
- * \name I/O Memory Access
- * \{
- */
-extern void    outb(Uint16 Port, Uint8 Data);
-extern void    outw(Uint16 Port, Uint16 Data);
-extern void    outd(Uint16 Port, Uint32 Data);
-extern void    outq(Uint16 Port, Uint64 Data);
-extern Uint8   inb(Uint16 Port);
-extern Uint16  inw(Uint16 Port);
-extern Uint32  ind(Uint16 Port);
-extern Uint64  inq(Uint16 Port);
-/**
- * \}
- */
-#endif
-// --- Memory Management ---
-/**
- * \name Memory Management
- * \{
- * \todo Move to mm_virt.h
- */
-/**
- * \brief Allocate a physical page at \a VAddr
- * \param VAddr        Virtual Address to allocate at
- * \return Physical address allocated
- */
-extern tPAddr  MM_Allocate(tVAddr VAddr) __attribute__ ((warn_unused_result));
-/**
- * \brief Deallocate a page
- * \param VAddr        Virtual address to unmap
- */
-extern void    MM_Deallocate(tVAddr VAddr);
-/**
- * \brief Map a physical page at \a PAddr to \a VAddr
- * \param VAddr        Target virtual address
- * \param PAddr        Physical address to map
- * \return Boolean Success
- */
-extern int     MM_Map(tVAddr VAddr, tPAddr PAddr);
-/**
- * \brief Get the physical address of \a Addr
- * \param Addr Address of the page to get the physical address of
- * \return Physical page mapped at \a Addr
- */
-extern tPAddr  MM_GetPhysAddr(tVAddr Addr);
-/**
- * \brief Set the access flags on a page
- * \param VAddr        Virtual address of the page
- * \param Flags New flags value
- * \param Mask Flags to set
- */
-extern void    MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask);
-/**
- * \brief Get the flags on a flag
- * \param VAddr        Virtual address of page
- * \return Flags value of the page
- */
-extern Uint    MM_GetFlags(tVAddr VAddr);
-/**
- * \brief Checks is a memory range is user accessable
- * \param VAddr        Base address to check
- * \return 1 if the memory is all user-accessable, 0 otherwise
- */
-#define MM_IsUser(VAddr)       (!(MM_GetFlags((VAddr))&MM_PFLAG_KERNEL))
-/**
- * \brief Temporarily map a page into the address space
- * \param PAddr        Physical addres to map
- * \return Virtual address of page in memory
- * \note There is only a limited ammount of slots avaliable
- */
-extern tVAddr  MM_MapTemp(tPAddr PAddr);
-/**
- * \brief Free a temporarily mapped page
- * \param VAddr        Allocate virtual addres of page
- */
-extern void    MM_FreeTemp(tVAddr VAddr);
-/**
- * \brief Map a physcal address range into the virtual address space
- * \param PAddr        Physical address to map in
- * \param Number       Number of pages to map
- */
-extern tVAddr  MM_MapHWPages(tPAddr PAddr, Uint Number);
-/**
- * \brief Allocates DMA physical memory
- * \param Pages        Number of pages required
- * \param MaxBits      Maximum number of bits the physical address can have
- * \param PhysAddr     Pointer to the location to place the physical address allocated
- * \return Virtual address allocate
- */
-extern tVAddr  MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr);
-/**
- * \brief Unmaps an allocated hardware range
- * \param VAddr        Virtual address allocate by ::MM_MapHWPages or ::MM_AllocDMA
- * \param Number       Number of pages to free
- */
-extern void    MM_UnmapHWPages(tVAddr VAddr, Uint Number);
-/**
- * \brief Allocate a single physical page
- * \return Physical address allocated
- */
-extern tPAddr  MM_AllocPhys(void);
-/**
- * \brief Allocate a contiguous range of physical pages
- * \param Pages        Number of pages to allocate
- * \param MaxBits      Maximum number of address bits allowed
- * \return First physical address allocated
- */
-extern tPAddr  MM_AllocPhysRange(int Pages, int MaxBits);
-/**
- * \brief Reference a physical page
- * \param PAddr        Page to mark as referenced
- */
-extern void    MM_RefPhys(tPAddr PAddr);
-/**
- * \brief Dereference a physical page
- * \param PAddr        Page to dereference
- */
-extern void    MM_DerefPhys(tPAddr PAddr);
-/**
- * \brief Get the number of times a page has been referenced
- * \param PAddr        Address to check
- * \return Reference count for the page
- */
-extern int     MM_GetRefCount(tPAddr PAddr);
-/**
- * \brief Set the node associated with a page
- * \param PAddr        Physical address of page
- * \param Node Node pointer (tVFS_Node)
- * \return Boolean failure
- * \retval 0   Success
- * \retval 1   Page not allocated
- */
-extern int     MM_SetPageNode(tPAddr PAddr, void *Node);
-/**
- * \brief Get the node associated with a page
- * \param PAddr        Physical address of page
- * \param Node Node pointer (tVFS_Node) destination
- * \return Boolean failure
- * \retval 0   Success
- * \retval 1   Page not allocated
- */
-extern int     MM_GetPageNode(tPAddr PAddr, void **Node);
-/**
- * \}
- */
-
-// --- Memory Manipulation ---
-/**
- * \name Memory Manipulation
- * \{
- */
-extern int     memcmp(const void *m1, const void *m2, size_t count);
-extern void    *memcpy(void *dest, const void *src, size_t count);
-extern void    *memcpyd(void *dest, const void *src, size_t count);
-extern void    *memmove(void *dest, const void *src, size_t len);
-extern void    *memset(void *dest, int val, size_t count);
-extern void    *memsetd(void *dest, Uint32 val, size_t count);
-/**
- * \}
- */
-/**
- * \name Memory Validation
- * \{
- */
-extern int     CheckString(const char *String);
-extern int     CheckMem(const void *Mem, int Num);
-/**
- * \}
- */
-
-// --- Endianness ---
-/**
- * \name Endianness Swapping
- * \{
- */
-#ifdef __BIG_ENDIAN__
-#define        LittleEndian16(_val)    SwapEndian16(_val)
-#define        LittleEndian32(_val)    SwapEndian32(_val)
-#define        BigEndian16(_val)       (_val)
-#define        BigEndian32(_val)       (_val)
-#else
-#define        LittleEndian16(_val)    (_val)
-#define        LittleEndian32(_val)    (_val)
-#define        BigEndian16(_val)       SwapEndian16(_val)
-#define        BigEndian32(_val)       SwapEndian32(_val)
-#endif
-extern Uint16  SwapEndian16(Uint16 Val);
-extern Uint32  SwapEndian32(Uint32 Val);
-/**
- * \}
- */
-
-// --- Strings ---
-/**
- * \name Strings
- * \{
- */
-extern int     vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
-extern int     sprintf(char *__s, const char *__format, ...);
-extern size_t  strlen(const char *Str);
-extern char    *strcpy(char *__dest, const char *__src);
-extern char    *strncpy(char *__dest, const char *__src, size_t max);
-extern char    *strcat(char *__dest, const char *__src);
-extern char    *strncat(char *__dest, const char *__src, size_t n);
-extern int     strcmp(const char *__str1, const char *__str2);
-extern int     strncmp(const char *Str1, const char *Str2, size_t num);
-extern int     strucmp(const char *Str1, const char *Str2);
-// strdup macro is defined in heap.h
-extern char    *_strdup(const char *File, int Line, const char *Str);
-extern char    **str_split(const char *__str, char __ch);
-extern char    *strchr(const char *__s, int __c);
-extern int     strpos(const char *Str, char Ch);
-extern int     strpos8(const char *str, Uint32 search);
-extern void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
-extern int     atoi(const char *string);
-extern int     ParseInt(const char *string, int *Val);
-extern int     ReadUTF8(const Uint8 *str, Uint32 *Val);
-extern int     WriteUTF8(Uint8 *str, Uint32 Val);
-extern int     ModUtil_SetIdent(char *Dest, const char *Value);
-extern int     ModUtil_LookupString(const char **Array, const char *Needle);
-
-extern Uint8   ByteSum(const void *Ptr, int Size);
-extern int     Hex(char *Dest, size_t Size, const Uint8 *SourceData);
-extern int     UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
-/**
- * \}
- */
-
-/**
- * \brief Get a random number
- * \return Random number
- * \note Current implementation is a linear congruency
- */
-extern int     rand(void);
-/**
- * \brief Call a function with a variable number of arguments
- * \param Function     Function address
- * \param NArgs        Number of entries in \a Args
- * \param Args Array of arguments
- * \return Integer from called Function
- */
-extern int     CallWithArgArray(void *Function, int NArgs, Uint *Args);
-
-// --- Heap ---
-#include <heap.h>
-/**
- * \brief Magic heap allocation function
- */
-extern void    *alloca(size_t Size);
-
-// --- Modules ---
-/**
- * \name Modules
- * \{
- */
-extern int     Module_LoadMem(void *Buffer, Uint Length, const char *ArgStr);
-extern int     Module_LoadFile(const char *Path, const char *ArgStr);
-/**
- * \}
- */
-
-// --- Timing ---
-/**
- * \name Time and Timing
- * \{
- */
-/**
- * \brief Create a timestamp from a time
- */
-extern tTime   timestamp(int sec, int mins, int hrs, int day, int month, int year);
-/**
- * \brief Extract the date/time from a timestamp
- */
-extern void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
-/**
- * \brief Gets the current timestamp (miliseconds since Midnight 1st January 1970)
- */
-extern Sint64  now(void);
-/**
- * \}
- */
-
-// --- Threads ---
-/**
- * \name Threads and Processes
- * \{
- */
-extern int     Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
-extern int     Proc_Spawn(const char *Path);
-extern int     Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
-extern int     Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
-extern void    Threads_Exit(int TID, int Status);
-extern void    Threads_Yield(void);
-extern void    Threads_Sleep(void);
-extern int     Threads_WakeTID(tTID Thread);
-extern tPID    Threads_GetPID(void);
-extern tTID    Threads_GetTID(void);
-extern tUID    Threads_GetUID(void);
-extern tGID    Threads_GetGID(void);
-extern int     SpawnTask(tThreadFunction Function, void *Arg);
-extern int     *Threads_GetErrno(void);
-extern int     Threads_SetName(const char *NewName);
-/**
- * \}
- */
-
-// --- Simple Math ---
-//! Divide and round up
-extern int     DivUp(int num, int dem);
-//! Divide and Modulo 64-bit unsigned integer
-extern Uint64  DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem);
-
-static inline int MIN(int a, int b) { return a < b ? a : b; }
-static inline int MAX(int a, int b) { return a > b ? a : b; }
-
-#include <binary_ext.h>
-#include <vfs_ext.h>
-#include <mutex.h>
-
-#endif
diff --git a/Kernel/include/adt.h b/Kernel/include/adt.h
deleted file mode 100644 (file)
index 67e1266..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* 
- * Acess2
- * - Abstract Data Types
- */
-#ifndef _ADT_H_
-#define _ADT_H_
-
-/**
- * \name Ring Buffers
- * \{
- */
-typedef struct sRingBuffer
-{
-       size_t  Start;  //!< Start of data in ring buffer
-       size_t  Length; //!< Number of data bytes in buffer
-       size_t  Space;  //!< Allocated space in buffer
-       tShortSpinlock  Lock;   //!< Lock to prevent collisions
-       char    Data[]; //!< Buffer
-}      tRingBuffer;
-
-/**
- * \brief Create a ring buffer \a Space bytes large
- * \param Space        Ammount of space to allocate within the buffer
- * \return Pointer to the buffer structure
- */
-extern tRingBuffer     *RingBuffer_Create(size_t Space);
-/**
- * \brief Read at most \a Length bytes from the buffer
- * \param Dest Destinaton buffer
- * \param Buffer       Source ring buffer
- * \param Length       Requested number of bytes
- * \return Number of bytes read
- */
-extern size_t  RingBuffer_Read(void *Dest, tRingBuffer *Buffer, size_t Length);
-/**
- * \brief Write at most \a Length bytes to the buffer
- * \param Buffer       Destination ring buffer
- * \param Source       Source buffer
- * \param Length       Provided number of bytes
- * \return Number of bytes written
- */
-extern size_t  RingBuffer_Write(tRingBuffer *Buffer, const void *Source, size_t Length);
-/**
- * \}
- */
-
-
-#endif
diff --git a/Kernel/include/api_drv_common.h b/Kernel/include/api_drv_common.h
deleted file mode 100644 (file)
index 59bef5f..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * \file api_drv_common.h
- * \brief Common Driver Interface Definitions
- * \author John Hodge (thePowersGang)
- * 
- * \section Introduction
- * There are two ways Acess drivers can communicate with userspace
- * applications, both are through the VFS. The first is by exposing a
- * device as a file buffer, the second is by sending commands via the
- * ioctl() system call.
- * All drivers in Acess must at least conform to the specifcation in this
- * file (even if it is just implementing eTplDrv_IOCtl.DRV_IOCTL_TYPE and
- * returning eTplDrv_Type.DRV_TYPE_NULL, however, doing so is discouraged)
- * 
- * \section ioctls Core IOCtl calls
- * As said, the core Acess driver specifcation defines specific IOCtl calls
- * that all drivers should implement. The four core IOCtls (defined in
- * ::eTplDrv_IOCtl) allow another binary (wether it be a user-mode application
- * or another driver) to tell what type of device a driver provides, the
- * basic identifcation of the driver (4 character ID and BCD version number)
- * and be able to use externally standardised calls that may not have
- * standardised call numbers.
- * NOTE: All ioctl calls WILL return -1 if the driver ran into an error
- * of its own fault while executing the call. If the user was at fault
- * (e.g. by passing a bad buffer) the call will return -2.
- * 
- * \section types Driver Types
- * When the eTplDrv_IOCtl.DRV_IOCTL_TYPE call is made, the driver should
- * return the relevant entry in the ::eTplDrv_Type enumeration that describes
- * what sub-specifcation (and hence, what device type) it implements.
- * These device types are described in their own files, which are liked
- * from their entries in ::eTplDrv_Type.
- */
-#ifndef _API_DRV_COMMON_H
-#define _API_DRV_COMMON_H
-
-/**
- * \enum eTplDrv_IOCtl
- * \brief Common IOCtl Calls
- */
-enum eTplDrv_IOCtl {
-       /**
-        * ioctl(...)
-        * \brief Get driver type
-        * \return The relevant entry from ::eTplDrv_Type
-        */
-       DRV_IOCTL_TYPE,
-       
-       /**
-        * ioctl(..., char *dest[32])
-        * \brief Get driver identifier string
-        * \return 0 on no error
-        * 
-        * This call sets the 32-byte array \a dest to the drivers 31 charater
-        * identifier. This identifier must be unique to the driver series.
-        */
-       DRV_IOCTL_IDENT,
-       
-       /**
-        * ioctl(...)
-        * \brief Get driver version number
-        * \return 24-bit BCD version number (2.2.2)
-        * 
-        * This call returns the 6-digit (2 major, 2 minor, 2 patch) version
-        * number of the driver.
-        */
-       DRV_IOCTL_VERSION,
-       
-       /**
-        * ioctl(..., char *name)
-        * \brief Get a IOCtl call ID from a symbolic name
-        * \return ID number of the call, or 0 if not found
-        * 
-        * This call allows user applications to not need to know the ID numbers
-        * of this driver's IOCtl calls by taking a string and returning the
-        * IOCtl call number associated with that method name.
-        */
-       DRV_IOCTL_LOOKUP,
-
-       /**
-        * \brief First non-reserved IOCtl number for driver extension
-        */
-       DRV_IOCTL_USERMIN = 0x1000,
-};
-
-/**
- * \brief eTplDrv_IOCtl.DRV_IOCTL_LOOKUP names for the core IOCtls
- * These are the official lookup names of the core calls
- */
-#define        DRV_IOCTLNAMES  "type", "ident", "version", "lookup"
-
-/**
- * \brief Helper macro for the base IOCtl calls
- * \param _type        Type number from eTplDrv_Type to return
- * \param _ident       String of max 32-characters that identifies this driver
- * \param _version     Driver's 8.8.8 BCD version number
- * \param _ioctls      Pointer to the IOCtls string array
- * \warning If you have DEBUG enabled in the calling file, this function
- *          will do LEAVE()s before returning, so make sure that the
- *          IOCtl function is ENTER()ed when using debug with this macro
- * 
- * Usage: (Id is the IOCtl call ID)
- * \code
- * switch(Id)
- * {
- * BASE_IOCTLS(DRV_TYPE_MISC, "Ident", 0x100, csaIOCtls)
- * // Your IOCtls go here, starting at index 4
- * }
- * \endcode
- */
-#define BASE_IOCTLS(_type, _ident, _version, _ioctls)  \
-       case DRV_IOCTL_TYPE:    LEAVE('i', (_type));    return (_type);\
-       case DRV_IOCTL_IDENT: {\
-               int tmp = ModUtil_SetIdent(Data, (_ident));\
-               LEAVE('i', tmp);        return tmp;\
-               }\
-       case DRV_IOCTL_VERSION: LEAVE('x', (_version)); return (_version);\
-       case DRV_IOCTL_LOOKUP:{\
-               int tmp = ModUtil_LookupString( _ioctls, (const char*)Data );\
-               LEAVE('i', tmp);\
-               return tmp;\
-               }
-
-/**
- * \enum eTplDrv_Type
- * \brief Driver Types returned by DRV_IOCTL_TYPE
- */
-enum eTplDrv_Type {
-       DRV_TYPE_NULL,          //!< NULL Type - Custom Interface
-       DRV_TYPE_MISC,          //!< Miscelanious Compilant - Supports the core calls
-       DRV_TYPE_TERMINAL,      //!< Terminal - see api_drv_terminal.h
-       DRV_TYPE_VIDEO,         //!< Video - see api_drv_video.h
-       DRV_TYPE_SOUND,         //!< Audio
-       DRV_TYPE_DISK,          //!< Disk - see api_drv_disk.h
-       DRV_TYPE_KEYBOARD,      //!< Keyboard - see api_drv_keyboard.h
-       DRV_TYPE_MOUSE,         //!< Mouse
-       DRV_TYPE_JOYSTICK,      //!< Joystick / Gamepad
-       DRV_TYPE_NETWORK        //!< Network Device - see api_drv_network.h
-};
-
-#endif
diff --git a/Kernel/include/api_drv_disk.h b/Kernel/include/api_drv_disk.h
deleted file mode 100644 (file)
index 94ea2c9..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/**\r
- * \file api_drv_disk.h\r
- * \brief Disk Driver Interface Definitions\r
- * \author John Hodge (thePowersGang)\r
- * \r
- * \section Nomeclature\r
- * All addreses are 64-bit counts of bytes from the logical beginning of\r
- * the disk unless explicitly stated.\r
- * \r
- * \section dirs VFS Layout\r
- * Disk drivers have a flexible directory layout. The root directory can\r
- * contain subdirectories, with the only conditions being that all nodes\r
- * must support ::eTplDrv_IOCtl with DRV_IOCTL_TYPE returning DRV_TYPE_DISK.\r
- * And all file nodes representing disk devices (or partitions) and implemeting\r
- * ::eTplDisk_IOCtl fully\r
- * \r
- * \section files Files\r
- * When a read or write occurs on a normal file in the disk driver it will\r
- * read/write the represented device. The accesses need not be aligned to\r
- * the block size, however aligned reads/writes should be handled specially\r
- * to improve speed (this can be aided by using ::DrvUtil_ReadBlock and\r
- * ::DrvUtil_WriteBlock)\r
- */\r
-#ifndef _API_DRV_DISK_H\r
-#define _API_DRV_DISK_H\r
-\r
-#include <api_drv_common.h>\r
-\r
-/**\r
- * \enum eTplDisk_IOCtl\r
- * \brief Common Disk IOCtl Calls\r
- * \extends eTplDrv_IOCtl\r
- */\r
-enum eTplDisk_IOCtl {\r
-       /**\r
-        * ioctl(..., void)\r
-        * \brief Get the block size\r
-        * \return Size of a hardware block for this device\r
-        */\r
-       DISK_IOCTL_GETBLOCKSIZE = 4,\r
-       \r
-       /**\r
-        * ioctl(..., tTplDisk_CacheRegion *RegionInfo)\r
-        * \brief Sets the cache importantce and protocol for a section of\r
-        *        memory.\r
-        * \param RegionInfo    Pointer to a region information structure\r
-        * \return Boolean failure\r
-        */\r
-       DISK_IOCTL_SETCACHEREGION,\r
-       \r
-       /**\r
-        * ioctl(..., Uint64 *Info[2])\r
-        * \brief Asks the driver to precache a region of disk.\r
-        * \param Region        64-bit Address and Size pair describing the area to cache\r
-        * \return Number of blocks cached\r
-        */\r
-       DISK_IOCTL_PRECACHE,\r
-       \r
-       /**\r
-        * ioclt(..., Uint64 *Region[2])\r
-        * \brief Asks to driver to flush the region back to disk\r
-        * \param Region        64-bit Address and Size pair describing the area to flush\r
-        * \note If Region[0] == -1 then the entire disk's cache is flushed\r
-        * \return Number of blocks flushed (or 0 for entire disk)\r
-        */\r
-       DISK_IOCTL_FLUSH\r
-};\r
-\r
-/**\r
- * \brief Describes the cache parameters of a region on the disk\r
- */\r
-typedef struct sTplDisk_CacheRegion\r
-{\r
-       Uint64  Base;   //!< Base of cache region\r
-       Uint64  Length; //!< Size of cache region\r
-       /**\r
-        * \brief Cache Protocol & Flags\r
-        * \r
-        * The low 4 bits denot the cache protocol to be used by the\r
-        * region (see ::eTplDisk_CacheProtocols for a list).\r
-        * The high 4 bits denote flags to apply to the cache (see\r
-        * ::eTplDisk_CacheFlags)\r
-        */\r
-       Uint8   Flags;\r
-       Uint8   Priority;       //!< Lower is a higher proritory\r
-       /**\r
-        * \brief Maximum size of cache, in blocks\r
-        * \note If CacheSize is zero, the implemenation defined limit is used\r
-        */\r
-       Uint16  CacheSize;\r
-}      tTplDisk_CacheRegion;\r
-\r
-/**\r
- * \brief Cache protocols to use\r
- */\r
-enum eTplDisk_CacheProtocols\r
-{\r
-       /**\r
-        * \brief Don't cache the region\r
-        */\r
-       \r
-       DISK_CACHEPROTO_DONTCACHE,\r
-       /**\r
-        * \brief Most recently used blocks cached\r
-        * \note This is the default action for undefined regions\r
-        */\r
-       DISK_CACHEPROTO_RECENTLYUSED,\r
-       /**\r
-        * \brief Cache the entire region in memory\r
-        * \r
-        * This is a faster version of setting Length to CacheSize*BlockSize\r
-        */\r
-       DISK_CACHEPROTO_FULLCACHE,\r
-       \r
-       /**\r
-        * \brief Cache only on demand\r
-        * \r
-        * Only cache when the ::DISK_IOCTL_PRECACHE IOCtl is used\r
-        */\r
-       DISK_CACHEPROTO_EXPLICIT\r
-};\r
-\r
-/**\r
- * \brief Flags for the cache\r
- */\r
-enum eTplDisk_CacheFlags\r
-{\r
-       /**\r
-        * \brief Write all changes to the region straight back to media\r
-        */\r
-       DISK_CACHEFLAG_WRITETHROUGH = 0x10\r
-};\r
-\r
-/**\r
- * \brief IOCtl name strings\r
- */\r
-#define        DRV_DISK_IOCTLNAMES     "get_block_size","set_cache_region","set_precache"\r
-\r
-/**\r
- * \name Disk Driver Utilities\r
- * \{\r
- */\r
-\r
-/**\r
- * \brief Callback function type used by DrvUtil_ReadBlock and DrvUtil_WriteBlock\r
- * \param Address      Zero based block number to read\r
- * \param Count        Number of blocks to read\r
- * \param Buffer       Destination for read blocks\r
- * \param Argument     Argument provided in ::DrvUtil_ReadBlock and ::DrvUtil_WriteBlock\r
- */\r
-typedef Uint   (*tDrvUtil_Read_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
-typedef Uint   (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *Buffer, Uint Argument);\r
-\r
-/**\r
- * \brief Reads a range from a block device using aligned reads\r
- * \param Start        Base byte offset\r
- * \param Length       Number of bytes to read\r
- * \param Buffer       Destination for read data\r
- * \param ReadBlocks   Callback function to read a sequence of blocks\r
- * \param BlockSize    Size of an individual block\r
- * \param Argument     An argument to pass to \a ReadBlocks\r
- * \return Number of bytes read\r
- */\r
-extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
-       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
-/**\r
- * \brief Writes a range to a block device using aligned writes\r
- * \param Start        Base byte offset\r
- * \param Length       Number of bytes to write\r
- * \param Buffer       Destination for read data\r
- * \param ReadBlocks   Callback function to read a sequence of blocks\r
- * \param WriteBlocks  Callback function to write a sequence of blocks\r
- * \param BlockSize    Size of an individual block\r
- * \param Argument     An argument to pass to \a ReadBlocks and \a WriteBlocks\r
- * \return Number of bytes written\r
- */\r
-extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
-       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
-       Uint64 BlockSize, Uint Argument);\r
-\r
-/**\r
- * \}\r
- */\r
-\r
-#endif\r
diff --git a/Kernel/include/api_drv_joystick.h b/Kernel/include/api_drv_joystick.h
deleted file mode 100644 (file)
index 3ec8597..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/**\r
- * \file api_drv_joystick.h\r
- * \brief Joystick Driver Interface Definitions\r
- * \author John Hodge (thePowersGang)\r
- * \r
- * \section dirs VFS Layout\r
- * Joystick drivers define a single VFS node, that acts as a fixed size file.\r
- * Reads from this file return the current state, writes are ignored.\r
- *\r
- * \section File Structure\r
- * The device file must begin with a valid sJoystick_FileHeader structure.\r
- * The file header is followed by \a NAxies instances of sJoystick_Axis, one\r
- * for each axis.\r
- * This is followed by \a NButtons boolean values (represented using \a Uint8),\r
- * each representing the state of a single button (where 0 is unpressed,\r
- * 0xFF is fully depressed - intermediate values are valid in the case of\r
- * variable-pressure buttons)\r
- */\r
-#ifndef _API_DRV_JOYSTICK_H\r
-#define _API_DRV_JOYSTICK_H\r
-\r
-#include <api_drv_common.h>\r
-\r
-/**\r
- * \enum eTplJoystick_IOCtl\r
- * \brief Common Joystick IOCtl Calls\r
- * \extends eTplDrv_IOCtl\r
- */\r
-enum eTplJoystick_IOCtl {\r
-       /**\r
-        * ioctl(..., tJoystick_Callback *Callback)\r
-        * \brief Sets the callback\r
-        * \note Can be called from kernel mode only\r
-        *\r
-        * Sets the callback that is called when a event occurs (button or axis\r
-        * change). This function pointer must be in kernel mode (although,\r
-        * kernel->user or kernel->ring3driver abstraction functions can be used)\r
-        * \r
-        * Axis events depend on the axis limit, if non-zero, the callback fires\r
-        * if the cursor position changes. Otherwise it fires when the axis value\r
-        * (cursor accelleration) changes.\r
-        */\r
-       JOY_IOCTL_SETCALLBACK = 4,\r
-\r
-       /**\r
-        * ioctl(..., int *Argument)\r
-        * \brief Set the argument passed as the first parameter to the callback\r
-        * \note Kernel mode only\r
-        */\r
-       JOY_IOCTL_SETCALLBACKARG,\r
-\r
-       /**\r
-        * ioctl(..., tJoystickNumValue *)\r
-        * \brief Set maximum value for sJoystick_Axis.CursorPos\r
-        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
-        */\r
-       JOY_IOCTL_GETSETAXISLIMIT,\r
-\r
-       /**\r
-        * ioctl(..., tJoystickNumValue *)\r
-        * \brief Set the value of sJoystick_Axis.CursorPos\r
-        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
-        */\r
-       JOY_IOCTL_GETSETAXISPOSITION,\r
-       \r
-       /**\r
-        * ioctl(..., tJoystickNumValue *)\r
-        * \brief Set axis flags\r
-        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
-        * \todo Define flag values\r
-        */\r
-       JOY_IOCTL_GETSETAXISFLAGS,\r
-\r
-       /**\r
-        * ioctl(..., tJoystickNumValue *)\r
-        * \brief Set Button Flags\r
-        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
-        * \todo Define flag values\r
-        */\r
-       JOY_IOCTL_GETSETBUTTONFLAGS,\r
-};\r
-\r
-/**\r
- * \brief Symbolic names for Joystick IOCtls\r
- */\r
-#define        DRV_JOY_IOCTLNAMES      "set_callback", "set_callback_arg", "getset_axis_limit", "getset_axis_position", \\r
-       "getset_axis_flags", "getset_button_flags"\r
-\r
-// === TYPES ===\r
-typedef struct sJoystick_NumValue      tJoystick_NumValue;\r
-typedef struct sJoystick_FileHeader    tJoystick_FileHeader;\r
-typedef struct sJoystick_Axis  tJoystick_Axis;\r
-\r
-/**\r
- * \brief Number/Value pair for joystick IOCtls\r
- */\r
-struct sJoystick_NumValue\r
-{\r
-        int    Num;    //!< Axis/Button number\r
-        int    Value;  //!< Value (see IOCtl defs for meaning)\r
-};\r
-\r
-/**\r
- * \brief Callback type for JOY_IOCTL_SETCALLBACK\r
- * \param Ident        Ident value passed to JOY_IOCTL_SETCALLBACK\r
- * \r
- */\r
-typedef void (*tJoystick_Callback)(int Ident, int bIsAxis, int Num, int Delta);\r
-\r
-/**\r
- * \struct sJoystick_FileHeader\r
- * \brief Format of the joystick VFS node's first bytes\r
- */\r
-struct sJoystick_FileHeader\r
-{\r
-       Uint16  NAxies; //!< Number of Axies\r
-       Uint16  NButtons;       //!< Number of buttons\r
-};\r
-\r
-/**\r
- * \brief Axis Definition in file data\r
- *\r
- * Describes the current state of an axis on the joystick.\r
- * \a CursorPos is between zero and the current limit set by the\r
- * JOY_IOCTL_GETSETAXISLIMIT IOCtl, while \a CurValue indicates the\r
- * current position of the joystick axis. This is defined to be between\r
- * \a MinValue and \a MaxValue.\r
- */\r
-struct sJoystick_Axis\r
-{\r
-       Sint16  MinValue;       //!< Minumum value for \a CurValue\r
-       Sint16  MaxValue;       //!< Maximum value for \a CurValue\r
-       Sint16  CurValue;       //!< Current value (joystick position)\r
-       Uint16  CursorPos;      //!< Current state (cursor position)\r
-};\r
-\r
-/**\r
- * \brief Macro to define a structure for a joystick's node\r
- * \param _naxies      Number of axies\r
- * \param _nbuttons    Number of buttons\r
- * \note This just defines the structure, it's up to the driver to set the\r
- *       sJoystick_FileHeader.NAxies and sJoystick_FileHeader.NButtons fields.\r
- */\r
-#define JOY_INFOSTRUCT(_naxies, _nbuttons) struct { \\r
-       Uint16  NAxies, NButtons;\\r
-       tJoystick_Axis  Axies[_naxies];\\r
-       Uint16  Buttons[_nbuttons];\\r
-       }\r
-\r
-#endif\r
diff --git a/Kernel/include/api_drv_keyboard.h b/Kernel/include/api_drv_keyboard.h
deleted file mode 100644 (file)
index 57ca247..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/**\r
- * \file api_drv_keyboard.h\r
- * \brief Keyboard Driver Interface Definitions\r
- * \author John Hodge (thePowersGang)\r
- * \r
- * \section dirs VFS Layout\r
- * Keyboard drivers consist of only a single node, which is a normal file\r
- * node with a size of zero. All reads and writes to this node are ignored\r
- * (tVFS_Node.Read and tVFS_Node.Write are NULL)\r
- */\r
-#ifndef _API_DRV_KEYBOARD_H\r
-#define _API_DRV_KEYBOARD_H\r
-\r
-#include <api_drv_common.h>\r
-\r
-/**\r
- * \enum eTplKeyboard_IOCtl\r
- * \brief Common Keyboard IOCtl Calls\r
- * \extends eTplDrv_IOCtl\r
- */\r
-enum eTplKeyboard_IOCtl {\r
-       /**\r
-        * ioctl(..., int *Rate)\r
-        * \brief Get/Set Repeat Rate\r
-        * \param Rate  New repeat rate (pointer)\r
-        * \return Current/New Repeat rate\r
-        * \r
-        * Gets/Set the repeat rate (actually the time in miliseconds between\r
-        * repeats) of a held down key.\r
-        * If the rate is set to zero, repeating will be disabled.\r
-        */\r
-       KB_IOCTL_REPEATRATE = 4,\r
-       \r
-       /**\r
-        * ioctl(..., int *Delay)\r
-        * \brief Get/Set Repeat Delay\r
-        * \param Delay New repeat delay (pointer)\r
-        * \return Current/New repeat delay\r
-        * \r
-        * Gets/Set the time in miliseconds before a key starts repeating\r
-        * after a key is pressed.\r
-        * Setting the delay to a negative number will cause the function to\r
-        * return -1\r
-        */\r
-       KB_IOCTL_REPEATDELAY,\r
-       \r
-       \r
-       /**\r
-        * ioctl(..., tKeybardCallback *Callback)\r
-        * \brief Sets the callback\r
-        * \note Can be called from kernel mode only\r
-        * \r
-        * Sets the function to be called when a key event occurs (press, release\r
-        * or repeat). This function pointer must be in kernel mode (although,\r
-        * kernel->user or kernel->ring3driver abstraction functions can be used)\r
-        *\r
-        * This function is called when a key is pressed, repeated or released.\r
-        * If the raw scancode is to be included with the key event, it should precede\r
-        * the event.\r
-        */\r
-       KB_IOCTL_SETCALLBACK\r
-};\r
-\r
-/**\r
- * \brief Symbolic names for Keyboard IOCtls\r
- */\r
-#define DRV_KEYBAORD_IOCTLNAMES        "getset_repeat_rate", "getset_repeat_delay", "set_callback"\r
-\r
-/**\r
- * \brief Callback type for KB_IOCTL_SETCALLBACK\r
- * \param Key  Key symbol (Unicode or eTplKeyboard_KeyCodes)\r
- */\r
-typedef void (*tKeybardCallback)(Uint32 Key);\r
-\r
-/**\r
- * \name Callback key flags\r
- * \brief Flags for values passed to the callback\r
- * \{\r
- */\r
-#define KEY_CODEPOINT_MASK     0x3FFFFFFF\r
-#define KEY_ACTION_MASK        0xC0000000\r
-#define KEY_ACTION_PRESS       0x00000000      //!< Key pressed\r
-#define KEY_ACTION_RELEASE     0x40000000      //!< Key released\r
-#define KEY_ACTION_REFIRE      0x80000000      //!< Repeated key\r
-#define KEY_ACTION_RAWSYM      0xC0000000      //!< Raw key symbol (comes before a press/repeat/release)\r
-/**\r
- * \}\r
- */\r
-\r
-/**\r
- * \brief Symbolic key codes\r
- * \r
- * These key codes represent non-pritable characters and are placed above\r
- * the Unicode character space.\r
- * If the using driver recieves a key code with the 31st bit set, it means\r
- * that that key has been released.\r
- */\r
-enum eTplKeyboard_KeyCodes {\r
-       KEY_ESC = 0x1B, //!< Escape Character\r
-       \r
-       KEY_NP_MASK = 0x20000000,       //! Mask for non-printable characters\r
-       \r
-       /**\r
-        * \name Special Keys\r
-        * \brief These keys are usually used on their own\r
-        * \{\r
-        */\r
-       KEY_CAPSLOCK,\r
-       KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,\r
-       KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, \r
-       KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,\r
-       KEY_NUMLOCK, KEY_SCROLLLOCK,\r
-       KEY_HOME, KEY_END, KEY_INS, KEY_DEL,\r
-       KEY_PAUSE, KEY_BREAK,\r
-       KEY_PGUP, KEY_PGDOWN,\r
-       KEY_KPENTER, KEY_KPSLASH, KEY_KPMINUS, KEY_KPPLUS, KEY_KPSTAR,\r
-       KEY_KPHOME, KEY_KPUP, KEY_KPPGUP, KEY_KPLEFT, KEY_KP5, KEY_KPRIGHT,\r
-       KEY_KPEND, KEY_KPDOWN, KEY_KPPGDN, KEY_KPINS, KEY_KPDEL,\r
-       KEY_LWIN, KEY_RWIN,\r
-       KEY_MENU,\r
-       /**\r
-        * \}\r
-        */\r
-       \r
-       // Modifiers\r
-       /**\r
-        * \name Modifiers\r
-        * \brief These keye usually alter the character stream sent to the user\r
-        * \{\r
-        */\r
-       KEY_MODIFIERS = 0x30000000,\r
-       KEY_LCTRL, KEY_RCTRL,\r
-       KEY_LALT, KEY_RALT,\r
-       KEY_LSHIFT, KEY_RSHIFT,\r
-       /**\r
-        * \}\r
-        */\r
-};\r
-\r
-\r
-#endif\r
diff --git a/Kernel/include/api_drv_network.h b/Kernel/include/api_drv_network.h
deleted file mode 100644 (file)
index 6cb8c34..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/**\r
- * \file api_drv_network.h\r
- * \brief Network Interface Driver Interface Definitions\r
- * \r
- * \section dirs VFS Layout\r
- * All network drivers must have the following basic VFS structure\r
- * The root of the driver will only contain files that are named from zero\r
- * upwards that represent the present network adapters that this driver\r
- * controls. All VFS nodes must implement ::eTplDrv_IOCtl with\r
- * DRV_IOCTL_TYPE returning DRV_TYPE_NETWORK.\r
- * The adapter nodes must also implement ::eTplNetwork_IOCtl fully\r
- * (unless it is noted in the ::eTplNetwork_IOCtl documentation that a\r
- * call is optional)\r
- * \r
- * \section files Adapter Files\r
- * \subsection Reading\r
- * When an adapter file is read from, the driver will block the reading\r
- * thread until a packet arrives (if there is not already an unhandled\r
- * packet in the queue) this will then be read into the destination buffer.\r
- * If the packet does not fit in the buffer, the end of it is discarded.\r
- * Likewise, if the packet does not completely fill the buffer, the call\r
- * will still read to the buffer and then return the size of the packet.\r
- * \subsection Writing\r
- * When an adapter is written to, the data written is encoded as a packet\r
- * and sent, if the data is not the correct size to be sent (if the packet\r
- * is too small, or if it is too large) -1 should be returned and the packet\r
- * will not be sent.\r
- */\r
-#ifndef _API_DRV_NETWORK_H\r
-#define _API_DRV_NETWORK_H\r
-\r
-#include <api_drv_common.h>\r
-\r
-/**\r
- * \enum eTplNetwork_IOCtl\r
- * \brief Common Network IOCtl Calls\r
- * \extends eTplDrv_IOCtl\r
- */\r
-enum eTplNetwork_IOCtl {\r
-       /**\r
-        * ioctl(..., Uint8 *MAC[6])\r
-        * \brief Get the MAC address of the interface\r
-        * \return 1 on success, 0 if the file is the root, -1 on error\r
-        * \r
-        * Copies the six byte Media Access Control (MAC) address of the\r
-        * adapter to the \a MAC array.\r
-       */\r
-       NET_IOCTL_GETMAC = 4\r
-};\r
-\r
-/**\r
- * \brief IOCtl name strings for use with eTplDrv_IOCtl.DRV_IOCTL_LOOKUP\r
- */\r
-#define        DRV_NETWORK_IOCTLNAMES  "get_mac_addr"\r
-\r
-#endif\r
diff --git a/Kernel/include/api_drv_terminal.h b/Kernel/include/api_drv_terminal.h
deleted file mode 100644 (file)
index 3142d33..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/**\r
- * \file api_drv_terminal.h\r
- * \brief Terminal Driver Interface Definitions\r
-*/\r
-#ifndef _API_DRV_TERMINAL_H\r
-#define _API_DRV_TERMINAL_H\r
-\r
-#include <api_drv_common.h>\r
-\r
-/**\r
- * \brief Common Terminal IOCtl Calls\r
- * \extends eTplDrv_IOCtl\r
- */\r
-enum eTplTerminal_IOCtl {\r
-       /**\r
-        * ioctl(..., int *mode)\r
-        * \brief Get/Set the current video mode type\r
-        * \param mode Pointer to an integer with the new mode number (or NULL)\r
-        *             If \a mode is non-NULL the current terminal mode is changed/updated\r
-        *             to the mode indicated by \a *mode\r
-        * \note See ::eTplTerminal_Modes\r
-        * \return Current/new terminal mode\r
-       */\r
-       TERM_IOCTL_MODETYPE = 4,\r
-       \r
-       /**\r
-        * ioctl(..., int *width)\r
-        * \brief Get/set the display width\r
-        * \param width Pointer to an integer containing the new width (or NULL)\r
-        * \return Current/new width\r
-        * \r
-        * If \a width is non-NULL the current width is updated (but is not\r
-        * applied until ::TERM_IOCTL_MODETYPE is called with \a mode non-NULL.\r
-        */\r
-       TERM_IOCTL_WIDTH,\r
-       \r
-       /**\r
-        * ioctl(..., int *height)\r
-        * \brief Get/set the display height\r
-        * \param height        Pointer to an integer containing the new height\r
-        * \return Current height\r
-        * \r
-        * If \a height is non-NULL the current height is updated (but is not\r
-        * applied until ::TERM_IOCTL_MODETYPE is called with a non-NULL \a mode.\r
-        */\r
-       TERM_IOCTL_HEIGHT,\r
-       \r
-       /**\r
-        * ioctl(..., tTerm_IOCtl_Mode *info)\r
-        * \brief Queries the current driver about it's native modes\r
-        * \param info  A pointer to a ::tTerm_IOCtl_Mode with \a ID set to\r
-        *        the mode index (or NULL)\r
-        * \return Number of modes\r
-        * \r
-        * If \a info is NULL, the number of avaliable vative display modes\r
-        * is returned. These display modes will have sequential ID numbers\r
-        * from zero up to this value.\r
-        * \r
-        * \note The id field of \a info is not for use with ::TERM_IOCTL_MODETYPE\r
-        *       This field is just for indexing the mode to get its information.\r
-        */\r
-       TERM_IOCTL_QUERYMODE,\r
-       \r
-       /**\r
-        * ioctl(...)\r
-        * \brief Forces the current terminal to be shown\r
-        */\r
-       TERM_IOCTL_FORCESHOW,\r
-       \r
-       /**\r
-        * ioctl(..., tVideo_IOCtl_Pos *pos)\r
-        * \brief Returns the current text cursor position\r
-        * \param pos   New cursor position. If NULL, the position is not changed\r
-        * \return Cursor position (as X+Y*Width)\r
-        */\r
-       TERM_IOCTL_GETSETCURSOR,\r
-       \r
-       /**\r
-        * ioctl(..., tVideo_IOCtl_Bitmap *Bmp)\r
-        * \brief Set the video cursor bitmap\r
-        * \param Bmp   New bitmap (if NULL, the current bitmap is removed)\r
-        * \return Boolean failure\r
-        */\r
-       TERM_IOCTL_SETCURSORBITMAP,\r
-};\r
-\r
-/**\r
- * \brief Virtual Terminal Mode\r
- * Describes a VTerm mode to the caller of ::TERM_IOCTL_QUERYMODE\r
- */\r
-typedef struct sTerm_IOCtl_Mode\r
-{\r
-       short   ID;             //!< Zero Based index of mode\r
-       short   DriverID;       //!< Driver's ID number (from ::tVideo_IOCtl_Mode)\r
-       Uint16  Height; //!< Height\r
-       Uint16  Width;  //!< Width\r
-       Uint8   Depth;  //!< Bits per cell\r
-       struct {\r
-               unsigned bText: 1;      //!< Text Mode marker\r
-               unsigned unused:        7;\r
-       };\r
-} tTerm_IOCtl_Mode;\r
-\r
-/**\r
- * \brief Terminal Modes\r
- */\r
-enum eTplTerminal_Modes {\r
-       /**\r
-        * \brief UTF-8 Text Mode\r
-        * Any writes to the terminal file are treated as UTF-8 encoded\r
-        * strings and reads will also return UTF-8 strings.\r
-        */\r
-       TERM_MODE_TEXT,\r
-       \r
-       /**\r
-        * \brief 32bpp Framebuffer\r
-        * Writes to the terminal file will write to the framebuffer.\r
-        * Reads will return UTF-32 characters\r
-        */\r
-       TERM_MODE_FB,\r
-       \r
-       /**\r
-        * \brief 32bpp 2D Accellerated mode\r
-        * Writes to the terminal file will be read as a command stream\r
-        * defined in ::eTplTerminal_2D_Commands\r
-        */\r
-       TERM_MODE_2DACCEL,\r
-       \r
-       /**\r
-        * \brief OpenGL 2D/3D\r
-        * Writes to the terminal file will send 3D commands\r
-        * Reads will return UTF-32 characters\r
-        * \note May or may not stay in the spec\r
-        */\r
-       TERM_MODE_3D,\r
-       \r
-       /**\r
-        * \brief Number of terminal modes\r
-        */\r
-       NUM_TERM_MODES\r
-};\r
-\r
-/**\r
- * \brief 2D Command IDs\r
- * \todo Complete this structure\r
- * \r
- * Command IDs for when the terminal type is eTplTerminal_Modes.TERM_MODE_2DACCEL\r
- */\r
-enum eTplTerminal_2D_Commands\r
-{\r
-       /**\r
-        * \brief No Operation - Used for padding\r
-        */\r
-       TERM_2DCMD_NOP,\r
-       \r
-       /**\r
-        * (Uint16 X, Y, W, H, Uint32 Data[])\r
-        * \brief Blits a bitmap to the display\r
-        * \param X,Y   Coordinates of Top-Left corner\r
-        * \param W,H   Dimensions\r
-        * \param Data  32-bpp pixel data\r
-        */\r
-       TERM_2DCMD_PUSH\r
-};\r
-\r
-#endif\r
diff --git a/Kernel/include/api_drv_video.h b/Kernel/include/api_drv_video.h
deleted file mode 100644 (file)
index ff9c395..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-/**\r
- * \file api_drv_video.h\r
- * \brief Video Driver Interface Definitions\r
- * \note For AcessOS Version 1\r
- * \r
- * Video drivers extend the common driver interface api_drv_common.h\r
- * and must support the IOCtl numbers defined in this file to be\r
- * compatable with Acess (drivers may implement more IOCtls above\r
- * DRV_IOCTL_USERMIN).\r
- * \r
- * \section IOCtls\r
- * As said, a compatable driver must implement these calls correctly,\r
- * but they may choose not to allow direct user access to the framebuffer.\r
- * \r
- * \section Screen Contents\r
- * Writes to the driver's file while in component colour modes\r
- * must correspond to a change of the contents of the screen. The framebuffer\r
- * must start at offset 0 in the file.\r
- * Reading from the screen must either return zero, or read from the\r
- * framebuffer.\r
- * \r
- * \section Mode Support\r
- * All video drivers must support text output for every resolution (hardware\r
- * accelerated or software), and at least the _BLIT and _FILL 2D operations\r
- * (these may be implemented specifically for text mode).\r
- */\r
-#ifndef _API_DRV_VIDEO_H\r
-#define _API_DRV_VIDEO_H\r
-\r
-#include <api_drv_common.h>\r
-\r
-/**\r
- * \enum eTplVideo_IOCtl\r
- * \brief Common Video IOCtl Calls\r
- * \extends eTplDrv_IOCtl\r
- */\r
-enum eTplVideo_IOCtl {\r
-       /**\r
-        * ioctl(..., int *mode)\r
-        * \brief Get/Set Mode\r
-        * \return Current mode ID or -1 on error\r
-        * \r
-        * If \a mode is non-NULL, the current video mode is set to \a *mode.\r
-        * This updated ID is then returned to the user.\r
-        */\r
-       VIDEO_IOCTL_GETSETMODE = 4,\r
-       \r
-       /**\r
-        * ioctl(..., tVideo_IOCtl_Mode *info)\r
-        * \brief Find a matching mode\r
-        * \return 1 if a mode was found, 0 otherwise\r
-        * \r
-        * Using avaliable modes matching the \a bpp and \a flags fields\r
-        * set the \a id, \a width and \a heights fields to the closest\r
-        * matching mode.\r
-        */\r
-       VIDEO_IOCTL_FINDMODE,\r
-       \r
-       /**\r
-        * ioctl(..., tVideo_IOCtl_Mode *info)\r
-        * \brief Get mode info\r
-        * \return 1 if the mode exists, 0 otherwise\r
-        * \r
-        * Set \a info's fields to the mode specified by the \a id field.\r
-        */\r
-       VIDEO_IOCTL_MODEINFO,\r
-       \r
-       /**\r
-        * ioctl(..., int *NewFormat)\r
-        * \brief Switches between Text, Framebuffer and 3D modes\r
-        * \param NewFormat     Pointer to the new format code (see eTplVideo_BufFormats)\r
-        * \return Original format\r
-        * \r
-        * Enabes and disables the video text mode, changing the behavior of\r
-        * writes to the device file.\r
-        */\r
-       VIDEO_IOCTL_SETBUFFORMAT,\r
-       \r
-       /**\r
-        * ioctl(..., tVideo_IOCtl_Pos *pos)\r
-        * \brief Sets the cursor position\r
-        * \return Boolean success\r
-        * \r
-        * Set the text mode cursor position (if it is supported)\r
-        * If the \a pos is set to (-1,-1) the cursor is hidden, otherwise\r
-        * \a pos MUST be within the current screen size (as given by the\r
-        * current mode's tVideo_IOCtl_Mode.width and tVideo_IOCtl_Mode.height\r
-        * fields).\r
-        */\r
-       VIDEO_IOCTL_SETCURSOR,\r
-       \r
-       /**\r
-        * ioctl(..., tVideo_IOCtl_Bitmap *Image)\r
-        * \brief Sets the cursor image\r
-        * \return Boolean success\r
-        *\r
-        * Sets the graphics mode cursor image\r
-        */\r
-       VIDEO_IOCTL_SETCURSORBITMAP\r
-};\r
-\r
-/**\r
- * \brief Symbolic names for Video IOCtls (#4 onwards)\r
- */\r
-#define DRV_VIDEO_IOCTLNAMES   "getset_mode", "find_mode", "mode_info", "set_buf_format", "set_cursor", "set_cursor_bitmap"\r
-\r
-/**\r
- * \brief Mode Structure used in IOCtl Calls\r
- * \r
- * Defines a video mode supported by (or requested of) this driver (depending\r
- * on what ioctl call is used)\r
- */\r
-typedef struct sVideo_IOCtl_Mode\r
-{\r
-       short   id;             //!< Mode ID\r
-       Uint16  width;  //!< Width\r
-       Uint16  height; //!< Height\r
-       Uint8   bpp;    //!< Bits per pixel\r
-       Uint8   flags;  //!< Mode Flags (none defined, should be zero)\r
-}      tVideo_IOCtl_Mode;\r
-\r
-/**\r
- * \brief Buffer Format Codes\r
- */\r
-enum eTplVideo_BufFormats\r
-{\r
-       /**\r
-        * \brief Text Mode\r
-        * \r
-        * The device file presents itself as an array of ::tVT_Char\r
-        * each describing a character cell on the screen.\r
-        * These cells are each \a giVT_CharWidth pixels wide and\r
-        * \a giVT_CharHeight high.\r
-        */\r
-       VIDEO_BUFFMT_TEXT,\r
-       /**\r
-        * \brief Framebuffer Mode\r
-        * \r
-        * The device file presents as an array of 32-bpp pixels describing\r
-        * the entire screen. The format of a single pixel is in xRGB format\r
-        * (top 8 bits ignored, next 8 bits red, next 8 bits green and\r
-        * the bottom 8 bits blue)\r
-        */\r
-       VIDEO_BUFFMT_FRAMEBUFFER,\r
-       /**\r
-        * \brief 2D Accelerated Mode\r
-        * \r
-        * The device file acts as a character device, accepting a stream of\r
-        * commands described in eTplVideo_2DCommands when written to.\r
-        */\r
-       VIDEO_BUFFMT_2DSTREAM,\r
-       /**\r
-        * \brief 3D Accelerated Mode\r
-        * \r
-        * The device file acts as a character device, accepting a stream of\r
-        * commands described in eTplVideo_3DCommands when written to.\r
-        */\r
-       VIDEO_BUFFMT_3DSTREAM\r
-};\r
-\r
-/**\r
- * \brief 2D Accellerated Video Commands\r
- * \r
- * Commands passed in the command stream for ::VIDEO_BUFFMT_2DSTREAM\r
- */\r
-enum eTplVideo_2DCommands\r
-{\r
-       /**\r
-        * \brief No Operation\r
-        */\r
-       VIDEO_2DOP_NOP,\r
-       /**\r
-        * \brief Fill a region\r
-        * \param X     Uint16 - Leftmost pixels of the region\r
-        * \param Y     Uint16 - Topmost pixels of the region\r
-        * \param W     Uint16 - Width of the region\r
-        * \param H     Uint16 - Height of the region\r
-        * \param Colour        Uint32 - Value to fill with\r
-        */\r
-       VIDEO_2DOP_FILL,\r
-       /**\r
-        * \brief Copy a region from one part of the framebuffer to another\r
-        * \param DestX Uint16 - Leftmost pixels of the destination\r
-        * \param DestY Uint16 - Topmost pixels of the destination\r
-        * \param SrcX  Uint16 - Leftmost pixels of the source\r
-        * \param SrcY  Uint16 - Topmost pixels of the source\r
-        * \param Width Uint16 - Width of the region\r
-        * \param Height        Uint16 - Height of the region\r
-        */\r
-       VIDEO_2DOP_BLIT,\r
-\r
-\r
-       /**\r
-        * \brief Copy a region from video memory to the framebuffer\r
-        */\r
-       VIDEO_2DOP_BLITBUF,\r
-\r
-       /**\r
-        * \brief Copy and scale a region from video memory to the framebuffer\r
-        */\r
-       VIDEO_2DOP_BLITSCALEBUF,\r
-\r
-       NUM_VIDEO_2DOPS\r
-};\r
-\r
-/**\r
- * \brief Describes a position in the video framebuffer\r
- */\r
-typedef struct sVideo_IOCtl_Pos\r
-{\r
-       Sint16  x;      //!< X Coordinate\r
-       Sint16  y;      //!< Y Coordinate\r
-}      tVideo_IOCtl_Pos;\r
-\r
-/**\r
- * \brief Bitmap object (out of band image)\r
- */\r
-typedef struct sVideo_IOCtl_Bitmap\r
-{\r
-       Sint16  W;      //!< Width of image\r
-       Sint16  H;      //!< Height of image\r
-       Sint16  XOfs;   //!< X Offset of center\r
-       Sint16  YOfs;   //!< Y Offset of center\r
-       Uint32  Data[]; //!< Image data (ARGB array)\r
-}      tVideo_IOCtl_Bitmap;\r
-\r
-/**\r
- * \brief Virtual Terminal Representation of a character\r
- */\r
-typedef struct sVT_Char\r
-{\r
-       Uint32  Ch;     //!< UTF-32 Character\r
-       union {\r
-               struct {\r
-                       Uint16  BGCol;  //!< 12-bit Foreground Colour\r
-                       Uint16  FGCol;  //!< 12-bit Background Colour\r
-               };\r
-               Uint32  Colour; //!< Compound colour for ease of access\r
-       };\r
-}      tVT_Char;\r
-\r
-/**\r
- * \name Basic builtin colour definitions\r
- * \{\r
- */\r
-#define        VT_COL_BLACK    0x0000\r
-#define        VT_COL_GREY             0x0888\r
-#define        VT_COL_LTGREY   0x0CCC\r
-#define        VT_COL_WHITE    0x0FFF\r
-/**\r
- * \}\r
- */\r
-\r
-//! \brief Defines the width of a rendered character\r
-extern int     giVT_CharWidth;\r
-//! \brief Defines the height of a rendered character\r
-extern int     giVT_CharHeight;\r
-/**\r
- * \name Font rendering\r
- * \{\r
- */\r
-/**\r
- * \brief Driver helper that renders a character to a buffer\r
- * \param Codepoint    Unicode character to render\r
- * \param Buffer       Buffer to render to\r
- * \param Depth        Bit depth of the destination buffer\r
- * \param Pitch        Number of bytes per line\r
- * \param BGC  32-bit Background Colour\r
- * \param FGC  32-bit Foreground Colour\r
- * \r
- * This function is provided to help video drivers to support a simple\r
- * text mode by keeping the character rendering abstracted from the driver,\r
- * easing the driver development and reducing code duplication.\r
- */\r
-extern void    VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC);\r
-/**\r
- * \fn Uint32 VT_Colour12to24(Uint16 Col12)\r
- * \brief Converts a colour from 12bpp to 24bpp\r
- * \param Col12        12-bpp input colour\r
- * \return Expanded 32-bpp (24-bit colour) version of \a Col12\r
- */\r
-extern Uint32  VT_Colour12to24(Uint16 Col12);\r
-/**\r
- * \brief Converts a colour from 12bpp to 14bpp\r
- * \param Col12        12-bpp input colour\r
- * \return 15 bits per pixel value\r
- */\r
-extern Uint16  VT_Colour12to15(Uint16 Col12);\r
-/**\r
- * \brief Converts a colour from 12bpp to 32bpp\r
- * \param Col12        12-bpp input colour\r
- * \param Depth        Desired bit depth\r
- * \return \a Depth bit number, denoting Col12\r
- * \r
- * Expands the source colour into a \a Depth bits per pixel representation.\r
- * The colours are expanded with preference to Green, Blue and Red in that order\r
- * (so, green gets the first spare pixel, blue gets the next, and red never gets\r
- * the spare). \n\r
- * The final bit of each component is used to fill the lower bits of the output.\r
- */\r
-extern Uint32  VT_Colour12toN(Uint16 Col12, int Depth);\r
-/**\r
- * \}\r
- */\r
-\r
-/**\r
- * \brief Maximum cursor width for using the DrvUtil software cursor\r
- */\r
-#define DRVUTIL_MAX_CURSOR_W   32\r
-/**\r
- * \brief Maximum cursor width for using the DrvUtil software cursor\r
- */\r
-#define DRVUTIL_MAX_CURSOR_H   32\r
-\r
-/**\r
- * \brief Framebuffer information used by all DrvUtil_Video functions\r
- */\r
-typedef struct sDrvUtil_Video_BufInfo\r
-{\r
-       /**\r
-        * \name Framebuffer state\r
-        * \{\r
-        */\r
-       /**\r
-        * \brief Framebuffer virtual address\r
-        */\r
-       void    *Framebuffer;\r
-       /**\r
-        * \brief Bytes between the start of each line\r
-        */\r
-        int    Pitch;\r
-       /**\r
-        * \brief Number of pixels in each line\r
-        */\r
-       short   Width;\r
-       /**\r
-        * \brief Total number of lines\r
-        */\r
-       short   Height;\r
-       /**\r
-        * \brief Bit depth of the framebuffer\r
-        */\r
-       short   Depth;\r
-       /*\r
-        * \}\r
-        */\r
-       \r
-       /**\r
-        * \brief Buffer write format\r
-        */\r
-       short   BufferFormat;\r
-       \r
-       /**\r
-        * \name Software cursor controls\r
-        * \{\r
-        */\r
-       /**\r
-        * \brief X coordinate of the cursor\r
-        */\r
-       short   CursorX;\r
-       /**\r
-        * \brief Y coordinate of the cursor\r
-        */\r
-       short   CursorY;\r
-\r
-       /**\r
-        * \brief Cursor bitmap\r
-        */\r
-       tVideo_IOCtl_Bitmap     *CursorBitmap;\r
-       /*\r
-        * \}\r
-        */\r
-\r
-       /*\r
-        * \name Internal fields\r
-        * \{\r
-        */\r
-\r
-       /**\r
-        * \brief Buffer to store the area under the cursor\r
-        */\r
-       void    *CursorSaveBuf;\r
-       \r
-        int    CursorReadX;    //!< X offset in cursor bitmap corresponding to \a CursorDestX\r
-        int    CursorReadY;    //!< Same as \a CursorReadX but for Y\r
-        int    CursorRenderW;  //!< Width of rendered cursor\r
-        int    CursorRenderH;  //!< Height of rendered cursor\r
-        int    CursorDestX;    //!< X coordinate Destination for rendered cursor\r
-        int    CursorDestY;    //!< Y coordinate destination for rendered cursor\r
-\r
-       /*\r
-        * \}\r
-        */\r
-} tDrvUtil_Video_BufInfo;\r
-\r
-/**\r
- * \brief Handlers for eTplVideo_2DCommands\r
- */\r
-typedef struct sDrvUtil_Video_2DHandlers\r
-{\r
-       /**\r
-        * \brief No Operation, Ignored\r
-        * \see VIDEO_2DOP_NOP\r
-        */\r
-       void    *Nop;\r
-       /**\r
-        * \brief Fill a buffer region\r
-        * \param X     Lefthand edge\r
-        * \param Y     Top edge\r
-        * \param W     Width\r
-        * \param H     Height\r
-        * \param Colour        Colour to fill with\r
-        * \see VIDEO_2DOP_FILL\r
-        */\r
-       void    (*Fill)(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
-       /**\r
-        * \brief Fill a buffer region\r
-        * \param DestX Lefthand edge of destination\r
-        * \param DestY Top edge of destination\r
-        * \param SrcX  Lefthand edge of source\r
-        * \param SrcY  Top edge of source\r
-        * \param W     Width\r
-        * \param H     Height\r
-        * \see VIDEO_2DOP_BLIT\r
-        */\r
-       void    (*Blit)(void *Ent, Uint16 DestX, Uint16 DestY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);\r
-} tDrvUtil_Video_2DHandlers;\r
-\r
-/**\r
- * \brief Handle a 2D operation stream for a driver\r
- * \param Ent  Value to pass to handlers\r
- * \param Buffer       Stream buffer\r
- * \param Length       Length of stream\r
- * \param Handlers     Handlers to use for the stream\r
- * \param SizeofHandlers       Size of \a tDrvUtil_Video_2DHandlers according\r
- *        to the driver. Used as version control and error avoidence.\r
- */\r
-extern int     DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,\r
-       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);\r
-\r
-/**\r
- * \brief Perform write operations to a LFB\r
- * \param FBInfo       Framebuffer descriptor, see type for details\r
- * \param Offset       Offset provided by VFS call\r
- * \param Length       Length provided by VFS call\r
- * \param Src  Data from VFS call\r
- * \return Number of bytes written\r
- *\r
- * Handles all write modes in software, using the VT font calls for rendering.\r
- * \note Calls the cursor clear and redraw if the cursor area is touched\r
- */\r
-extern int     DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Src);\r
-\r
-/**\r
- * \name Software cursor rendering\r
- * \{\r
- */\r
-/**\r
- * \brief Set the cursor bitmap for a buffer\r
- * \param Buf  Framebuffer descriptor\r
- * \param Bitmap       New cursor bitmap\r
- */\r
-extern int     DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);\r
-/**\r
- * \brief Render the cursor at (\a X, \a Y)\r
- * \param Buf  Framebuffer descriptor, see type for details\r
- * \param X    X coord of the cursor\r
- * \param Y    Y coord of the cursor\r
- */\r
-extern void    DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);\r
-/**\r
- * \brief Removes the rendered cursor from the screen\r
- * \param Buf  Framebuffer descriptor, see type for details\r
- */\r
-extern void    DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);\r
-\r
-/**\r
- * \brief Text mode cursor image\r
- */\r
-extern tVideo_IOCtl_Bitmap     gDrvUtil_TextModeCursor;\r
-/**\r
- * \}\r
- */\r
-#endif\r
diff --git a/Kernel/include/apidoc/arch_x86.h b/Kernel/include/apidoc/arch_x86.h
deleted file mode 100644 (file)
index 7818c8c..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * \file apidoc/arch_x86.h
- * \brief x86(-64) Specific Functions
- * \author John Hodge (thePowersGang)
- *
- * \section toc        Table of Contents
- * - \ref portio "Port IO"
- * - \ref dma "DMA - Direct Memory Access"
- * 
- * \section portio Port IO
- * The x86 architecture has two memory spaces, the first is the system
- * memory accessable using standard loads and stores. The second is the
- * 16-bit IO Bus. This bus is accessed using the \a in and \a out opcodes
- * and is used to configure devices attached to the system.
- * A driver should not use \a in and \a out directly, but instead use
- * the provided \a in* and \a out* functions to access the IO Bus.
- * This allows the kernel to run a driver in userspace if requested without
- * the binary needing to be altered.
- * 
- * \section dma        DMA - Direct Memory Access
- */
-
-/**
- * \name IO Bus Access
- * \{
- */
-extern Uint8   inb(Uint16 Port);       //!< Read 1 byte from the IO Bus
-extern Uint16  inw(Uint16 Port);       //!< Read 2 bytes from the IO Bus
-extern Uint32  inl(Uint16 Port);       //!< Read 4 bytes from the IO Bus
-extern Uint64  inq(Uint16 Port);       //!< Read 8 bytes from the IO Bus\
-
-extern void    outb(Uint16 Port, Uint8 Value); //!< Write 1 byte to the IO Bus
-extern void    outw(Uint16 Port, Uint16 Value);        //!< Write 2 bytes to the IO Bus
-extern void    outl(Uint16 Port, Uint32 Value);        //!< Write 4 bytes to the IO Bus
-extern void    outq(Uint16 Port, Uint64 Value);        //!< Write 8 bytes to the IO Bus
-/**
- * \}
- */
diff --git a/Kernel/include/apidoc_mainpage.h b/Kernel/include/apidoc_mainpage.h
deleted file mode 100644 (file)
index 0060baf..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * \file apidoc_mainpage.h
- * \brief API Documentation Home Page
- * \author John Hodge (thePowersGang)
- * 
- * \mainpage Acess 2 Kernel API Documentation
- * 
- * \section intro Introduction
- * These documents attempt to describe the standard Acess 2 (and hopefully
- * future versions) Kernel mode API.
- * The documentation covers filesystem drivers, binary formats and the
- * various device driver interface standards.
- * 
- * \section index      "Sections"
- * - \ref modules.h "Module Definitions"
- *  - Describes how a module is defined in Acess
- * - \ref binary.h     "Binary Formats"
- *  - Explains how to register a new binary format with the kernel
- * - \ref vfs.h        "VFS - The Virtual File System"
- *  - The VFS is the core of Acess's driver architecture
- * - \ref drivers      "Device Drivers"
- *  - Describes how drivers should use the VFS to expose themselves to the
- *    user.
- *  - Drivers for specific types of hardware must behave in the specific
- *    way described here.
- * 
- * \page drivers Device Drivers
- * 
- * \section toc        Contents
- * - \ref drvintro     "Introduction"
- * - \ref drv_misc "Miscelanious Devices"
- * - \ref drv_video    "Video Drivers"
- * 
- * \section drvintro   Introduction
- * All Acess2 device drivers communicate with user-level (and other parts
- * of the greater kernel) via the VFS. They register themselves in a similar
- * way to how filesystem drivers do, however instead of registering with
- * the VFS core, they register with a special filesystem driver called the
- * \ref fs_devfs.h "Device Filesystem" (devfs). The DevFS provides the
- * ::DevFS_AddDevice function that takes a ::tDevFS_Driver structure as
- * an agument. This structure specifies the driver's name and its root
- * VFS node. This node is used to provide the user access to the
- * driver's functions via IOCtl calls and Reading or Writing to the driver
- * file. Drivers are also able to expose a readonly buffer by using
- * \ref fs_sysfs.h "ProcDev", usually to provide state information or device
- * capabilities for the the user.
- * 
- * The device driver interfaces are all based on the core specifcation
- * in api_drv_common.h (Common Device Driver definitions).
- * The following subsections define the various specific types of driver
- * interfaces. These definitions only define the bare minimum of what the
- * driver must implement, if the driver author so wants to, they can add
- * IOCtl calls and/or files (where allowed by the type specifcation) to
- * their device's VFS layout.
- * 
- * \subsection drv_misc Miscelanious Devices
- * If a device type does not have a specifcation for it, the driver can
- * identify itself as a miscelanious device by returning DRV_TYPE_MISC
- * from \ref DRV_IOCTL_TYPE.
- * A misc device must at least implement the IOCtl calls defined in the
- * \ref api_drv_common.h "Common Device Driver definitions", allowing it
- * to be identified easily by the user and for interfacing programs to
- * utilise the DRV_IOCTL_LOOKUP call.
- * 
- * \subsection drv_video Video Devices
- * Video drivers are based on a framebuffer model (unless in 3D mode,
- * which is not yet fully standardised, so should be ignored).
- * The driver will contain only one VFS node, that exposes the video
- * framebuffer (this may not be the true framebuffer, to allow for double-buffering)
- * to the user. See the full documentation in api_drv_video.h for the
- * complete specifcation.
- * 
- * \subsection drv_disk Disk/Storage Devices
- * Storage devices present themselves as a linear collection of bytes.
- * Reads and writes to the device need not be aligned to the stated block
- * size, but it is suggested that users of a storage device file align
- * their accesses to block boundaries.
- * The functions DrvUtil_ReadBlock and DrvUtil_WriteBlock are provided
- * to storage drivers to assist in handling non-alinged reads and writes.
- * 
- * \see api_drv_common.h Common Spec.
- * \see api_drv_video.h Video Device Spec.
- * \see api_drv_keyboard.h Keyboard Device Spec.
- * \see api_drv_disk.h Disk/Storage Device Spec.
- * \see api_drv_network.h Network Device Spec.
- * \see api_drv_terminal.h Virtual Terminal Spec.
- */
diff --git a/Kernel/include/binary.h b/Kernel/include/binary.h
deleted file mode 100644 (file)
index c94a1b0..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * \file binary.h
- * \brief Binary Loader Definitions
- * \author John Hodge (thePowersGang)
- */
-#ifndef _BINARY_H
-#define _BINARY_H
-
-// === TYPES ===
-/**
- * \brief Representation of a section in a binary file
- * 
- * Tells the binary loader where the page data resides on disk and where
- * to load it to (relative to the binary base). Once the data is read,
- * the \a Physical field contains the physical address of the page.
- */
-typedef struct sBinarySection
-{
-       Uint64  Offset;         //!< File offset of the section
-       tVAddr  Virtual;        //!< Virtual load address
-       size_t  FileSize;       //!< Number of bytes to load from the file
-       size_t  MemSize;        //!< Number of bytes in memory
-       Uint    Flags;  //!< Load Flags
-}      tBinarySection;
-
-/**
- * \brief Flags for ::tBinarySection.Flags
- * \name Binary Section Flags
- * \{
- */
-//! \brief Read-only
-#define BIN_SECTFLAG_RO                0x0001
-//! \brief Executable
-#define BIN_SECTFLAG_EXEC      0x0002
-/**
- * \}
- */
-
-/**
- * \brief Defines a binary file
- * 
- * This structure defines and maintains the state of a binary during and
- * after loading.
- * Before the binary is loaded into memory (when it has just been returned
- * from tBinaryType.Load) the \a Pages array will contain the file offsets
- * to the page data in the \a Physical fields (or -1 for uninitialised
- * data) and the \a Size fields define how much data is stored in-file
- * for the page (to allow partial pages to be loaded from disk)
- * Once the binary is loaded (NOTE: Drivers do not need to know about this,
- * it is here for information only) the \a Physical fields now contain the
- * physical addresses of the pages filled with the data. The \a Virtual
- * fields contain the preferred virtual address of the pages (a given
- * process may have these pages mapped to a different location).
- */
-typedef struct sBinary
-{
-       struct sBinary  *Next;  //!< Pointer used by the kernel
-
-       tMount  MountID;        //!< Mount ID
-       tInode  Inode;          //!< Inode (Used for fast reopen)
-
-       /**
-        * \brief Interpreter used to load the file
-        * \note This can be either requested by the individual file, or a per-driver option
-        */
-       const char      *Interpreter;
-       /**
-        * \brief Entrypoint of the binary (at requested base);
-        */
-       tVAddr  Entry;
-       /**
-        * \brief File's requested load base
-        */
-       tVAddr  Base;
-       /**
-        * \brief Number of times this binary has been mapped
-        */
-        int    ReferenceCount;
-       /**
-        * \brief Number of sections defined in the file
-        */
-        int    NumSections;
-       /**
-        * \brief Array of sections defined by this binary
-        * \note Contains \a NumSections entries
-        */
-       tBinarySection  LoadSections[];
-}      tBinary;
-
-/**
- * \brief Binary type definition
- * 
- * This structure is used to define a loader for a specific binary type
- * so that the kernel's core binary loader can understand that type.
- * The tBinaryType.Relocate and tBinaryType.GetSymbol need only be non-NULL
- * if the binary type is to be used for kernel modules, otherwise it will
- * only be able to load binaries for user space.
- */
-typedef struct sBinaryType
-{
-       /**
-        * \brief Pointer used by the kernel
-        * \note Should not be touched by the driver (initialise to NULL)
-        */
-       struct sBinaryType      *Next;
-       /**
-        * \brief Identifying DWord
-        * 
-        * If he first 32-bits of the file match this value (when ANDed with
-        * tBinaryType.Mask), this binary loader will be used to load the file.
-        */
-       Uint32  Ident;
-       Uint32  Mask;   //!< Mask value for tBinaryType.Ident
-       const char      *Name;  //!< Name of this executable type (for debug purpouses)
-       /**
-        * \brief Read a binary from a file
-        * \param FD    VFS File handle to file to load
-        * \return Pointer to a ::tBinary that describes how to load the file
-        * 
-        * This function reads a binary file and returns a ::tBinary pointer
-        * that tells the core binary loader how to read the data from the file
-        * and where to map it to.
-        */
-       tBinary *(*Load)(int FD);
-       
-       /**
-        * \brief Prepares a mapped binary for execution at this address
-        * \param Base  Binary loaded in memory
-        * \return Boolean Success
-        * \note This pointer can be NULL, but then the binary cannot be used
-        *       to load a kernel module.
-        * 
-        * tBinaryType.Relocate takes a binary that was loaded according to
-        * tBinaryType.Load and prepares it to run at the address it is
-        * loaded to, attempting to satisfy any external unresolved symbols
-        * required, if a symbol cannot be located, the function will return
-        * zero.
-        */
-        int    (*Relocate)(void *Base);
-        
-        /**
-         * \brief Gets a symbol's address from a loaded binary
-         * \note The binary pointed to by \a Base may not have been through
-         *       tBinaryType.Relocate at this time, so the driver should
-         *       accomodate this.
-         */
-        int    (*GetSymbol)(void *Base, const char *Name, Uint *Dest);
-} tBinaryType;
-
-/**
- * \brief Registers an interpreter path with the binary loader
- * \param Path Path to the requested interpreter (need not be a "true" path)
- * \return Pointer to the cached string
- * 
- * Speeds up checking if the intepreter is loaded in the kernel by allowing
- * the search to use pointer comparisons instead of string comparisons.
- */
-extern char    *Binary_RegInterp(char *Path);
-
-/**
- * \brief Registers a binary type with the kernel's loader
- * \param Type Pointer to the loader's type structure
- * \return Boolean success
- * \note The structure \a Type must be persistant (usually it will be a
- *       constant global variable)
- * 
- * This function tells the binary loader about a new file type, and gives
- * it the functions to read the type into a ::tBinary structure, relocate
- * it and to find the value of symbols defined within the binary.
- */
-extern  int    Binary_RegisterType(tBinaryType *Type);
-
-#endif
diff --git a/Kernel/include/binary_ext.h b/Kernel/include/binary_ext.h
deleted file mode 100644 (file)
index b2fc89d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Acess 2
- * binary_ext.h
- * - Exported Symbols from the binary loader
- */
-#ifndef _BINARY_EXT_H
-#define _BINARY_EXT_H
-
-// === FUNCTIONS ===
-extern void    *Binary_LoadFile(const char *Path);
-extern void    *Binary_LoadKernel(const char *Path);
-extern Uint    Binary_Relocate(void *Mem);
-extern void    Binary_Unload(void *Base);
-extern int     Binary_GetSymbol(const char *Name, Uint *Dest);
-extern Uint    Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
-
-#endif
diff --git a/Kernel/include/drv_pci.h b/Kernel/include/drv_pci.h
deleted file mode 100644 (file)
index 33c4a3e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/**\r
- * \file drv_pci.h\r
- * \brief PCI Bus Driver\r
- * \author John Hodge (thePowersGang)\r
- */\r
-#ifndef _DRV_PCI_H\r
-#define _DRV_PCI_H\r
-\r
-/**\r
- * \brief PCI Class Codes\r
- */\r
-enum ePCIClasses\r
-{\r
-       PCI_CLASS_PRE20 = 0x00,\r
-       PCI_CLASS_STORAGE,\r
-       PCI_CLASS_NETWORK,\r
-       PCI_CLASS_DISPLAY,\r
-       PCI_CLASS_MULTIMEDIA,\r
-       PCI_CLASS_MEMORY,\r
-       PCI_CLASS_BRIDGE,\r
-       PCI_CLASS_COMM,\r
-       PCI_CLASS_PREPH,\r
-       PCI_CLASS_INPUT,\r
-       PCI_CLASS_DOCKING,\r
-       PCI_CLASS_PROCESSORS,\r
-       PCI_CLASS_SERIALBUS,\r
-       PCI_CLASS_MISC = 0xFF\r
-};\r
-\r
-enum ePCIOverClasses\r
-{\r
-       PCI_OC_PCIBRIDGE = 0x060400,\r
-       PCI_OC_SCSI = 0x010000\r
-};\r
-\r
-typedef int    tPCIDev;\r
-\r
-/**\r
- * \brief Count PCI Devices\r
- * \r
- * Counts the number of devices with specified Vendor and Device IDs\r
- */\r
-extern int     PCI_CountDevices(Uint16 VendorID, Uint16 DeviceID);\r
-extern tPCIDev PCI_GetDevice(Uint16 VendorID, Uint16 DeviceID, int index);\r
-/**\r
- * \param ClassCode (Class:SubClass:PI)\r
- */\r
-extern tPCIDev PCI_GetDeviceByClass(Uint32 ClassCode, Uint32 Mask, tPCIDev prev);\r
-\r
-extern int     PCI_GetDeviceInfo(tPCIDev id, Uint16 *Vendor, Uint16 *Device, Uint32 *Class);\r
-extern int     PCI_GetDeviceVersion(tPCIDev id, Uint8 *Revision);\r
-extern int     PCI_GetDeviceSubsys(tPCIDev id, Uint16 *SubsystemVendor, Uint16 *SubsystemID);\r
-\r
-extern Uint32  PCI_ConfigRead(tPCIDev id, int Offset, int Size);\r
-extern void    PCI_ConfigWrite(tPCIDev id, int Offset, int Size, Uint32 Value);\r
-\r
-extern Uint8   PCI_GetIRQ(tPCIDev id);\r
-extern Uint32  PCI_GetBAR(tPCIDev id, int BAR);\r
-//extern Uint16        PCI_AssignPort(tPCIDev id, int bar, int count);\r
-\r
-#endif\r
diff --git a/Kernel/include/drv_pci_int.h b/Kernel/include/drv_pci_int.h
deleted file mode 100644 (file)
index f168141..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * drv_pci_int.h
- * - PCI internal definitions
- */
-#ifndef _DRV_PCI_INT_H
-#define _DRV_PCI_INT_H
-
-#include <acess.h>
-
-extern Uint32  PCI_CfgReadDWord(Uint32 Addr);
-extern void    PCI_CfgWriteDWord(Uint32 Addr, Uint32 data);
-
-#endif
-
diff --git a/Kernel/include/errno.h b/Kernel/include/errno.h
deleted file mode 100644 (file)
index 3652f19..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Acess2
- * errno.h
- */
-#ifndef _ERRNO_H
-#define _ERRNO_H
-
-enum eErrorNums
-{
-       EOK,
-       
-       ENOSYS, // Invalid Instruction
-       EINVAL, // Invalid Paramater
-       ENOMEM, // No free memory
-       EACCES, // Not permitted
-       ENOTFOUND,      // Item not found
-       EREADONLY,      // Read only
-       ENOTIMPL,       // Not implemented
-       ENOENT, // No entry?
-       EEXIST, // Already exists
-       ENFILE, // Too many open files
-       ENOTDIR,        // Not a directory
-       
-       EALREADY,       // Operation was a NOP
-       EINTERNAL,      // Internal Error
-       
-       NUM_ERRS
-};
-
-#endif
diff --git a/Kernel/include/events.h b/Kernel/include/events.h
deleted file mode 100644 (file)
index 675c3db..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * events.h
- * - Thread Events
- */
-#ifndef _EVENTS_H_
-#define _EVENTS_H_
-
-#include <threads.h>
-
-#define THREAD_EVENT_VFS       0x00000001
-#define THREAD_EVENT_IPCMSG    0x00000002
-#define THREAD_EVENT_SIGNAL    0x00000004
-#define THREAD_EVENT_TIMER     0x00000008
-
-// === FUNCTIONS ===
-extern void    Threads_PostEvent(tThread *Thread, Uint32 EventMask);
-extern Uint32  Threads_WaitEvents(Uint32 EventMask);
-
-#endif
-
diff --git a/Kernel/include/fs_devfs.h b/Kernel/include/fs_devfs.h
deleted file mode 100644 (file)
index c099fc6..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * \file fs_devfs.h
- * \brief Acess Device Filesystem interface
- * \author John Hodge (thePowersGang)
- */
-#ifndef _FS_DEVFS_H
-#define _FS_DEVFS_H
-#include <vfs.h>
-
-// === TYPES ===
-/**
- * \brief DevFS driver definition
- */
-typedef struct sDevFS_Driver
-{
-       struct sDevFS_Driver    *Next;  //!< Set to NULL by drivers (used internally)
-       const char      *Name;  //!< Name of the driver file/folder (must be unique)
-       tVFS_Node       RootNode;       //!< Root node of driver
-} tDevFS_Driver;
-
-// === FUNCTIONS ===
-/**
- * \fn int DevFS_AddDevice(tDevFS_Driver *Device)
- * \brief Registers a device in the Device Filesystem
- * \param Device       Pointer to a persistant structure that represents the driver
- * \return Boolean success
- */
-extern int     DevFS_AddDevice(tDevFS_Driver *Device);
-
-/**
- * \brief Unregisters a device with the Device Filesystem
- */
-extern void    DevFS_DelDevice(tDevFS_Driver *Device);
-
-#endif
diff --git a/Kernel/include/fs_sysfs.h b/Kernel/include/fs_sysfs.h
deleted file mode 100644 (file)
index aac64d9..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Acess2
- * - SysFS Export Header
- */
-/**
- * \file fs_sysfs.h
- * \brief ProcDev/SysFS Interface
- * \author John Hodge (thePowersGang)
- * 
- * 
- */
-#ifndef _FS_SYSFS_H_
-#define _FS_SYSFS_H_
-
-/**
- * \brief Registers a file in the SysFS tree
- * \param Path Path relative to the SysFS root (no .. or .)
- * \param Data File buffer address
- * \param Length       Length of the file buffer
- * \return An ID number to refer to the file, or -1 on error
- * \note \a Data must be maintained until ::SysFS_UpdateFile is called
- *       with a different buffer, or ::SysFS_RemoveFile is called.
- */
-extern int     SysFS_RegisterFile(const char *Path, const char *Data, int Length);
-
-/**
- * \brief Updates the size/pointer associated with a SysFD file
- * \param ID   Number returned by ::SysFS_RegisterFile
- * \param Data New buffer address
- * \param Length       New length of the file
- * \return Boolean Success
- */
-extern int     SysFS_UpdateFile(int ID, const char *Data, int Length);
-
-/**
- * \brief Removes a file from the SysFS tree
- * \param ID   Number returned by ::SysFS_RegisterFile
- */
-extern int     SysFS_RemoveFile(int ID);
-
-#endif
diff --git a/Kernel/include/hal_proc.h b/Kernel/include/hal_proc.h
deleted file mode 100644 (file)
index 0f21a1c..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Acess2
- * - By John Hodge (thePowersGang)
- *
- * include/hal_proc.h
- * - HAL Process management functions
- * 
- */
-#ifndef _HAL_PROC_H_
-#define _HAL_PROC_H_
-/**
- * \file hal_proc.h
- * \brief Achitecture defined thread/process management functions
- */
-
-#include <threads_int.h>
-
-/**
- * \brief Initialise the architecture dependent side of threading
- */
-extern void    ArchThreads_Init(void);
-/**
- * \brief Start preemptive multithreading (if needed)
- */
-extern void    Proc_Start(void);
-/**
- * \brief Called just before a thread is freed
- */
-extern void    Proc_ClearThread(tThread *Thread);
-/**
- * \brief Called just before a process is freed
- */
-extern void    Proc_ClearProcess(tProcess *Process);
-/**
- * \brief Get the ID of this CPU
- * \return Zero based CPU ID
- */
-extern int     GetCPUNum(void);
-/**
- * \brief Create a copy of the current process
- * \param Flags        Options for the clone
- * \return ID of the new thread/process
- */
-extern tTID    Proc_Clone(Uint Flags);
-/**
- * \brief Create a new kernel thread for the process
- * \param Fnc  Thread root function
- * \param Ptr  Argument to pass the root function
- * \return ID of new thread
- */
-extern tTID    Proc_NewKThread( void (*Fnc)(void*), void *Ptr );
-/**
- * \brief Start a user task
- * \param Entrypoint   User entrypoint
- * \param Base Base of executable (argument for ld-acess)
- * \param ArgC Number of arguments when the program was invoked
- * \param ArgV Heap allocated arguments and environment (two NULL terminated lists)
- * \param DataSize     Size of the \a ArgV buffer in bytes
- * \note This function should free \a ArgV
- */
-extern void    Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize) NORETURN;
-/**
- * \brief Call the fault handler for a thread
- * \param Thread       Thread that is at fault :)
- */
-extern void    Proc_CallFaultHandler(tThread *Thread);
-/**
- * \brief Dump the CPU state for a thread
- */
-extern void    Proc_DumpThreadCPUState(tThread *Thread);
-/**
- * \brief Select a new task and run it, suspending this
- */
-extern void    Proc_Reschedule(void);
-
-/**
- * \brief Clear the user's memory space back to the minimum required to run
- */
-extern void    MM_ClearUser(void);
-/**
- * \brief Dump the address space to the debug channel
- * \param Start        First address
- * \param End  Last address
- */
-extern void    MM_DumpTables(tVAddr Start, tVAddr End);
-
-/**
- * \brief Check if a buffer is valid (and all user if originally user)
- * \param Addr Base address
- * \param Size Size of the buffer in bytes
- * \return Boolean valid (0: invalid, non-0: Valid)
- */
-extern int     MM_IsValidBuffer(tVAddr Addr, size_t Size);
-#endif
diff --git a/Kernel/include/heap.h b/Kernel/include/heap.h
deleted file mode 100644 (file)
index b058e8b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Acess2 Kernel
- * heap.h
- * - Dynamic Memory Allocation exports
- */
-
-#ifndef _HEAP_H_
-#define _HEAP_H_
-
-extern void    *Heap_Allocate(const char *File, int Line, size_t Bytes);
-extern void    *Heap_AllocateZero(const char *File, int Line, size_t Bytes);
-extern void    *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes);
-extern void    Heap_Deallocate(void *Ptr);
-extern int     Heap_IsHeapAddr(void *Ptr);
-extern void    Heap_Validate(void);
-
-#define malloc(size)   Heap_Allocate(_MODULE_NAME_"/"__FILE__, __LINE__, (size))
-#define calloc(num,size)       Heap_AllocateZero(_MODULE_NAME_"/"__FILE__, __LINE__, (num)*(size))
-#define realloc(ptr,size)      Heap_Reallocate(_MODULE_NAME_"/"__FILE__, __LINE__, (ptr), (size))
-#define        free(ptr)       Heap_Deallocate((ptr))
-#define IsHeap(ptr)    Heap_IsHeapAddr((ptr))
-
-#define strdup(Str)    _strdup(_MODULE_NAME_"/"__FILE__, __LINE__, (Str))
-
-#endif
diff --git a/Kernel/include/heap_int.h b/Kernel/include/heap_int.h
deleted file mode 100644 (file)
index 12a709b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * heap_int.h
- * - Internal Heap Header
- */
-#ifndef _HEAP_INT_H
-#define _HEAP_INT_H
-
-typedef struct {
-       Uint    Size;
-        int    ValidSize;
-       const char      *File;
-        int    Line;
-       Uint    Magic;
-       tTime   AllocateTime;
-       char    Data[];
-} tHeapHead;
-
-typedef struct {
-       Uint    Magic;
-       tHeapHead       *Head;
-       tHeapHead       NextHead[];     // Array to make it act like an element, but have no size and refer to the next block
-} tHeapFoot;
-
-#endif
diff --git a/Kernel/include/init.h b/Kernel/include/init.h
deleted file mode 100644 (file)
index 9f2fc10..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * init.h
- */
-#ifndef _INIT_H
-#define _INIT_H
-
-extern void    Arch_LoadBootModules(void);
-extern void    StartupPrint(const char *String);
-
-#endif
diff --git a/Kernel/include/iocache.h b/Kernel/include/iocache.h
deleted file mode 100644 (file)
index f008a2d..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Acess2 Kernel
- * - IO Cache
- * 
- * By thePowersGang (John Hodge)
- */
-/**
- * \file iocache.h
- * \brief I/O Caching Helper Subsystem
- * 
- * The IO Cache abstracts caching of disk sectors away from the device
- * driver to reduce code duplication and allow a central location for
- * disk cache management that can be flushed simply by the kernel, without
- * having to ask each driver to do it indivitually.
- */
-#ifndef _IOCHACHE_H_
-#define _IOCHACHE_H_
-
-// === TYPES ===
-/**
- * \brief IO Cache Handle
- */
-typedef struct sIOCache        tIOCache;
-/**
- * \brief Write Callback
- * 
- * Called to write a sector back to the device
- */
-typedef int    (*tIOCache_WriteCallback)(Uint32 ID, Uint64 Sector, void *Buffer);
-
-// === CONSTANTS ===
-/**
- * \brief I/O Cache handling modes
- */
-enum eIOCache_Modess {
-       /**
-        * \brief Writeback
-        * 
-        * Transparently writes data straight to the device when the cache
-        * is written to.
-        */
-       IOCACHE_WRITEBACK,
-       /**
-        * \brief Delay Write
-        * 
-        * Only writes when instructed to (by ::IOCache_Flush) or when a
-        * cached sector is being reallocated.
-        */
-       IOCACHE_DELAYWRITE,
-       /**
-        * \brief Virtual - No Writes
-        * 
-        * Changes to the cache contents are only reflected in memory,
-        * any calls to ::IOCache_Flush will silently return without doing
-        * anything and if a sector is reallocated, all changes will be lost
-        */
-       IOCACHE_VIRTUAL
-};
-
-// === FUNCTIONS ===
-/**
- * \brief Creates a new IO Cache
- * \param Write        Function to call to write a sector to the device
- * \param ID   ID to pass to \a Write
- * \param SectorSize   Size of a cached sector
- * \param CacheSize    Maximum number of objects that can be in the cache at one time
- */
-tIOCache       *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize );
-
-/**
- * \brief Reads from a cached sector
- * \param Cache        Cache handle returned by ::IOCache_Create
- * \param Sector       Sector's ID number
- * \param Buffer       Destination for the data read
- * \return     1 if the data was read, 0 if the sector is not cached, -1 on error
- */
- int   IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer );
-
-/**
- * \brief Adds a sector to the cache
- * \param Cache        Cache handle returned by ::IOCache_Create
- * \param Sector       Sector's ID number
- * \param Buffer       Data to cache
- * \return     1 on success, 0 if the sector is already cached, -1 on error
- */
- int   IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer );
-
-/**
- * \brief Writes to a cached sector
- * \param Cache        Cache handle returned by ::IOCache_Create
- * \param Sector       Sector's ID number
- * \param Buffer       Data to write to the cache
- * \return     1 if the data was read, 0 if the sector is not cached, -1 on error
- * 
- * If the sector is in the cache, it is updated.
- * Wether the Write callback is called depends on the selected caching
- * behaviour.
- */
- int   IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer );
-
-/**
- * \brief Flush altered sectors out to the device
- * \param Cache        Cache handle returned by ::IOCache_Create
- * 
- * This will call the cache's write callback on each altered sector
- * to flush the write cache.
- */
-void   IOCache_Flush( tIOCache *Cache );
-
-/**
- * \brief Flushes the cache and then removes it
- * \param Cache        Cache handle returned by ::IOCache_Create
- * \note After this is called \a Cache is no longer valid
- * 
- * IOCache_Destroy writes all changed sectors to the device and then
- * deallocates the cache for other systems to use.
- */
-void   IOCache_Destroy( tIOCache *Cache );
-
-#endif
diff --git a/Kernel/include/lib/keyvalue.h b/Kernel/include/lib/keyvalue.h
deleted file mode 100644 (file)
index ef37d5b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge
- *
- * include/keyvalue.h
- * - Key/Value pair parsing
- */
-#ifndef _ACESS_KEYVALUE_H_
-#define _ACESS_KEYVALUE_H_
-
-typedef struct sKeyVal_ParseRules      tKeyVal_ParseRules;
-typedef struct sKeyVal_int_Rule        tKeyVal_int_Rule;
-typedef void (*tKeyVal_UnkCb)(char *String);
-typedef void (*tKeyVal_KeyCb)(const char *Key, char *Value);
-
-/**
- * \brief Handling rule for a key
- */
-struct sKeyVal_int_Rule
-{
-       const char      *Key;
-       const char      *Type;  // Acess printf format, with 'F' being a tKeyVal_KeyCb
-       void    *Data;
-};
-
-struct sKeyVal_ParseRules
-{
-       /**
-        * \brief Function to call when no match is found
-        */
-       tKeyVal_UnkCb   Unknown;
-       tKeyVal_int_Rule        Rules[];
-};
-
-/**
- * \brief Parse a NULL terminated list of strings as Key/Value pairs
- * \param Rules        Parsing rules
- * \param Strings      Input string list
- */
-extern int     KeyVal_ParseNull(tKeyVal_ParseRules *Rules, char **Strings);
-
-#endif
-
diff --git a/Kernel/include/mboot.h b/Kernel/include/mboot.h
deleted file mode 100644 (file)
index c7f33dd..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * mboot.h
- */
-#ifndef _MBOOT_H
-#define _MBOOT_H
-
-#define MULTIBOOT_MAGIC        0x2BADB002
-
-// === TYPES ===
-typedef struct {
-       Uint32  Flags;
-       Uint32  LowMem;
-       Uint32  HighMem;
-       Uint32  BootDevice;
-       Uint32  CommandLine;
-       Uint32  ModuleCount;
-       Uint32  Modules;
-       Uint32  SymbolInfo[4];  // #32 UNUSED
-       Uint32  MMapLength;
-       Uint32  MMapAddr;               // #40
-} tMBoot_Info;
-
-typedef struct {
-       Uint32  Start;
-       Uint32  End;
-       Uint32  String;
-       Uint32  Resvd;
-} tMBoot_Module;
-
-typedef struct {
-       Uint32  Size;   // (May be at offset -4)
-       Uint64  Base;
-       Uint64  Length;
-       Uint32  Type;   //1:RAM,Else Reserved
-} __attribute__ ((packed)) tMBoot_MMapEnt;
-
-#endif
diff --git a/Kernel/include/modules.h b/Kernel/include/modules.h
deleted file mode 100644 (file)
index d728133..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * AcessOS 2
- * - Module Loader
- */
-/**
- * \file modules.h
- * \brief Module Handling and Loader Definitions
- * \author John Hodge (thePowersGang)
- * 
- * This file serves two pourposes. First it defines the format for native
- * Acess2 modules and the functions to create them.
- * Second, it defines the structure and register function for new module
- * loaders, allowing Acess to understand many different module / driver
- * formats.
- * 
- * Modules are defined by including this file in the module's main source
- * file and using the ::MODULE_DEFINE macro to create the module header.
- * 
- * To register a new module loader with the kernel, the loader module must
- * create and populate an instance of ::tModuleLoader then pass it to
- * ::Module_RegisterLoader
- */
-#ifndef _MODULE_H
-#define _MODULE_H
-
-/**
- * \brief Module header magic value
- */
-#define MODULE_MAGIC   ('A'|('M'<<8)|('D'<<16)|('\2'<<24))
-
-/**
- * \def MODULE_ARCH_ID
- * \brief Architecture ID
- */
-// IA32 - Architecture 1
-#if ARCHDIR == x86
-# define MODULE_ARCH_ID        1
-// IA64 - Architecture 2
-#elif ARCHDIR == x86_64
-# define MODULE_ARCH_ID        2
-#else
-# error "Unknown architecture when determining MODULE_ARCH_ID ('" #ARCHDIR "')"
-#endif
-
-/**
- * \brief Define a module
- * \param _flags       Module Flags
- * \param _ver Module Version
- * \param _ident       Unique Module Name
- * \param _entry       Module initialiser / entrypoint
- * \param _deinit      Module cleanup / unloader
- * \param _deps        NULL terminated list of this's module's dependencies
- *                     Contains the identifiers of the required modules.
- */
-#define MODULE_DEFINE(_flags,_ver,_ident,_entry,_deinit,_deps...) \
-       const char *EXPAND_CONCAT(_DriverDeps_,_ident)[]={_deps};\
-       tModule __attribute__ ((section ("KMODULES"),unused))\
-       EXPAND_CONCAT(_DriverInfo_,_ident)=\
-       {MODULE_MAGIC,MODULE_ARCH_ID,_flags,_ver,NULL,EXPAND_STR(_ident),\
-       _entry,_deinit,EXPAND_CONCAT(_DriverDeps_,_ident)}
-
-/**
- * \brief Module header
- * \note There is no reason for a module to touch this structure beyond
- *       using ::MODULE_DEFINE to create it.
- */
-typedef struct sModule 
-{
-       Uint32  Magic;  //!< Identifying magic value (See ::MODULE_MAGIC)
-       Uint8   Arch;   //!< Achitecture ID (See ::MODULE_ARCH_ID)
-       Uint8   Flags;  //!< Module Flags
-       Uint16  Version;        //!< Module Version in Major.Minor 8.8 form
-       struct sModule  *Next;  //!< Next module in list (not to be touched by the driver)
-       const char      *Name;  //!< Module Name/Identifier
-        int    (*Init)(char **Arguments);      //!< Module initialiser / entrypoint
-       void    (*Deinit)(void);        //!< Cleanup Function
-       const char      **Dependencies; //!< NULL terminated list of dependencies
-} PACKED tModule;
-
-/**
- * \brief Return values for tModule.Init
- */
-enum eModuleErrors
-{
-       MODULE_ERR_OK,  //!< No Error
-       MODULE_ERR_MISC,        //!< Misc Error
-       MODULE_ERR_NOTNEEDED,   //!< Module not needed
-       MODULE_ERR_MALLOC,      //!< Error with malloc/realloc/calloc
-       
-       MODULE_ERR_BADMODULE,   //!< Bad module (only used by loader)
-       MODULE_ERR_MAX  //!< Maximum defined error code
-};
-
-/**
- * \brief Module Loader definition
- * 
- * Allows a module to extend the loader to recognise other module types
- * E.g. EDI, UDI, Windows, Linux, ...
- */
-typedef struct sModuleLoader
-{
-       struct sModuleLoader    *Next;  //!< Kernel Only - Next loader in list
-       char    *Name;  //!< Friendly name for the loader
-        int    (*Detector)(void *Base);        //!< Simple detector function
-        int    (*Loader)(void *Base);  //!< Initialises the module
-        int    (*Unloader)(void *Base);        //!< Calls module's cleanup
-} PACKED tModuleLoader;
-
-/**
- * \brief Registers a tModuleLoader with the kernel
- * \param Loader       Pointer to loader structure (must be persistent)
- * \return Boolean Success
- */
-extern int     Module_RegisterLoader(tModuleLoader *Loader);
-
-/**
- * \brief Initialises (if needed) a named module
- * \param Name Module name to initialise
- * \return -1 on not existing, 0 if the module initialised (or if it was already initialised)
- */
-extern int     Module_EnsureLoaded(const char *Name);
-
-#endif
diff --git a/Kernel/include/mutex.h b/Kernel/include/mutex.h
deleted file mode 100644 (file)
index 326dbd2..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Acess2 Kernel
- * mutex.h
- * - Mutual Exclusion syncronisation primitive
- */
-#ifndef _MUTEX_H
-#define _MUTEX_H
-
-#include <acess.h>
-
-typedef struct sMutex  tMutex;
-
-struct sMutex
-{
-       tShortSpinlock  Protector;      //!< Protector for the lock strucure
-       const char      *Name;  //!< Human-readable name
-       struct sThread  *volatile Owner;        //!< Owner of the lock (set upon getting the lock)
-       struct sThread  *Waiting;       //!< Waiting threads
-       struct sThread  *LastWaiting;   //!< Waiting threads
-};
-
-/**
- * \brief Acquire a heavy mutex
- * \param Mutex        Mutex to acquire
- * \return zero on success, -1 if terminated
- * 
- * This type of mutex checks if the mutex is avaliable, and acquires it
- * if it is. Otherwise, the current thread is added to the mutex's wait
- * queue and the thread suspends. When the holder of the mutex completes,
- * the oldest thread (top thread) on the queue is given the lock and
- * restarted.
- */
-extern int     Mutex_Acquire(tMutex *Mutex);
-
-/**
- * \brief Release a held mutex
- * \param Mutex        Mutex to release
- * \note Releasing a non-held mutex has no effect
- */
-extern void    Mutex_Release(tMutex *Mutex);
-
-/**
- * \brief Is this mutex locked?
- * \param Mutex        Mutex pointer
- */
-extern int     Mutex_IsLocked(tMutex *Mutex);
-
-#endif
diff --git a/Kernel/include/semaphore.h b/Kernel/include/semaphore.h
deleted file mode 100644 (file)
index db0b279..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Acess2 Kernel
- * semaphore.h
- * - Semaphore syncronisation primitive
- */
-#ifndef _SEMAPHORE_H
-#define _SEMAPHORE_H
-
-#include <acess.h>
-
-/**
- * \brief Semaphore typedef
- */
-typedef struct sSemaphore      tSemaphore;
-
-/**
- * \brief Semaphore structure
- */
-struct sSemaphore {
-       tShortSpinlock  Protector;      //!< Protector for the lock strucure
-       const char      *ModName;       //!< Human-readable module name
-       const char      *Name;  //!< Human-readable name
-       volatile int    Value;  //!< Current value
-       volatile int    MaxValue;       //!< Maximum value (signal will wait if it will go over this)
-       
-       struct sThread  *Waiting;       //!< Waiting threads
-       struct sThread  *LastWaiting;   //!< Waiting threads
-       struct sThread  *Signaling;     //!< Waiting threads (from Semaphore_Signal)
-       struct sThread  *LastSignaling; //!< Last waiting thread (from Semaphore_Signal)
-};
-
-/**
- * \brief Initialise the semaphore
- * \param Sem  Semaphore structure to initialsie
- * \param InitValue    Initial value of the semaphore
- * \param MaxValue     Maximum value for the semaphore
- * \param Module       Module name
- * \param Name Symbolic name
- * \note Not always needed, as initialising to 0 is valid, but it is preferred
- *       if all semaphores have \a Name set
- * 
- * \note \a Module and \a Name must be avaliable for as long as the semaphore is used
- */
-extern void    Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name);
-/**
- * \brief Acquire items from the semaphore
- * \param Sem  Semaphore structure to use
- * \param MaxToTake    Maximum number of items to take off the list (if zero, as much as possible is taken)
- * \return Number of items fetched
- * \retval 0   Semaphore interrupted (signal/message)
- * \retval -1  Unspecified error
- */
-extern int     Semaphore_Wait(tSemaphore *Sem, int MaxToTake);
-/**
- * \brief Add an "item" to the semaphore
- * \param Sem  Semaphore to use
- * \param AmmountToAdd Number of items to add
- * \return Actual number of items added
- * \retval 0   Semaphore interrupted
- * \retval -1  Unspecified error
- */
-extern int     Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd);
-/**
- * \brief Get the number of items waiting in a semaphore
- * \param Sem  Semaphore to use
- * \return Number of waiting items
- */
-extern int     Semaphore_GetValue(tSemaphore *Sem);
-
-#endif
diff --git a/Kernel/include/signal.h b/Kernel/include/signal.h
deleted file mode 100644 (file)
index d97d6dc..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Acess2 Kernel
- * Signal List
- */
-#ifndef _SIGNAL_H_
-#define _SIGNAL_H_
-
-enum eSignals {
-       SIGKILL,
-       SIGSTOP,
-       SIGCONT,
-       SIGCHLD,
-       NSIG
-};
-
-#endif
diff --git a/Kernel/include/syscalls.h b/Kernel/include/syscalls.h
deleted file mode 100644 (file)
index 5ce2814..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Acess2
- * syscalls.h
- * - System Call List
- *
- * NOTE: Generated from Kernel/syscalls.lst
- */
-#ifndef _SYSCALLS_H
-#define _SYSCALLS_H
-
-#define SYS_EXIT       0       // Kill this thread
-#define SYS_CLONE      1       // Create a new thread
-#define SYS_KILL       2       // Send a signal
-#define SYS_SETFAULTHANDLER    3       // Set signal Handler
-#define SYS_YIELD      4       // Yield remainder of timestamp
-#define SYS_SLEEP      5       // Sleep until messaged or signaled
-#define SYS_WAITEVENT  6       // Wait for an event
-#define SYS_WAITTID    7       // Wait for a thread to do something
-#define SYS_SETNAME    8       // Sets the name of the current thread
-#define SYS_GETNAME    9       // Gets the name of a thread
-#define SYS_GETTID     10      // Get current thread ID
-#define SYS_GETPID     11      // Get current thread group ID
-#define SYS_SETPRI     12      // Set process priority
-#define SYS_SENDMSG    13      // Send an IPC message
-#define SYS_GETMSG     14      // Recieve an IPC message
-#define SYS_GETTIME    15      // Get the current timestamp
-#define SYS_SPAWN      16      // Spawn a new process
-#define SYS_EXECVE     17      // Replace the current process
-#define SYS_LOADBIN    18      // Load a binary into the current address space
-#define SYS_UNLOADBIN  19      // Unload a loaded binary
-#define SYS_LOADMOD    20      // Load a module into the kernel
-#define SYS_GETPHYS    32      // Get the physical address of a page
-#define SYS_MAP        33      // Map a physical address
-#define SYS_ALLOCATE   34      // Allocate a page
-#define SYS_UNMAP      35      // Unmap a page
-#define SYS_PREALLOC   36      // Preallocate a page
-#define SYS_SETFLAGS   37      // Set a page's flags
-#define SYS_SHAREWITH  38      // Share a page with another thread
-#define SYS_GETUID     39      // Get current User ID
-#define SYS_GETGID     40      // Get current Group ID
-#define SYS_SETUID     41      // Set current user ID
-#define SYS_SETGID     42      // Set current Group ID
-#define SYS_OPEN       64      // Open a file
-#define SYS_REOPEN     65      // Close a file and reuse its handle
-#define SYS_CLOSE      66      // Close a file
-#define SYS_READ       67      // Read from an open file
-#define SYS_WRITE      68      // Write to an open file
-#define SYS_IOCTL      69      // Perform an IOCtl Call
-#define SYS_SEEK       70      // Seek to a new position in the file
-#define SYS_READDIR    71      // Read from an open directory
-#define SYS_OPENCHILD  72      // Open a child entry in a directory
-#define SYS_GETACL     73      // Get an ACL Value
-#define SYS_SETACL     74      // Set an ACL Value
-#define SYS_FINFO      75      // Get file information
-#define SYS_MKDIR      76      // Create a new directory
-#define SYS_LINK       77      // Create a new link to a file
-#define SYS_SYMLINK    78      // Create a symbolic link
-#define SYS_UNLINK     79      // Delete a file
-#define SYS_TELL       80      // Return the current file position
-#define SYS_CHDIR      81      // Change current directory
-#define SYS_GETCWD     82      // Get current directory
-#define SYS_MOUNT      83      // Mount a filesystem
-#define SYS_SELECT     84      // Wait for file handles
-
-#define NUM_SYSCALLS   85
-#define SYS_DEBUG      0x100
-
-#ifndef __ASSEMBLER__
-static const char *cSYSCALL_NAMES[] = {
-       "SYS_EXIT",
-       "SYS_CLONE",
-       "SYS_KILL",
-       "SYS_SETFAULTHANDLER",
-       "SYS_YIELD",
-       "SYS_SLEEP",
-       "SYS_WAITEVENT",
-       "SYS_WAITTID",
-       "SYS_SETNAME",
-       "SYS_GETNAME",
-       "SYS_GETTID",
-       "SYS_GETPID",
-       "SYS_SETPRI",
-       "SYS_SENDMSG",
-       "SYS_GETMSG",
-       "SYS_GETTIME",
-       "SYS_SPAWN",
-       "SYS_EXECVE",
-       "SYS_LOADBIN",
-       "SYS_UNLOADBIN",
-       "SYS_LOADMOD",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "SYS_GETPHYS",
-       "SYS_MAP",
-       "SYS_ALLOCATE",
-       "SYS_UNMAP",
-       "SYS_PREALLOC",
-       "SYS_SETFLAGS",
-       "SYS_SHAREWITH",
-       "SYS_GETUID",
-       "SYS_GETGID",
-       "SYS_SETUID",
-       "SYS_SETGID",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "",
-       "SYS_OPEN",
-       "SYS_REOPEN",
-       "SYS_CLOSE",
-       "SYS_READ",
-       "SYS_WRITE",
-       "SYS_IOCTL",
-       "SYS_SEEK",
-       "SYS_READDIR",
-       "SYS_OPENCHILD",
-       "SYS_GETACL",
-       "SYS_SETACL",
-       "SYS_FINFO",
-       "SYS_MKDIR",
-       "SYS_LINK",
-       "SYS_SYMLINK",
-       "SYS_UNLINK",
-       "SYS_TELL",
-       "SYS_CHDIR",
-       "SYS_GETCWD",
-       "SYS_MOUNT",
-       "SYS_SELECT",
-
-       ""
-};
-#endif
-
-#endif
diff --git a/Kernel/include/syscalls.inc.asm b/Kernel/include/syscalls.inc.asm
deleted file mode 100644 (file)
index 149fe37..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-; Acess2
-; System Calls List
-; 
-
-%define SYS_EXIT       0        ;Kill this thread
-%define SYS_CLONE      1        ;Create a new thread
-%define SYS_KILL       2        ;Send a signal
-%define SYS_SETFAULTHANDLER    3        ;Set signal Handler
-%define SYS_YIELD      4        ;Yield remainder of timestamp
-%define SYS_SLEEP      5        ;Sleep until messaged or signaled
-%define SYS_WAITEVENT  6        ;Wait for an event
-%define SYS_WAITTID    7        ;Wait for a thread to do something
-%define SYS_SETNAME    8        ;Sets the name of the current thread
-%define SYS_GETNAME    9        ;Gets the name of a thread
-%define SYS_GETTID     10       ;Get current thread ID
-%define SYS_GETPID     11       ;Get current thread group ID
-%define SYS_SETPRI     12       ;Set process priority
-%define SYS_SENDMSG    13       ;Send an IPC message
-%define SYS_GETMSG     14       ;Recieve an IPC message
-%define SYS_GETTIME    15       ;Get the current timestamp
-%define SYS_SPAWN      16       ;Spawn a new process
-%define SYS_EXECVE     17       ;Replace the current process
-%define SYS_LOADBIN    18       ;Load a binary into the current address space
-%define SYS_UNLOADBIN  19       ;Unload a loaded binary
-%define SYS_LOADMOD    20       ;Load a module into the kernel
-%define SYS_GETPHYS    32       ;Get the physical address of a page
-%define SYS_MAP        33       ;Map a physical address
-%define SYS_ALLOCATE   34       ;Allocate a page
-%define SYS_UNMAP      35       ;Unmap a page
-%define SYS_PREALLOC   36       ;Preallocate a page
-%define SYS_SETFLAGS   37       ;Set a page's flags
-%define SYS_SHAREWITH  38       ;Share a page with another thread
-%define SYS_GETUID     39       ;Get current User ID
-%define SYS_GETGID     40       ;Get current Group ID
-%define SYS_SETUID     41       ;Set current user ID
-%define SYS_SETGID     42       ;Set current Group ID
-%define SYS_OPEN       64       ;Open a file
-%define SYS_REOPEN     65       ;Close a file and reuse its handle
-%define SYS_CLOSE      66       ;Close a file
-%define SYS_READ       67       ;Read from an open file
-%define SYS_WRITE      68       ;Write to an open file
-%define SYS_IOCTL      69       ;Perform an IOCtl Call
-%define SYS_SEEK       70       ;Seek to a new position in the file
-%define SYS_READDIR    71       ;Read from an open directory
-%define SYS_OPENCHILD  72       ;Open a child entry in a directory
-%define SYS_GETACL     73       ;Get an ACL Value
-%define SYS_SETACL     74       ;Set an ACL Value
-%define SYS_FINFO      75       ;Get file information
-%define SYS_MKDIR      76       ;Create a new directory
-%define SYS_LINK       77       ;Create a new link to a file
-%define SYS_SYMLINK    78       ;Create a symbolic link
-%define SYS_UNLINK     79       ;Delete a file
-%define SYS_TELL       80       ;Return the current file position
-%define SYS_CHDIR      81       ;Change current directory
-%define SYS_GETCWD     82       ;Get current directory
-%define SYS_MOUNT      83       ;Mount a filesystem
-%define SYS_SELECT     84       ;Wait for file handles
diff --git a/Kernel/include/threads.h b/Kernel/include/threads.h
deleted file mode 100644 (file)
index 9ff7b62..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Acess2 Kernel
- */
-#ifndef _THREADS_H_
-#define _THREADS_H_
-
-#include <arch.h>
-#include <signal.h>
-//#include <proc.h>
-
-enum eFaultNumbers
-{
-       FAULT_MISC,
-       FAULT_PAGE,
-       FAULT_ACCESS,
-       FAULT_DIV0,
-       FAULT_OPCODE,
-       FAULT_FLOAT
-};
-
-#define GETMSG_IGNORE  ((void*)-1)
-
-typedef struct sThread tThread;
-
-// === FUNCTIONS ===
-extern void    Threads_SetFaultHandler(Uint Handler);
-
-extern int     Threads_SetUID(tUID ID);
-extern int     Threads_SetGID(tUID ID);
-extern tTID    Threads_WaitTID(int TID, int *Status);
-
-
-extern int     *Threads_GetMaxFD(void);
-extern char    **Threads_GetCWD(void);
-extern char    **Threads_GetChroot(void);
-
-extern int     Proc_SendMessage(Uint Dest, int Length, void *Data);
-extern int     Proc_GetMessage(Uint *Source, void *Buffer);
-
-#endif
diff --git a/Kernel/include/threads_int.h b/Kernel/include/threads_int.h
deleted file mode 100644 (file)
index 66bb8c1..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Internal Threading header
- * - Only for use by stuff that needs access to the thread type.
- */
-#ifndef _THREADS_INT_H_
-#define _THREADS_INT_H_
-
-#include <threads.h>
-#include <proc.h>
-
-
-typedef struct sProcess        tProcess;
-
-/**
- * \brief IPC Message
- */
-typedef struct sMessage
-{
-       struct sMessage *Next;  //!< Next message in thread's inbox
-       tTID    Source; //!< Source thread ID
-       Uint    Length; //!< Length of message data in bytes
-       Uint8   Data[]; //!< Message data
-} tMsg;
-
-/**
- * \brief Process state
- */
-struct sProcess
-{
-       tPID    PID;
-        int    nThreads;
-       
-       tUID    UID;    //!< User ID
-       tGID    GID;    //!< User and Group
-       tMemoryState    MemState;
-
-        int    MaxFD;
-       char    *CurrentWorkingDir;
-       char    *RootDir;
-};
-
-/**
- * \brief Core threading structure
- * 
- */
-struct sThread
-{
-       // --- threads.c's
-       /**
-        * \brief Next thread in current list
-        * \note Required to be first for linked list hacks to work
-        */
-       struct sThread  *Next;
-       struct sThread  *GlobalNext;    //!< Next thread in global list
-       struct sThread  *GlobalPrev;    //!< Previous thread in global list
-       tShortSpinlock  IsLocked;       //!< Thread's spinlock
-       volatile int    Status;         //!< Thread Status
-       void    *WaitPointer;   //!< What (Mutex/Thread/other) is the thread waiting on
-        int    RetStatus;      //!< Return Status
-       
-       tTID    TID;    //!< Thread ID
-       struct sProcess *Process;       //!< Thread Group / Process
-       struct sThread  *Parent;        //!< Parent Thread
-       char    *ThreadName;    //!< Name of thread
-       
-       // --- arch/proc.c's responsibility
-       //! Kernel Stack Base
-       tVAddr  KernelStack;
-       
-       //! State on task switch
-       tTaskState      SavedState;
-       
-       // --- threads.c's
-        int    CurFaultNum;    //!< Current fault number, 0: none
-       tVAddr  FaultHandler;   //!< Fault Handler
-       
-       tMsg * volatile Messages;       //!< Message Queue
-       tMsg    *LastMessage;   //!< Last Message (speeds up insertion)
-       
-        int    Quantum, Remaining;     //!< Quantum Size and remaining timesteps
-        int    Priority;       //!< Priority - 0: Realtime, higher means less time
-       
-        int    _errno;
-       
-       volatile int    CurCPU;
-       
-       bool    bInstrTrace;
-       
-       // --- event.c
-       Uint32  EventState;
-};
-
-
-enum {
-       THREAD_STAT_NULL,       // Invalid process
-       THREAD_STAT_ACTIVE,     // Running and schedulable process
-       THREAD_STAT_SLEEPING,   // Message Sleep
-       THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
-       THREAD_STAT_SEMAPHORESLEEP,     // Semaphore Sleep
-       THREAD_STAT_QUEUESLEEP, // Queue
-       THREAD_STAT_EVENTSLEEP, // Event sleep
-       THREAD_STAT_WAITING,    // ??? (Waiting for a thread)
-       THREAD_STAT_PREINIT,    // Being created
-       THREAD_STAT_ZOMBIE,     // Died/Killed, but parent not informed
-       THREAD_STAT_DEAD,       // Awaiting burial (free)
-       THREAD_STAT_BURIED      // If it's still on the list here, something's wrong
-};
-static const char * const casTHREAD_STAT[] = {
-       "THREAD_STAT_NULL",
-       "THREAD_STAT_ACTIVE",
-       "THREAD_STAT_SLEEPING",
-       "THREAD_STAT_MUTEXSLEEP",
-       "THREAD_STAT_SEMAPHORESLEEP",
-       "THREAD_STAT_QUEUESLEEP",
-       "THREAD_STAT_EVENTSLEEP",
-       "THREAD_STAT_WAITING",
-       "THREAD_STAT_PREINIT",
-       "THREAD_STAT_ZOMBIE",
-       "THREAD_STAT_DEAD",
-       "THREAD_STAT_BURIED"
-};
-
-// === GLOBALS ===
-extern BOOL    gaThreads_NoTaskSwitch[MAX_CPUS];
-extern tShortSpinlock  glThreadListLock;
-
-// === FUNCTIONS ===
-extern tThread *Proc_GetCurThread(void);
-
-extern tThread *Threads_GetThread(Uint TID);
-extern void    Threads_SetPriority(tThread *Thread, int Pri);
-extern int     Threads_Wake(tThread *Thread);
-extern void    Threads_Kill(tThread *Thread, int Status);
-extern void    Threads_AddActive(tThread *Thread);
-extern tThread *Threads_RemActive(void);
-extern void    Threads_Delete(tThread *Thread);
-extern tThread *Threads_GetNextToRun(int CPU, tThread *Last);
-
-extern tThread *Threads_CloneTCB(Uint Flags);
-extern tThread *Threads_CloneThreadZero(void);
-
-#endif
diff --git a/Kernel/include/timers.h b/Kernel/include/timers.h
deleted file mode 100644 (file)
index 22dd5c6..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * timers.h
- * - Kernel timers
- */
-#ifndef _KERNEL_TIMERS_H_
-#define _KERNEL_TIMERS_H_
-/**
- * \file timers.h
- * \brief Kernel timers
- */
-
-typedef struct sTimer  tTimer;
-
-/**
- * \brief Timer callback function
- */
-typedef void (tTimerCallback)(void *);
-
-/**
- * \brief Creates a one-shot timer
- * \param Delta        Period of the timer
- * \param Callback     Function to call each time
- * \param Argument     Argument to pass to the callback
- */
-extern tTimer  *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument);
-/**
- * \brief Removed an active timer
- */
-extern void    Time_RemoveTimer(tTimer *Timer);
-/**
- * \brief Wait for a period of milliseconds
- */
-extern void    Time_Delay(int Delay);
-
-#endif
-
diff --git a/Kernel/include/tpl_mm_phys_bitmap.h b/Kernel/include/tpl_mm_phys_bitmap.h
deleted file mode 100644 (file)
index 39444d9..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Acess2 Core
- * 
- * include/tpl_mm_phys_bitmap.h
- * Physical Memory Manager Template
- */
-/*
- * Bitmap Edition
- * 
- * Uses 4.125+PtrSize bytes per page
- */
-
-#define MM_PAGE_REFCOUNTS      MM_PMM_BASE
-#define MM_PAGE_NODES  (MM_PMM_BASE+(MM_MAXPHYSPAGE*sizeof(Uint32)))
-#define MM_PAGE_BITMAP (MM_PAGE_NODES+(MM_MAXPHYSPAGE*sizeof(void*)))
-
-#define PAGE_BITMAP_FREE(__pg) (gaPageBitmaps[(__pg)/32] & (1LL << ((__pg)&31)))
-#define PAGE_BITMAP_SETFREE(__pg)      do{gaPageBitmaps[(__pg)/32] |= (1LL << ((__pg)&31));}while(0)
-#define PAGE_BITMAP_SETUSED(__pg)      do{gaPageBitmaps[(__pg)/32] &= ~(1LL << ((__pg)&31));}while(0)
-
-// === PROTOTYPES ===
-//void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
-//tPAddr       MM_AllocPhysRange(int Num, int Bits);
-//tPAddr       MM_AllocPhys(void);
-//void MM_RefPhys(tPAddr PAddr);
-//void MM_DerefPhys(tPAddr PAddr);
- int   MM_int_GetRangeID( tPAddr Addr );
- int   MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length );
-void   MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap);
-
-// === GLOBALS ===
-tMutex glPhysicalPages;
-void   **gapPageNodes = (void*)MM_PAGE_NODES;  //!< Associated VFS Node for each page
-Uint32 *gaiPageReferences = (void*)MM_PAGE_REFCOUNTS;  // Reference Counts
-Uint32 *gaPageBitmaps = (void*)MM_PAGE_BITMAP; // Used bitmap (1 == avail)
-Uint64 giMaxPhysPage = 0;      // Maximum Physical page
- int   gbPMM_Init = 0;
- int   giPhysFirstFree;
- int   giPhysLastFree;
- int   giPhysNumFree;
-
-// === CODE ===
-/**
- * \brief Initialise the physical memory manager with a passed memory map
- */
-void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap)
-{
-        int    mapIndex = 0;
-       tPAddr  rangeStart, rangeLen;
-
-       if( MM_PAGE_BITMAP + (MM_MAXPHYSPAGE/8) > MM_PMM_END ) {
-               Log_KernelPanic("PMM", "Config Error, PMM cannot fit data in allocated range");
-       }
-
-       giMaxPhysPage = MaxRAMPage;
-
-//     for( i = 0; i < MM_RANGE_MAX; i ++ )
-//             gaiPhysRangeFirstFree[i] = -1;
-       giPhysFirstFree = -1;
-
-       while( MM_int_GetMapEntry(MemoryMap, mapIndex++, &rangeStart, &rangeLen) )
-       {
-               tVAddr  bitmap_page;
-               
-               LOG("Range %i, %P to %P", mapIndex-1, rangeStart, rangeLen);
-               rangeStart /= PAGE_SIZE;
-               rangeLen /= PAGE_SIZE;
-
-               giPhysNumFree += rangeLen;
-
-               LOG("rangeStart = 0x%x, rangeLen = 0x%x", rangeStart, rangeLen);
-
-               if( giPhysFirstFree == -1 || giPhysFirstFree > rangeStart )
-                       giPhysFirstFree = rangeStart;
-
-               if( giPhysLastFree < rangeStart + rangeLen )
-                       giPhysLastFree = rangeStart + rangeLen;
-
-               LOG("giPhysFirstFree = 0x%x, giPhysLastFree = 0x%x", giPhysFirstFree, giPhysLastFree);
-
-               bitmap_page = (tVAddr)&gaPageBitmaps[rangeStart/32];
-               bitmap_page &= ~(PAGE_SIZE-1);
-
-               // Only need to allocate bitmaps
-               if( !MM_GetPhysAddr( bitmap_page ) ) {
-                       if( !MM_Allocate( bitmap_page ) ) {
-                               Log_KernelPanic("PMM", "Out of memory during init, this is bad");
-                               return ;
-                       }
-//                     memset( (void*)bitmap_page, 0, (rangeStart/8) & ~(PAGE_SIZE-1) );
-                       memset( (void*)bitmap_page, 0, PAGE_SIZE );
-               }
-               
-               // Align to 32 pages
-               for( ; (rangeStart & 31) && rangeLen > 0; rangeStart++, rangeLen-- ) {
-                       gaPageBitmaps[rangeStart / 32] |= 1 << (rangeStart&31);
-                       LOG("gaPageBitmaps[%i] = 0x%x", rangeStart/32, gaPageBitmaps[rangeStart/32]);
-               }
-               // Mark blocks of 32 as avail
-               for( ; rangeLen > 31; rangeStart += 32, rangeLen -= 32 ) {
-                       gaPageBitmaps[rangeStart / 32] = -1;
-               }
-               // Mark the tail
-               for( ; rangeLen > 0; rangeStart ++, rangeLen -- ) {
-                       gaPageBitmaps[rangeStart / 32] |= 1 << (rangeStart&31);
-               }
-       }
-
-       gbPMM_Init = 1;
-
-       LOG("giPhysFirstFree = 0x%x, giPhysLastFree = 0x%x", giPhysFirstFree, giPhysLastFree);
-       LEAVE('-');
-}
-
-/**
- * \brief Allocate a contiguous range of physical pages with a maximum
- *        bit size of \a MaxBits
- * \param Pages        Number of pages to allocate
- * \param MaxBits      Maximum size of the physical address
- * \note If \a MaxBits is <= 0, any sized address is used (with preference
- *       to higher addresses)
- */
-tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
-{
-       tPAddr  addr, ret;
-        int    nFree = 0, i;
-       
-       ENTER("iPages iBits", Pages, MaxBits);
-       
-       Mutex_Acquire(&glPhysicalPages);
-       
-       // Check if there is enough in the range
-       if(giPhysNumFree >= Pages)
-       {
-               LOG("{0x%x -> 0x%x}", giPhysFirstFree, giPhysLastFree);
-               // Do a cheap scan, scanning upwards from the first free page in
-               // the range
-               nFree = 0;
-               addr = giPhysFirstFree;
-               while( addr <= giPhysLastFree )
-               {
-                       #if USE_SUPER_BITMAP
-                       // Check the super bitmap
-                       if( gaSuperBitmap[addr / (32*32)] == 0 )
-                       {
-                               LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr += (32*32);
-                               addr &= ~(32*32-1);     // (1LL << 6+6) - 1
-                               continue;
-                       }
-                       #endif
-                       LOG("gaPageBitmaps[%i] = 0x%x", addr/32, gaPageBitmaps[addr/32]);
-                       // Check page block (32 pages)
-                       if( gaPageBitmaps[addr / 32] == 0) {
-                               LOG("nFree = %i = 0 (block) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr += 32;
-                               addr &= ~31;
-                               continue;
-                       }
-                       // Check individual page
-                       if( !(gaPageBitmaps[addr / 32] & (1LL << (addr & 31))) )
-                       {
-                               LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr ++;
-                               continue;
-                       }
-                       nFree ++;
-                       addr ++;
-                       LOG("nFree(%i) == %i (1x%x)", nFree, Pages, addr);
-                       if(nFree == Pages)
-                               break;
-               }
-               LOG("nFree = %i", nFree);
-               // If we don't find a contiguous block, nFree will not be equal
-               // to Num, so we set it to zero and do the expensive lookup.
-               if(nFree != Pages)      nFree = 0;
-       }
-       
-       if( !nFree )
-       {
-#if 0
-               // Oops. ok, let's do an expensive check (scan down the list
-               // until a free range is found)
-               nFree = 1;
-               addr = gaiPhysRangeLastFree[ rangeID ];
-               // TODO
-#endif
-               Mutex_Release(&glPhysicalPages);
-               // TODO: Page out
-               // ATM. Just Warning
-               Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
-               Log_Warning("PMM",
-                       "Out of memory (unable to fulfil request for %i pages)",
-                       Pages   
-                       );
-               LEAVE('i', 0);
-               return 0;
-       }
-       LOG("nFree = %i, addr = 0x%08x", nFree, (addr-Pages) << 12);
-       
-       // Mark pages as allocated
-       addr -= Pages;
-       for( i = 0; i < Pages; i++, addr++ )
-       {
-               // Mark as used
-               PAGE_BITMAP_SETUSED(addr);
-               // Maintain first possible free
-               giPhysNumFree --;
-               if(addr == giPhysFirstFree)
-                       giPhysFirstFree += 1;
-       
-               LOG("if( MM_GetPhysAddr( %p ) )", &gaiPageReferences[addr]);
-               // Mark as referenced if the reference count page is valid      
-               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) ) {
-                       gaiPageReferences[addr] = 1;
-               }
-       }
-       ret = addr - Pages;     // Save the return address
-       LOG("ret = %x", ret);   
-
-       #if TRACE_ALLOCS
-       LogF("MM_AllocPhysRange: %P (%i pages)\n", ret, Pages);
-       if(Pages > 1) {
-               LogF(" also");
-               for(i = 1; i < Pages; i++)
-                       LogF(" %P", ret+i);
-               LogF("\n");
-       }
-       #endif
-
-       #if USE_SUPER_BITMAP
-       // Update super bitmap
-       Pages += addr & (32-1);
-       addr &= ~(32-1);
-       Pages = (Pages + (32-1)) & ~(32-1);
-       for( i = 0; i < Pages/32; i++ )
-       {
-               if( gaPageBitmaps[ addr / 32 ] + 1 == 0 )
-                       gaSuperBitmap[addr / (32*32)] |= 1LL << ((addr / 32) & 31);
-       }
-       #endif
-       
-       Mutex_Release(&glPhysicalPages);
-       LEAVE('x', ret << 12);
-       return ret << 12;
-}
-
-/**
- * \brief Allocate a single physical page, with no preference as to address size.
- */
-tPAddr MM_AllocPhys(void)
-{
-        int    i;
-
-       if( !gbPMM_Init )
-       {       
-               // Hack to allow allocation during setup
-               for(i = 0; i < NUM_STATIC_ALLOC; i++) {
-                       if( gaiStaticAllocPages[i] ) {
-                               tPAddr  ret = gaiStaticAllocPages[i];
-                               gaiStaticAllocPages[i] = 0;
-                               Log("MM_AllocPhys: Return %x, static alloc %i", ret, i);
-                               return ret;
-                       }
-               }
-               
-               tPAddr  ret = 0;
-               for( ret = 0; ret < giMaxPhysPage; ret ++ )
-               {
-                       if( !MM_GetPhysAddr( (tVAddr)&gaPageBitmaps[ret/32] ) ) {
-                               ret += PAGE_SIZE*8;
-                               continue ;
-                       }
-                       if( gaPageBitmaps[ret/32] == 0 ) {
-                               ret += 32-1;
-                               continue ;
-                       }
-                       if( gaPageBitmaps[ret/32] & (1 << (ret&31)) ) {
-                               gaPageBitmaps[ret/32] &= ~(1 << (ret&31));
-                               return ret * PAGE_SIZE;
-                       }
-               }
-               Log_Error("PMM", "MM_AllocPhys failed duing init");
-               return 0;
-       }
-       #if TRACE_ALLOCS
-       Log("AllocPhys by %p", __builtin_return_address(0));
-       #endif
-       
-       return MM_AllocPhysRange(1, -1);
-}
-
-/**
- * \brief Reference a physical page
- */
-void MM_RefPhys(tPAddr PAddr)
-{
-       tPAddr  page = PAddr / PAGE_SIZE;
-       tVAddr  refpage = (tVAddr)&gaiPageReferences[page] & ~(PAGE_SIZE-1);
-       
-       if( page >= giMaxPhysPage )     return ;
-
-       if( PAGE_BITMAP_FREE(page) )
-       {
-               // Allocate
-               PAGE_BITMAP_SETUSED(page);
-               #if USE_SUPER_BITMAP
-               if( gaPageBitmaps[page / 32] == 0 )
-                       gaSuperBitmap[page / (32*32)] &= ~(1LL << ((page / 32) & 31));
-               #endif
-               if( MM_GetPhysAddr( refpage ) )
-                       gaiPageReferences[page] = 1;
-       }
-       else
-       {
-               // Reference again
-               if( !MM_GetPhysAddr( refpage ) )
-               {
-                        int    pages_per_page, basepage, i;
-                       if( MM_Allocate(refpage) == 0 ) {
-                               // Out of memory, can this be resolved?
-                               // TODO: Reclaim memory
-                               Log_Error("PMM", "Out of memory (MM_RefPhys)");
-                               return ;
-                       }
-                       pages_per_page = PAGE_SIZE/sizeof(*gaiPageReferences);
-                       basepage = page & ~(pages_per_page-1);
-                       for( i = 0; i < pages_per_page; i ++ ) {
-                               if( PAGE_BITMAP_FREE(basepage+i) )
-                                       gaiPageReferences[basepage+i] = 0;
-                               else
-                                       gaiPageReferences[basepage+i] = 1;
-                       }
-                       gaiPageReferences[page] = 2;
-               }
-               else
-                       gaiPageReferences[ page ] ++;
-       }
-}
-
-int MM_GetRefCount(tPAddr PAddr)
-{
-       PAddr >>= 12;
-       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
-               return gaiPageReferences[PAddr];
-       }
-       
-       if( gaPageBitmaps[ PAddr / 32 ] & (1LL << (PAddr&31)) ) {
-               return 1;
-       }
-       
-       return 0;
-}
-
-/**
- * \brief Dereference a physical page
- */
-void MM_DerefPhys(tPAddr PAddr)
-{
-       Uint64  page = PAddr >> 12;
-       
-       if( PAddr >> 12 > giMaxPhysPage )       return ;
-
-       ENTER("PPAddr", PAddr);
-       
-       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
-       {
-               if( gaiPageReferences[page] > 0 )
-                       gaiPageReferences[ page ] --;
-               if( gaiPageReferences[ page ] == 0 ) {
-                       gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
-                       // TODO: Catch when all pages in this range have been dereferenced
-               }
-       }
-       else
-               gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
-       // Clear node if needed
-       if( MM_GetPhysAddr( (tVAddr)&gapPageNodes[page] ) ) {
-               gapPageNodes[page] = NULL;
-               // TODO: Catch when all pages in this range are not using nodes
-       }
-       
-       // Update the free counts if the page was freed
-       if( gaPageBitmaps[ page / 32 ] & (1LL << (page&31)) )
-       {
-               giPhysNumFree ++;
-               if( giPhysFirstFree == -1 || giPhysFirstFree > page )
-                       giPhysFirstFree = page;
-               if( giPhysLastFree < page )
-                       giPhysLastFree = page;
-       }
-
-       #if USE_SUPER_BITMAP    
-       // If the bitmap entry is not zero, set the bit free in the super bitmap
-       if(gaPageBitmaps[ page / 32 ] != 0 ) {
-               gaSuperBitmap[page / (32*32)] |= 1LL << ((page / 32) & 31);
-       }
-       #endif
-       LEAVE('-');
-}
-
-int MM_SetPageNode(tPAddr PAddr, void *Node)
-{
-       tPAddr  page = PAddr >> 12;
-       tVAddr  node_page = ((tVAddr)&gapPageNodes[page]) & ~(PAGE_SIZE-1);
-
-       if( !MM_GetRefCount(PAddr) )    return 1;
-       
-       if( !MM_GetPhysAddr(node_page) ) {
-               if( !MM_Allocate(node_page) )
-                       return -1;
-               memset( (void*)node_page, 0, PAGE_SIZE );
-       }
-
-       gapPageNodes[page] = Node;
-       return 0;
-}
-
-int MM_GetPageNode(tPAddr PAddr, void **Node)
-{
-       if( !MM_GetRefCount(PAddr) )    return 1;
-       PAddr >>= 12;
-       
-       if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
-               *Node = NULL;
-               return 0;
-       }
-
-       *Node = gapPageNodes[PAddr];
-       return 0;
-}
-
diff --git a/Kernel/include/tpl_mm_phys_stack.h b/Kernel/include/tpl_mm_phys_stack.h
deleted file mode 100644 (file)
index 46ceb97..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Acess2 Core
- * 
- * include/tpl_mm_phys.h
- * Physical Memory Manager Template
- */
-#define DEBUG  0
-
-/**
- * \file tpl_mm_phys_stack.h
- * \brief Template physical memory manager
- *
- * An extensible physical memory manager
- *
- * Usage: Requires NUM_MM_PHYS_RANGES to be set to the number of address
- * "classes" wanted.
- * MAX_PHYS_PAGES - Used to calculate structure sizes
- * PADDR_TYPE
- */
-
-// === PROTOTYPES ===
-//void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
-//tPAddr       MM_AllocPhysRange(int Num, int Bits);
-//tPAddr       MM_AllocPhys(void);
-//void MM_RefPhys(tPAddr PAddr);
-//void MM_DerefPhys(tPAddr PAddr);
- int   MM_int_GetRangeID( tPAddr Addr );
- int   MM_int_IsPhysUnavail( tPageNum Page );
-
-// === GLOBALS ===
-tMutex glPhysicalPages;
-//Uint64       *gaPageStacks[NUM_MM_PHYS_RANGES];      // Page stacks
- int   giPageStackSizes[NUM_MM_PHYS_RANGES];   // Points to the first unused slot
-Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS;     // Reference Counts
-Uint64 giMaxPhysPage = 0;      // Maximum Physical page
-
-// === CODE ===
-/**
- * \brief Initialise the physical memory map using a Multiboot 1 map
- */
-void MM_Tpl_InitPhys(int MaxRAMPage)
-{
-       const int       PAGE_SIZE = 0x1000;
-       const int       pagesPerPageOnStack = PAGE_SIZE / sizeof(gaPageStack[0]);
-        int    i;
-       tPageNum        page;
-
-//     ENTER("pMBoot=%p", MBoot);
-       
-       giMaxPhysPage = MaxRAMPage;
-       
-       tPAddr  page = 0;
-       for( i = 0; i < NUM_MM_PHYS_RANGES; i ++ )
-       {
-               for( ; page < giPageRangeMax[i] && page < giMaxPhysPage; page ++ )
-               {
-                        int    rangeSize;
-
-                       rangeSize = MM_int_IsPhysUnavail(page);
-                       if( rangeSize > 0 ) {
-                               page += rangeSize;
-                               continue;
-                       }
-                       // Page is avaliable for use
-       
-                       // Check if the page stack is allocated
-                       tVAddr  stack_page = &gaPageStacks[i][giPageStackSizes[i]&~pagesPerPageOnStack];
-                       if( !MM_GetPhysAddr( stack_page ) ) {
-                               MM_Map( stack_page, page*PAGE_SIZE );
-                       }
-                       else {
-                               gaPageStacks[i][ giPageStackSizes[i] ] = page;
-                               giPageStackSizes[i] ++;
-                       }
-               }
-       }
-       
-       LEAVE('-');
-}
-
-/**
- * \brief Allocate a contiguous range of physical pages with a maximum
- *        bit size of \a MaxBits
- * \param Pages        Number of pages to allocate
- * \param MaxBits      Maximum size of the physical address
- * \note If \a MaxBits is <= 0, any sized address is used (with preference
- *       to higher addresses)
- */
-tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
-{
-       tPAddr  addr, ret;
-        int    rangeID;
-        int    nFree = 0, i;
-       
-       ENTER("iPages iBits", Pages, MaxBits);
-       
-       if( MaxBits <= 0 || MaxBits >= 64 )     // Speedup for the common case
-               rangeID = MM_PHYS_MAX;
-       else
-               rangeID = MM_int_GetRangeID( (1LL << MaxBits) - 1 );
-       
-       LOG("rangeID = %i", rangeID);
-       
-       Mutex_Acquire(&glPhysicalPages);
-       
-       // Check if the range actually has any free pages
-       while(giPageStackSizes[rangeID] == 0 && rangeID)
-               rangeID --;
-       
-       LOG("rangeID = %i", rangeID);
-       
-       // What the? Oh, man. No free pages
-       if(giPageStackSizes[rangeID] == 0) {
-               Mutex_Release(&glPhysicalPages);
-               // TODO: Page out / attack the cache
-               // ATM. Just Warning
-               Warning(" MM_AllocPhysRange: Out of free pages");
-               Log_Warning("Arch",
-                       "Out of memory (unable to fulfil request for %i pages), zero remaining",
-                       Pages
-                       );
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Check if there is enough in the range
-       if(giPhysRangeFree[rangeID] >= Pages)
-       {
-               LOG("{%i,0x%x -> 0x%x}",
-                       giPhysRangeFree[rangeID],
-                       giPhysRangeFirst[rangeID], giPhysRangeLast[rangeID]
-                       );
-               // Do a cheap scan, scanning upwards from the first free page in
-               // the range
-               nFree = 0;
-               addr = giPhysRangeFirst[ rangeID ];
-               while( addr <= giPhysRangeLast[ rangeID ] )
-               {
-                       //Log(" MM_AllocPhysRange: addr = 0x%x", addr);
-                       // Check the super bitmap
-                       if( gaSuperBitmap[addr >> (6+6)] + 1 == 0 ) {
-                               LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr += 1LL << (6+6);
-                               addr &= ~0xFFF; // (1LL << 6+6) - 1
-                               continue;
-                       }
-                       // Check page block (64 pages)
-                       if( gaMainBitmap[addr >> 6] + 1 == 0) {
-                               LOG("nFree = %i = 0 (main) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr += 1LL << (6);
-                               addr &= ~0x3F;
-                               continue;
-                       }
-                       // Check individual page
-                       if( gaMainBitmap[addr >> 6] & (1LL << (addr & 63)) ) {
-                               LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
-                               nFree = 0;
-                               addr ++;
-                               continue;
-                       }
-                       nFree ++;
-                       addr ++;
-                       LOG("nFree(%i) == %i (0x%x)", nFree, Pages, addr);
-                       if(nFree == Pages)
-                               break;
-               }
-               LOG("nFree = %i", nFree);
-               // If we don't find a contiguous block, nFree will not be equal
-               // to Num, so we set it to zero and do the expensive lookup.
-               if(nFree != Pages)      nFree = 0;
-       }
-       
-       if( !nFree )
-       {
-               // Oops. ok, let's do an expensive check (scan down the list
-               // until a free range is found)
-               nFree = 1;
-               addr = giPhysRangeLast[ rangeID ];
-               // TODO
-               Mutex_Release(&glPhysicalPages);
-               // TODO: Page out
-               // ATM. Just Warning
-               Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
-               Log_Warning("Arch",
-                       "Out of memory (unable to fulfil request for %i pages)",
-                       Pages   
-                       );
-               LEAVE('i', 0);
-               return 0;
-       }
-       LOG("nFree = %i, addr = 0x%08x", nFree, addr);
-       
-       // Mark pages as allocated
-       addr -= Pages;
-       for( i = 0; i < Pages; i++, addr++ )
-       {
-               gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
-               rangeID = MM_int_GetRangeID(addr << 12);
-               giPhysRangeFree[ rangeID ] --;
-               LOG("%x == %x", addr, giPhysRangeFirst[ rangeID ]);
-               if(addr == giPhysRangeFirst[ rangeID ])
-                       giPhysRangeFirst[ rangeID ] += 1;
-       }
-       ret = addr;     // Save the return address
-       
-       // Update super bitmap
-       Pages += addr & (64-1);
-       addr &= ~(64-1);
-       Pages = (Pages + (64-1)) & ~(64-1);
-       for( i = 0; i < Pages/64; i++ )
-       {
-               if( gaMainBitmap[ addr >> 6 ] + 1 == 0 )
-                       gaSuperBitmap[addr>>12] |= 1LL << ((addr >> 6) & 63);
-       }
-       
-       Mutex_Release(&glPhysicalPages);
-       LEAVE('x', ret << 12);
-       return ret << 12;
-}
-
-/**
- * \brief Allocate a single physical page, with no preference as to address
- *        size.
- */
-tPAddr MM_AllocPhys(void)
-{
-        int    i;
-       
-       // Hack to allow allocation during setup
-       for(i = 0; i < NUM_STATIC_ALLOC; i++) {
-               if( gaiStaticAllocPages[i] ) {
-                       tPAddr  ret = gaiStaticAllocPages[i];
-                       gaiStaticAllocPages[i] = 0;
-                       Log("MM_AllocPhys: Return %x, static alloc %i", ret, i);
-                       return ret;
-               }
-       }
-       
-       return MM_AllocPhysRange(1, -1);
-}
-
-/**
- * \brief Reference a physical page
- */
-void MM_RefPhys(tPAddr PAddr)
-{
-       Uint64  page = PAddr >> 12;
-       
-       if( PAddr >> 12 > giMaxPhysPage )       return ;
-       
-       if( gaMainBitmap[ page >> 6 ] & (1LL << (page&63)) )
-       {
-               // Reference again
-               gaMultiBitmap[ page >> 6 ] |= 1LL << (page&63);
-               gaiPageReferences[ page ] ++;
-       }
-       else
-       {
-               // Allocate
-               gaMainBitmap[page >> 6] |= 1LL << (page&63);
-               if( gaMainBitmap[page >> 6 ] + 1 == 0 )
-                       gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
-       }
-}
-
-/**
- * \brief Dereference a physical page
- */
-void MM_DerefPhys(tPAddr PAddr)
-{
-       Uint64  page = PAddr >> 12;
-       
-       if( PAddr >> 12 > giMaxPhysPage )       return ;
-       
-       if( gaMultiBitmap[ page >> 6 ] & (1LL << (page&63)) ) {
-               gaiPageReferences[ page ] --;
-               if( gaiPageReferences[ page ] == 1 )
-                       gaMultiBitmap[ page >> 6 ] &= ~(1LL << (page&63));
-               if( gaiPageReferences[ page ] == 0 )
-                       gaMainBitmap[ page >> 6 ] &= ~(1LL << (page&63));
-       }
-       else
-               gaMainBitmap[ page >> 6 ] &= ~(1LL << (page&63));
-       
-       // Update the free counts if the page was freed
-       if( !(gaMainBitmap[ page >> 6 ] & (1LL << (page&63))) )
-       {
-                int    rangeID;
-               rangeID = MM_int_GetRangeID( PAddr );
-               giPhysRangeFree[ rangeID ] ++;
-               if( giPhysRangeFirst[rangeID] > page )
-                       giPhysRangeFirst[rangeID] = page;
-               if( giPhysRangeLast[rangeID] < page )
-                       giPhysRangeLast[rangeID] = page;
-       }
-       
-       // If the bitmap entry is not -1, unset the bit in the super bitmap
-       if(gaMainBitmap[ page >> 6 ] + 1 != 0 ) {
-               gaSuperBitmap[page >> 12] &= ~(1LL << ((page >> 6) & 63));
-       }
-}
-
-/**
- * \brief Takes a physical address and returns the ID of its range
- * \param Addr Physical address of page
- * \return Range ID from eMMPhys_Ranges
- */
-int MM_int_GetRangeID( tPAddr Addr )
-{
-       if(Addr >> 32)
-               return MM_PHYS_MAX;
-       else if(Addr >> 24)
-               return MM_PHYS_32BIT;
-       else if(Addr >> 20)
-               return MM_PHYS_24BIT;
-       else if(Addr >> 16)
-               return MM_PHYS_20BIT;
-       else
-               return MM_PHYS_16BIT;
-}
diff --git a/Kernel/include/vfs.h b/Kernel/include/vfs.h
deleted file mode 100644 (file)
index 1aa073b..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-/* 
- * Acess2
- * VFS Common Header
- */
-/**
- * \file vfs.h
- * \brief Acess VFS Layer
- * 
- * The Acess Virtual File System (VFS) provides abstraction of multiple
- * physical filesystems, network storage and devices (both hardware and
- * virtual) to the user.
- * 
- * The core of the VFS is the concept of a \ref tVFS_Node "VFS Node".
- * A VFS Node represents a "file" in the VFS tree, this can be any sort
- * of file (an ordinary file, a directory, a symbolic link or a device)
- * depending on the bits set in the \ref tVFS_Node.Flags Flags field.
- * - For more information see "VFS Node Flags"
- */
-#ifndef _VFS_H
-#define _VFS_H
-
-#include <acess.h>
-
-/**
- * \brief Thread list datatype for VFS_Select
- */
-typedef struct sVFS_SelectList tVFS_SelectList;
-
-typedef struct sVFS_NodeType   tVFS_NodeType;
-
-/**
- * \name tVFS_Node Flags
- * \brief Flag values for tVFS_Node.Flags
- * \{
- */
-//! \todo Is this still needed
-#define VFS_FFLAG_READONLY     0x01    //!< Readonly File
-/**
- * \brief Directory Flag
- * 
- * This flag marks the tVFS_Node as describing a directory, and says
- * that the tVFS_Node.FindDir, tVFS_Node.ReadDir, tVFS_Node.MkNod and
- * tVFS_Node.Relink function pointers are valid.
- * For a directory the tVFS_Node.Size field contains the number of files
- * within the directory, or -1 for undetermined.
- */
-#define VFS_FFLAG_DIRECTORY    0x02
-/**
- * \brief Symbolic Link Flag
- * 
- * Marks a file as a symbolic link
- */
-#define VFS_FFLAG_SYMLINK      0x04
-/**
- * \brief Set User ID Flag
- * 
- * Allows an executable file to change it's executing user to the file's
- * owner.
- * In the case of a directory, it means that all immediate children will
- * inherit the UID of the parent.
- */
-#define VFS_FFLAG_SETUID       0x08
-/**
- * \brief Set Group ID Flag
- * 
- * Allows an executable file to change it's executing group to the file's
- * owning group.
- * In the case of a directory, it means that all immediate children will
- * inherit the GID of the parent.
- */
-#define VFS_FFLAG_SETGID       0x10
-
-/**
- * \brief "Don't do Write-Back" Flag
- *
- * Stops the VFS from calling tVFS_Node.Write on dirty pages when a region
- * is unmapped. Nice for read-only files and memory-only files (or 
- * pseudo-readonly filesystems)
- */
-#define VFS_FFLAG_NOWRITEBACK
-/**
- * \}
- */
-
-/**
- * \brief Represents a node (file or directory) in the VFS tree
- * 
- * This structure provides the VFS with the functions required to read/write
- * the file (or directory) that it represents.
- */
-typedef struct sVFS_Node
-{
-       /**
-        * \name Identifiers
-        * \brief Fields used by the driver to identify what data this node
-        *        corresponds to.
-        * \{
-        */
-       Uint64  Inode;  //!< Inode ID - Must identify the node uniquely if tVFS_Driver.GetNodeFromINode is non-NULL
-       Uint    ImplInt;        //!< Implementation Usable Integer
-       void    *ImplPtr;       //!< Implementation Usable Pointer
-       /**
-        * \}
-        */
-       
-       /**
-        * \name Node State
-        * \brief Stores the misc information about the node
-        * \{
-        */
-        int    ReferenceCount; //!< Number of times the node is used
-       
-       Uint64  Size;   //!< File Size
-       
-       Uint32  Flags;  //!< File Flags
-       
-       /**
-        * \brief Pointer to cached data (FS Specific)
-        * \note The Inode_* functions will free when the node is uncached
-        *       this if needed
-        */
-       void    *Data;
-       
-       /**
-        * \brief Node mutex
-        * \note Provided for the Filesystem driver's use
-        */
-       tMutex  Lock;
-       
-       /**
-        * \}
-        */
-       
-       /**
-        * \name Times
-        * \{
-        */
-       Sint64  ATime;  //!< Last Accessed Time
-       Sint64  MTime;  //!< Last Modified Time
-       Sint64  CTime;  //!< Creation Time
-       /**
-        * \}
-        */
-       
-       /**
-        * \name Access control
-        * \{
-        */
-       tUID    UID;    //!< ID of Owning User
-       tGID    GID;    //!< ID of Owning Group
-       
-        int    NumACLs;        //!< Number of ACL entries
-       tVFS_ACL        *ACLs;  //!< Access Controll List pointer
-       /**
-        * \}
-        */
-       
-       /**
-        * \name VFS_Select() fields
-        * \note Used by the VFS internals, drivers should use VFS_Mark*
-        * \{
-        */
-        int    DataAvaliable;
-       tVFS_SelectList *ReadThreads;   //!< Threads waiting to read
-        int    BufferFull;
-       tVFS_SelectList *WriteThreads;  //!< Threads waiting to write
-        int    ErrorOccurred;
-       tVFS_SelectList *ErrorThreads;  //!< Threads waiting for an error
-       /**
-        * \}
-        */
-
-       /**
-        * \name VFS_MMap() fields
-        * \{
-        */
-       void    *MMapInfo;
-       /**
-        * \}
-        */
-       
-       /**
-        * \brief Functions associated with the node
-        */
-       tVFS_NodeType   *Type;
-} tVFS_Node;
-
-/**
- * \brief Functions for a specific node type
- */
-struct sVFS_NodeType
-{
-       /**
-        * \brief Debug name for the type
-        */
-       const char      *TypeName;
-
-       /**
-        * \name Common Functions
-        * \brief Functions that are used no matter the value of .Flags
-        * \{
-        */
-       /**
-        * \brief Reference the node
-        * \param Node Pointer to this node
-        */
-       void    (*Reference)(struct sVFS_Node *Node);
-       /**
-        * \brief Close (dereference) the node
-        * \param Node  Pointer to this node
-        * 
-        * Usually .Close is used to write any changes to the node back to
-        * the persistent storage.
-        */
-       void    (*Close)(struct sVFS_Node *Node);
-       
-       /**
-        * \brief Send an IO Control
-        * \param Node  Pointer to this node
-        * \param Id    IOCtl call number
-        * \param Data  Pointer to data to pass to the driver
-        * \return Implementation defined
-        */
-        int    (*IOCtl)(struct sVFS_Node *Node, int Id, void *Data);
-       
-       /**
-        * \}
-        */
-       
-       /**
-        * \name Buffer Functions
-        * \brief Functions for accessing a buffer-type file (normal file or
-        *        symbolic link)
-        * \{
-        */
-       
-       /**
-        * \brief Read from the file
-        * \param Node  Pointer to this node
-        * \param Offset        Byte offset in the file
-        * \param Length        Number of bytes to read
-        * \param Buffer        Destination for read data
-        * \return Number of bytes read
-        */
-       Uint64  (*Read)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-       /**
-        * \brief Write to the file
-        * \param Node  Pointer to this node
-        * \param Offset        Byte offser in the file
-        * \param Length        Number of bytes to write
-        * \param Buffer        Source of written data
-        * \return Number of bytes read
-        */
-       Uint64  (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
-
-       /**
-        * \brief Map a region of a file into memory
-        * \param Node  Pointer to this node
-        * \param Offset        Start of the region (page aligned)
-        * \param Length        Length of the region (page aligned)
-        * \param Dest  Location to which to map
-        * \return Boolean Failure
-        * \note If NULL, the VFS implements it using .Read
-        */
-        int    (*MMap)(struct sVFS_Node *Node, Uint64 Offset, int Length, void *Dest);
-       
-       /**
-        * \}
-        */
-       
-       /**
-        * \name Directory Functions
-        * \{
-        */
-       /**
-        * \brief Find an directory entry by name
-        * \param Node  Pointer to this node
-        * \param Name  Name of the file wanted
-        * \return Pointer to the requested node or NULL if it cannot be found
-        * \note The node returned must be accessable until ::tVFS_Node.Close
-        *       is called and ReferenceCount reaches zero.
-        */
-       struct sVFS_Node        *(*FindDir)(struct sVFS_Node *Node, const char *Name);
-       
-       /**
-        * \brief Read from a directory
-        * \param Node  Pointer to this node
-        * \param Pos   Offset in the directory
-        * \return Pointer to the name of the item on the heap (will be freed
-        *         by the caller). If the directory end has been reached, NULL
-        *         will be returned.
-        *         If an item is required to be skipped either &::NULLNode,
-        *         ::VFS_SKIP or ::VFS_SKIPN(0...1023) will be returned.
-        */
-       char    *(*ReadDir)(struct sVFS_Node *Node, int Pos);
-       
-       /**
-        * \brief Create a node in a directory
-        * \param Node  Pointer to this node
-        * \param Name  Name of the new child
-        * \param Flags Flags to apply to the new child (directory or symlink)
-        * \return Zero on Success, non-zero on error (see errno.h)
-        */
-        int    (*MkNod)(struct sVFS_Node *Node, const char *Name, Uint Flags);
-       
-       /**
-        * \brief Relink (Rename/Remove) a file/directory
-        * \param Node  Pointer to this node
-        * \param OldName       Name of the item to move/delete
-        * \param NewName       New name (or NULL if unlinking is wanted)
-        * \return Zero on Success, non-zero on error (see errno.h)
-        */
-        int    (*Relink)(struct sVFS_Node *Node, const char *OldName, const char *NewName);
-       
-       /**
-        * \brief Link a node to a name
-        * \param Node  Pointer to this node (directory)
-        * \param Child Node to create a new link to
-        * \param NewName       Name for the new link
-        * \retur Zeron on success, non-zero on error (see errno.h)
-        */
-        int    (*Link)(struct sVFS_Node *Node, struct sVFS_Node *Child, const char *NewName);
-        
-        /**
-         * \}
-         */
-};
-
-/**
- * \brief VFS Driver (Filesystem) Definition
- */
-typedef struct sVFS_Driver
-{
-       /**
-        * \brief Unique Identifier for this filesystem type
-        */
-       const char      *Name;
-       /**
-        * \brief Flags applying to this driver
-        */
-       Uint    Flags;
-       
-       /**
-        * \brief Callback to mount a device
-        */
-       tVFS_Node       *(*InitDevice)(const char *Device, const char **Options);
-       /**
-        * \brief Callback to unmount a device
-        */
-       void    (*Unmount)(tVFS_Node *Node);
-       /**
-        * \brief Retrieve a VFS node from an inode
-        */
-       tVFS_Node       *(*GetNodeFromINode)(tVFS_Node *RootNode, Uint64 InodeValue);
-       /**
-        * \brief Used internally (next driver in the chain)
-        */
-       struct sVFS_Driver      *Next;
-} tVFS_Driver;
-
-// === GLOBALS ===
-//! \brief Maximum number of elements that can be skipped in one return
-#define        VFS_MAXSKIP     ((void*)1024)
-//! \brief Skip a single entry in readdir
-#define        VFS_SKIP        ((void*)1)
-//! \brief Skip \a n entries in readdir
-#define        VFS_SKIPN(n)    ((void*)(n))
-
-extern tVFS_Node       NULLNode;       //!< NULL VFS Node (Ignored/Skipped)
-/**
- * \name Static ACLs
- * \brief Simple ACLs to aid writing drivers
- * \{
- */
-extern tVFS_ACL        gVFS_ACL_EveryoneRWX;   //!< Everyone Read/Write/Execute
-extern tVFS_ACL        gVFS_ACL_EveryoneRW;    //!< Everyone Read/Write
-extern tVFS_ACL        gVFS_ACL_EveryoneRX;    //!< Everyone Read/Execute
-extern tVFS_ACL        gVFS_ACL_EveryoneRO;    //!< Everyone Read only
-/**
- * \}
- */
-
-// === FUNCTIONS ===
-/**
- * \fn int VFS_AddDriver(tVFS_Driver *Info)
- * \brief Registers the driver with the DevFS layer
- * \param Info Driver information structure
- */
-extern int     VFS_AddDriver(tVFS_Driver *Info);
-/**
- * \brief Get the information structure of a driver given its name
- * \param Name Name of filesystem driver to find
- */
-extern tVFS_Driver     *VFS_GetFSByName(const char *Name);
-
-
-/**
- * \brief Prepare a node for use
- */
-extern void    VFS_InitNode(tVFS_Node *Node);
-
-/**
- * \brief Clean up a node, ready for deletion
- * \note This should ALWAYS be called before a node is freed, as it
- *       cleans up VFS internal structures.
- */
-extern void    VFS_CleanupNode(tVFS_Node *Node);
-
-/**
- * \fn tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
- * \brief Transforms Unix Permssions into Acess ACLs
- * \param Mode Unix RWXrwxRWX mask
- * \param Owner        UID of the file's owner
- * \param Group        GID of the file's owning group
- * \return An array of 3 Acess ACLs
- */
-extern tVFS_ACL        *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group);
-
-/**
- * \brief Flags fro \a TypeFlag of VFS_SelectNode
- * \{
- */
-#define VFS_SELECT_READ        0x01
-#define VFS_SELECT_WRITE       0x02
-#define VFS_SELECT_ERROR       0x04
-/**
- * \}
- */
-
-/**
- * \brief Wait for an event on a node
- * \param Node Node to wait on
- * \param Type Type of wait
- * \param Timeout      Time to wait (NULL for infinite wait)
- * \param Name Name to show in debug output
- * \return Number of nodes that actioned (0 or 1)
- */
-extern int     VFS_SelectNode(tVFS_Node *Node, int Type, tTime *Timeout, const char *Name);
-
-/**
- * \brief Change the full flag on a node
- */
-extern int     VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull);
-/**
- * \brief Alter the space avaliable flag on a node
- */
-extern int     VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable);
-/**
- * \brief Alter the error flags on a node
- */
-extern int     VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState);
-
-// --- Node Cache --
-/**
- * \name Node Cache
- * \brief Functions to allow a node to be cached in memory by the VFS
- * 
- * These functions store a node for the driver, to prevent it from having
- * to re-generate the node on each call to FindDir. It also allows for
- * fast cleanup when a filesystem is unmounted.
- * \{
- */
-/**
- * \fn int Inode_GetHandle(void)
- * \brief Gets a unique handle to the Node Cache
- * \return A unique handle for use for the rest of the Inode_* functions
- */
-extern int     Inode_GetHandle(void);
-/**
- * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
- * \brief Gets an inode from the node cache
- * \param Handle       A handle returned by Inode_GetHandle()
- * \param Inode        Value of the Inode field of the ::tVFS_Node you want
- * \return A pointer to the cached node
- */
-extern tVFS_Node       *Inode_GetCache(int Handle, Uint64 Inode);
-/**
- * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
- * \brief Caches a node in the Node Cache
- * \param Handle       A handle returned by Inode_GetHandle()
- * \param Node A pointer to the node to be cached (a copy is taken)
- * \return A pointer to the node in the node cache
- */
-extern tVFS_Node       *Inode_CacheNode(int Handle, tVFS_Node *Node);
-/**
- * \fn int Inode_UncacheNode(int Handle, Uint64 Inode)
- * \brief Dereferences (and removes if needed) a node from the cache
- * \param Handle       A handle returned by Inode_GetHandle()
- * \param Inode        Value of the Inode field of the ::tVFS_Node you want to remove
- */
-extern void    Inode_UncacheNode(int Handle, Uint64 Inode);
-/**
- * \fn void Inode_ClearCache(int Handle)
- * \brief Clears the cache for a handle
- * \param Handle       A handle returned by Inode_GetHandle()
- */
-extern void    Inode_ClearCache(int Handle);
-
-/**
- * \}
- */
-
-#endif
diff --git a/Kernel/include/vfs_ext.h b/Kernel/include/vfs_ext.h
deleted file mode 100644 (file)
index b4d5e2a..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/**
- * \file vfs_ext.h
- * \brief Exported VFS Definitions
- * \author John Hodge (thePowersGang)
- */
-#ifndef _VFS_EXT_H
-#define _VFS_EXT_H
-
-//! Inode number type
-typedef Uint64 tInode;
-
-//! Mountpoint identifier type
-typedef Uint32 tMount;
-
-// === CONSTANTS ===
-//! Maximum size of a Memory Path generated by VFS_GetMemPath
-#define        VFS_MEMPATH_SIZE        (3 + (BITS/4)*2)
-/**
- * \name Flags for VFS_Open
- * \{
- */
-//! Open for execution
-#define VFS_OPENFLAG_EXEC      0x01
-//! Open for reading
-#define VFS_OPENFLAG_READ      0x02
-//! Open for writing
-#define VFS_OPENFLAG_WRITE     0x04
-//! Do not resolve the final symbolic link
-#define        VFS_OPENFLAG_NOLINK     0x40
-//! Create the file if it doesn't exist
-#define VFS_OPENFLAG_CREATE    0x80
-//! Open as a user
-#define        VFS_OPENFLAG_USER       0x8000
-/**
- * \}
- */
-//! Marks a VFS handle as belonging to the kernel
-#define VFS_KERNEL_FLAG        0x40000000
-
-//! Architectual maximum number of file descriptors
-#define MAX_FILE_DESCS 128
-
-/**
- * \brief VFS_Seek directions
- */
-enum eVFS_SeekDirs
-{
-       SEEK_SET = 1,   //!< Set the current file offset
-       SEEK_CUR = 0,   //!< Seek relative to the current position
-       SEEK_END = -1   //!< Seek from the end of the file backwards
-};
-
-/**
- * \name ACL Permissions
- * \{
- */
-/**
- * \brief Readable
- */
-#define VFS_PERM_READ  0x00000001
-/**
- * \brief Writeable
- */
-#define VFS_PERM_WRITE 0x00000002
-/**
- * \brief Append allowed
- */
-#define VFS_PERM_APPEND        0x00000004
-/**
- * \brief Executable
- */
-#define VFS_PERM_EXECUTE       0x00000008
-/**
- * \brief All permissions granted
- */
-#define VFS_PERM_ALL   0x7FFFFFFF      // Mask for permissions
-/**
- * \brief Denies instead of granting permissions
- * \note Denials take precedence
- */
-#define VFS_PERM_DENY  0x80000000      // Inverts permissions
-/**
- * \}
- */
-
-/**
- * \brief MMap protection flags
- * \{
- */
-#define MMAP_PROT_READ 0x001   //!< Readable memory
-#define MMAP_PROT_WRITE        0x002   //!< Writable memory
-#define MMAP_PROT_EXEC 0x004   //!< Executable memory
-/**
- * \}
- */
-
-/**
- * \brief MMap mapping flags
- * \{
- */
-#define MMAP_MAP_SHARED        0x001   //!< Shared with all other users of the FD
-#define MMAP_MAP_PRIVATE       0x002   //!< Local (COW) copy
-#define MMAP_MAP_FIXED         0x004   //!< Load to a fixed address
-#define MMAP_MAP_ANONYMOUS     0x008   //!< Not associated with a FD
-/**
- * \}
- */
-
-// -- System Call Structures ---
-/**
- * \brief ACL Defintion Structure
- */
-typedef struct sVFS_ACL
-{
-       struct {
-               unsigned Group: 1;      //!< Group (as opposed to user) flag
-               unsigned ID:    31;     //!< ID of Group/User (-1 for nobody/world)
-       };
-       struct {
-               unsigned Inv:   1;      //!< Invert Permissions
-               unsigned Perms: 31;     //!< Permission Flags
-       };
-} tVFS_ACL;
-
-/**
- * \brief SYS_FINFO structure
- */
-typedef struct sFInfo
-{
-       tMount  mount;  //!< Mountpoint ID
-       tInode  inode;  //!< Inode
-       Uint32  uid;    //!< Owning User ID
-       Uint32  gid;    //!< Owning Group ID
-       Uint32  flags;  //!< File flags
-       Uint64  size;   //!< File Size
-       Sint64  atime;  //!< Last Accessed time
-       Sint64  mtime;  //!< Last modified time
-       Sint64  ctime;  //!< Creation time
-       Sint32  numacls;        //!< Total number of ACL entries
-       tVFS_ACL        acls[]; //!< ACL buffer (size is passed in the \a MaxACLs argument to VFS_FInfo)
-} PACKED tFInfo;
-
-/**
- * \brief fd_set for select()
- */
-typedef struct
-{
-       //! Bitmap of set file descriptors
-       Uint16  flags[MAX_FILE_DESCS/16];
-}      fd_set;
-
-/**
- * \brief Clear a descriptor flag in a fd_set
- * \param fd   File descriptor to clear
- * \param fdsetp       Set to modify
- */
-#define FD_CLR(fd, fdsetp) ((fdsetp)->flags[(fd)/16]&=~(1<<((fd)%16)))
-/**
- * \brief Set a descriptor flag in a fd_set
- * \param fd   File descriptor to set
- * \param fdsetp       Set to modify
- */
-#define FD_SET(fd, fdsetp) ((fdsetp)->flags[(fd)/16]|=~(1<<((fd)%16)))
-/**
- * \brief Test a descriptor flag in a fd_set
- * \param fd   File descriptor to test
- * \param fdsetp       Set to modify
- */
-#define FD_ISSET(fd, fdsetp) ((fdsetp)->flags[(fd)/16]&(1<<((fd)%16)))
-
-// === FUNCTIONS ===
-/**
- * \brief Initialise the VFS (called by system.c)
- * \return Boolean Success
- */
-extern int     VFS_Init(void);
-
-/**
- * \brief Open a file
- * \param Path Absolute or relative path to the file
- * \param Flags        Flags defining how to open the file
- * \return VFS Handle (an integer) or -1 if an error occured
- * \note Calls VFS_OpenEx(Path, Flags, 0)
- */
-extern int     VFS_Open(const char *Path, Uint Flags);
-/**
- * \brief Open a file
- * \param Path Absolute or relative path to the file
- * \param Flags        Flags defining how to open the file
- * \param Mode Mode for newly created file (POSIX compatability)
- * \return VFS Handle (an integer) or -1 if an error occured
- */
-extern int     VFS_OpenEx(const char *Path, Uint Flags, Uint Mode);
-/**
- * \brief Opens a file via an open directory
- * \note The file to open must be a direct child of the parent
- * \param FD   Parent Directory
- * \param Name Child name
- * \param Mode Open mode
- * \return File handle (same as returned from VFS_Open)
- */
-extern int     VFS_OpenChild(int FD, const char *Name, Uint Mode);
-/**
- * \brief Opens a file given a mount ID and an inode number
- * \param Mount        Mount ID returned by FInfo
- * \param Inode        Inode number from FInfo
- * \param Mode Open mode (see VFS_Open)
- * \return File handle (same as VFS_Open)
- */
-extern int     VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode);
-
-/**
- * \brief Close a currently open file
- * \param FD   Handle returned by ::VFS_Open
- */
-extern void    VFS_Close(int FD);
-
-/**
- * \brief Get file information from an open file
- * \param FD   File handle returned by ::VFS_Open
- * \param Dest Destination for the read information
- * \param MaxACLs      Number of ACL slots allocated in the \a Dest structure
- * \return Boolean Success
- * 
- * If the \a NumACLs is smaller than the number of ACLs the node has, only
- * \a NumACLs will be copied into \a Dest, but the tFInfo.numacls field
- * will be set to the true ammount of ACLs. It is up to the user to do with
- * this information how they like.
- */
-extern int     VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs);
-/**
- * \brief Gets the permissions appling to a user/group.
- * \param FD   File handle returned by ::VFS_Open
- * \param Dest ACL information structure to edit
- * \return Boolean success
- * 
- * This function sets the tVFS_ACL.Inv and tVFS_ACL.Perms fields to what
- * permissions the user/group specied in tVFS_ACL.ID has on the file.
- */
-extern int     VFS_GetACL(int FD, tVFS_ACL *Dest);
-/**
- * \brief Changes the user's current working directory
- * \param Dest New working directory (either absolute or relative to the current)
- * \return Boolean Success
- */
-extern int     VFS_ChDir(const char *Dest);
-/**
- * \brief Change the current virtual root for the user
- * \param New New virtual root (same as ::VFS_ChDir but cannot go
- *            above the current virtual root)
- * \return Boolean success
- */
-extern int     VFS_ChRoot(const char *New);
-
-/**
- * \brief Change the location of the current file pointer
- * \param FD   File handle returned by ::VFS_Open
- * \param Offset       Offset within the file to go to
- * \param Whence       A direction from ::eVFS_SeekDirs
- * \return Boolean success
- */
-extern int     VFS_Seek(int FD, Sint64 Offset, int Whence);
-/**
- * \brief Returns the current file pointer
- * \param FD   File handle returned by ::VFS_Open
- * \return Current file position
- */
-extern Uint64  VFS_Tell(int FD);
-
-/**
- * \brief Reads data from a file
- * \param FD   File handle returned by ::VFS_Open
- * \param Length       Number of bytes to read from the file
- * \param Buffer       Destination of read data
- * \return Number of read bytes
- */
-extern Uint64  VFS_Read(int FD, Uint64 Length, void *Buffer);
-/**
- * \brief Writes data to a file
- * \param FD   File handle returned by ::VFS_Open
- * \param Length       Number of bytes to write to the file
- * \param Buffer       Source of written data
- * \return Number of bytes written
- */
-extern Uint64  VFS_Write(int FD, Uint64 Length, const void *Buffer);
-
-/**
- * \brief Reads from a specific offset in the file
- * \param FD   File handle returned by ::VFS_Open
- * \param Offset       Byte offset in the file
- * \param Length       Number of bytes to read from the file
- * \param Buffer       Source of read data
- * \return Number of bytes read
- */
-extern Uint64  VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
-/**
- * \brief Writes to a specific offset in the file
- * \param FD   File handle returned by ::VFS_Open
- * \param Offset       Byte offset in the file
- * \param Length       Number of bytes to write to the file
- * \param Buffer       Source of written data
- * \return Number of bytes written
- */
-extern Uint64  VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer);
-
-/**
- * \brief Sends an IOCtl request to the driver
- * \param FD   File handle returned by ::VFS_Open
- * \param ID   IOCtl call ID (driver specific)
- * \param Buffer       Data pointer to send to the driver
- * \return Driver specific response
- */
-extern int     VFS_IOCtl(int FD, int ID, void *Buffer);
-
-/**
- * \brief Creates a VFS Memory path from a pointer and size
- * \param Dest Destination for the created path
- * \param Base Base of the memory file
- * \param Length       Length of the memory buffer
- * \note A maximum of VFS_MEMPATH_SIZE bytes will be required in \a Dest
- */
-extern void    VFS_GetMemPath(char *Dest, void *Base, Uint Length);
-/**
- * \brief Gets the canoical (true) path of a file
- * \param Path File path (may contain symlinks, relative elements etc.)
- * \return Absolute path with no symlinks
- */
-extern char    *VFS_GetTruePath(const char *Path);
-
-/**
- * \brief Mounts a filesystem
- * \param Device       Device to mount
- * \param MountPoint   Location to mount
- * \param Filesystem   Filesystem to use
- * \param Options      Options string to pass the driver
- * \return 1 on succes, -1 on error
- */
-extern int     VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
-/**
- * \brief Create a new directory
- * \param Path Path to new directory (absolute or relative)
- * \return Boolean success
- * \note The parent of the directory must exist
- */
-extern int     VFS_MkDir(const char *Path);
-/**
- * \brief Create a symbolic link
- * \param Name Name of the symbolic link
- * \param Link File the symlink points to
- * \return Boolean success (\a Link is not tested for existence)
- */
-extern int     VFS_Symlink(const char *Name, const char *Link);
-/**
- * \brief Read from a directory
- * \param FD   File handle returned by ::VFS_Open
- * \param Dest Destination array for the file name (max 255 bytes)
- * \return Boolean Success
- */
-extern int     VFS_ReadDir(int FD, char *Dest);
-/**
- * \brief Wait for an aciton on a file descriptor
- * \param MaxHandle    Maximum set handle in \a *Handles
- * \param ReadHandles  Handles to wait for data on
- * \param WriteHandles Handles to wait to write to
- * \param ErrHandles   Handle to wait for errors on
- * \param Timeout      Timeout for select() (if null, there is no timeout), if zero select() is non blocking
- * \param ExtraEvents  Extra event set to wait on
- * \param IsKernel     Use kernel handles as opposed to user handles
- * \return Number of handles that actioned
- */
-extern int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
-
-/**
- * \brief Map a file into memory
- * \param DestHint     Suggested place for read data
- * \param Length       Size of area to map
- * \param Protection   Protection type (see `man mmap`)
- * \param Flags        Mapping flags
- * \param FD   File descriptor to load from
- * \param Offset       Start of region
- */
-extern void    *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset);
-
-/**
- * \brief Unmap memory allocated by VFS_MMap
- * \param Addr Address of data to unmap
- * \param Length       Length of data
- */
-extern int     VFS_MUnmap(void *Addr, size_t Length);
-#endif
diff --git a/Kernel/include/vfs_int.h b/Kernel/include/vfs_int.h
deleted file mode 100644 (file)
index a8eadb6..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* 
- * Acess Micro - VFS Server Ver 1
- */
-#ifndef _VFS_INT_H
-#define _VFS_INT_H
-
-#include "vfs.h"
-
-// === TYPES ===
-typedef struct sVFS_Mount {
-       struct sVFS_Mount       *Next;
-       char    *MountPoint;
-       size_t  MountPointLen;
-       Uint32  Identifier;
-       char    *Device;
-       char    *Options;
-       tVFS_Driver     *Filesystem;
-       tVFS_Node       *RootNode;
-       char    StrData[];
-} tVFS_Mount;
-
-typedef struct sVFS_Handle {
-       tVFS_Node       *Node;
-       tVFS_Mount      *Mount;
-       Uint64  Position;
-       Uint    Mode;
-} tVFS_Handle;
-
-typedef struct sVFS_Proc {
-       struct sVFS_Proc        *Next;
-        int    ID;
-        int    CwdLen;
-       Uint    UID, GID;
-       char    *Cwd;
-        int    MaxHandles;
-       tVFS_Handle     Handles[];
-} tVFS_Proc;
-
-typedef struct sVFS_MMapPage {
-       Uint64  FileOffset;
-       tPAddr  PAddr;
-} tVFS_MMapPage;
-
-// === GLOBALS ===
-extern tVFS_Mount      *gVFS_Mounts;
-
-// === PROTOTYPES ===
-// --- open.c ---
-extern char    *VFS_GetAbsPath(const char *Path);
-extern tVFS_Node       *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPoint);
-extern tVFS_Handle     *VFS_GetHandle(int FD);
-// --- acls.c ---
-extern int     VFS_CheckACL(tVFS_Node *Node, Uint Permissions);
-// --- mount.c ---
-extern tVFS_Mount      *VFS_GetMountByIdent(Uint32 MountID);
-// --- dir.c ---
-extern int     VFS_MkNod(const char *Path, Uint Flags);
-
-
-// --- VFS Helpers ---
-static inline void _CloseNode(tVFS_Node *Node)
-{
-       if(Node && Node->Type && Node->Type->Close)
-               Node->Type->Close( Node );
-}
-
-
-#endif
diff --git a/Kernel/include/vfs_ramfs.h b/Kernel/include/vfs_ramfs.h
deleted file mode 100644 (file)
index 8bbc8b5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* 
- * AcessMicro VFS
- * - RAM Filesystem Coommon Structures
- */
-#ifndef _RAMFS_H
-#define _RAMFS_H
-#include <vfs.h>
-
-typedef struct sRamFS_File {
-       struct sRamFS_File      *Next;
-       struct sRamFS_File      *Parent;
-       char    Name[32];
-       tVFS_Node       Node;
-       union {
-               struct sRamFS_File      *FirstChild;
-               char    *Bytes;
-       } Data;
-} tRamFS_File;
-
-#endif 
diff --git a/Kernel/include/vfs_threads.h b/Kernel/include/vfs_threads.h
deleted file mode 100644 (file)
index 95ec227..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * include/vfs_threads.h
- * - Handle maintainance functions for the VFS used by threading code
- */
-#ifndef _VFS_THREADS_H_
-#define _VFS_THREADS_H_
-
-// === FUNCTIONS ===
-extern void    VFS_ReferenceUserHandles(void);
-extern void    VFS_CloseAllUserHandles(void);
-
-extern void    *VFS_SaveHandles(int NumFDs, int *FDs);
-extern void    VFS_RestoreHandles(int NumFDs, void *Handles);
-extern void    VFS_FreeSavedHandles(int NumFDs, void *Handles);
-
-#endif
diff --git a/Kernel/include/workqueue.h b/Kernel/include/workqueue.h
deleted file mode 100644 (file)
index ff0c7f4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * workqueue.h
- * - FIFO Queue
- */
-#ifndef _WORKQUEUE_H_
-#define _WORKQUEUE_H_
-
-#include <acess.h>
-
-typedef struct sWorkqueue      tWorkqueue;
-
-struct sWorkqueue
-{
-       tShortSpinlock  Protector;
-       const char      *Name;
-        int    NextOffset;
-       
-       void    *Head;
-       void    *Tail;
-       struct sThread  *Sleeper;
-};
-
-extern void    Workqueue_Init(tWorkqueue *Queue, const char *Name, size_t NextOfset);
-extern void    *Workqueue_GetWork(tWorkqueue *Queue);
-extern void    Workqueue_AddWork(tWorkqueue *Queue, void *Ptr);
-
-#endif
-
diff --git a/Kernel/lib.c b/Kernel/lib.c
deleted file mode 100644 (file)
index 60cbd4c..0000000
+++ /dev/null
@@ -1,1084 +0,0 @@
-/*
- * Acess2
- * Common Library Functions
- */
-#include <acess.h>
-#include <hal_proc.h>
-
-// === CONSTANTS ===
-#define        RANDOM_SEED     0xACE55052
-#define        RANDOM_A        0x00731ADE
-#define        RANDOM_C        12345
-#define        RANDOM_SPRUCE   0xf12b039
-//                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
-const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
-#define UNIX_TO_2K     ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
-
-// === PROTOTYPES ===
-#if 0
- int   atoi(const char *string);
-void   itoa(char *buf, Uint64 num, int base, int minLength, char pad);
- int   vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
- int   sprintf(char *__s, const char *__format, ...);
-#endif
- int   tolower(int c);
-#if 0
- int   strucmp(const char *Str1, const char *Str2);
-char   *strchr(const char *__s, int __c);
- int   strpos(const char *Str, char Ch);
- Uint8 ByteSum(void *Ptr, int Size);
-size_t strlen(const char *__s);
-char   *strcpy(char *__str1, const char *__str2);
-char   *strncpy(char *__str1, const char *__str2, size_t max);
- int   strcmp(const char *str1, const char *str2);
- int   strncmp(const char *str1, const char *str2, size_t num);
-char   *_strdup(const char *File, int Line, const char *Str);
-char   **str_split(const char *__str, char __ch);
- int   strpos8(const char *str, Uint32 Search);
- int   ReadUTF8(Uint8 *str, Uint32 *Val);
- int   WriteUTF8(Uint8 *str, Uint32 Val);
- int   DivUp(int num, int dem);
-Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
-void   format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
- int   rand(void);
- int   CheckString(char *String);
- int   CheckMem(void *Mem, int NumBytes);
- int   ModUtil_LookupString(char **Array, char *Needle);
- int   ModUtil_SetIdent(char *Dest, char *Value);
- int   Hex(char *Dest, size_t Size, const Uint8 *SourceData);
- int   UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
-#endif
-
-// === EXPORTS ===
-EXPORT(atoi);
-EXPORT(itoa);
-EXPORT(vsnprintf);
-EXPORT(sprintf);
-EXPORT(tolower);
-EXPORT(strucmp);
-EXPORT(strchr);
-EXPORT(strpos);
-EXPORT(ByteSum);
-EXPORT(strlen);
-EXPORT(strcpy);
-EXPORT(strncpy);
-EXPORT(strcat);
-EXPORT(strncat);
-EXPORT(strcmp);
-EXPORT(strncmp);
-//EXPORT(strdup);
-EXPORT(_strdup);       // Takes File/Line too
-EXPORT(str_split);
-EXPORT(strpos8);
-EXPORT(DivUp);
-EXPORT(ReadUTF8);
-EXPORT(WriteUTF8);
-EXPORT(timestamp);
-EXPORT(CheckString);
-EXPORT(CheckMem);
-EXPORT(ModUtil_LookupString);
-EXPORT(ModUtil_SetIdent);
-EXPORT(UnHex);
-EXPORT(SwapEndian16);
-EXPORT(SwapEndian32);
-EXPORT(memmove);
-
-// === CODE ===
-/**
- * \brief Convert a string into an integer
- */
-int atoi(const char *string)
-{
-       int ret = 0;
-       ParseInt(string, &ret);
-       return ret;
-}
-int ParseInt(const char *string, int *Val)
-{
-        int    ret = 0;
-        int    bNeg = 0;
-       const char *orig_string = string;
-       
-       //Log("atoi: (string='%s')", string);
-       
-       // Clear non-numeric characters
-       while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
-       if( *string == '-' ) {
-               bNeg = 1;
-               while( !('0' <= *string && *string <= '9') )    string++;
-       }
-       
-       if(*string == '0')
-       {
-               string ++;
-               if(*string == 'x')
-               {
-                       // Hex
-                       string ++;
-                       for( ;; string ++ )
-                       {
-                               if('0' <= *string && *string <= '9') {
-                                       ret *= 16;
-                                       ret += *string - '0';
-                               }
-                               else if('A' <= *string && *string <= 'F') {
-                                       ret *= 16;
-                                       ret += *string - 'A' + 10;
-                               }
-                               else if('a' <= *string && *string <= 'f') {
-                                       ret *= 16;
-                                       ret += *string - 'a' + 10;
-                               }
-                               else
-                                       break;
-                       }
-               }
-               else    // Octal
-               {
-                       for( ; '0' <= *string && *string <= '7'; string ++ )
-                       {
-                               ret *= 8;
-                               ret += *string - '0';
-                       }
-               }
-       }
-       else    // Decimal
-       {
-               for( ; '0' <= *string && *string <= '9'; string++)
-               {
-                       ret *= 10;
-                       ret += *string - '0';
-               }
-               // Error check
-               if( ret == 0 )  return 0;
-       }
-       
-       if(bNeg)        ret = -ret;
-       
-       //Log("atoi: RETURN %i", ret);
-       
-       if(Val) *Val = ret;
-       
-       return string - orig_string;
-}
-
-static const char cUCDIGITS[] = "0123456789ABCDEF";
-/**
- * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
- * \brief Convert an integer into a character string
- */
-void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
-{
-       char    tmpBuf[64+1];
-        int    pos=0, i;
-       Uint64  rem;
-
-       // Sanity check
-       if(!buf)        return;
-       
-       // Sanity Check
-       if(base > 16 || base < 2) {
-               buf[0] = 0;
-               return;
-       }
-       
-       // Convert 
-       while(num > base-1) {
-               num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
-               tmpBuf[pos] = cUCDIGITS[ rem ];
-               pos++;
-       }
-       tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
-       
-       // Put in reverse
-       i = 0;
-       minLength -= pos;
-       while(minLength-- > 0)  buf[i++] = pad;
-       while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
-       buf[i] = 0;
-}
-
-/**
- * \brief Append a character the the vsnprintf output
- */
-#define PUTCH(c)       _putch(c)
-#define GETVAL()       do {\
-       if(isLongLong)  val = va_arg(args, Uint64);\
-       else    val = va_arg(args, unsigned int);\
-       }while(0)
-/**
- * \brief VArg String Number Print Formatted
- */
-int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
-{
-       char    c, pad = ' ';
-        int    minSize = 0, precision = -1, len;
-       char    tmpBuf[34];     // For Integers
-       const char      *p = NULL;
-        int    isLongLong = 0;
-       Uint64  val;
-       size_t  pos = 0;
-       // Flags
-        int    bPadLeft = 0;
-       
-       auto void _putch(char ch);
-
-       void _putch(char ch)
-       {
-               if(pos < __maxlen)
-               {
-                       if(__s) __s[pos] = ch;
-                       pos ++;
-               }
-       }
-
-       while((c = *__format++) != 0)
-       {
-               // Non control character
-               if(c != '%') { PUTCH(c); continue; }
-
-               c = *__format++;
-               if(c == '\0')   break;
-               
-               // Literal %
-               if(c == '%') { PUTCH('%'); continue; }
-               
-               // Pointer - Done first for debugging
-               if(c == 'p') {
-                       Uint    ptr = va_arg(args, Uint);
-                       PUTCH('*');     PUTCH('0');     PUTCH('x');
-                       for( len = BITS/4; len --; )
-                               PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
-                       continue ;
-               }
-               
-               // - Padding Side Flag
-               if(c == '-') {
-                       bPadLeft = 1;
-                       c = *__format++;
-               }
-               
-               // - Padding
-               if(c == '0') {
-                       pad = '0';
-                       c = *__format++;
-               }
-               else
-                       pad = ' ';
-               
-               // - Minimum length
-               if(c == '*') {  // Dynamic length
-                       minSize = va_arg(args, unsigned int);
-                       c = *__format++;
-               }
-               else if('1' <= c && c <= '9')
-               {
-                       minSize = 0;
-                       while('0' <= c && c <= '9')
-                       {
-                               minSize *= 10;
-                               minSize += c - '0';
-                               c = *__format++;
-                       }
-               }
-               else
-                       minSize = 0;
-               
-               // - Precision
-               precision = -1;
-               if( c == '.' ) {
-                       c = *__format++;
-                       
-                       if(c == '*') {  // Dynamic length
-                               precision = va_arg(args, unsigned int);
-                               c = *__format++;
-                       }
-                       else if('1' <= c && c <= '9')
-                       {
-                               precision = 0;
-                               while('0' <= c && c <= '9')
-                               {
-                                       precision *= 10;
-                                       precision += c - '0';
-                                       c = *__format++;
-                               }
-                       }
-               }
-               
-               // - Default, Long or LongLong?
-               isLongLong = 0;
-               if(c == 'l')    // Long is actually the default on x86
-               {
-                       c = *__format++;
-                       if(c == 'l') {
-                               c = *__format++;
-                               isLongLong = 1;
-                       }
-               }
-               
-               // - Now get the format code
-               p = tmpBuf;
-               switch(c)
-               {
-               case 'd':
-               case 'i':
-                       GETVAL();
-                       if( isLongLong && val >> 63 ) {
-                               PUTCH('-');
-                               val = -val;
-                       }
-                       else if( !isLongLong && val >> 31 ) {
-                               PUTCH('-');
-                               val = -(Sint32)val;
-                       }
-                       itoa(tmpBuf, val, 10, minSize, pad);
-                       goto printString;
-               case 'u':       // Unsigned
-                       GETVAL();
-                       itoa(tmpBuf, val, 10, minSize, pad);
-                       goto printString;
-               case 'P':       // Physical Address
-                       PUTCH('0');
-                       PUTCH('x');
-                       if(sizeof(tPAddr) > 4)  isLongLong = 1;
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-               case 'X':       // Hex
-                       if(BITS == 64)
-                               isLongLong = 1; // TODO: Handle non-x86 64-bit archs
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-                       
-               case 'x':       // Lower case hex
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-               case 'o':       // Octal
-                       GETVAL();
-                       itoa(tmpBuf, val, 8, minSize, pad);
-                       goto printString;
-               case 'b':
-                       GETVAL();
-                       itoa(tmpBuf, val, 2, minSize, pad);
-                       goto printString;
-
-               case 'B':       //Boolean
-                       val = va_arg(args, unsigned int);
-                       if(val) p = "True";
-                       else    p = "False";
-                       goto printString;
-               
-               // String - Null Terminated Array
-               case 's':
-                       p = va_arg(args, char*);        // Get Argument
-                       if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
-               printString:
-                       if(!p)          p = "(null)";
-                       len = strlen(p);
-                       if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
-                       while(*p && precision--)        PUTCH(*p++);
-                       if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
-                       break;
-               
-               case 'C':       // Non-Null Terminated Character Array
-                       p = va_arg(args, char*);
-                       if( !CheckMem(p, minSize) )     continue;       // No #PFs please
-                       if(!p)  goto printString;
-                       while(minSize--)        PUTCH(*p++);
-                       break;
-               
-               // Single Character
-               case 'c':
-               default:
-                       GETVAL();
-                       PUTCH( (Uint8)val );
-                       break;
-               }
-       }
-       
-       if(__s && pos != __maxlen)
-               __s[pos] = '\0';
-       
-       return pos;
-}
-#undef PUTCH
-
-/**
- */
-int sprintf(char *__s, const char *__format, ...)
-{
-       va_list args;
-        int    ret;
-       
-       va_start(args, __format);
-       ret = vsnprintf(__s, -1, __format, args);
-       va_end(args);
-       
-       return ret;
-}
-
-/**
- * \fn int tolower(int c)
- * \brief Converts a character to lower case
- */
-int tolower(int c)
-{
-       if('A' <= c && c <= 'Z')
-               return c - 'A' + 'a';
-       return c;
-}
-
-/**
- * \fn int strucmp(const char *Str1, const char *Str2)
- * \brief Compare \a Str1 and \a Str2 case-insensitively
- */
-int strucmp(const char *Str1, const char *Str2)
-{
-       while(*Str1 && tolower(*Str1) == tolower(*Str2))
-               Str1++, Str2++;
-       return tolower(*Str1) - tolower(*Str2);
-}
-
-/**
- * \brief Locate a byte in a string
- */
-char *strchr(const char *__s, int __c)
-{
-       for( ; *__s; __s ++ )
-       {
-               if( *__s == __c )       return (char*)__s;
-       }
-       return NULL;
-}
-
-/**
- * \fn int strpos(const char *Str, char Ch)
- * \brief Search a string for an ascii character
- */
-int strpos(const char *Str, char Ch)
-{
-        int    pos;
-       for(pos=0;Str[pos];pos++)
-       {
-               if(Str[pos] == Ch)      return pos;
-       }
-       return -1;
-}
-
-/**
- * \fn Uint8 ByteSum(void *Ptr, int Size)
- * \brief Adds the bytes in a memory region and returns the sum
- */
-Uint8 ByteSum(const void *Ptr, int Size)
-{
-       Uint8   sum = 0;
-       const Uint8     *data = Ptr;
-       while(Size--)   sum += *(data++);
-       return sum;
-}
-
-/**
- * \fn size_t strlen(const char *__str)
- * \brief Get the length of string
- */
-size_t strlen(const char *__str)
-{
-       size_t  ret = 0;
-       while(*__str++) ret++;
-       return ret;
-}
-
-/**
- * \brief Copy a string to a new location
- */
-char *strcpy(char *__str1, const char *__str2)
-{
-       while(*__str2)
-               *__str1++ = *__str2++;
-       *__str1 = '\0'; // Terminate String
-       return __str1;
-}
-
-/**
- * \brief Copy a string to a new location
- * \note Copies at most `max` chars
- */
-char *strncpy(char *__str1, const char *__str2, size_t __max)
-{
-       while(*__str2 && __max-- >= 1)
-               *__str1++ = *__str2++;
-       if(__max)
-               *__str1 = '\0'; // Terminate String
-       return __str1;
-}
-
-/**
- * \brief Append a string to another
- */
-char *strcat(char *__dest, const char *__src)
-{
-       while(*__dest++);
-       __dest--;
-       while(*__src)
-               *__dest++ = *__src++;
-       *__dest = '\0';
-       return __dest;
-}
-
-/**
- * \brief Append at most \a n chars to a string from another
- * \note At most n+1 chars are written (the dest is always zero terminated)
- */
-char *strncat(char *__dest, const char *__src, size_t n)
-{
-       while(*__dest++);
-       while(*__src && n-- >= 1)
-               *__dest++ = *__src++;
-       *__dest = '\0';
-       return __dest;
-}
-
-/**
- * \fn int strcmp(const char *str1, const char *str2)
- * \brief Compare two strings return the difference between
- *        the first non-matching characters.
- */
-int strcmp(const char *str1, const char *str2)
-{
-       while(*str1 && *str1 == *str2)
-               str1++, str2++;
-       return *str1 - *str2;
-}
-
-/**
- * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
- * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
- */
-int strncmp(const char *Str1, const char *Str2, size_t num)
-{
-       if(num == 0)    return 0;       // TODO: Check what should officially happen here
-       while(--num && *Str1 && *Str1 == *Str2)
-               Str1++, Str2++;
-       return *Str1-*Str2;
-}
-
-#if 0
-/**
- * \fn char *strdup(const char *Str)
- * \brief Duplicates a string
- */
-char *strdup(const char *Str)
-{
-       char    *ret;
-       ret = malloc(strlen(Str)+1);
-       if( !ret )      return NULL;
-       strcpy(ret, Str);
-       return ret;
-}
-#else
-
-/**
- * \fn char *_strdup(const char *File, int Line, const char *Str)
- * \brief Duplicates a string
- */
-char *_strdup(const char *File, int Line, const char *Str)
-{
-       char    *ret;
-       ret = Heap_Allocate(File, Line, strlen(Str)+1);
-       if( !ret )      return NULL;
-       strcpy(ret, Str);
-       return ret;
-}
-#endif
-
-/**
- * \brief Split a string using the passed character
- * \return NULL terminated array of strings on the heap
- * \param __str        String to split
- * \param __ch Character to split by
- */
-char **str_split(const char *__str, char __ch)
-{
-        int    i, j;
-        int    len = 1;
-       char    **ret;
-       char    *start;
-       
-       for( i = 0; __str[i]; i++ )
-       {
-               if(__str[i] == __ch)
-                       len ++;
-       }
-       
-       ret = malloc( sizeof(char*)*(len+1) + (i + 1) );
-       if( !ret )      return NULL;
-       
-       j = 1;
-       start = (char *)&ret[len+1];
-       ret[0] = start;
-       for( i = 0; __str[i]; i++ )
-       {
-               if(__str[i] == __ch) {
-                       *start++ = '\0';
-                       ret[j++] = start;
-               }
-               else {
-                       *start++ = __str[i]; 
-               }
-       }
-       *start = '\0';
-       ret[j] = NULL;
-       
-       return ret;
-}
-
-/**
- * \fn int DivUp(int num, int dem)
- * \brief Divide two numbers, rounding up
- * \param num  Numerator
- * \param dem  Denominator
- */
-int DivUp(int num, int dem)
-{
-       return (num+dem-1)/dem;
-}
-
-/**
- * \fn int strpos8(const char *str, Uint32 search)
- * \brief Search a string for a UTF-8 character
- */
-int strpos8(const char *str, Uint32 Search)
-{
-        int    pos;
-       Uint32  val = 0;
-       for(pos=0;str[pos];pos++)
-       {
-               // ASCII Range
-               if(Search < 128) {
-                       if(str[pos] == Search)  return pos;
-                       continue;
-               }
-               if(*(Uint8*)(str+pos) < 128)    continue;
-               
-               pos += ReadUTF8( (Uint8*)&str[pos], &val );
-               if(val == Search)       return pos;
-       }
-       return -1;
-}
-
-/**
- * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
- * \brief Read a UTF-8 character from a string
- */
-int ReadUTF8(const Uint8 *str, Uint32 *Val)
-{
-       *Val = 0xFFFD;  // Assume invalid character
-       
-       // ASCII
-       if( !(*str & 0x80) ) {
-               *Val = *str;
-               return 1;
-       }
-       
-       // Middle of a sequence
-       if( (*str & 0xC0) == 0x80 ) {
-               return 1;
-       }
-       
-       // Two Byte
-       if( (*str & 0xE0) == 0xC0 ) {
-               *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
-               return 2;
-       }
-       
-       // Three Byte
-       if( (*str & 0xF0) == 0xE0 ) {
-               *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
-               return 3;
-       }
-       
-       // Four Byte
-       if( (*str & 0xF1) == 0xF0 ) {
-               *Val = (*str & 0x07) << 18;     // Upper 3 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
-               return 4;
-       }
-       
-       // UTF-8 Doesn't support more than four bytes
-       return 4;
-}
-
-/**
- * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
- * \brief Write a UTF-8 character sequence to a string
- */
-int WriteUTF8(Uint8 *str, Uint32 Val)
-{
-       // ASCII
-       if( Val < 128 ) {
-               if( str ) {
-                       *str = Val;
-               }
-               return 1;
-       }
-       
-       // Two Byte
-       if( Val < 0x8000 ) {
-               if( str ) {
-                       *str++ = 0xC0 | (Val >> 6);
-                       *str++ = 0x80 | (Val & 0x3F);
-               }
-               return 2;
-       }
-       
-       // Three Byte
-       if( Val < 0x10000 ) {
-               if( str ) {
-                       *str++ = 0xE0 | (Val >> 12);
-                       *str++ = 0x80 | ((Val >> 6) & 0x3F);
-                       *str++ = 0x80 | (Val & 0x3F);
-               }
-               return 3;
-       }
-       
-       // Four Byte
-       if( Val < 0x110000 ) {
-               if( str ) {
-                       *str++ = 0xF0 | (Val >> 18);
-                       *str++ = 0x80 | ((Val >> 12) & 0x3F);
-                       *str++ = 0x80 | ((Val >> 6) & 0x3F);
-                       *str++ = 0x80 | (Val & 0x3F);
-               }
-               return 4;
-       }
-       
-       // UTF-8 Doesn't support more than four bytes
-       return 0;
-}
-
-/**
- * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
- * \brief Converts a date into an Acess Timestamp
- */
-Sint64 timestamp(int sec, int min, int hrs, int day, int month, int year)
-{
-        int    is_leap;
-       Sint64  stamp;
-
-       if( !(0 <= sec && sec < 60) )   return 0;
-       if( !(0 <= min && min < 60) )   return 0;
-       if( !(0 <= hrs && hrs < 24) )   return 0;
-       if( !(0 <= day && day < 31) )   return 0;
-       if( !(0 <= month && month < 12) )       return 0;
-
-       stamp = DAYS_BEFORE[month] + day;
-
-       // Every 4 years
-       // - every 100 years
-       // + every 400 years
-       is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
-       ASSERT(is_leap == 0 || is_leap == 1);
-
-       if( is_leap && month > 1 )      // Leap year and after feb
-               stamp += 1;
-
-       // Get seconds before the first of specified year
-       year -= 2000;   // Base off Y2K
-       // base year days + total leap year days
-       stamp += year*365 + (year/400) - (year/100) + (year/4);
-       
-       stamp *= 3600*24;
-       stamp += UNIX_TO_2K;
-       stamp += sec;
-       stamp += min*60;
-       stamp += hrs*3600;
-       
-       return stamp * 1000;
-}
-
-void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms)
-{
-        int    is_leap = 0, i;
-
-       auto Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R);
-       
-       Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R)
-       {
-               int sign = (N < 0) != (D < 0);
-               if(N < 0)       N = -N;
-               if(D < 0)       D = -D;
-               if(sign)
-                       return -DivMod64U(N, D, (Uint64*)R);
-               else
-                       return DivMod64U(N, D, (Uint64*)R);
-       }
-
-       // Get time
-       // TODO: Leap-seconds?
-       {
-               Sint64  rem;
-               TS = DivMod64( TS, 1000, &rem );
-               *ms = rem;
-               TS = DivMod64( TS, 60, &rem );
-               *sec = rem;
-               TS = DivMod64( TS, 60, &rem );
-               *mins = rem;
-               TS = DivMod64( TS, 24, &rem );
-               *hrs = rem;
-       }
-
-       // Adjust to Y2K
-       TS -= UNIX_TO_2K/(3600*24);
-
-       // Year (400 yr blocks) - (400/4-3) leap years
-       *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS );
-       if( TS < 366 )  // First year in 400 is a leap
-               is_leap = 1;
-       else
-       {
-               // 100 yr blocks - 100/4-1 leap years
-               *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS );
-               if( TS < 366 )  // First year in 100 isn't a leap
-                       is_leap = 0;
-               else
-               {
-                       *year += 4 * DivMod64( TS, 365*4 + 1, &TS );
-                       if( TS < 366 )  // First year in 4 is a leap
-                               is_leap = 1;
-                       else
-                       {
-                               *year += DivMod64( TS, 356, &TS );
-                       }
-               }
-       }
-       *year += 2000;
-
-       ASSERT(TS >= 0);
-       
-       *day = 0;
-       // Month (if after the first of march, which is 29 Feb in a leap year)
-       if( is_leap && TS > DAYS_BEFORE[2] ) {
-               TS -= 1;        // Shifts 29 Feb to 28 Feb
-               *day = 1;
-       }
-       // Get what month it is
-       for( i = 0; i < 12; i ++ ) {
-               if( TS < DAYS_BEFORE[i] )
-                       break;
-       }
-       *month = i - 1;
-       // Get day
-       TS -= DAYS_BEFORE[i-1];
-       *day += TS;     // Plus offset from leap handling above
-}
-
-/**
- * \fn int rand()
- * \brief Pseudo random number generator
- */
-int rand(void)
-{
-       #if 0
-       static Uint     state = RANDOM_SEED;
-       Uint    old = state;
-       // Get the next state value
-       giRandomState = (RANDOM_A*state + RANDOM_C);
-       // Check if it has changed, and if it hasn't, change it
-       if(state == old)        state += RANDOM_SPRUCE;
-       return state;
-       #else
-       // http://en.wikipedia.org/wiki/Xorshift
-       // 2010-10-03
-       static Uint32   x = 123456789;
-       static Uint32   y = 362436069;
-       static Uint32   z = 521288629;
-       static Uint32   w = 88675123; 
-       Uint32  t;
-       t = x ^ (x << 11);
-       x = y; y = z; z = w;
-       return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
-       #endif
-}
-
-/* *
- * \name Memory Validation
- * \{
- */
-/**
- * \brief Checks if a string resides fully in valid memory
- */
-int CheckString(const char *String)
-{
-       tVAddr  addr;
-        int    bUser;
-
-       addr = (tVAddr)String;
-
-       if( !MM_GetPhysAddr( addr ) )
-               return 0;
-       
-       // Check 1st page
-       bUser = MM_IsUser( addr );
-       
-       while( *(char*)addr )
-       {
-               if( (addr & (PAGE_SIZE-1)) == 0 )
-               {
-                       if(bUser && !MM_IsUser(addr) )
-                               return 0;
-                       if(!bUser && !MM_GetPhysAddr(addr) )
-                               return 0;
-               }
-               addr ++;
-       }
-       return 1;
-}
-
-/**
- * \brief Check if a sized memory region is valid memory
- * \return Boolean success
- */
-int CheckMem(const void *Mem, int NumBytes)
-{
-       return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
-}
-/* *
- * \}
- */
-
-/**
- * \brief Search a string array for \a Needle
- * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
- */
-int ModUtil_LookupString(const char **Array, const char *Needle)
-{
-        int    i;
-       if( !CheckString(Needle) )      return -1;
-       for( i = 0; Array[i]; i++ )
-       {
-               if(strcmp(Array[i], Needle) == 0)       return i;
-       }
-       return -1;
-}
-
-int ModUtil_SetIdent(char *Dest, const char *Value)
-{
-       if( !CheckMem(Dest, 32) )       return -1;
-       strncpy(Dest, Value, 32);
-       return 1;
-}
-
-int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
-{
-        int    i;
-       for( i = 0; i < Size; i ++ )
-       {
-               sprintf(Dest + i*2, "%02x", SourceData[i]);
-       }
-       return i*2;
-}
-
-/**
- * \brief Convert a string of hexadecimal digits into a byte stream
- */
-int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
-{
-        int    i;
-       
-       for( i = 0; i < DestSize*2; i += 2 )
-       {
-               Uint8   val = 0;
-               
-               if(SourceString[i] == '\0')     break;
-               
-               if('0' <= SourceString[i] && SourceString[i] <= '9')
-                       val |= (SourceString[i]-'0') << 4;
-               else if('A' <= SourceString[i] && SourceString[i] <= 'F')
-                       val |= (SourceString[i]-'A'+10) << 4;
-               else if('a' <= SourceString[i] && SourceString[i] <= 'f')
-                       val |= (SourceString[i]-'a'+10) << 4;
-                       
-               if(SourceString[i+1] == '\0')   break;
-               
-               if('0' <= SourceString[i+1] && SourceString[i+1] <= '9')
-                       val |= (SourceString[i+1] - '0');
-               else if('A' <= SourceString[i+1] && SourceString[i+1] <= 'F')
-                       val |= (SourceString[i+1] - 'A' + 10);
-               else if('a' <= SourceString[i+1] && SourceString[i+1] <= 'f')
-                       val |= (SourceString[i+1] - 'a' + 10);
-               
-               Dest[i/2] = val;
-       }
-       return i/2;
-}
-
-Uint16 SwapEndian16(Uint16 Val)
-{
-       return ((Val&0xFF)<<8) | ((Val>>8)&0xFF);
-}
-Uint32 SwapEndian32(Uint32 Val)
-{
-       return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
-}
-
-void *memmove(void *__dest, const void *__src, size_t len)
-{
-       size_t  block_size;
-       char    *dest = __dest;
-       const char      *src = __src;
-       void    *ret = __dest;
-
-       if( len == 0 || dest == src )
-               return dest;
-       
-       if( (tVAddr)dest > (tVAddr)src + len )
-               return memcpy(dest, src, len);
-       if( (tVAddr)dest + len < (tVAddr)src )
-               return memcpy(dest, src, len);
-       
-       // NOTE: Assumes memcpy works forward
-       if( (tVAddr)dest < (tVAddr)src )
-               return memcpy(dest, src, len);
-
-       if( (tVAddr)dest < (tVAddr)src )
-               block_size = (tVAddr)src - (tVAddr)dest;
-       else
-               block_size = (tVAddr)dest - (tVAddr)src;
-       
-       block_size &= ~0xF;
-       
-       while(len >= block_size)
-       {
-               memcpy(dest, src, block_size);
-               len -= block_size;
-               dest += block_size;
-               src += block_size;
-       }
-       memcpy(dest, src, len);
-       return ret;
-       
-}
-
diff --git a/Kernel/logging.c b/Kernel/logging.c
deleted file mode 100644 (file)
index b419be3..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Acess 2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * logging.c - Kernel Logging Service
- */
-#include <acess.h>
-#include <adt.h>
-
-#define CACHE_MESSAGES 0
-#define PRINT_ON_APPEND        1
-#define USE_RING_BUFFER        1
-#define RING_BUFFER_SIZE       4096
-
-// === CONSTANTS ===
-enum eLogLevels
-{
-       LOG_LEVEL_KPANIC,
-       LOG_LEVEL_PANIC,
-       LOG_LEVEL_FATAL,
-       LOG_LEVEL_ERROR,
-       LOG_LEVEL_WARNING,
-       LOG_LEVEL_NOTICE,
-       LOG_LEVEL_LOG,
-       LOG_LEVEL_DEBUG,
-       NUM_LOG_LEVELS
-};
-const char     *csaLevelColours[] = {
-               "\x1B[35m", "\x1B[34m", "\x1B[36m", "\x1B[31m",
-               "\x1B[33m", "\x1B[32m", "\x1B[0m", "\x1B[0m"
-               };
-const char     *csaLevelCodes[] =  {"k","p","f","e","w","n","l","d"};
-
-// === TYPES ===
-typedef struct sLogEntry
-{
-       struct sLogEntry        *Next;
-       struct sLogEntry        *LevelNext;
-       Sint64  Time;
-        int    Level;
-        int    Length;
-       char    Ident[9];
-       char    Data[];
-}      tLogEntry;
-typedef struct sLogList
-{
-       tLogEntry       *Head;
-       tLogEntry       *Tail;
-}      tLogList;
-
-// === PROTOTYPES ===
-void   Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args);
-static void    Log_Int_PrintMessage(tLogEntry *Entry);
-//void Log_KernelPanic(const char *Ident, const char *Message, ...);
-//void Log_Panic(const char *Ident, const char *Message, ...);
-//void Log_Error(const char *Ident, const char *Message, ...);
-//void Log_Warning(const char *Ident, const char *Message, ...);
-//void Log_Notice(const char *Ident, const char *Message, ...);
-//void Log_Log(const char *Ident, const char *Message, ...);
-//void Log_Debug(const char *Ident, const char *Message, ...);
-
-// === EXPORTS ===
-EXPORT(Log_Panic);
-EXPORT(Log_Error);
-EXPORT(Log_Warning);
-EXPORT(Log_Notice);
-EXPORT(Log_Log);
-EXPORT(Log_Debug);
-
-// === GLOBALS ===
-tShortSpinlock glLogOutput;
-#if USE_RING_BUFFER
-Uint8  gaLog_RingBufferData[sizeof(tRingBuffer)+RING_BUFFER_SIZE];
-tRingBuffer    *gpLog_RingBuffer = (void*)gaLog_RingBufferData;
-#else
-tMutex glLog;
-tLogList       gLog;
-tLogList       gLog_Levels[NUM_LOG_LEVELS];
-#endif
-
-// === CODE ===
-/**
- * \brief Adds an event to the log
- */
-void Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args)
-{
-        int    len;
-       tLogEntry       *ent;
-       va_list args_tmp;
-       
-       if( Level >= NUM_LOG_LEVELS )   return;
-       
-       va_copy(args_tmp, Args);
-       len = vsnprintf(NULL, 256, Format, args_tmp);
-       
-       //Log("len = %i", len);
-       
-       #if USE_RING_BUFFER || !CACHE_MESSAGES
-       {
-       char    buf[sizeof(tLogEntry)+len+1];
-       ent = (void*)buf;
-       #else
-       ent = malloc(sizeof(tLogEntry)+len+1);
-       #endif
-       ent->Time = now();
-       strncpy(ent->Ident, Ident, 8);
-       ent->Ident[8] = '\0';
-       ent->Level = Level;
-       ent->Length = len;
-       vsnprintf( ent->Data, len+1, Format, Args );
-
-       #if CACHE_MESSAGES
-       # if USE_RING_BUFFER
-       {
-               #define LOG_HDR_LEN     (14+1+2+8+2)
-               char    newData[ LOG_HDR_LEN + len + 2 + 1 ];
-               char    _ident[9];
-               strncpy(_ident, Ident, 9);
-               sprintf( newData, "%014lli%s [%-8s] ",
-                       ent->Time, csaLevelCodes[Level], Ident);
-               strcpy( newData + LOG_HDR_LEN, ent->Data );
-               strcpy( newData + LOG_HDR_LEN + len, "\r\n" );
-               gpLog_RingBuffer->Space = RING_BUFFER_SIZE;     // Needed to init the buffer
-               RingBuffer_Write( gpLog_RingBuffer, newData, LOG_HDR_LEN + len + 2 );
-       }
-       # else
-       Mutex_Acquire( &glLog );
-       
-       ent->Next = gLog.Tail;
-       if(gLog.Head)
-               gLog.Tail = ent;
-       else
-               gLog.Tail = gLog.Head = ent;
-       
-       ent->LevelNext = gLog_Levels[Level].Tail;
-       if(gLog_Levels[Level].Head)
-               gLog_Levels[Level].Tail = ent;
-       else
-               gLog_Levels[Level].Tail = gLog_Levels[Level].Head = ent;
-       
-       Mutex_Release( &glLog );
-       # endif
-       #endif
-       
-       #if PRINT_ON_APPEND || !CACHE_MESSAGES
-       Log_Int_PrintMessage( ent );
-       #endif
-       
-       #if USE_RING_BUFFER || !CACHE_MESSAGES
-       }
-       #endif
-}
-
-/**
- * \brief Prints a log message to the debug console
- */
-void Log_Int_PrintMessage(tLogEntry *Entry)
-{
-       SHORTLOCK( &glLogOutput );
-       LogF("%s%014lli%s [%-8s] %i - %s",
-               csaLevelColours[Entry->Level],
-               Entry->Time,
-               csaLevelCodes[Entry->Level],
-               Entry->Ident,
-               Threads_GetTID(),
-               Entry->Data
-               );
-       LogF("\x1B[0m\r\n");    // Separate in case Entry->Data is too long
-       SHORTREL( &glLogOutput );
-}
-
-/**
- * \brief KERNEL PANIC!!!!
- */
-void Log_KernelPanic(const char *Ident, const char *Message, ...)
-{
-       va_list args;   
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_KPANIC, Message, args);
-       va_end(args);
-       Panic("Log_KernelPanic - %s", Ident);
-}
-
-/**
- * \brief Panic Message - Driver Unrecoverable error
- */
-void Log_Panic(const char *Ident, const char *Message, ...)
-{
-       va_list args;   
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_PANIC, Message, args);
-       va_end(args);
-}
-
-/**
- * \brief Error Message - Recoverable Error
- */
-void Log_Error(const char *Ident, const char *Message, ...)
-{
-       va_list args;   
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_ERROR, Message, args);
-       va_end(args);
-}
-
-/**
- * \brief Warning Message - Something the user should know
- */
-void Log_Warning(const char *Ident, const char *Message, ...)
-{
-       va_list args;
-       
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_WARNING, Message, args);
-       va_end(args);
-}
-
-/**
- * \brief Notice Message - Something the user might like to know
- */
-void Log_Notice(const char *Ident, const char *Message, ...)
-{
-       va_list args;   
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_NOTICE, Message, args);
-       va_end(args);
-}
-
-/**
- * \brief Log Message - Possibly useful information
- */
-void Log_Log(const char *Ident, const char *Message, ...)
-{
-       va_list args;   
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_LOG, Message, args);
-       va_end(args);
-}
-
-/**
- * \brief Debug Message - Only a developer would want this info
- */
-void Log_Debug(const char *Ident, const char *Message, ...)
-{
-       va_list args;   
-       va_start(args, Message);
-       Log_AddEvent(Ident, LOG_LEVEL_DEBUG, Message, args);
-       va_end(args);
-}
diff --git a/Kernel/messages.c b/Kernel/messages.c
deleted file mode 100644 (file)
index afdcdbd..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * messages.c
- * - IPC Messages
- */
-#define DEBUG  0
-#include <acess.h>
-#include <threads.h>
-#include <threads_int.h>
-#include <errno.h>
-#include <events.h>
-
-// === CODE ===
-/**
- * \fn int Proc_SendMessage(Uint Dest, int Length, void *Data)
- * \brief Send an IPC message
- * \param Dest Destination Thread
- * \param Length       Length of the message
- * \param Data Message data
- */
-int Proc_SendMessage(Uint Dest, int Length, void *Data)
-{
-       tThread *thread;
-       tMsg    *msg;
-       
-       ENTER("pErr iDest iLength pData", Err, Dest, Length, Data);
-       
-       if(Length <= 0 || !Data) {
-               errno = -EINVAL;
-               LEAVE_RET('i', -1);
-       }
-       
-       // TODO: Check message length against global/per-thread maximums
-       // TODO: Restrict queue length
-
-       // Get thread
-       thread = Threads_GetThread( Dest );
-       
-       // Error check
-       if(!thread)     LEAVE_RET('i', -1);
-       
-       // Get Spinlock
-       SHORTLOCK( &thread->IsLocked );
-       
-       // Check if thread is still alive
-       if(thread->Status == THREAD_STAT_DEAD) {
-               SHORTREL( &thread->IsLocked );
-               LEAVE_RET('i', -1);
-       }
-       
-       // Create message
-       msg = malloc( sizeof(tMsg)+Length );
-       msg->Next = NULL;
-       msg->Source = Proc_GetCurThread()->TID;
-       msg->Length = Length;
-       memcpy(msg->Data, Data, Length);
-       
-       // If there are already messages
-       if(thread->LastMessage) {
-               thread->LastMessage->Next = msg;
-               thread->LastMessage = msg;
-       } else {
-               thread->Messages = msg;
-               thread->LastMessage = msg;
-       }
-       
-       SHORTREL(&thread->IsLocked);
-
-       // Wake the thread      
-       LOG("Waking %p (%i %s)", thread, thread->TID, thread->ThreadName);
-       Threads_PostEvent( thread, THREAD_EVENT_IPCMSG );
-       
-       LEAVE_RET('i', 0);
-}
-
-/**
- * \fn int Proc_GetMessage(Uint *Source, void *Buffer)
- * \brief Gets a message
- * \param Source       Where to put the source TID
- * \param Buffer       Buffer to place the message data (set to NULL to just get message length)
- * \return Message length
- */
-int Proc_GetMessage(Uint *Source, void *Buffer)
-{
-        int    ret;
-       void    *tmp;
-       tThread *cur = Proc_GetCurThread();
-
-       ENTER("pSource pBuffer", Source, Buffer);
-       
-       // Check if queue has any items
-       if(!cur->Messages) {
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       SHORTLOCK( &cur->IsLocked );
-       
-       if(Source) {
-               *Source = cur->Messages->Source;
-               LOG("*Source = %i", *Source);
-       }
-       
-       // Get message length
-       if( !Buffer ) {
-               ret = cur->Messages->Length;
-               SHORTREL( &cur->IsLocked );
-               LEAVE('i', ret);
-               return ret;
-       }
-       
-       // Get message
-       if(Buffer != GETMSG_IGNORE)
-       {
-               if( !CheckMem( Buffer, cur->Messages->Length ) )
-               {
-                       LOG("Invalid buffer");
-                       errno = -EINVAL;
-                       SHORTREL( &cur->IsLocked );
-                       LEAVE('i', -1);
-                       return -1;
-               }
-               LOG("Copied to buffer");
-               memcpy(Buffer, cur->Messages->Data, cur->Messages->Length);
-       }
-       ret = cur->Messages->Length;
-       
-       // Remove from list
-       tmp = cur->Messages;
-       cur->Messages = cur->Messages->Next;
-       if(cur->Messages == NULL)       cur->LastMessage = NULL;
-       
-       SHORTREL( &cur->IsLocked );
-       
-       free(tmp);      // Free outside of lock
-
-       LEAVE('i', ret);
-       return ret;
-}
diff --git a/Kernel/modules.c b/Kernel/modules.c
deleted file mode 100644 (file)
index 98ca1a1..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Acess2
- * - Module Loader
- */
-#define DEBUG  0
-#include <acess.h>
-#include <modules.h>
-
-#define        USE_EDI 0
-#define        USE_UDI 0
-
-// === PROTOTYPES ===
- int   Module_int_Initialise(tModule *Module, const char *ArgString);
-void   Modules_int_GetBuiltinArray(void);
-void   Modules_LoadBuiltins(void);
-void   Modules_SetBuiltinParams(const char *Name, char *ArgString);
- int   Modules_InitialiseBuiltin(const char *Name);
-// int Module_RegisterLoader(tModuleLoader *Loader);
-// int Module_LoadMem(void *Buffer, Uint Length, char *ArgString);
-// int Module_LoadFile(char *Path, char *ArgString);
- int   Module_int_ResolveDeps(tModule *Info);
- int   Module_IsLoaded(const char *Name);
-// int Module_EnsureLoaded(const char *Name);
-
-// === EXPORTS ===
-EXPORT(Module_RegisterLoader);
-
-// === IMPORTS ===
-#if USE_UDI
-extern int     UDI_LoadDriver(void *Base);
-#endif
-extern void    StartupPrint(const char *Str);
-extern tModule gKernelModules;
-extern tModule gKernelModulesEnd;
-
-// === GLOBALS ===
- int   giNumBuiltinModules = 0;
-tShortSpinlock glModuleSpinlock;
-tModule        *gLoadedModules = NULL;
-tModuleLoader  *gModule_Loaders = NULL;
-tModule        *gLoadingModules = NULL;
-tModule        **gapBuiltinModules = NULL;
-char   **gasBuiltinModuleArgs;
-
-// === CODE ===
-/**
- * \brief Initialises a module
- * \param Module       Pointer to the module header
- * \param ArgString    Comma separated list of module arguments
- * \return Zero on success, eModuleErrors or -1 on error
- * \retval -1  Returned if a dependency fails, or a circular dependency
- *              exists.
- * \retval 0   Returned on success
- * \retval >0  Error code form the module's initialisation function
- */
-int Module_int_Initialise(tModule *Module, const char *ArgString)
-{
-        int    i, j;
-        int    ret;
-       const char      **deps;
-       char    **args;
-       tModule *mod;
-       
-       ENTER("pModule", Module);
-       LOG("Module->Magic = 0x%x", Module->Magic);
-       if(Module->Magic != MODULE_MAGIC) {
-               Log_Warning(
-                       "Module",
-                       "Module %p is no a valid Acess2 module (0x%08x != 0x%08x)",
-                       Module, Module->Magic, MODULE_MAGIC
-                       );
-               LEAVE('i', MODULE_ERR_BADMODULE);
-               return MODULE_ERR_BADMODULE;
-       }
-       LOG("Module->Name = %p \"%s\"", Module->Name, Module->Name);
-       
-       if(Module->Arch != MODULE_ARCH_ID) {
-               Log_Warning(
-                       "Module",
-                       "Module %p (%s) is for another architecture (%i)",
-                       Module, Module->Name, Module->Arch
-                       );
-       }
-       
-       deps = Module->Dependencies;
-       
-       // Check if the module has been loaded
-       for( mod = gLoadedModules; mod; mod = mod->Next )
-       {
-               if(mod == Module)       LEAVE_RET('i', 0);
-       }
-       
-       // Add to the "loading" (prevents circular deps)
-       Module->Next = gLoadingModules;
-       gLoadingModules = Module;
-       
-       // Scan dependency list
-       for( j = 0; deps && deps[j]; j++ )
-       {
-               // Check if the module is already loaded
-               for( mod = gLoadedModules; mod; mod = mod->Next )
-               {
-                       if(strcmp(deps[j], mod->Name) == 0)
-                               break;
-               }
-               if( mod )       continue;       // Dependency is loaded, check the rest
-               
-               // Ok, check if it's loading
-               for( mod = gLoadingModules->Next; mod; mod = mod->Next )
-               {
-                       if(strcmp(deps[j], mod->Name) == 0)
-                               break;
-               }
-               if( mod ) {
-                       Log_Warning("Module", "Circular dependency detected (%s and %s)",
-                               mod->Name, Module->Name);
-                       LEAVE_RET('i', -1);
-               }
-               
-               // So, if it's not loaded, we better load it then
-               for( i = 0; i < giNumBuiltinModules; i ++ )
-               {
-                       if( strcmp(deps[j], gapBuiltinModules[i]->Name) == 0 )
-                               break;
-               }
-               if( i == giNumBuiltinModules ) {
-                       Log_Warning("Module", "Dependency '%s' for module '%s' failed",
-                               deps[j], Module->Name);
-                       return -1;
-               }
-               
-               // Dependency is not loaded, so load it
-               ret = Module_int_Initialise(
-                       gapBuiltinModules[i],
-                       gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL
-                       );
-               if( ret )
-               {
-                       // The only "ok" error is NOTNEEDED
-                       if(ret != MODULE_ERR_NOTNEEDED)
-                               LEAVE_RET('i', -1);
-               }
-       }
-       
-       // All Dependencies OK? Initialise
-       StartupPrint(Module->Name);
-       Log_Log("Module", "Starting %p '%s' v%i.%i",
-               Module, Module->Name,
-               Module->Version >> 8, Module->Version & 0xFF
-               );
-       
-       if( ArgString )
-               args = str_split( ArgString, ',' );
-       else
-               args = NULL;
-       
-       ret = Module->Init(args);
-       
-       if(args)        free(args);
-       
-       // Remove from loading list
-       gLoadingModules = gLoadingModules->Next;
-       
-       if( ret != MODULE_ERR_OK ) {
-               switch(ret)
-               {
-               case MODULE_ERR_MISC:
-                       Log_Warning("Module", "Unable to load, reason: Miscelanious");
-                       break;
-               case MODULE_ERR_NOTNEEDED:
-                       Log_Debug("Module", "Unable to load, reason: Module not needed");
-                       break;
-               case MODULE_ERR_MALLOC:
-                       Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
-                       break;
-               default:
-                       Log_Warning("Module", "Unable to load reason - Unknown code %i", ret);
-                       break;
-               }
-               LEAVE_RET('i', ret);
-               return ret;
-       }
-       LOG("ret = %i", ret);
-       
-       // Add to loaded list
-       SHORTLOCK( &glModuleSpinlock );
-       Module->Next = gLoadedModules;
-       gLoadedModules = Module;
-       SHORTREL( &glModuleSpinlock );
-       
-       LEAVE_RET('i', 0);
-}
-
-/**
- * \brief Scans the builtin modules and creates an array of them
- */
-void Modules_int_GetBuiltinArray(void)
-{
-        int    i;
-       tModule *module;
-       
-       // Count
-       module = &gKernelModules;
-       i = 0;
-       while( (tVAddr)module < (tVAddr)&gKernelModulesEnd )
-       {
-               if(module->Magic == MODULE_MAGIC) {
-                       i ++;
-                       module ++;
-               }
-               else
-                       module = (void*)( (tVAddr)module + 4 );
-       }
-       
-       // Create
-       giNumBuiltinModules = i;
-       gasBuiltinModuleArgs = calloc( giNumBuiltinModules, sizeof(char*) );
-       gapBuiltinModules = malloc( giNumBuiltinModules * sizeof(tModule*) );
-       
-       
-       // Fill
-       module = &gKernelModules;
-       i = 0;
-       while( (tVAddr)module < (tVAddr)&gKernelModulesEnd )
-       {
-               if(module->Magic == MODULE_MAGIC) {
-                       gapBuiltinModules[i] = module;
-                       i ++;
-                       module ++;
-               }
-               else
-                       module = (void*)( (tVAddr)module + 4 );
-       }
-}
-
-/**
- * \brief Initialises builtin modules
- */
-void Modules_LoadBuiltins()
-{
-        int    i;
-       
-       if( !gapBuiltinModules )
-               Modules_int_GetBuiltinArray();
-       
-       for( i = 0; i < giNumBuiltinModules; i++ )
-       {
-               Module_int_Initialise(
-                       gapBuiltinModules[i],
-                       (gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL)
-                       );
-       }
-       
-       if( gasBuiltinModuleArgs != NULL )
-               free(gasBuiltinModuleArgs);
-}
-
-/**
- * \brief Initialise a builtin module given it's name
- * 
- * E.g. Used by VTerm to load an alternate video driver at runtime
- */
-int Modules_InitialiseBuiltin(const char *Name)
-{
-        int    i;
-       
-       // Check if it's loaded
-       if( Module_IsLoaded(Name) )
-               return 0;
-       
-       if( !gapBuiltinModules )
-               Modules_int_GetBuiltinArray();
-       
-       for( i = 0; i < giNumBuiltinModules; i++ )
-       {
-               if( strcmp(gapBuiltinModules[i]->Name, Name) == 0 ) {
-                       return Module_int_Initialise(gapBuiltinModules[i],
-                               (gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL)
-                               );
-               }
-       }
-       return -1;
-}
-
-/**
- * \brief Sets the parameters for a builtin module
- */
-void Modules_SetBuiltinParams(const char *Name, char *ArgString)
-{
-        int    i;
-       
-       if( gasBuiltinModuleArgs == NULL )
-       {
-               Modules_int_GetBuiltinArray();
-       }
-       
-       // I hate expensive scans
-       for( i = 0; i < giNumBuiltinModules; i++ )
-       {
-               if(strcmp( gapBuiltinModules[i]->Name, Name ) == 0) {
-                       gasBuiltinModuleArgs[i] = ArgString;
-                       return ;
-               }
-       }
-       
-       Log_Warning("Modules", "Unknown builtin kernel module '%s'", Name);
-}
-
-/**
- * \brief Registers a tModuleLoader with the kernel
- * \param Loader       Pointer to loader structure (must be persistent)
- */
-int Module_RegisterLoader(tModuleLoader *Loader)
-{
-       if(!Loader)     return 1;
-       
-       Loader->Next = gModule_Loaders;
-       gModule_Loaders = Loader;
-       
-       return 0;
-}
-
-/**
- * \fn int Module_LoadMem(void *Buffer, Uint Length, char *ArgString)
- * \brief Load a module from a memory location
- */
-int Module_LoadMem(void *Buffer, Uint Length, const char *ArgString)
-{
-       char    path[VFS_MEMPATH_SIZE];
-       
-       VFS_GetMemPath(path, Buffer, Length);
-       
-       return Module_LoadFile( path, ArgString );
-}
-
-/**
- * \fn int Module_LoadFile(const char *Path, const char *ArgString)
- * \brief Load a module from a file
- */
-int Module_LoadFile(const char *Path, const char *ArgString)
-{
-       void    *base;
-       tModule *info;
-       
-       // Load Binary
-       base = Binary_LoadKernel(Path);
-       
-       // Error check
-       if(base == NULL) {
-               Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
-               return 0;
-       }
-       
-       // Check for Acess Driver
-       if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
-       {
-               tModuleLoader   *tmp;
-               for( tmp = gModule_Loaders; tmp; tmp = tmp->Next)
-               {
-                       if( tmp->Detector(base) == 0 )  continue;
-                       
-                       return tmp->Loader(base);
-               }
-               
-               #if USE_EDI
-               // Check for EDI Driver
-               if( Binary_FindSymbol(base, "driver_init", NULL ) != 0 )
-               {
-                       return Module_InitEDI( base );  // And intialise
-               }
-               #endif
-               
-               // Unknown module type?, return error
-               Binary_Unload(base);
-               #if USE_EDI
-               Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
-               #else
-               Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
-               #endif
-               return 0;
-       }
-       
-       // Initialise (and register)
-       if( Module_int_Initialise( info, ArgString ) )
-       {
-               Binary_Unload(base);
-               return 0;
-       }
-       
-       return 1;
-}
-
-/**
- * \fn int Module_int_ResolveDeps(tModule *Info)
- * \brief Resolves the dependencies
- * \todo Implement
- * \note Currently does not resolve the dependencies, just checks them
- */
-int Module_int_ResolveDeps(tModule *Info)
-{
-       const char      **names = Info->Dependencies;
-       
-       // Walk dependencies array
-       for( ; *names; names++ )
-       {
-               // Check if the module is loaded
-               if( !Module_IsLoaded(*names) ) {
-                       Log_Warning("Module", "Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-/**
- * \fn int Module_IsLoaded(const char *Name)
- * \brief Checks if a module is loaded
- * \param Name Name of module to find
- */
-int Module_IsLoaded(const char *Name)
-{
-       tModule *mod = gLoadedModules;
-       
-       // Scan loaded list
-       for( ; mod; mod = mod->Next )
-       {
-               // If found, return true
-               if(strcmp(mod->Name, Name) == 0)
-                       return 1;
-       }
-       // not found - return false
-       return 0;
-}
-
-/**
- * \brief Load a module if needed
- */
-int Module_EnsureLoaded(const char *Name)
-{
-       if( Module_IsLoaded(Name) )
-               return 0;
-
-       if( Modules_InitialiseBuiltin(Name) == 0 )
-               return 0;
-
-       // TODO: Load from a file?
-
-       return -1;
-}
diff --git a/Kernel/mutex.c b/Kernel/mutex.c
deleted file mode 100644 (file)
index 597242b..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * mutex.c
- * - Mutexes
- */
-#include <acess.h>
-#include <threads_int.h>
-#include <mutex.h>
-
-// === PROTOTYPES ===
-#if 0
- int   Mutex_Acquire(tMutex *Mutex);
-void   Mutex_Release(tMutex *Mutex);
- int   Mutex_IsLocked(tMutex *Mutex);
-#endif
-
-// === CODE ===
-//
-// Acquire mutex (see mutex.h for documentation)
-//
-int Mutex_Acquire(tMutex *Mutex)
-{
-       tThread *us = Proc_GetCurThread();
-       
-       // Get protector
-       SHORTLOCK( &Mutex->Protector );
-       
-//     Log("Mutex_Acquire: (%p)", Mutex);
-       
-       // Check if the lock is already held
-       if( Mutex->Owner ) {
-               SHORTLOCK( &glThreadListLock );
-               // - Remove from active list
-               us = Threads_RemActive();
-               us->Next = NULL;
-               // - Mark as sleeping
-               us->Status = THREAD_STAT_MUTEXSLEEP;
-               us->WaitPointer = Mutex;
-               
-               // - Add to waiting
-               if(Mutex->LastWaiting) {
-                       Mutex->LastWaiting->Next = us;
-                       Mutex->LastWaiting = us;
-               }
-               else {
-                       Mutex->Waiting = us;
-                       Mutex->LastWaiting = us;
-               }
-               
-               #if DEBUG_TRACE_STATE
-               Log("%p (%i %s) waiting on mutex %p",
-                       us, us->TID, us->ThreadName, Mutex);
-               #endif
-               
-               #if 0
-               {
-                        int    i = 0;
-                       tThread *t;
-                       for( t = Mutex->Waiting; t; t = t->Next, i++ )
-                               Log("[%i] (tMutex)%p->Waiting[%i] = %p (%i %s)", us->TID, Mutex, i,
-                                       t, t->TID, t->ThreadName);
-               }
-               #endif
-               
-               SHORTREL( &glThreadListLock );
-               SHORTREL( &Mutex->Protector );
-               while(us->Status == THREAD_STAT_MUTEXSLEEP)     Threads_Yield();
-               // We're only woken when we get the lock
-               us->WaitPointer = NULL;
-       }
-       // Ooh, let's take it!
-       else {
-               Mutex->Owner = us;
-               SHORTREL( &Mutex->Protector );
-       }
-       
-       #if 0
-       extern tMutex   glPhysAlloc;
-       if( Mutex != &glPhysAlloc )
-               LogF("Mutex %p taken by %i %p\n", Mutex, us->TID, __builtin_return_address(0));
-       #endif
-       
-       return 0;
-}
-
-// Release a mutex
-void Mutex_Release(tMutex *Mutex)
-{
-       SHORTLOCK( &Mutex->Protector );
-       //Log("Mutex_Release: (%p)", Mutex);
-       if( Mutex->Waiting ) {
-               Mutex->Owner = Mutex->Waiting;  // Set owner
-               Mutex->Waiting = Mutex->Waiting->Next;  // Next!
-               // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
-               if( Mutex->LastWaiting == Mutex->Owner )
-                       Mutex->LastWaiting = NULL;
-               
-               // Wake new owner
-               if( Mutex->Owner->Status != THREAD_STAT_ACTIVE )
-                       Threads_AddActive(Mutex->Owner);
-       }
-       else {
-               Mutex->Owner = NULL;
-       }
-       SHORTREL( &Mutex->Protector );
-       
-       #if 0
-       extern tMutex   glPhysAlloc;
-       if( Mutex != &glPhysAlloc )
-               LogF("Mutex %p released by %i %p\n", Mutex, Threads_GetTID(), __builtin_return_address(0));
-       #endif
-}
-
-// Check if a mutex is locked
-int Mutex_IsLocked(tMutex *Mutex)
-{
-       return Mutex->Owner != NULL;
-}
-
-// === EXPORTS ===
-EXPORT(Mutex_Acquire);
-EXPORT(Mutex_Release);
-EXPORT(Mutex_IsLocked);
diff --git a/Kernel/semaphore.c b/Kernel/semaphore.c
deleted file mode 100644 (file)
index d4583e7..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * semaphore.c
- * - Semaphores
- */
-#include <acess.h>
-#include <semaphore.h>
-#include <threads_int.h>
-
-#define SEMAPHORE_DEBUG        0       // Debug semaphores
-
-// === CODE ===
-//
-// Initialise a semaphore
-//
-void Semaphore_Init(tSemaphore *Sem, int Value, int MaxValue, const char *Module, const char *Name)
-{
-       memset(Sem, 0, sizeof(tSemaphore));
-       Sem->Value = Value;
-       Sem->ModName = Module;
-       Sem->Name = Name;
-       Sem->MaxValue = MaxValue;
-}
-//
-// Wait for items to be avaliable
-//
-int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
-{
-       tThread *us;
-        int    taken;
-       if( MaxToTake < 0 ) {
-               Log_Warning("Threads", "Semaphore_Wait: User bug - MaxToTake(%i) < 0, Sem=%p(%s)",
-                       MaxToTake, Sem, Sem->Name);
-       }
-       
-       SHORTLOCK( &Sem->Protector );
-       
-       // Check if there's already items avaliable
-       if( Sem->Value > 0 )
-       {
-               // Take what we need
-               if( MaxToTake && Sem->Value > MaxToTake )
-                       taken = MaxToTake;
-               else
-                       taken = Sem->Value;
-               Sem->Value -= taken;
-       }
-       else
-       {
-               SHORTLOCK( &glThreadListLock );
-               
-               // - Remove from active list
-               us = Threads_RemActive();
-               us->Next = NULL;
-               // - Mark as sleeping
-               us->Status = THREAD_STAT_SEMAPHORESLEEP;
-               us->WaitPointer = Sem;
-               us->RetStatus = MaxToTake;      // Use RetStatus as a temp variable
-               
-               // - Add to waiting
-               if(Sem->LastWaiting) {
-                       Sem->LastWaiting->Next = us;
-                       Sem->LastWaiting = us;
-               }
-               else {
-                       Sem->Waiting = us;
-                       Sem->LastWaiting = us;
-               }
-               
-               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-               Log("%p (%i %s) waiting on semaphore %p %s:%s",
-                       us, us->TID, us->ThreadName,
-                       Sem, Sem->ModName, Sem->Name);
-               #endif
-               
-               SHORTREL( &Sem->Protector );    // Release first to make sure it is released
-               SHORTREL( &glThreadListLock );
-               while( us->Status == THREAD_STAT_SEMAPHORESLEEP )
-               {
-                       Threads_Yield();
-                       if(us->Status == THREAD_STAT_SEMAPHORESLEEP)
-                               Log_Warning("Threads", "Semaphore %p %s:%s re-schedulued while asleep",
-                                       Sem, Sem->ModName, Sem->Name);
-               }
-               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-               Log("Semaphore %p %s:%s woken", Sem, Sem->ModName, Sem->Name);
-               #endif
-               // We're only woken when there's something avaliable (or a signal arrives)
-               us->WaitPointer = NULL;
-               
-               taken = us->RetStatus;
-               
-               // Get the lock again
-               SHORTLOCK( &Sem->Protector );
-       }
-       
-       // While there is space, and there are thread waiting
-       // wake the first thread and give it what it wants (or what's left)
-       while( (Sem->MaxValue == 0 || Sem->Value < Sem->MaxValue) && Sem->Signaling )
-       {
-                int    given;
-               tThread *toWake = Sem->Signaling;
-               
-               Sem->Signaling = Sem->Signaling->Next;
-               // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
-               if( Sem->Signaling == NULL )
-                       Sem->LastSignaling = NULL;
-               
-               // Figure out how much to give
-               if( toWake->RetStatus && Sem->Value + toWake->RetStatus < Sem->MaxValue )
-                       given = toWake->RetStatus;
-               else
-                       given = Sem->MaxValue - Sem->Value;
-               Sem->Value -= given;
-               
-               
-               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-               Log("%p (%i %s) woken by wait on %p %s:%s",
-                       toWake, toWake->TID, toWake->ThreadName,
-                       Sem, Sem->ModName, Sem->Name);
-               #endif
-               
-               // Save the number we gave to the thread's status
-               toWake->RetStatus = given;
-               
-               // Wake the sleeper
-               SHORTLOCK( &glThreadListLock );
-               if( toWake->Status != THREAD_STAT_ACTIVE )
-                       Threads_AddActive(toWake);
-               SHORTREL( &glThreadListLock );
-       }
-       SHORTREL( &Sem->Protector );
-       
-       #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-       Log("Semaphore %p %s:%s took %i by wait",
-               Sem, Sem->ModName, Sem->Name, taken);
-       #endif
-
-       return taken;
-}
-
-//
-// Add items to a semaphore
-//
-int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
-{
-        int    given;
-        int    added;
-       
-       if( AmmountToAdd < 0 ) {
-               Log_Warning("Threads", "Semaphore_Signal: User bug - AmmountToAdd(%i) < 0, Sem=%p(%s)",
-                       AmmountToAdd, Sem, Sem->Name);
-       }
-       SHORTLOCK( &Sem->Protector );
-       
-       // Check if we have to block
-       if( Sem->MaxValue && Sem->Value == Sem->MaxValue )
-       {
-               tThread *us;
-               #if 0
-               Log_Debug("Threads", "Semaphore_Signal: IDLE Sem = %s:%s", Sem->ModName, Sem->Name);
-               Log_Debug("Threads", "Semaphore_Signal: Sem->Value(%i) == Sem->MaxValue(%i)", Sem->Value, Sem->MaxValue);
-               #endif
-               
-               SHORTLOCK( &glThreadListLock );
-               // - Remove from active list
-               us = Threads_RemActive();
-               us->Next = NULL;
-               // - Mark as sleeping
-               us->Status = THREAD_STAT_SEMAPHORESLEEP;
-               us->WaitPointer = Sem;
-               us->RetStatus = AmmountToAdd;   // Use RetStatus as a temp variable
-               
-               // - Add to waiting
-               if(Sem->LastSignaling) {
-                       Sem->LastSignaling->Next = us;
-                       Sem->LastSignaling = us;
-               }
-               else {
-                       Sem->Signaling = us;
-                       Sem->LastSignaling = us;
-               }
-               
-               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-               Log("%p (%i %s) signaling semaphore %p %s:%s",
-                       us, us->TID, us->ThreadName,
-                       Sem, Sem->ModName, Sem->Name);
-               #endif
-               
-               SHORTREL( &glThreadListLock );  
-               SHORTREL( &Sem->Protector );
-               while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield();
-               // We're only woken when there's something avaliable
-               us->WaitPointer = NULL;
-               
-               added = us->RetStatus;
-               
-               // Get the lock again
-               SHORTLOCK( &Sem->Protector );
-       }
-       // Non blocking
-       else
-       {
-               // Figure out how much we need to take off
-               if( Sem->MaxValue && Sem->Value + AmmountToAdd > Sem->MaxValue)
-                       added = Sem->MaxValue - Sem->Value;
-               else
-                       added = AmmountToAdd;
-               Sem->Value += added;
-       }
-       
-       // While there are items avaliable, and there are thread waiting
-       // wake the first thread and give it what it wants (or what's left)
-       while( Sem->Value && Sem->Waiting )
-       {
-               tThread *toWake = Sem->Waiting;
-               
-               // Remove thread from list (double ended, so clear LastWaiting if needed)
-               Sem->Waiting = Sem->Waiting->Next;
-               if( Sem->Waiting == NULL )
-                       Sem->LastWaiting = NULL;
-               
-               // Figure out how much to give to woken thread
-               // - Requested count is stored in ->RetStatus
-               if( toWake->RetStatus && Sem->Value > toWake->RetStatus )
-                       given = toWake->RetStatus;
-               else
-                       given = Sem->Value;
-               Sem->Value -= given;
-               
-               // Save the number we gave to the thread's status
-               toWake->RetStatus = given;
-               
-               if(toWake->bInstrTrace)
-                       Log("%s(%i) given %i from %p", toWake->ThreadName, toWake->TID, given, Sem);
-               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-               Log("%p (%i %s) woken by signal on %p %s:%s",
-                       toWake, toWake->TID, toWake->ThreadName,
-                       Sem, Sem->ModName, Sem->Name);
-               #endif
-               
-               // Wake the sleeper
-               if( toWake->Status != THREAD_STAT_ACTIVE )
-                       Threads_AddActive(toWake);
-               else
-                       Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName);
-       }
-       SHORTREL( &Sem->Protector );
-       
-       return added;
-}
-
-//
-// Get the current value of a semaphore
-//
-int Semaphore_GetValue(tSemaphore *Sem)
-{
-       return Sem->Value;
-}
-
-// === EXPORTS ===
-EXPORT(Semaphore_Init);
-EXPORT(Semaphore_Wait);
-EXPORT(Semaphore_Signal);
diff --git a/Kernel/syscalls.c b/Kernel/syscalls.c
deleted file mode 100644 (file)
index 5580187..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * AcessOS Microkernel Version
- * syscalls.c
- */
-#define DEBUG  0
-
-#include <acess.h>
-#include <syscalls.h>
-#include <proc.h>
-#include <hal_proc.h>
-#include <errno.h>
-#include <threads.h>
-#include <events.h>
-
-#define CHECK_NUM_NULLOK(v,size)       \
-       if((v)&&!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
-#define CHECK_STR_NULLOK(v)    \
-       if((v)&&!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
-#define CHECK_NUM_NONULL(v,size)       \
-       if(!(v)||!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
-#define CHECK_STR_NONULL(v)    \
-       if(!(v)||!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
-#define CHECK_STR_ARRAY(arr)   do {\
-        int    i;\
-       char    **tmp = (char**)arr; \
-       CHECK_NUM_NONULL( tmp, sizeof(char**) ); \
-       for(i=0;tmp[i];i++) { \
-               CHECK_STR_NONULL( tmp[i] ); \
-               CHECK_NUM_NONULL( &tmp[i+1], sizeof(char*) ); \
-       }\
-       if(tmp[i]) break;\
-} while(0)
-
-// === IMPORTS ===
-extern Uint    Binary_Load(const char *file, Uint *entryPoint);
-
-// === PROTOTYPES ===
-void   SyscallHandler(tSyscallRegs *Regs);
- int   Syscall_ValidString(const char *Addr);
- int   Syscall_Valid(int Size, const void *Addr);
-
-// === CODE ===
-// TODO: Do sanity checking on arguments, ATM the user can really fuck with the kernel
-void SyscallHandler(tSyscallRegs *Regs)
-{
-       Uint64  ret = 0;
-       Uint    err = -EOK;
-        int    callNum = Regs->Num;
-       
-       #if DEBUG < 2
-       if(callNum != SYS_READ && callNum != SYS_WRITE) {
-       #endif
-       ENTER("iThread iNum", Threads_GetTID(), callNum);
-       if(callNum < NUM_SYSCALLS)
-               LOG("Syscall %s", cSYSCALL_NAMES[callNum]);
-       LOG("Arg1: 0x%x, Arg2: 0x%x, Arg3: 0x%x, Arg4: 0x%x", Regs->Arg1, Regs->Arg2, Regs->Arg3, Regs->Arg4);
-       #if DEBUG < 2
-       }
-       #endif
-       
-       switch(Regs->Num)
-       {
-       // -- Exit the current thread
-       case SYS_EXIT:  Threads_Exit(0, Regs->Arg1);    break;
-       
-       // -- Put the current thread to sleep
-       case SYS_SLEEP: Threads_Sleep();        break;
-       
-       // -- Yield current timeslice
-       case SYS_YIELD: Threads_Yield();        break;
-       
-       // -- Set Error Handler
-       case SYS_SETFAULTHANDLER:
-               Threads_SetFaultHandler(Regs->Arg1);
-               break;
-       
-       // -- Clone the current thread
-       case SYS_CLONE:
-               // Call clone system call
-               ret = Proc_Clone(Regs->Arg1);
-               break;
-       
-       // -- Send a signal
-       case SYS_KILL:
-               err = -ENOSYS;
-               ret = -1;
-               break;
-
-       // -- Wait fr an event  
-       case SYS_WAITEVENT:
-               // Message mask
-               ret = Threads_WaitEvents(Regs->Arg1);
-               break;
-
-       // -- Wait for a thread
-       case SYS_WAITTID:
-               // Sanity Check (Status can be NULL)
-               CHECK_NUM_NULLOK( (int*)Regs->Arg2, sizeof(int) );
-               // TID, *Status
-               ret = Threads_WaitTID(Regs->Arg1, (int*)Regs->Arg2);
-               break;
-       
-       // -- Get the physical address of a page
-       case SYS_GETPHYS:
-               ret = MM_GetPhysAddr(Regs->Arg1);
-               break;
-       
-       // -- Map an address
-       case SYS_MAP:   MM_Map(Regs->Arg1, Regs->Arg2); break;
-       
-       // -- Allocate an address
-       case SYS_ALLOCATE:      ret = MM_Allocate(Regs->Arg1);  break;
-       
-       // -- Unmap an address
-       case SYS_UNMAP:         MM_Deallocate(Regs->Arg1);      break;
-       
-       // -- Get Thread/Process IDs
-       case SYS_GETTID:        ret = Threads_GetTID(); break;
-       case SYS_GETPID:        ret = Threads_GetPID(); break;
-       
-       // -- Get User/Group IDs
-       case SYS_GETUID:        ret = Threads_GetUID(); break;
-       case SYS_GETGID:        ret = Threads_GetGID(); break;
-       
-       // -- Set User/Group IDs
-       case SYS_SETUID:        ret = Threads_SetUID(Regs->Arg1);       break;
-       case SYS_SETGID:        ret = Threads_SetGID(Regs->Arg1);       break;
-       
-       // -- Send Message
-       case SYS_SENDMSG:
-               CHECK_NUM_NONULL( (void*)Regs->Arg3, Regs->Arg2 );
-               // Destination, Size, *Data
-               ret = Proc_SendMessage(Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
-               break;
-       // -- Check for messages
-       case SYS_GETMSG:
-               CHECK_NUM_NULLOK( (Uint*)Regs->Arg1, sizeof(Uint) );
-               // NOTE: Can't do range checking as we don't know the size
-               // - Should be done by Proc_GetMessage
-               if( Regs->Arg2 && Regs->Arg2 != -1 && !MM_IsUser(Regs->Arg2) ) {
-                       err = -EINVAL;  ret = -1;       break;
-               }
-               // *Source, *Data
-               ret = Proc_GetMessage((Uint*)Regs->Arg1, (void*)Regs->Arg2);
-               break;
-       
-       // -- Get the current timestamp
-       case SYS_GETTIME:
-               ret = now();
-               break;
-       
-       // -- Set the thread's name
-       case SYS_SETNAME:
-               CHECK_STR_NONULL( (char*) Regs->Arg1);
-               Threads_SetName( (char*)Regs->Arg1 );
-               break;
-       
-       // ---
-       // Binary Control
-       // ---
-       // -- Create a new process
-       case SYS_SPAWN:
-               CHECK_STR_NONULL((const char*)Regs->Arg1);
-               CHECK_STR_ARRAY((const char**)Regs->Arg2);
-               CHECK_STR_ARRAY((const char**)Regs->Arg3);
-               CHECK_NUM_NONULL((void*)Regs->Arg5, Regs->Arg4*sizeof(int));
-               ret = Proc_SysSpawn(
-                       (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
-                       Regs->Arg4, (int*)Regs->Arg5
-                       );
-               break;
-       // -- Replace the current process with another
-       case SYS_EXECVE:
-               CHECK_STR_NONULL((char*)Regs->Arg1);
-               CHECK_STR_ARRAY( (char**)Regs->Arg2 );
-               if( Regs->Arg3 )
-                       CHECK_STR_ARRAY( (char**)Regs->Arg3 );
-               LEAVE('s', "Assuming 0");
-               // Path, **Argv, **Envp, DataSize (=0 to tell it to create a copy)
-               ret = Proc_Execve(
-                       (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
-                       0
-                       );
-               break;
-       // -- Load a binary into the current process
-       case SYS_LOADBIN:
-               CHECK_STR_NONULL( (char*)Regs->Arg1 );
-               CHECK_NUM_NONULL( (Uint*)Regs->Arg2, sizeof(Uint) );
-               // Path, *Entrypoint
-               ret = Binary_Load((char*)Regs->Arg1, (Uint*)Regs->Arg2);
-               break;
-       
-       // ---
-       // Virtual Filesystem
-       // ---
-       case SYS_OPEN:
-               CHECK_STR_NONULL( (char*)Regs->Arg1 );
-               LOG("VFS_Open(\"%s\", 0x%x)", (char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
-               ret = VFS_Open((char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
-               break;
-       
-       case SYS_CLOSE:
-               LOG("VFS_Close(%i)", Regs->Arg1);
-               VFS_Close( Regs->Arg1 );
-               break;
-       
-       case SYS_SEEK:
-               #if BITS == 64
-               ret = VFS_Seek( Regs->Arg1, Regs->Arg2, Regs->Arg3 );
-               #else
-               ret = VFS_Seek( Regs->Arg1, Regs->Arg2|(((Uint64)Regs->Arg3)<<32), Regs->Arg4 );
-               #endif
-               break;
-               
-       case SYS_TELL:
-               ret = VFS_Tell( Regs->Arg1 );
-               break;
-       
-       case SYS_WRITE:
-               CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 );
-               ret = VFS_Write( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 );
-               break;
-       
-       case SYS_READ:
-               CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 );
-               ret = VFS_Read( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 );
-               break;
-       
-       case SYS_FINFO:
-               CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tFInfo) + Regs->Arg3*sizeof(tVFS_ACL) );
-               // FP, Dest, MaxACLs
-               ret = VFS_FInfo( Regs->Arg1, (void*)Regs->Arg2, Regs->Arg3 );
-               break;
-       
-       // Get ACL Value
-       case SYS_GETACL:
-               CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tVFS_ACL) );
-               ret = VFS_GetACL( Regs->Arg1, (void*)Regs->Arg2 );
-               break;
-       
-       // Read Directory
-       case SYS_READDIR:
-               // TODO: What if the filename is longer?
-               // Maybe force it to be a 256 byte buffer
-               CHECK_NUM_NONULL( (void*)Regs->Arg2, 256 );
-               ret = VFS_ReadDir( Regs->Arg1, (void*)Regs->Arg2 );
-               break;
-       
-       // Open a file that is a entry in an open directory
-       case SYS_OPENCHILD:
-               CHECK_STR_NONULL( (char*)Regs->Arg2 );
-               ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3 | VFS_OPENFLAG_USER);
-               break;
-       
-       // Change Directory
-       case SYS_CHDIR:
-               CHECK_STR_NONULL( (const char*)Regs->Arg1 );
-               ret = VFS_ChDir( (const char*)Regs->Arg1 );
-               break;
-       
-       // IO Control
-       case SYS_IOCTL:
-               // All sanity checking should be done by the driver
-               if( Regs->Arg3 && !MM_IsUser(Regs->Arg3) ) {
-                       err = -EINVAL;  ret = -1;       break;
-               }
-               ret = VFS_IOCtl( Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3 );
-               break;
-       
-       // Mount a filesystem
-       case SYS_MOUNT:
-               // Only root can mount filesystems
-               if(Threads_GetUID() != 0) {
-                       err = -EACCES;
-                       ret = -1;
-                       break;
-               }
-               // Sanity check the paths
-               if(!Syscall_ValidString((char*)Regs->Arg1)
-               || !Syscall_ValidString((char*)Regs->Arg2)
-               || !Syscall_ValidString((char*)Regs->Arg3)
-               || !Syscall_ValidString((char*)Regs->Arg4) ) {
-                       err = -EINVAL;
-                       ret = -1;
-                       break;
-               }
-               ret = VFS_Mount(
-                       (char*)Regs->Arg1,      // Device
-                       (char*)Regs->Arg2,      // Mount point
-                       (char*)Regs->Arg3,      // Filesystem
-                       (char*)Regs->Arg4       // Options
-                       );
-               break;
-               
-       // Wait on a set of handles
-       case SYS_SELECT:
-               // Sanity checks
-               if( (Regs->Arg2 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg2))
-                || (Regs->Arg3 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg3))
-                || (Regs->Arg4 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg4))
-                || (Regs->Arg5 && !Syscall_Valid(sizeof(tTime), (void*)Regs->Arg5)) )
-               {
-                       err = -EINVAL;
-                       ret = -1;
-                       break;
-               }
-               // Perform the call
-               ret = VFS_Select(
-                       Regs->Arg1,     // Max handle
-                       (fd_set *)Regs->Arg2,   // Read
-                       (fd_set *)Regs->Arg3,   // Write
-                       (fd_set *)Regs->Arg4,   // Errors
-                       (tTime *)Regs->Arg5,    // Timeout
-                       (Uint32)Regs->Arg6,     // Extra wakeup events
-                       0       // User handles
-                       );
-               break;
-       
-       // -- Debug
-       //#if DEBUG_BUILD
-       case SYS_DEBUG:
-               CHECK_STR_NONULL( (char*)Regs->Arg1 );
-               LogF("Log: %08lli [%i] ", now(), Threads_GetTID());
-               LogF((const char*)Regs->Arg1,
-                       Regs->Arg2, Regs->Arg3, Regs->Arg4, Regs->Arg5, Regs->Arg6);
-               LogF("\r\n");
-               break;
-       //#endif
-       
-       // -- Default (Return Error)
-       default:
-               Log_Warning("Syscalls", "Unknown System Call %i", Regs->Num);
-               if(Regs->Num < NUM_SYSCALLS)
-                       Log_Warning("Syscall", " named '%s'", cSYSCALL_NAMES[Regs->Num]);
-               err = -ENOSYS;
-               ret = -1;
-               break;
-       }
-
-       if(err == 0)    err = errno;
-       
-       if(err != 0) {
-               LOG("ID: %i, Return errno = %i", Regs->Num, err);
-       }
-       
-       #if BITS < 64
-       Regs->Return = ret&0xFFFFFFFF;
-       Regs->RetHi = ret >> 32;
-       #else
-       Regs->Return = ret;
-       #endif
-       Regs->Error = err;
-       #if DEBUG
-       # if DEBUG < 2
-       if( callNum != SYS_READ && callNum != SYS_WRITE ) {
-       # endif
-       LOG("err = %i", err);
-       if( callNum == SYS_EXECVE )
-               LOG("Actual %i", ret);
-       else
-               LEAVE('x', ret);
-       # if DEBUG < 2
-       }
-       # endif
-       #endif
-}
-
-/**
- * \fn int Syscall_ValidString(const char *Addr)
- * \brief Checks if a memory address contains a valid string
- */
-int Syscall_ValidString(const char *Addr)
-{
-       // Check if the memory is user memory
-       if(!MM_IsUser( (tVAddr) Addr))  return 0;
-       
-       return CheckString( Addr );
-}
-
-/**
- * \fn int Syscall_Valid(int Size, const void *Addr)
- * \brief Checks if a memory address is valid
- */
-int Syscall_Valid(int Size, const void *Addr)
-{
-       if(!MM_IsUser( (tVAddr)Addr ))  return 0;
-       
-       return CheckMem( Addr, Size );
-}
diff --git a/Kernel/syscalls.lst b/Kernel/syscalls.lst
deleted file mode 100644 (file)
index 283caf9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-
-0
-SYS_EXIT       Kill this thread
-SYS_CLONE      Create a new thread
-SYS_KILL       Send a signal
-SYS_SETFAULTHANDLER    Set signal Handler
-SYS_YIELD      Yield remainder of timestamp
-SYS_SLEEP      Sleep until messaged or signaled
-SYS_WAITEVENT  Wait for an event
-SYS_WAITTID    Wait for a thread to do something
-
-SYS_SETNAME    Sets the name of the current thread
-SYS_GETNAME    Gets the name of a thread
-SYS_GETTID     Get current thread ID
-SYS_GETPID     Get current thread group ID
-SYS_SETPRI     Set process priority
-
-SYS_SENDMSG    Send an IPC message
-SYS_GETMSG     Recieve an IPC message
-
-SYS_GETTIME    Get the current timestamp
-
-SYS_SPAWN      Spawn a new process
-SYS_EXECVE     Replace the current process
-SYS_LOADBIN    Load a binary into the current address space
-SYS_UNLOADBIN  Unload a loaded binary
-SYS_LOADMOD    Load a module into the kernel
-
-32
-SYS_GETPHYS    Get the physical address of a page
-SYS_MAP                Map a physical address
-SYS_ALLOCATE   Allocate a page
-SYS_UNMAP      Unmap a page
-SYS_PREALLOC   Preallocate a page
-SYS_SETFLAGS   Set a page's flags
-SYS_SHAREWITH  Share a page with another thread
-
-SYS_GETUID     Get current User ID
-SYS_GETGID     Get current Group ID
-SYS_SETUID     Set current user ID
-SYS_SETGID     Set current Group ID
-
-64
-SYS_OPEN       Open a file
-SYS_REOPEN     Close a file and reuse its handle
-SYS_CLOSE      Close a file
-SYS_READ       Read from an open file
-SYS_WRITE      Write to an open file
-SYS_IOCTL      Perform an IOCtl Call
-SYS_SEEK       Seek to a new position in the file
-SYS_READDIR    Read from an open directory
-SYS_OPENCHILD  Open a child entry in a directory
-SYS_GETACL     Get an ACL Value
-SYS_SETACL     Set an ACL Value
-SYS_FINFO      Get file information
-SYS_MKDIR      Create a new directory
-SYS_LINK       Create a new link to a file
-SYS_SYMLINK    Create a symbolic link
-SYS_UNLINK     Delete a file
-SYS_TELL       Return the current file position
-SYS_CHDIR      Change current directory
-SYS_GETCWD     Get current directory
-SYS_MOUNT      Mount a filesystem
-SYS_SELECT     Wait for file handles
diff --git a/Kernel/system.c b/Kernel/system.c
deleted file mode 100644 (file)
index 8fc2a1c..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Acess 2 Kernel
- * - By John Hodge (thePowersGang)
- * system.c
- * - Architecture Independent System Init
- */
-#define DEBUG  0
-#include <acess.h>
-
-// === IMPORTS ===
-extern void    Arch_LoadBootModules(void);
-extern int     Modules_LoadBuiltins(void);
-extern void    Modules_SetBuiltinParams(char *Name, char *ArgString);
-extern void    Debug_SetKTerminal(const char *File);
-
-// === PROTOTYPES ===
-void   System_Init(char *Commandline);
-void   System_ParseCommandLine(char *ArgString);
-void   System_ExecuteCommandLine(void);
-void   System_ParseVFS(char *Arg);
-void   System_ParseModuleArgs(char *Arg);
-void   System_ParseSetting(char *Arg);
-
-// === GLOBALS ===
-const char     *gsInitBinary = "/Acess/SBin/init";
-char   *argv[32];
- int   argc;
-
-// === CODE ===
-void System_Init(char *CommandLine)
-{
-       // Parse Kernel's Command Line
-       System_ParseCommandLine(CommandLine);
-       
-       // Initialise modules
-       Log_Log("Config", "Initialising builtin modules...");
-       Modules_LoadBuiltins();
-       Arch_LoadBootModules();
-       
-       System_ExecuteCommandLine();
-       
-       // - Execute the Config Script
-       Log_Log("Config", "Spawning init '%s'", gsInitBinary);
-       Proc_Spawn(gsInitBinary);
-       
-       // Set the debug to be echoed to the terminal
-       Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)");
-       Debug_SetKTerminal("/Devices/VTerm/7");
-}
-
-/**
- * \fn void System_ParseCommandLine(char *ArgString)
- * \brief Parses the kernel's command line and sets the environment
- */
-void System_ParseCommandLine(char *ArgString)
-{
-        int    i;
-       char    *str;
-       
-       Log_Log("Config", "Kernel Invocation (%p) \"%s\"", ArgString, ArgString);
-       
-       // --- Get Arguments ---
-       str = ArgString;
-       for( argc = 0; argc < 32; argc++ )
-       {
-               // Eat Whitespace
-               while(*str == ' ')      str++;
-               // Check for the end of the string
-               if(*str == '\0') {      argc--; break;} 
-               argv[argc] = str;
-               if(*str == '"') {
-                       while(*str && !(*str == '"' && str[-1] != '\\'))
-                               str ++;
-               }
-               else {
-                       while(*str && *str != ' ')
-                               str++;
-               }
-               if(*str == '\0')        break;  // Check for EOS
-               *str = '\0';    // Cap off argument string
-               str ++; // and increment the string pointer
-       }
-       if(argc < 32)
-               argc ++;        // Count last argument
-       
-       // --- Parse Arguments (Pass 1) ---
-       for( i = 1; i < argc; i++ )
-       {
-               switch(argv[i][0])
-               {
-               // --- VFS ---
-               // Ignored on this pass
-               case '/':
-                       break;
-               
-               // --- Module Paramaters ---
-               // -VTerm:Width=640,Height=480,Scrollback=2
-               case '-':
-                       System_ParseModuleArgs( argv[i] );
-                       break;
-               // --- Config Options ---
-               // SCRIPT=/Acess/Conf/BootConf.cfg
-               default:
-                       System_ParseSetting( argv[i] );
-                       break;
-               }
-       }
-}
-
-void System_ExecuteCommandLine(void)
-{
-        int    i;
-       if(argc > 0)
-               LOG("Invocation '%s'", argv[0]);
-       for( i = 1; i < argc; i++ )
-       {
-               LOG("argv[%i] = '%s'", i, argv[i]);
-               switch(argv[i][0])
-               {
-               // --- VFS ---
-               // Mount    /System=ext2:/Devices/ATA/A1
-               // Symlink  /Acess=/System/Acess2
-               case '/':
-                       System_ParseVFS( argv[i] );
-                       break;
-               }
-       }
-}
-
-/**
- * \fn void System_ParseVFS(char *Arg)
- */
-void System_ParseVFS(char *Arg)
-{
-       char    *value;
-        int    fd;
-       
-       value = Arg;
-       // Search for the '=' token
-       while( *value && *value != '=' )
-               value++;
-       
-       // Check if the equals was found
-       if( *value == '\0' ) {
-               Log_Warning("Config", "Expected '=' in the string '%s'", Arg);
-               return ;
-       }
-       
-       // Edit string
-       *value = '\0';  value ++;
-       
-       // Check assignment type
-       // - Symbolic Link <link>=<destination>
-       if(value[0] == '/')
-       {
-               Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
-               VFS_Symlink(Arg, value);
-       }
-       // - Mount <mountpoint>=<fs>:<device>
-       else
-       {
-               char    *dev = value;
-               // Find colon
-               while(*dev && *dev != ':')      dev++;
-               if(*dev) {
-                       *dev = '\0';
-                       dev++;  // Eat ':'
-               }
-               // Create Mountpoint
-               if( (fd = VFS_Open(Arg, 0)) == -1 ) {
-                       Log_Log("Config", "Creating directory '%s'", Arg, value);
-                       VFS_MkDir( Arg );
-               } else {
-                       VFS_Close(fd);
-               }
-               // Mount
-               Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
-               VFS_Mount(dev, Arg, value, "");
-       }
-}
-
-/**
- * \brief Parse a module argument string
- * \param Arg  Argument string
- */
-void System_ParseModuleArgs(char *Arg)
-{
-       char    *name, *args;
-        int    i;
-       
-       // Remove '-'   
-       name = Arg + 1;
-       
-       // Find the start of the args
-       i = strpos(name, ':');
-       if( i == -1 ) {
-               Log_Warning("Config", "Module spec with no arguments");
-               #if 1
-               return ;
-               #else
-               i = strlen(name);
-               args = name + i;
-               #endif
-       }
-       else {
-               name[i] = '\0';
-               args = name + i + 1;
-       }
-       
-       Log_Log("Config", "Setting boot parameters for '%s' to '%s'", name, args);
-       Modules_SetBuiltinParams(name, args);
-}
-
-/**
- * \fn void System_ParseSetting(char *Arg)
- */
-void System_ParseSetting(char *Arg)
-{
-       char    *value;
-       value = Arg;
-
-       // Search for the '=' token
-       while( *value && *value != '=' )
-               value++;
-       
-       // Check for boolean/flag (no '=')
-       if(*value == '\0')
-       {
-               //if(strcmp(Arg, "") == 0) {
-               //} else {
-                       Log_Warning("Config", "Kernel flag '%s' is not recognised", Arg);
-               //}
-       }
-       else
-       {
-               *value = '\0';  // Remove '='
-               value ++;       // and eat it's position
-               
-               if(strcmp(Arg, "INIT") == 0) {
-                       Log_Log("Config", "Init binary: '%s'", value);
-                       if(strlen(value) == 0)
-                               gsInitBinary = NULL;
-                       else
-                               gsInitBinary = value;
-               }
-               else {
-                       Log_Warning("Config", "Kernel config setting '%s' is not recognised", Arg);
-               }
-               
-       }
-}
-
diff --git a/Kernel/threads.c b/Kernel/threads.c
deleted file mode 100644 (file)
index 956eede..0000000
+++ /dev/null
@@ -1,1355 +0,0 @@
-/*
- * Acess2
- * threads.c
- * - Common Thread Control
- */
-#include <acess.h>
-#include <threads.h>
-#include <threads_int.h>
-#include <errno.h>
-#include <hal_proc.h>
-#include <semaphore.h>
-#include <vfs_threads.h>       // VFS Handle maintainence
-
-// Configuration
-#define DEBUG_TRACE_TICKETS    0       // Trace ticket counts
-#define DEBUG_TRACE_STATE      0       // Trace state changes (sleep/wake)
-
-// --- Schedulers ---
-#define SCHED_UNDEF    0
-#define SCHED_LOTTERY  1       // Lottery scheduler
-#define SCHED_RR_SIM   2       // Single Queue Round Robin
-#define SCHED_RR_PRI   3       // Multi Queue Round Robin
-// Set scheduler type
-#define SCHEDULER_TYPE SCHED_RR_PRI
-
-// === CONSTANTS ===
-#define        DEFAULT_QUANTUM 5
-#define        DEFAULT_PRIORITY        5
-#define MIN_PRIORITY           10
-
-// === IMPORTS ===
-
-// === TYPE ===
-typedef struct
-{
-       tThread *Head;
-       tThread *Tail;
-} tThreadList;
-
-// === PROTOTYPES ===
-void   Threads_Init(void);
-#if 0
-void   Threads_Delete(tThread *Thread);
- int   Threads_SetName(const char *NewName);
-#endif
-char   *Threads_GetName(tTID ID);
-#if 0
-void   Threads_SetPriority(tThread *Thread, int Pri);
-tThread        *Threads_CloneTCB(Uint *Err, Uint Flags);
- int   Threads_WaitTID(int TID, int *status);
-tThread        *Threads_GetThread(Uint TID);
-#endif
-tThread        *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread);
-void   Threads_int_AddToList(tThreadList *List, tThread *Thread);
-#if 0
-void   Threads_Exit(int TID, int Status);
-void   Threads_Kill(tThread *Thread, int Status);
-void   Threads_Yield(void);
-void   Threads_Sleep(void);
- int   Threads_Wake(tThread *Thread);
-void   Threads_AddActive(tThread *Thread);
-tThread        *Threads_RemActive(void);
-#endif
-void   Threads_ToggleTrace(int TID);
-void   Threads_Fault(int Num);
-void   Threads_SegFault(tVAddr Addr);
-#if 0
- int   Threads_GetPID(void);
- int   Threads_GetTID(void);
-tUID   Threads_GetUID(void);
-tGID   Threads_GetGID(void);
- int   Threads_SetUID(Uint *Errno, tUID ID);
- int   Threads_SetGID(Uint *Errno, tUID ID);
-#endif
-void   Threads_Dump(void);
-void   Threads_DumpActive(void);
-
-// === GLOBALS ===
-// -- Core Thread --
-struct sProcess        gProcessZero = {
-       };
-// Only used for the core kernel
-tThread        gThreadZero = {
-       .Status         = THREAD_STAT_ACTIVE,   // Status
-       .ThreadName     = (char*)"ThreadZero",  // Name
-       .Quantum        = DEFAULT_QUANTUM,      // Default Quantum
-       .Remaining      = DEFAULT_QUANTUM,      // Current Quantum
-       .Priority       = DEFAULT_PRIORITY      // Number of tickets
-       };
-// -- Processes --
-// --- Locks ---
-tShortSpinlock glThreadListLock;       ///\note NEVER use a heap function while locked
-// --- Current State ---
-volatile int   giNumActiveThreads = 0; // Number of threads on the active queue
-volatile Uint  giNextTID = 1;  // Next TID to allocate
-// --- Thread Lists ---
-tThread        *gAllThreads = NULL;            // All allocated threads
-tThreadList    gSleepingThreads;       // Sleeping Threads
- int   giNumCPUs = 1;  // Number of CPUs
-BOOL     gaThreads_NoTaskSwitch[MAX_CPUS];     // Disables task switches for each core (Pseudo-IF)
-// --- Scheduler Types ---
-#if SCHEDULER_TYPE == SCHED_LOTTERY
-const int      caiTICKET_COUNTS[MIN_PRIORITY+1] = {100,81,64,49,36,25,16,9,4,1,0};
-volatile int   giFreeTickets = 0;      // Number of tickets held by non-scheduled threads
-tThreadList    gActiveThreads;         // Currently Running Threads
-#elif SCHEDULER_TYPE == SCHED_RR_SIM
-tThreadList    gActiveThreads;         // Currently Running Threads
-#elif SCHEDULER_TYPE == SCHED_RR_PRI
-tThreadList    gaActiveThreads[MIN_PRIORITY+1];        // Active threads for each priority level
-#else
-# error "Unkown scheduler type"
-#endif
-
-// === CODE ===
-/**
- * \fn void Threads_Init(void)
- * \brief Initialse the thread list
- */
-void Threads_Init(void)
-{
-       ArchThreads_Init();
-       
-       Log_Debug("Threads", "Offsets of tThread");
-       Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority));
-       Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
-       
-       // Create Initial Task
-//     #if SCHEDULER_TYPE == SCHED_RR_PRI
-//     gaActiveThreads[gThreadZero.Priority].Head = &gThreadZero;
-//     gaActiveThreads[gThreadZero.Priority].Tail = &gThreadZero;
-//     #else
-//     gActiveThreads.Head = &gThreadZero;
-//     gActiveThreads.Tail = &gThreadZero;
-//     #endif
-       
-       gAllThreads = &gThreadZero;
-       giNumActiveThreads = 1;
-       gThreadZero.Process = &gProcessZero;
-               
-       Proc_Start();
-}
-
-void Threads_Delete(tThread *Thread)
-{
-       // Set to dead
-       Thread->Status = THREAD_STAT_BURIED;
-
-       // Clear out process state
-       Proc_ClearThread(Thread);                       
-
-       Thread->Process->nThreads --;
-       if( Thread->Process->nThreads == 0 )
-       {
-               tProcess        *proc = Thread->Process;
-               // VFS Cleanup
-               VFS_CloseAllUserHandles();
-               // Architecture cleanup
-               Proc_ClearProcess( proc );
-               // VFS Configuration strings
-               if( proc->CurrentWorkingDir)
-                       free( proc->CurrentWorkingDir );
-               if( proc->RootDir )
-                       free( proc->RootDir );
-               // Process descriptor
-               free( proc );
-       }
-       
-       // Free name
-       if( IsHeap(Thread->ThreadName) )
-               free(Thread->ThreadName);
-       
-       // Remove from global list
-       // TODO: Lock this too
-       if( Thread == gAllThreads )
-               gAllThreads = Thread->GlobalNext;
-       else
-               Thread->GlobalPrev->GlobalNext = Thread->GlobalNext;
-       
-       free(Thread);
-}
-
-/**
- * \fn void Threads_SetName(const char *NewName)
- * \brief Sets the current thread's name
- * \param NewName      New name for the thread
- * \return Boolean Failure
- */
-int Threads_SetName(const char *NewName)
-{
-       tThread *cur = Proc_GetCurThread();
-       char    *oldname = cur->ThreadName;
-       
-       // NOTE: There is a possibility of non-thread safety here
-       // A thread could read the current name pointer before it is zeroed
-       
-       cur->ThreadName = NULL;
-       
-       if( IsHeap(oldname) )   free( oldname );        
-       cur->ThreadName = strdup(NewName);
-
-       Log_Debug("Threads", "Thread renamed to '%s'", NewName);        
-
-       return 0;
-}
-
-/**
- * \fn char *Threads_GetName(int ID)
- * \brief Gets a thread's name
- * \param ID   Thread ID (-1 indicates current thread)
- * \return Pointer to name
- * \retval NULL        Failure
- */
-char *Threads_GetName(tTID ID)
-{
-       if(ID == -1) {
-               return Proc_GetCurThread()->ThreadName;
-       }
-       return Threads_GetThread(ID)->ThreadName;
-}
-
-/**
- * \fn void Threads_SetPriority(tThread *Thread, int Pri)
- * \brief Sets the priority of a task
- * \param Thread       Thread to update ticket count (NULL means current thread)
- * \param Pri  New priority
- */
-void Threads_SetPriority(tThread *Thread, int Pri)
-{
-       // Get current thread
-       if(Thread == NULL)      Thread = Proc_GetCurThread();
-       // Bounds checking
-       // - If < 0, set to lowest priority
-       // - Minumum priority is actualy a high number, 0 is highest
-       if(Pri < 0)     Pri = MIN_PRIORITY;
-       if(Pri > MIN_PRIORITY)  Pri = MIN_PRIORITY;
-       
-       // Do we actually have to do anything?
-       if( Pri == Thread->Priority )   return;
-       
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-       if( Thread != Proc_GetCurThread() )
-       {
-               SHORTLOCK( &glThreadListLock );
-               // Remove from old priority
-               Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
-               // And add to new
-               Threads_int_AddToList( &gaActiveThreads[Pri], Thread );
-               Thread->Priority = Pri;
-               SHORTREL( &glThreadListLock );
-       }
-       else
-               Thread->Priority = Pri;
-       #else
-       // If this isn't the current thread, we need to lock
-       if( Thread != Proc_GetCurThread() )
-       {
-               SHORTLOCK( &glThreadListLock );
-               
-               #if SCHEDULER_TYPE == SCHED_LOTTERY
-               giFreeTickets -= caiTICKET_COUNTS[Thread->Priority] - caiTICKET_COUNTS[Pri];
-               # if DEBUG_TRACE_TICKETS
-               Log("Threads_SetTickets: new giFreeTickets = %i [-%i+%i]",
-                       giFreeTickets,
-                       caiTICKET_COUNTS[Thread->Priority], caiTICKET_COUNTS[Pri]);
-               # endif
-               #endif
-               Thread->Priority = Pri;
-               SHORTREL( &glThreadListLock );
-       }
-       else
-               Thread->Priority = Pri;
-       #endif
-       
-       #if DEBUG_TRACE_STATE
-       Log("Threads_SetPriority: %p(%i %s) pri set %i",
-               Thread, Thread->TID, Thread->ThreadName,
-               Pri);
-       #endif
-}
-
-/**
- * \brief Clone the TCB of the current thread
- * \param Flags        Flags for something... (What is this for?)
- */
-tThread *Threads_CloneTCB(Uint Flags)
-{
-       tThread *cur, *new;
-       cur = Proc_GetCurThread();
-       
-       // Allocate and duplicate
-       new = malloc(sizeof(tThread));
-       if(new == NULL) { errno = -ENOMEM; return NULL; }
-       memcpy(new, cur, sizeof(tThread));
-       
-       new->CurCPU = -1;
-       new->Next = NULL;
-       memset( &new->IsLocked, 0, sizeof(new->IsLocked));
-       new->Status = THREAD_STAT_PREINIT;
-       new->RetStatus = 0;
-       
-       // Get Thread ID
-       new->TID = giNextTID++;
-       new->Parent = cur;
-       new->bInstrTrace = 0;
-       
-       // Clone Name
-       new->ThreadName = strdup(cur->ThreadName);
-       
-       // Set Thread Group ID (PID)
-       if(Flags & CLONE_VM) {
-               tProcess        *newproc, *oldproc;
-               oldproc = cur->Process;
-               new->Process = malloc( sizeof(struct sProcess) );
-               newproc = new->Process;
-               newproc->PID = new->TID;
-               newproc->UID = oldproc->UID;
-               newproc->GID = oldproc->GID;
-               newproc->MaxFD = oldproc->MaxFD;
-               if( oldproc->CurrentWorkingDir )
-                       newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir );
-               else
-                       newproc->CurrentWorkingDir = NULL;
-               if( oldproc->RootDir )
-                       newproc->RootDir = strdup( oldproc->RootDir );
-               else
-                       newproc->RootDir = NULL;
-               newproc->nThreads = 1;
-               // Reference all handles in the VFS
-               VFS_ReferenceUserHandles();
-       }
-       else {
-               new->Process->nThreads ++;
-       }
-       
-       // Messages are not inherited
-       new->Messages = NULL;
-       new->LastMessage = NULL;
-       
-       // Set State
-       new->Remaining = new->Quantum = cur->Quantum;
-       new->Priority = cur->Priority;
-       new->_errno = 0;
-       
-       // Set Signal Handlers
-       new->CurFaultNum = 0;
-       new->FaultHandler = cur->FaultHandler;
-       
-       // Maintain a global list of threads
-       SHORTLOCK( &glThreadListLock );
-       new->GlobalPrev = NULL; // Protect against bugs
-       new->GlobalNext = gAllThreads;
-       gAllThreads->GlobalPrev = new;
-       gAllThreads = new;
-       SHORTREL( &glThreadListLock );
-       
-       return new;
-}
-
-/**
- * \brief Clone the TCB of the kernel thread
- */
-tThread *Threads_CloneThreadZero(void)
-{
-       tThread *new;
-       
-       // Allocate and duplicate
-       new = malloc(sizeof(tThread));
-       if(new == NULL) {
-               return NULL;
-       }
-       memcpy(new, &gThreadZero, sizeof(tThread));
-
-       new->Process->nThreads ++;
-       
-       new->CurCPU = -1;
-       new->Next = NULL;
-       memset( &new->IsLocked, 0, sizeof(new->IsLocked));
-       new->Status = THREAD_STAT_PREINIT;
-       new->RetStatus = 0;
-       
-       // Get Thread ID
-       new->TID = giNextTID++;
-       new->Parent = 0;
-       
-       // Clone Name
-       new->ThreadName = NULL;
-       
-       // Messages are not inherited
-       new->Messages = NULL;
-       new->LastMessage = NULL;
-       
-       // Set State
-       new->Remaining = new->Quantum = DEFAULT_QUANTUM;
-       new->Priority = DEFAULT_PRIORITY;
-       new->bInstrTrace = 0;
-       
-       // Set Signal Handlers
-       new->CurFaultNum = 0;
-       new->FaultHandler = 0;
-       
-       // Maintain a global list of threads
-       SHORTLOCK( &glThreadListLock );
-       new->GlobalPrev = NULL; // Protect against bugs
-       new->GlobalNext = gAllThreads;
-       gAllThreads->GlobalPrev = new;
-       gAllThreads = new;
-       SHORTREL( &glThreadListLock );
-       
-       return new;
-}
-
-/**
- * \brief Wait for a task to change state
- * \param TID  Thread ID to wait on (-1: Any child thread, 0: Any Child/Sibling, <-1: -PID)
- * \param Status       Thread return status
- * \return TID of child that changed state
- */
-tTID Threads_WaitTID(int TID, int *Status)
-{      
-       // Any Child
-       if(TID == -1) {
-               Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
-               return -1;
-       }
-       
-       // Any peer/child thread
-       if(TID == 0) {
-               Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
-               return -1;
-       }
-       
-       // TGID = abs(TID)
-       if(TID < -1) {
-               Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
-               return -1;
-       }
-       
-       // Specific Thread
-       if(TID > 0) {
-               tThread *t = Threads_GetThread(TID);
-               tTID    ret;
-               
-               // Wait for the thread to die!
-               // TODO: Handle child also being suspended if wanted
-               while(t->Status != THREAD_STAT_ZOMBIE) {
-                       Threads_Sleep();
-                       Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
-                               Threads_GetTID(), t->TID, t->Status);
-               }
-               
-               // Set return status
-               ret = t->TID;
-               switch(t->Status)
-               {
-               case THREAD_STAT_ZOMBIE:
-                       // Kill the thread
-                       t->Status = THREAD_STAT_DEAD;
-                       // TODO: Child return value?
-                       if(Status)      *Status = t->RetStatus;
-                       // add to delete queue
-                       Threads_Delete( t );
-                       break;
-               default:
-                       if(Status)      *Status = -1;
-                       break;
-               }
-               return ret;
-       }
-       
-       return -1;
-}
-
-/**
- * \brief Gets a thread given its TID
- * \param TID  Thread ID
- * \return Thread pointer
- */
-tThread *Threads_GetThread(Uint TID)
-{
-       tThread *thread;
-       
-       // Search global list
-       for(thread = gAllThreads;
-               thread;
-               thread = thread->GlobalNext)
-       {
-               if(thread->TID == TID)
-                       return thread;
-       }
-
-       Log("Unable to find TID %i on main list\n", TID);
-       
-       return NULL;
-}
-
-/**
- * \brief Deletes an entry from a list
- * \param List Pointer to the list head
- * \param Thread       Thread to find
- * \return \a Thread
- */
-tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread)
-{
-       tThread *ret, *prev = NULL;
-       
-       for(ret = List->Head;
-               ret && ret != Thread;
-               prev = ret, ret = ret->Next
-               );
-       
-       // Is the thread on the list
-       if(!ret) {
-               //LogF("%p(%s) is not on list %p\n", Thread, Thread->ThreadName, List);
-               return NULL;
-       }
-       
-       if( !prev ) {
-               List->Head = Thread->Next;
-               //LogF("%p(%s) removed from head of %p\n", Thread, Thread->ThreadName, List);
-       }
-       else {
-               prev->Next = Thread->Next;
-               //LogF("%p(%s) removed from %p (prev=%p)\n", Thread, Thread->ThreadName, List, prev);
-       }
-       if( Thread->Next == NULL )
-               List->Tail = prev;
-       
-       return Thread;
-}
-
-void Threads_int_AddToList(tThreadList *List, tThread *Thread)
-{
-       if( List->Head )
-               List->Tail->Next = Thread;
-       else
-               List->Head = Thread;
-       List->Tail = Thread;
-       Thread->Next = NULL;
-}
-
-/**
- * \brief Exit the current process (or another?)
- * \param TID  Thread ID to kill
- * \param Status       Exit status
- */
-void Threads_Exit(int TID, int Status)
-{
-       if( TID == 0 )
-               Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
-       else
-               Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
-       
-       // Halt forever, just in case
-       for(;;) HALT();
-}
-
-/**
- * \fn void Threads_Kill(tThread *Thread, int Status)
- * \brief Kill a thread
- * \param Thread       Thread to kill
- * \param Status       Status code to return to the parent
- */
-void Threads_Kill(tThread *Thread, int Status)
-{
-       tMsg    *msg;
-        int    isCurThread = Thread == Proc_GetCurThread();
-       
-       // TODO: Disown all children?
-       #if 1
-       {
-               tThread *child;
-               // TODO: I should keep a .Children list
-               for(child = gAllThreads;
-                       child;
-                       child = child->GlobalNext)
-               {
-                       if(child->Parent == Thread)
-                               child->Parent = &gThreadZero;
-               }
-       }
-       #endif
-       
-       ///\note Double lock is needed due to overlap of lock areas
-       
-       // Lock thread (stop us recieving messages)
-       SHORTLOCK( &Thread->IsLocked );
-       
-       // Clear Message Queue
-       while( Thread->Messages )
-       {
-               msg = Thread->Messages->Next;
-               free( Thread->Messages );
-               Thread->Messages = msg;
-       }
-       
-       // Lock thread list
-       SHORTLOCK( &glThreadListLock );
-       
-       switch(Thread->Status)
-       {
-       case THREAD_STAT_PREINIT:       // Only on main list
-               break;
-       
-       // Currently active thread
-       case THREAD_STAT_ACTIVE:
-               if( Thread != Proc_GetCurThread() )
-               {
-                       #if SCHEDULER_TYPE == SCHED_RR_PRI
-                       tThreadList     *list = &gaActiveThreads[Thread->Priority];
-                       #else
-                       tThreadList     *list = &gActiveThreads;
-                       #endif
-                       if( Threads_int_DelFromQueue( list, Thread ) )
-                       {
-                       }
-                       else
-                       {
-                               Log_Warning("Threads",
-                                       "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
-                                       Thread, Thread->TID, Thread->ThreadName
-                                       );
-                       }
-                       #if SCHEDULER_TYPE == SCHED_LOTTERY
-                       giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
-                       #endif
-               }
-               // Ensure that we are not rescheduled
-               Thread->Remaining = 0;  // Clear Remaining Quantum
-               Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
-                       
-               // Update bookkeeping
-               giNumActiveThreads --;
-               break;
-       // Kill it while it sleeps!
-       case THREAD_STAT_SLEEPING:
-               if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) )
-               {
-                       Log_Warning("Threads",
-                               "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list",
-                               Thread, Thread->TID, Thread->ThreadName
-                               );
-               }
-               break;
-       
-       // Brains!... You cannot kill something that is already dead
-       case THREAD_STAT_ZOMBIE:
-               Log_Warning("Threads", "Threads_Kill - Thread %p(%i,%s) is undead, you cannot kill it",
-                       Thread, Thread->TID, Thread->ThreadName);
-               SHORTREL( &glThreadListLock );
-               SHORTREL( &Thread->IsLocked );
-               return ;
-       
-       default:
-               Log_Warning("Threads", "Threads_Kill - BUG Un-checked status (%i)",
-                       Thread->Status);
-               break;
-       }
-       
-       // Save exit status
-       Thread->RetStatus = Status;
-
-       SHORTREL( &Thread->IsLocked );
-
-       Thread->Status = THREAD_STAT_ZOMBIE;
-       SHORTREL( &glThreadListLock );
-       // TODO: Send something like SIGCHLD
-       Threads_Wake( Thread->Parent );
-       
-       Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
-       
-       // And, reschedule
-       if(isCurThread)
-       {
-               for( ;; )
-                       Proc_Reschedule();
-       }
-}
-
-/**
- * \brief Yield remainder of the current thread's timeslice
- */
-void Threads_Yield(void)
-{
-//     Log("Threads_Yield: by %p", __builtin_return_address(0));
-       Proc_Reschedule();
-}
-
-/**
- * \fn void Threads_Sleep(void)
- * \brief Take the current process off the run queue
- */
-void Threads_Sleep(void)
-{
-       tThread *cur = Proc_GetCurThread();
-       
-       // Acquire Spinlock
-       SHORTLOCK( &glThreadListLock );
-       
-       // Don't sleep if there is a message waiting
-       if( cur->Messages ) {
-               SHORTREL( &glThreadListLock );
-               return;
-       }
-       
-       // Remove us from running queue
-       Threads_RemActive();
-       // Mark thread as sleeping
-       cur->Status = THREAD_STAT_SLEEPING;
-       
-       // Add to Sleeping List (at the top)
-       Threads_int_AddToList( &gSleepingThreads, cur );
-       
-       #if DEBUG_TRACE_STATE
-       Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
-       #endif
-       
-       // Release Spinlock
-       SHORTREL( &glThreadListLock );
-
-       while(cur->Status != THREAD_STAT_ACTIVE) {
-               Proc_Reschedule();
-               if( cur->Status != THREAD_STAT_ACTIVE )
-                       Log("%i - Huh? why am I up? zzzz...", cur->TID);
-       }
-}
-
-
-/**
- * \brief Wakes a sleeping/waiting thread up
- * \param Thread       Thread to wake
- * \return Boolean Failure (Returns ERRNO)
- * \warning This should ONLY be called with task switches disabled
- */
-int Threads_Wake(tThread *Thread)
-{
-       if(!Thread)
-               return -EINVAL;
-       
-       switch(Thread->Status)
-       {
-       case THREAD_STAT_ACTIVE:
-               Log("Threads_Wake - Waking awake thread (%i)", Thread->TID);
-               return -EALREADY;
-       
-       case THREAD_STAT_SLEEPING:
-               SHORTLOCK( &glThreadListLock );
-               // Remove from sleeping queue
-               Threads_int_DelFromQueue(&gSleepingThreads, Thread);
-               
-               SHORTREL( &glThreadListLock );
-               Threads_AddActive( Thread );
-               
-               #if DEBUG_TRACE_STATE
-               Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName);
-               #endif
-               return -EOK;
-       
-       case THREAD_STAT_SEMAPHORESLEEP: {
-               tSemaphore      *sem;
-               tThread *th, *prev=NULL;
-               
-               sem = Thread->WaitPointer;
-               
-               SHORTLOCK( &sem->Protector );
-               
-               // Remove from sleeping queue
-               for( th = sem->Waiting; th; prev = th, th = th->Next )
-                       if( th == Thread )      break;
-               if( th )
-               {
-                       if(prev)
-                               prev->Next = Thread->Next;
-                       else
-                               sem->Waiting = Thread->Next;
-                       if(sem->LastWaiting == Thread)
-                               sem->LastWaiting = prev;
-               }
-               else
-               {
-                       prev = NULL;
-                       for( th = sem->Signaling; th; prev = th, th = th->Next )
-                               if( th == Thread )      break;
-                       if( !th ) {
-                               Log_Warning("Threads", "Thread %p(%i %s) is not on semaphore %p(%s:%s)",
-                                       Thread, Thread->TID, Thread->ThreadName,
-                                       sem, sem->ModName, sem->Name);
-                               return -EINTERNAL;
-                       }
-                       
-                       if(prev)
-                               prev->Next = Thread->Next;
-                       else
-                               sem->Signaling = Thread->Next;
-                       if(sem->LastSignaling == Thread)
-                               sem->LastSignaling = prev;
-               }
-               
-               Thread->RetStatus = 0;  // It didn't get anything
-               Threads_AddActive( Thread );
-               
-               #if DEBUG_TRACE_STATE
-               Log("Threads_Sleep: %p(%i %s) woken from semaphore", Thread, Thread->TID, Thread->ThreadName);
-               #endif
-               SHORTREL( &sem->Protector );
-               } return -EOK;
-       
-       case THREAD_STAT_WAITING:
-               Warning("Threads_Wake - Waiting threads are not currently supported");
-               return -ENOTIMPL;
-       
-       case THREAD_STAT_DEAD:
-               Warning("Threads_Wake - Attempt to wake dead thread (%i)", Thread->TID);
-               return -ENOTIMPL;
-       
-       default:
-               Warning("Threads_Wake - Unknown process status (%i)\n", Thread->Status);
-               return -EINTERNAL;
-       }
-}
-
-/**
- * \brief Wake a thread given the TID
- * \param TID  Thread ID to wake
- * \return Boolean Faulure (errno)
- */
-int Threads_WakeTID(tTID TID)
-{
-       tThread *thread = Threads_GetThread(TID);
-        int    ret;
-       if(!thread)
-               return -ENOENT;
-       ret = Threads_Wake( thread );
-       //Log_Debug("Threads", "TID %i woke %i (%p)", Threads_GetTID(), TID, thread);
-       return ret;
-}
-
-void Threads_ToggleTrace(int TID)
-{
-       tThread *thread = Threads_GetThread(TID);
-       if(!thread)     return ;
-       thread->bInstrTrace = !thread->bInstrTrace;
-}
-
-/**
- * \brief Adds a thread to the active queue
- */
-void Threads_AddActive(tThread *Thread)
-{
-       SHORTLOCK( &glThreadListLock );
-       
-       if( Thread->Status == THREAD_STAT_ACTIVE ) {
-               tThread *cur = Proc_GetCurThread();
-               Log_Warning("Threads", "WTF, %p CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
-                       __builtin_return_address(0),
-                       GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName);
-               SHORTREL( &glThreadListLock );
-               return ;
-       }
-       
-       // Set state
-       Thread->Status = THREAD_STAT_ACTIVE;
-//     Thread->CurCPU = -1;
-       // Add to active list
-       {
-               #if SCHEDULER_TYPE == SCHED_RR_PRI
-               tThreadList     *list = &gaActiveThreads[Thread->Priority];
-               #else
-               tThreadList     *list = &gActiveThreads;
-               #endif
-               Threads_int_AddToList( list, Thread );
-       }
-       
-       // Update bookkeeping
-       giNumActiveThreads ++;
-       
-       #if SCHEDULER_TYPE == SCHED_LOTTERY
-       {
-                int    delta;
-               // Only change the ticket count if the thread is un-scheduled
-               if(Thread->CurCPU != -1)
-                       delta = 0;
-               else
-                       delta = caiTICKET_COUNTS[ Thread->Priority ];
-               
-               giFreeTickets += delta;
-               # if DEBUG_TRACE_TICKETS
-               Log("CPU%i %p (%i %s) added, new giFreeTickets = %i [+%i]",
-                       GetCPUNum(), Thread, Thread->TID, Thread->ThreadName,
-                       giFreeTickets, delta
-                       );
-               # endif
-       }
-       #endif
-       
-       SHORTREL( &glThreadListLock );
-}
-
-/**
- * \brief Removes the current thread from the active queue
- * \warning This should ONLY be called with the lock held
- * \return Current thread pointer
- */
-tThread *Threads_RemActive(void)
-{
-       #if 0
-       tThread *ret = Proc_GetCurThread();
-
-       if( !IS_LOCKED(&glThreadListLock) ) {
-               Log_KernelPanic("Threads", "Threads_RemActive called without lock held");
-               return NULL;
-       }
-       
-       // Delete from active queue
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-       if( !Threads_int_DelFromQueue(&gaActiveThreads[ret->Priority], ret) )
-       #else
-       if( !Threads_int_DelFromQueue(&gActiveThreads, ret) )
-       #endif
-       {
-               Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue",
-                       ret, ret->TID, ret->ThreadName
-                       );
-               return NULL;
-       }
-       
-       ret->Next = NULL;
-       ret->Remaining = 0;
-       
-       giNumActiveThreads --;
-       // no need to decrement tickets, scheduler did it for us
-       
-       #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
-       Log("CPU%i %p (%i %s) removed, giFreeTickets = %i [nc]",
-               GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets);
-       #endif
-       
-       return ret;
-       #else
-       return Proc_GetCurThread();
-       #endif
-}
-
-/**
- * \fn void Threads_SetFaultHandler(Uint Handler)
- * \brief Sets the signal handler for a signal
- */
-void Threads_SetFaultHandler(Uint Handler)
-{      
-       //Log_Debug("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
-       Proc_GetCurThread()->FaultHandler = Handler;
-}
-
-/**
- * \fn void Threads_Fault(int Num)
- * \brief Calls a fault handler
- */
-void Threads_Fault(int Num)
-{
-       tThread *thread = Proc_GetCurThread();
-       
-       if(!thread)     return ;
-       
-       Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
-       
-       switch(thread->FaultHandler)
-       {
-       case 0: // Panic?
-               Threads_Kill(thread, -1);
-               HALT();
-               return ;
-       case 1: // Dump Core?
-               Threads_Kill(thread, -1);
-               HALT();
-               return ;
-       }
-       
-       // Double Fault? Oh, F**k
-       if(thread->CurFaultNum != 0) {
-               Log_Warning("Threads", "Threads_Fault: Double fault on %i", thread->TID);
-               Threads_Kill(thread, -1);       // For now, just kill
-               HALT();
-       }
-       
-       thread->CurFaultNum = Num;
-       
-       Proc_CallFaultHandler(thread);
-}
-
-/**
- * \fn void Threads_SegFault(tVAddr Addr)
- * \brief Called when a Segment Fault occurs
- */
-void Threads_SegFault(tVAddr Addr)
-{
-       tThread *cur = Proc_GetCurThread();
-       cur->bInstrTrace = 0;
-       Log_Warning("Threads", "Thread #%i committed a segfault at address %p", cur->TID, Addr);
-       MM_DumpTables(0, USER_MAX);
-       Threads_Fault( 1 );
-       //Threads_Exit( 0, -1 );
-}
-
-// --- Process Structure Access Functions ---
-tPID Threads_GetPID(void)
-{
-       return Proc_GetCurThread()->Process->PID;
-}
-tTID Threads_GetTID(void)
-{
-       return Proc_GetCurThread()->TID;
-}
-tUID Threads_GetUID(void)
-{
-       return Proc_GetCurThread()->Process->UID;
-}
-tGID Threads_GetGID(void)
-{
-       return Proc_GetCurThread()->Process->GID;
-}
-
-int Threads_SetUID(tUID ID)
-{
-       tThread *t = Proc_GetCurThread();
-       if( t->Process->UID != 0 ) {
-               errno = -EACCES;
-               return -1;
-       }
-       Log_Debug("Threads", "PID %i's UID set to %i", t->Process->PID, ID);
-       t->Process->UID = ID;
-       return 0;
-}
-
-int Threads_SetGID(tGID ID)
-{
-       tThread *t = Proc_GetCurThread();
-       if( t->Process->UID != 0 ) {
-               errno = -EACCES;
-               return -1;
-       }
-       Log_Debug("Threads", "PID %i's GID set to %i", t->Process->PID, ID);
-       t->Process->GID = ID;
-       return 0;
-}
-
-// --- Per-thread storage ---
-int *Threads_GetErrno(void)
-{
-       return &Proc_GetCurThread()->_errno;
-}
-
-// --- Configuration ---
-int *Threads_GetMaxFD(void)
-{
-       return &Proc_GetCurThread()->Process->MaxFD;
-}
-char **Threads_GetChroot(void)
-{
-       return &Proc_GetCurThread()->Process->RootDir;
-}
-char **Threads_GetCWD(void)
-{
-       return &Proc_GetCurThread()->Process->CurrentWorkingDir;
-}
-// ---
-
-/**
- * \fn void Threads_Dump(void)
- */
-void Threads_DumpActive(void)
-{
-       tThread *thread;
-       tThreadList     *list;
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-        int    i;
-       #endif
-       
-       Log("Active Threads: (%i reported)", giNumActiveThreads);
-       
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-       for( i = 0; i < MIN_PRIORITY+1; i++ )
-       {
-               list = &gaActiveThreads[i];
-       #else
-               list = &gActiveThreads;
-       #endif
-               for(thread=list->Head;thread;thread=thread->Next)
-               {
-                       Log(" %p %i (%i) - %s (CPU %i)",
-                               thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
-                       if(thread->Status != THREAD_STAT_ACTIVE)
-                               Log("  ERROR State (%i) != THREAD_STAT_ACTIVE (%i)",
-                                       thread->Status, THREAD_STAT_ACTIVE);
-                       Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
-                       Log("  KStack 0x%x", thread->KernelStack);
-                       if( thread->bInstrTrace )
-                               Log("  Tracing Enabled");
-                       Proc_DumpThreadCPUState(thread);
-               }
-       
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-       }
-       #endif
-}
-
-/**
- * \fn void Threads_Dump(void)
- * \brief Dumps a list of currently running threads
- */
-void Threads_Dump(void)
-{
-       tThread *thread;
-       
-       Log("--- Thread Dump ---");
-       Threads_DumpActive();
-       
-       Log("All Threads:");
-       for(thread=gAllThreads;thread;thread=thread->GlobalNext)
-       {
-               Log(" %p %i (%i) - %s (CPU %i)",
-                       thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
-               Log("  State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
-               switch(thread->Status)
-               {
-               case THREAD_STAT_MUTEXSLEEP:
-                       Log("  Mutex Pointer: %p", thread->WaitPointer);
-                       break;
-               case THREAD_STAT_SEMAPHORESLEEP:
-                       Log("  Semaphore Pointer: %p", thread->WaitPointer);
-                       Log("  Semaphore Name: %s:%s", 
-                               ((tSemaphore*)thread->WaitPointer)->ModName,
-                               ((tSemaphore*)thread->WaitPointer)->Name
-                               );
-                       break;
-               case THREAD_STAT_ZOMBIE:
-                       Log("  Return Status: %i", thread->RetStatus);
-                       break;
-               default:        break;
-               }
-               Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
-               Log("  KStack 0x%x", thread->KernelStack);
-               if( thread->bInstrTrace )
-                       Log("  Tracing Enabled");
-               Proc_DumpThreadCPUState(thread);
-       }
-}
-
-/**
- * \brief Gets the next thread to run
- * \param CPU  Current CPU
- * \param Last The thread the CPU was running
- */
-tThread *Threads_GetNextToRun(int CPU, tThread *Last)
-{
-       tThread *thread;
-       
-       // If this CPU has the lock, we must let it complete
-       if( CPU_HAS_LOCK( &glThreadListLock ) )
-               return Last;
-       
-       // Don't change threads if the current CPU has switches disabled
-       if( gaThreads_NoTaskSwitch[CPU] )
-               return Last;
-
-       // Lock thread list
-       SHORTLOCK( &glThreadListLock );
-       
-       // Make sure the current (well, old) thread is marked as de-scheduled   
-       if(Last)        Last->CurCPU = -1;
-
-       // No active threads, just take a nap
-       if(giNumActiveThreads == 0) {
-               SHORTREL( &glThreadListLock );
-               #if DEBUG_TRACE_TICKETS
-               Log("No active threads");
-               #endif
-               return NULL;
-       }
-
-       #if 0   
-       #if SCHEDULER_TYPE != SCHED_RR_PRI
-       // Special case: 1 thread
-       if(giNumActiveThreads == 1) {
-               if( gActiveThreads.Head->CurCPU == -1 )
-                       gActiveThreads.Head->CurCPU = CPU;
-               
-               SHORTREL( &glThreadListLock );
-               
-               if( gActiveThreads.Head->CurCPU == CPU )
-                       return gActiveThreads.Head;
-               
-               return NULL;    // CPU has nothing to do
-       }
-       #endif
-       #endif  
-
-       // Allow the old thread to be scheduled again
-       if( Last ) {
-               if( Last->Status == THREAD_STAT_ACTIVE ) {
-                       tThreadList     *list;
-                       #if SCHEDULER_TYPE == SCHED_LOTTERY
-                       giFreeTickets += caiTICKET_COUNTS[ Last->Priority ];
-                       # if DEBUG_TRACE_TICKETS
-                       LogF("Log: CPU%i released %p (%i %s) into the pool (%i [+%i] tickets in pool)\n",
-                               CPU, Last, Last->TID, Last->ThreadName, giFreeTickets,
-                               caiTICKET_COUNTS[ Last->Priority ]);
-                       # endif
-                       #endif
-                       
-                       #if SCHEDULER_TYPE == SCHED_RR_PRI
-                       list = &gaActiveThreads[ Last->Priority ];
-                       #else
-                       list = &gActiveThreads;
-                       #endif
-                       // Add to end of list
-                       Threads_int_AddToList( list, Last );
-               }
-               #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
-               else
-                       LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released,not in pool)\n",
-                               CPU, Last, Last->TID, Last->ThreadName, Last->Status);
-               #endif
-               Last->CurCPU = -1;
-       }
-       
-       // ---
-       // Lottery Scheduler
-       // ---
-       #if SCHEDULER_TYPE == SCHED_LOTTERY
-       {
-                int    ticket, number;
-               # if 1
-               number = 0;
-               for(thread = gActiveThreads.Head; thread; thread = thread->Next)
-               {
-                       if(thread->Status != THREAD_STAT_ACTIVE)
-                               Panic("Bookkeeping fail - %p %i(%s) is on the active queue with a status of %i",
-                                       thread, thread->TID, thread->ThreadName, thread->Status);
-                       if(thread->Next == thread) {
-                               Panic("Bookkeeping fail - %p %i(%s) loops back on itself",
-                                       thread, thread->TID, thread->ThreadName, thread->Status);
-                       }
-                       number += caiTICKET_COUNTS[ thread->Priority ];
-               }
-               if(number != giFreeTickets) {
-                       Panic("Bookkeeping fail (giFreeTickets(%i) != number(%i)) - CPU%i",
-                               giFreeTickets, number, CPU);
-               }
-               # endif
-               
-               // No free tickets (all tasks delegated to cores)
-               if( giFreeTickets == 0 ) {
-                       SHORTREL(&glThreadListLock);
-                       return NULL;
-               }
-               
-               // Get the ticket number
-               ticket = number = rand() % giFreeTickets;
-               
-               // Find the next thread
-               for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
-               {
-                       if( caiTICKET_COUNTS[ thread->Priority ] > number)      break;
-                       number -= caiTICKET_COUNTS[ thread->Priority ];
-               }
-               
-               // If we didn't find a thread, something went wrong
-               if(thread == NULL)
-               {
-                       number = 0;
-                       for(thread=gActiveThreads;thread;thread=thread->Next) {
-                               if(thread->CurCPU >= 0) continue;
-                               number += caiTICKET_COUNTS[ thread->Priority ];
-                       }
-                       Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
-                               giFreeTickets, number);
-               }
-
-               // Remove
-               if(prev)
-                       prev->Next = thread->Next;
-               else
-                       gActiveThreads.Head = thread->Next;
-               if(!thread->Next)
-                       gActiveThreads.Tail = prev;             
-
-               giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ];
-               # if DEBUG_TRACE_TICKETS
-               LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n",
-                       CPU, thread, thread->TID, thread->ThreadName,
-                       giFreeTickets, caiTICKET_COUNTS[ thread->Priority ]);
-               # endif
-       }
-       
-       // ---
-       // Priority based round robin scheduler
-       // ---
-       #elif SCHEDULER_TYPE == SCHED_RR_PRI
-       {
-                int    i;
-               thread = NULL;
-               for( i = 0; i < MIN_PRIORITY + 1; i ++ )
-               {
-                       if( !gaActiveThreads[i].Head )
-                               continue ;
-       
-                       thread = gaActiveThreads[i].Head;
-                       
-                       // Remove from head
-                       gaActiveThreads[i].Head = thread->Next;
-                       if(!thread->Next)
-                               gaActiveThreads[i].Tail = NULL;
-                       thread->Next = NULL;
-                       break;
-               }
-               
-               // Anything to do?
-               if( !thread ) {
-                       SHORTREL(&glThreadListLock);
-                       return NULL;
-               }
-               if( thread->Status != THREAD_STAT_ACTIVE ) {
-                       LogF("Oops, Thread %i (%s) is not active\n", thread->TID, thread->ThreadName);
-               }
-       }
-       #elif SCHEDULER_TYPE == SCHED_RR_SIM
-       {
-               // Get the next thread off the list
-               thread = gActiveThreads.Head;   
-               gActiveThreads.Head = thread->Next;
-               if(!thread->Next)
-                       gaActiveThreads.Tail = NULL;
-               thread->Next = NULL;
-               
-               // Anything to do?
-               if( !thread ) {
-                       SHORTREL(&glThreadListLock);
-                       return NULL;
-               }
-       }
-       #else
-       # error "Unimplemented scheduling algorithm"
-       #endif
-       
-       // Make the new thread non-schedulable
-       thread->CurCPU = CPU;
-       thread->Remaining = thread->Quantum;
-       
-       SHORTREL( &glThreadListLock );
-       
-       return thread;
-}
-
-// === EXPORTS ===
-EXPORT(Threads_GetUID);
-EXPORT(Threads_GetGID);
diff --git a/Kernel/time.c b/Kernel/time.c
deleted file mode 100644 (file)
index 2c83fa3..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Acess 2
- * - By John Hodge (thePowersGang) 
- *
- * Timer Code
- */
-#include <acess.h>
-#include <timers.h>
-#include <events.h>
-#include <hal_proc.h>  // Proc_GetCurThread
-
-// === CONSTANTS ===
-#define        NUM_TIMERS      8
-
-// === TYPEDEFS ===
-struct sTimer {
-       tTimer  *Next;
-       Sint64  FiresAfter;
-       void    (*Callback)(void*);
-       void    *Argument;
-};
-
-// === PROTOTYPES ===
-void   Timer_CallTimers(void);
-
-// === GLOBALS ===
-volatile Uint64        giTicks = 0;
-volatile Sint64        giTimestamp = 0;
-volatile Uint64        giPartMiliseconds = 0;
-tTimer *gTimers;       // TODO: Replace by a ring-list timer
-
-// === CODE ===
-/**
- * \fn void Timer_CallTimers()
- */
-void Timer_CallTimers()
-{
-       while( gTimers && gTimers->FiresAfter < now() )
-       {
-               tTimer  *next;
-       
-               if( gTimers->Callback )
-                       gTimers->Callback(gTimers->Argument);
-               else
-                       Threads_PostEvent(gTimers->Argument, THREAD_EVENT_TIMER);
-               
-               next = gTimers->Next;
-               free(gTimers);
-               gTimers = next;
-       }
-}
-
-/**
- * \brief Schedule an action
- */
-tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument)
-{
-       tTimer  *ret;
-       tTimer  *t, *p;
-       
-       if(Callback == NULL)
-               Argument = Proc_GetCurThread();
-
-       // TODO: Use a pool instead?
-       ret = malloc(sizeof(tTimer));
-       
-       ret->Callback = Callback;
-       ret->FiresAfter = now() + Delta;
-       ret->Argument = Argument;
-
-       // Add into list (sorted)
-       for( p = (tTimer*)&gTimers, t = gTimers; t; p = t, t = t->Next )
-       {
-               if( t->FiresAfter > ret->FiresAfter )   break;
-       }
-       ret->Next = t;
-       p->Next = ret;
-
-       return ret;
-}
-
-/**
- * \brief Delete a timer
- */
-void Time_RemoveTimer(tTimer *Timer)
-{
-       tTimer  *t, *p;
-       for( p = (tTimer*)&gTimers, t = gTimers; t; p = t, t = t->Next )
-       {
-               if( t == Timer )
-               {
-                       p->Next = t->Next;
-                       free(Timer);
-                       return ;
-               }
-       }
-}
-
-/**
- * \fn void Time_Delay(int Delay)
- * \brief Delay for a small ammount of time
- */
-void Time_Delay(int Delay)
-{
-//     tTime   dest = now() + Delay;
-//     while(dest > now())     Threads_Yield();
-       Time_CreateTimer(Delay, NULL, NULL);
-       Threads_WaitEvents(THREAD_EVENT_TIMER);
-}
-
-// === EXPORTS ===
-EXPORT(Time_CreateTimer);
-EXPORT(Time_RemoveTimer);
-EXPORT(Time_Delay);
diff --git a/Kernel/vfs/acls.c b/Kernel/vfs/acls.c
deleted file mode 100644 (file)
index ab88b98..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/* 
- * Acess Micro VFS
- */
-#include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
-
-// === GLOBALS ===
-tVFS_ACL       gVFS_ACL_EveryoneRWX = { {1,-1}, {0,VFS_PERM_ALL} };
-tVFS_ACL       gVFS_ACL_EveryoneRW = { {1,-1}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE} };
-tVFS_ACL       gVFS_ACL_EveryoneRX = { {1,-1}, {0,VFS_PERM_READ|VFS_PERM_EXECUTE} };
-tVFS_ACL       gVFS_ACL_EveryoneRO = { {1,-1}, {0,VFS_PERM_READ} };
-
-// === CODE ===
-/**
- * \fn int VFS_CheckACL(tVFS_Node *Node, Uint Permissions)
- * \brief Checks the permissions on a file
- */
-int VFS_CheckACL(tVFS_Node *Node, Uint Permissions)
-{
-        int    i;
-        int    uid = Threads_GetUID();
-        int    gid = Threads_GetGID();
-       
-       // Root can do anything
-       if(uid == 0)    return 1;
-       
-       // Root only file?, fast return
-       if( Node->NumACLs == 0 ) {
-               Log("VFS_CheckACL - %p inaccesable, NumACLs = 0, uid=%i", Node, uid);
-               return 0;
-       }
-       
-       // Check Deny Permissions
-       for(i=0;i<Node->NumACLs;i++)
-       {
-               if(!Node->ACLs[i].Inv)  continue;       // Ignore ALLOWs
-               if(Node->ACLs[i].ID != 0x7FFFFFFF)
-               {
-                       if(!Node->ACLs[i].Group && Node->ACLs[i].ID != uid)     continue;
-                       if(Node->ACLs[i].Group && Node->ACLs[i].ID != gid)      continue;
-               }
-               
-               //Log("Deny %x", Node->ACLs[i].Perms);
-               
-               if(Node->ACLs[i].Perms & Permissions) {
-                       Log("VFS_CheckACL - %p inaccesable, %x denied",
-                               Node, Node->ACLs[i].Perms & Permissions);
-                       return 0;
-               }
-       }
-       
-       // Check for allow permissions
-       for(i=0;i<Node->NumACLs;i++)
-       {
-               if(Node->ACLs[i].Inv)   continue;       // Ignore DENYs
-               if(Node->ACLs[i].ID != 0x7FFFFFFF)
-               {
-                       if(!Node->ACLs[i].Group && Node->ACLs[i].ID != uid)     continue;
-                       if(Node->ACLs[i].Group && Node->ACLs[i].ID != gid)      continue;
-               }
-               
-               //Log("Allow %x", Node->ACLs[i].Perms);
-               
-               if((Node->ACLs[i].Perms & Permissions) == Permissions)  return 1;
-       }
-       
-       Log("VFS_CheckACL - %p inaccesable, %x not allowed", Node, Permissions);
-       return 0;
-}
-/**
- * \fn int VFS_GetACL(int FD, tVFS_ACL *Dest)
- */
-int VFS_GetACL(int FD, tVFS_ACL *Dest)
-{
-        int    i;
-       tVFS_Handle     *h = VFS_GetHandle(FD);
-       
-       // Error check
-       if(!h) {
-               return -1;
-       }
-       
-       // Root can do anything
-       if(Dest->Group == 0 && Dest->ID == 0) {
-               Dest->Inv = 0;
-               Dest->Perms = -1;
-               return 1;
-       }
-       
-       // Root only file?, fast return
-       if( h->Node->NumACLs == 0 ) {
-               Dest->Inv = 0;
-               Dest->Perms = 0;
-               return 0;
-       }
-       
-       // Check Deny Permissions
-       for(i=0;i<h->Node->NumACLs;i++)
-       {
-               if(h->Node->ACLs[i].Group != Dest->Group)       continue;
-               if(h->Node->ACLs[i].ID != Dest->ID)     continue;
-               
-               Dest->Inv = h->Node->ACLs[i].Inv;
-               Dest->Perms = h->Node->ACLs[i].Perms;
-               return 1;
-       }
-       
-       
-       Dest->Inv = 0;
-       Dest->Perms = 0;
-       return 0;
-}
-
-/**
- * \fn tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
- * \brief Converts UNIX permissions to three Acess ACL entries
- */
-tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
-{
-       tVFS_ACL        *ret = malloc(sizeof(tVFS_ACL)*3);
-       
-       // Error Check
-       if(!ret)        return NULL;
-       
-       // Owner
-       ret[0].Group = 0;       ret[0].ID = Owner;
-       ret[0].Inv = 0;         ret[0].Perms = 0;
-       if(Mode & 0400) ret[0].Perms |= VFS_PERM_READ;
-       if(Mode & 0200) ret[0].Perms |= VFS_PERM_WRITE;
-       if(Mode & 0100) ret[0].Perms |= VFS_PERM_EXECUTE;
-       
-       // Group
-       ret[1].Group = 1;       ret[1].ID = Group;
-       ret[1].Inv = 0;         ret[1].Perms = 0;
-       if(Mode & 0040) ret[1].Perms |= VFS_PERM_READ;
-       if(Mode & 0020) ret[1].Perms |= VFS_PERM_WRITE;
-       if(Mode & 0010) ret[1].Perms |= VFS_PERM_EXECUTE;
-       
-       // Global
-       ret[2].Group = 1;       ret[2].ID = -1;
-       ret[2].Inv = 0;         ret[2].Perms = 0;
-       if(Mode & 0004) ret[2].Perms |= VFS_PERM_READ;
-       if(Mode & 0002) ret[2].Perms |= VFS_PERM_WRITE;
-       if(Mode & 0001) ret[2].Perms |= VFS_PERM_EXECUTE;
-       
-       // Return buffer
-       return ret;
-}
-
-// === EXPORTS ===
-// --- Variables ---
-EXPORTV(gVFS_ACL_EveryoneRWX);
-EXPORTV(gVFS_ACL_EveryoneRW);
-EXPORTV(gVFS_ACL_EveryoneRX);
-// --- Functions ---
-EXPORT(VFS_UnixToAcessACL);
diff --git a/Kernel/vfs/dir.c b/Kernel/vfs/dir.c
deleted file mode 100644 (file)
index d4c1530..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Acess2 VFS
- * - Directory Management Functions
- */
-#define DEBUG  0
-#include <acess.h>
-#include <vfs.h>
-#include <vfs_int.h>
-
-// === IMPORTS ===
-extern tVFS_Mount      *gRootMount;
-
-// === PROTOTYPES ===
-#if 0
- int   VFS_MkDir(const char *Path);
- int   VFS_MkNod(const char *Path, Uint Flags);
- int   VFS_Symlink(const char *Name, const char *Link);
-#endif
-
-// === CODE ===
-/**
- * \fn int VFS_MkDir(char *Path)
- * \brief Create a new node
- * \param Path Path of directory to create
- */
-int VFS_MkDir(const char *Path)
-{
-       return VFS_MkNod(Path, VFS_FFLAG_DIRECTORY);
-}
-
-/**
- * \fn int VFS_MkNod(char *Path, Uint Flags)
- * \brief Create a new node in a directory
- * \param Path Path of new node
- * \param Flags        Flags to apply to the node
- */
-int VFS_MkNod(const char *Path, Uint Flags)
-{
-       char    *absPath, *name;
-        int    pos = 0, oldpos = 0;
-        int    next = 0;
-       tVFS_Node       *parent;
-        int    ret;
-       
-       ENTER("sPath xFlags", Path, Flags);
-       
-       absPath = VFS_GetAbsPath(Path);
-       LOG("absPath = '%s'", absPath);
-       
-       while( (next = strpos(&absPath[pos+1], '/')) != -1 ) {
-               LOG("next = %i", next);
-               pos += next+1;
-               LOG("pos = %i", pos);
-               oldpos = pos;
-       }
-       absPath[oldpos] = '\0'; // Mutilate path
-       name = &absPath[oldpos+1];
-       
-       LOG("absPath = '%s', name = '%s'", absPath, name);
-       
-       // Check for root
-       if(absPath[0] == '\0')
-               parent = VFS_ParsePath("/", NULL, NULL);
-       else
-               parent = VFS_ParsePath(absPath, NULL, NULL);
-       
-       LOG("parent = %p", parent);
-       
-       if(!parent) {
-               LEAVE('i', -1);
-               return -1;      // Error Check
-       }
-       
-       // Permissions Check
-       if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
-               _CloseNode(parent);
-               free(absPath);
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       LOG("parent = %p", parent);
-       
-       if(!parent->Type || !parent->Type->MkNod) {
-               Warning("VFS_MkNod - Directory has no MkNod method");
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       // Create node
-       ret = parent->Type->MkNod(parent, name, Flags);
-       
-       // Free allocated string
-       free(absPath);
-       
-       // Free Parent
-       _CloseNode(parent);
-       
-       // Error Check
-       if(ret == 0) {
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \fn int VFS_Symlink(const char *Name, const char *Link)
- * \brief Creates a symlink called \a Name to \a Link
- * \param Name Name of symbolic link
- * \param Link Destination of symbolic link
- */
-int VFS_Symlink(const char *Name, const char *Link)
-{
-       char    *realLink;
-        int    fp;
-       
-       ENTER("sName sLink", Name, Link);
-       
-       // Get absolue path name
-       realLink = VFS_GetAbsPath( Link );
-       if(!realLink) {
-               Log_Warning("VFS", "Path '%s' is badly formed", Link);
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       LOG("realLink = '%s'", realLink);
-
-       // Make node
-       if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
-               Log_Warning("VFS", "Unable to create link node '%s'", Name);
-               free(realLink);
-               LEAVE('i', -2);
-               return -2;      // Make link node
-       }
-       
-       // Write link address
-       fp = VFS_Open(Name, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_NOLINK);
-       VFS_Write(fp, strlen(realLink), realLink);
-       VFS_Close(fp);
-       
-       free(realLink);
-       
-       LEAVE('i', 1);
-       return 1;
-}
-
-/**
- * \fn int VFS_ReadDir(int FD, char *Dest)
- * \brief Read from a directory
- */
-int VFS_ReadDir(int FD, char *Dest)
-{
-       tVFS_Handle     *h = VFS_GetHandle(FD);
-       char    *tmp;
-       
-       //ENTER("ph pDest", h, Dest);
-       
-       if(!h || !h->Node->Type || !h->Node->Type->ReadDir) {
-               //LEAVE('i', 0);
-               return 0;
-       }
-       
-       if(h->Node->Size != -1 && h->Position >= h->Node->Size) {
-               //LEAVE('i', 0);
-               return 0;
-       }
-       
-       do {
-               tmp = h->Node->Type->ReadDir(h->Node, h->Position);
-               if((Uint)tmp < (Uint)VFS_MAXSKIP)
-                       h->Position += (Uint)tmp;
-               else
-                       h->Position ++;
-       } while(tmp != NULL && (Uint)tmp < (Uint)VFS_MAXSKIP);
-       
-       //LOG("tmp = '%s'", tmp);
-       
-       if(!tmp) {
-               //LEAVE('i', 0);
-               return 0;
-       }
-       
-       strcpy(Dest, tmp);
-       free(tmp);
-       
-       //LEAVE('i', 1);
-       return 1;
-}
diff --git a/Kernel/vfs/fs/devfs.c b/Kernel/vfs/fs/devfs.c
deleted file mode 100644 (file)
index b3f4a57..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Acess 2
- * Device Filesystem (DevFS)
- * - vfs/fs/devfs.c
- */
-#include <acess.h>
-#include <vfs.h>
-#include <fs_devfs.h>
-
-// === PROTOTYPES ===
-#if 0
- int   DevFS_AddDevice(tDevFS_Driver *Device);
-void   DevFS_DelDevice(tDevFS_Driver *Device);
-#endif
-tVFS_Node      *DevFS_InitDevice(const char *Device, const char **Options);
-char   *DevFS_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *DevFS_FindDir(tVFS_Node *Node, const char *Name);
-
-// === GLOBALS ===
-tVFS_Driver    gDevFS_Info = {
-       "devfs", 0, DevFS_InitDevice, NULL, NULL
-       };
-tVFS_NodeType  gDevFS_DirType = {
-       .TypeName = "DevFS-Dir",
-       .ReadDir = DevFS_ReadDir,
-       .FindDir = DevFS_FindDir
-       };
-tVFS_Node      gDevFS_RootNode = {
-       .Size = 0,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Type = &gDevFS_DirType
-       };
-tDevFS_Driver  *gDevFS_Drivers = NULL;
- int   giDevFS_NextID = 1;
-tShortSpinlock glDevFS_ListLock;
-
-// === CODE ===
-/**
- * \fn int DevFS_AddDevice(tDevFS_Driver *Device)
- */
-int DevFS_AddDevice(tDevFS_Driver *Device)
-{
-        int    ret = 0;
-       tDevFS_Driver   *dev;
-       
-       SHORTLOCK( &glDevFS_ListLock );
-       
-       // Check if the device is already registered or the name is taken
-       for( dev = gDevFS_Drivers; dev; dev = dev->Next )
-       {
-               if(dev == Device)       break;
-               if(strcmp(dev->Name, Device->Name) == 0)        break;
-       }
-       
-       if(dev) {
-               if(dev == Device)
-                       Log_Warning("DevFS", "Device %p '%s' attempted to register itself twice",
-                               dev, dev->Name);
-               else
-                       Log_Warning("DevFS", "Device %p attempted to register '%s' which was owned by %p",
-                               Device, dev->Name, dev);
-               ret = 0;        // Error
-       }
-       else {
-               Device->Next = gDevFS_Drivers;
-               gDevFS_Drivers = Device;
-               gDevFS_RootNode.Size ++;
-               ret = giDevFS_NextID ++;
-       }
-       SHORTREL( &glDevFS_ListLock );
-       
-       return ret;
-}
-
-/**
- * \brief Delete a device from the DevFS folder
- */
-void DevFS_DelDevice(tDevFS_Driver *Device)
-{
-       tDevFS_Driver   *prev = NULL, *dev;
-       
-       SHORTLOCK( &glDevFS_ListLock );
-       // Search list for device
-       for(dev = gDevFS_Drivers;
-               dev && dev != Device;
-               prev = dev, dev = dev->Next
-               );
-       
-       // Check if it was found
-       if(dev)
-       {
-               if(prev)
-                       prev->Next = Device->Next;
-               else
-                       gDevFS_Drivers = Device->Next;
-       }
-       else
-               Log_Warning("DevFS", "Attempted to unregister device %p '%s' which was not registered",
-                       Device, Device->Name);
-       
-       SHORTREL( &glDevFS_ListLock );
-}
-
-/**
- * \brief Initialise the DevFS and detect double-mounting, or just do nothing
- * \note STUB
- */
-tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options)
-{
-       return &gDevFS_RootNode;
-}
-
-/**
- * \fn char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
- */
-char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tDevFS_Driver   *dev;
-       
-       if(Pos < 0)     return NULL;
-       
-       for(dev = gDevFS_Drivers;
-               dev && Pos--;
-               dev = dev->Next
-               );
-       
-       if(dev)
-               return strdup(dev->Name);
-       else
-               return NULL;
-}
-
-/**
- * \fn tVFS_Node *DevFS_FindDir(tVFS_Node *Node, const char *Name)
- * \brief Get an entry from the devices directory
- */
-tVFS_Node *DevFS_FindDir(tVFS_Node *Node, const char *Name)
-{
-       tDevFS_Driver   *dev;
-       
-       //ENTER("pNode sName", Node, Name);
-       
-       for(dev = gDevFS_Drivers;
-               dev;
-               dev = dev->Next
-               )
-       {
-               //LOG("dev = %p", dev);
-               //LOG("dev->Name = '%s'", dev->Name);
-               if(strcmp(dev->Name, Name) == 0) {
-                       //LEAVE('p', &dev->RootNode);
-                       return &dev->RootNode;
-               }
-       }
-       
-       //LEAVE('n');
-       return NULL;
-}
-
-// --- EXPORTS ---
-EXPORT(DevFS_AddDevice);
-EXPORT(DevFS_DelDevice);
diff --git a/Kernel/vfs/fs/root.c b/Kernel/vfs/fs/root.c
deleted file mode 100644 (file)
index 9fa1732..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/* 
- * AcessMicro VFS
- * - Root Filesystem Driver
- */
-#define DEBUG  0
-#include <acess.h>
-#include <vfs.h>
-#include <vfs_ramfs.h>
-
-// === CONSTANTS ===
-#define MAX_FILES      64
-#define        MAX_FILE_SIZE   1024
-
-// === PROTOTYPES ===
-tVFS_Node      *Root_InitDevice(const char *Device, const char **Options);
- int   Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
-tVFS_Node      *Root_FindDir(tVFS_Node *Node, const char *Name);
-char   *Root_ReadDir(tVFS_Node *Node, int Pos);
-Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
-tRamFS_File    *Root_int_AllocFile(void);
-
-// === GLOBALS ===
-tVFS_Driver    gRootFS_Info = {
-       "rootfs", 0, Root_InitDevice, NULL, NULL
-       };
-tRamFS_File    RootFS_Files[MAX_FILES];
-tVFS_ACL       RootFS_DirACLs[3] = {
-       {{0,0}, {0,VFS_PERM_ALL}},      // Owner (Root)
-       {{1,0}, {0,VFS_PERM_ALL}},      // Group (Root)
-       {{0,-1}, {0,VFS_PERM_ALL^VFS_PERM_WRITE}}       // World (Nobody)
-};
-tVFS_ACL       RootFS_FileACLs[3] = {
-       {{0,0}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE}},     // Owner (Root)
-       {{1,0}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE}},     // Group (Root)
-       {{0,-1}, {0,VFS_PERM_READ}}     // World (Nobody)
-};
-tVFS_NodeType  gRootFS_DirType = {
-       .TypeName = "RootFS-Dir",
-       .ReadDir = Root_ReadDir,
-       .FindDir = Root_FindDir,
-       .MkNod = Root_MkNod
-};
-tVFS_NodeType  gRootFS_FileType = {
-       .TypeName = "RootFS-File",
-       .Read = Root_Read,
-       .Write = Root_Write,
-};
-
-// === CODE ===
-/**
- * \brief Initialise the root filesystem
- */
-tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
-{
-       tRamFS_File     *root;
-       if(strcmp(Device, "root") != 0) {
-               return NULL;
-       }
-       
-       // Create Root Node
-       root = &RootFS_Files[0];
-       
-       root->Node.ImplPtr = root;
-       
-       root->Node.CTime
-               = root->Node.MTime
-               = root->Node.ATime = now();
-       root->Node.NumACLs = 3;
-       root->Node.ACLs = RootFS_DirACLs;
-
-       root->Node.Type = &gRootFS_DirType;
-       
-       return &root->Node;
-}
-
-/**
- * \fn int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
- * \brief Create an entry in the root directory
- */
-int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
-{
-       tRamFS_File     *parent = Node->ImplPtr;
-       tRamFS_File     *child;
-       tRamFS_File     *prev = (tRamFS_File *) &parent->Data.FirstChild;
-       
-       ENTER("pNode sName xFlags", Node, Name, Flags);
-       
-       LOG("%i > %i", strlen(Name)+1, sizeof(child->Name));
-       if(strlen(Name) + 1 > sizeof(child->Name))
-               LEAVE_RET('i', 0);
-       
-       // Find last child, while we're at it, check for duplication
-       for( child = parent->Data.FirstChild; child; prev = child, child = child->Next )
-       {
-               if(strcmp(child->Name, Name) == 0) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-       }
-       
-       child = Root_int_AllocFile();
-       memset(child, 0, sizeof(tRamFS_File));
-       
-       strcpy(child->Name, Name);
-       
-       child->Parent = parent;
-       child->Next = NULL;
-       child->Data.FirstChild = NULL;
-       
-       child->Node.ImplPtr = child;
-       child->Node.Flags = Flags;
-       child->Node.NumACLs = 3;
-       child->Node.Size = 0;
-       
-       if(Flags & VFS_FFLAG_DIRECTORY)
-       {
-               child->Node.ACLs = RootFS_DirACLs;
-               child->Node.Type = &gRootFS_DirType;
-       } else {
-               if(Flags & VFS_FFLAG_SYMLINK)
-                       child->Node.ACLs = RootFS_DirACLs;
-               else
-                       child->Node.ACLs = RootFS_FileACLs;
-               child->Node.Type = &gRootFS_FileType;
-       }
-       
-       prev->Next = child;
-       
-       parent->Node.Size ++;
-       
-       LEAVE('i', 1);
-       return 1;
-}
-
-/**
- * \fn tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
- * \brief Find an entry in the filesystem
- */
-tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
-{
-       tRamFS_File     *parent = Node->ImplPtr;
-       tRamFS_File     *child = parent->Data.FirstChild;
-       
-       //Log("Root_FindDir: (Node=%p, Name='%s')", Node, Name);
-       
-       for(;child;child = child->Next)
-       {
-               //Log(" Root_FindDir: strcmp('%s', '%s')", child->Node.Name, Name);
-               if(strcmp(child->Name, Name) == 0)      return &child->Node;
-       }
-       
-       return NULL;
-}
-
-/**
- * \fn char *Root_ReadDir(tVFS_Node *Node, int Pos)
- * \brief Get an entry from the filesystem
- */
-char *Root_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tRamFS_File     *parent = Node->ImplPtr;
-       tRamFS_File     *child = parent->Data.FirstChild;
-       
-       for( ; child && Pos--; child = child->Next ) ;
-       
-       if(child)       return strdup(child->Name);
-       
-       return NULL;
-}
-
-/**
- * \fn Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from a file in the root directory
- */
-Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tRamFS_File     *file = Node->ImplPtr;
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       if(Offset > Node->Size) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       if(Length > Node->Size) Length = Node->Size;
-       
-       if(Offset+Length > Node->Size)
-               Length = Node->Size - Offset;
-       
-       memcpy(Buffer, file->Data.Bytes+Offset, Length);
-       LOG("Buffer = '%.*s'", (int)Length, Buffer);
-
-       LEAVE('i', Length);
-       return Length;
-}
-
-/**
- * \fn Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Write to a file in the root directory
- */
-Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tRamFS_File     *file = Node->ImplPtr;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
-       if(Offset > Node->Size) {
-               LEAVE('i', -1);
-               return -1;
-       }       
-
-       if(Offset + Length > MAX_FILE_SIZE)
-       {
-               Length = MAX_FILE_SIZE - Offset;
-       }
-
-       LOG("Buffer = '%.*s'", (int)Length, Buffer);
-       
-       // Check if buffer needs to be expanded
-       if(Offset + Length > Node->Size)
-       {
-               void *tmp = realloc( file->Data.Bytes, Offset + Length );
-               if(tmp == NULL) {
-                       Warning("Root_Write - Increasing buffer size failed");
-                       LEAVE('i', -1);
-                       return -1;
-               }
-               file->Data.Bytes = tmp;
-               Node->Size = Offset + Length;
-               LOG("Expanded buffer to %i bytes", (int)Node->Size);
-       }
-       
-       memcpy(file->Data.Bytes+Offset, Buffer, Length);
-       LOG("File - '%.*s'", Node->Size, file->Data.Bytes);
-       
-       LEAVE('i', Length);
-       return Length;
-}
-
-/**
- * \fn tRamFS_File *Root_int_AllocFile(void)
- * \brief Allocates a file from the pool
- */
-tRamFS_File *Root_int_AllocFile(void)
-{
-        int    i;
-       for( i = 0; i < MAX_FILES; i ++ )
-       {
-               if( RootFS_Files[i].Name[0] == '\0' )
-               {
-                       return &RootFS_Files[i];
-               }
-       }
-       return NULL;
-}
diff --git a/Kernel/vfs/handle.c b/Kernel/vfs/handle.c
deleted file mode 100644 (file)
index d22f965..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Acess2 VFS
- * - AllocHandle, GetHandle
- */
-#define DEBUG  0
-#include <acess.h>
-#include <mm_virt.h>
-#include "vfs.h"
-#include "vfs_int.h"
-#include "vfs_ext.h"
-#include <threads.h>   // GetMaxFD
-#include <vfs_threads.h>       // Handle maintainance
-
-// === CONSTANTS ===
-#define MAX_KERNEL_FILES       128
-
-// === PROTOTYPES ===
-#if 0
-tVFS_Handle    *VFS_GetHandle(int FD);
-#endif
- int   VFS_AllocHandle(int FD, tVFS_Node *Node, int Mode);
-
-// === GLOBALS ===
-tVFS_Handle    *gaUserHandles = (void*)MM_PPD_HANDLES;
-tVFS_Handle    *gaKernelHandles = (void*)MM_KERNEL_VFS;
-
-// === CODE ===
-/**
- * \fn tVFS_Handle *VFS_GetHandle(int FD)
- * \brief Gets a pointer to the handle information structure
- */
-tVFS_Handle *VFS_GetHandle(int FD)
-{
-       tVFS_Handle     *h;
-       
-       //Log_Debug("VFS", "VFS_GetHandle: (FD=0x%x)", FD);
-       
-       if(FD < 0)      return NULL;
-       
-       if(FD & VFS_KERNEL_FLAG) {
-               FD &= (VFS_KERNEL_FLAG - 1);
-               if(FD >= MAX_KERNEL_FILES)      return NULL;
-               h = &gaKernelHandles[ FD ];
-       } else {
-               if(FD >= *Threads_GetMaxFD())   return NULL;
-               h = &gaUserHandles[ FD ];
-       }
-       
-       if(h->Node == NULL)     return NULL;
-       //Log_Debug("VFS", "VFS_GetHandle: RETURN %p", h);
-       return h;
-}
-
-int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
-{
-        int    i;
-       
-       // Check for a user open
-       if(bIsUser)
-       {
-                int    max_handles = *Threads_GetMaxFD();
-               // Allocate Buffer
-               if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
-               {
-                       Uint    addr, size;
-                       size = max_handles * sizeof(tVFS_Handle);
-                       for(addr = 0; addr < size; addr += 0x1000)
-                       {
-                               if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
-                               {
-                                       Warning("OOM - VFS_AllocHandle");
-                                       Threads_Exit(0, 0xFF);  // Terminate user
-                               }
-                       }
-                       memset( gaUserHandles, 0, size );
-               }
-               // Get a handle
-               for( i = 0; i < max_handles; i ++ )
-               {
-                       if(gaUserHandles[i].Node)       continue;
-                       gaUserHandles[i].Node = Node;
-                       gaUserHandles[i].Position = 0;
-                       gaUserHandles[i].Mode = Mode;
-                       return i;
-               }
-       }
-       else
-       {
-               // Allocate space if not already
-               if( MM_GetPhysAddr( (tVAddr)gaKernelHandles ) == 0 )
-               {
-                       Uint    addr, size;
-                       size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
-                       for(addr = 0; addr < size; addr += 0x1000)
-                       {
-                               if( !MM_Allocate( (tVAddr)gaKernelHandles + addr ) )
-                               {
-                                       Panic("OOM - VFS_AllocHandle");
-                                       Threads_Exit(0, 0xFF);  // Terminate application (get some space back)
-                               }
-                       }
-                       memset( gaKernelHandles, 0, size );
-               }
-               // Get a handle
-               for(i=0;i<MAX_KERNEL_FILES;i++)
-               {
-                       if(gaKernelHandles[i].Node)     continue;
-                       gaKernelHandles[i].Node = Node;
-                       gaKernelHandles[i].Position = 0;
-                       gaKernelHandles[i].Mode = Mode;
-                       return i|VFS_KERNEL_FLAG;
-               }
-       }
-       
-       return -1;
-}
-
-void VFS_ReferenceUserHandles(void)
-{
-        int    i;
-        int    max_handles = *Threads_GetMaxFD();
-
-       // Check if this process has any handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
-               return ;
-       
-       for( i = 0; i < max_handles; i ++ )
-       {
-               tVFS_Handle     *h;
-               h = &gaUserHandles[i];
-               if( !h->Node )
-                       continue ;
-               if( h->Node->Type && h->Node->Type->Reference )
-                       h->Node->Type->Reference( h->Node );
-       }
-}
-
-void VFS_CloseAllUserHandles(void)
-{
-        int    i;
-        int    max_handles = *Threads_GetMaxFD();
-
-       // Check if this process has any handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
-               return ;
-       
-       for( i = 0; i < max_handles; i ++ )
-       {
-               tVFS_Handle     *h;
-               h = &gaUserHandles[i];
-               if( !h->Node )
-                       continue ;
-               if( h->Node->Type && h->Node->Type->Close )
-                       h->Node->Type->Close( h->Node );
-       }
-}
-
-/**
- * \brief Take a backup of a set of file descriptors
- */
-void *VFS_SaveHandles(int NumFDs, int *FDs)
-{
-       tVFS_Handle     *ret;
-        int    i;
-        int    max_handles = *Threads_GetMaxFD();
-       
-       // Check if this process has any handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
-               return NULL;
-
-       // Allocate
-       ret = malloc( NumFDs * sizeof(tVFS_Handle) );
-       if( !ret )
-               return NULL;    
-
-       if( NumFDs > max_handles )
-               NumFDs = max_handles;
-
-       // Take copies of the handles
-       for( i = 0; i < NumFDs; i ++ )
-       {
-               tVFS_Handle     *h;
-               if( FDs == NULL )
-                       h = &gaUserHandles[i];
-               else {
-                       h = VFS_GetHandle(FDs[i] & (VFS_KERNEL_FLAG - 1));
-                       if(!h) {
-                               Log_Warning("VFS", "VFS_SaveHandles - Invalid FD %i",
-                                       FDs[i] & (VFS_KERNEL_FLAG - 1) );
-                               free(ret);
-                               return NULL;
-                       }
-               }
-               memcpy( &ret[i], h, sizeof(tVFS_Handle) );
-               
-               // Reference node
-               if( !h->Node )
-                       continue ;
-               if( h->Node->Type && h->Node->Type->Reference )
-                       h->Node->Type->Reference( h->Node );
-       }       
-
-       return ret;
-}
-
-void VFS_RestoreHandles(int NumFDs, void *Handles)
-{
-       tVFS_Handle     *handles = Handles;
-        int    i;
-
-       // NULL = nothing to do
-       if( !Handles )
-               return ;        
-
-       // Check if there is already a set of handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
-               return ;
-       
-       
-       // Allocate user handle area
-       {
-               Uint    addr, size;
-                int    max_handles = *Threads_GetMaxFD();
-               size = max_handles * sizeof(tVFS_Handle);
-               for(addr = 0; addr < size; addr += 0x1000)
-               {
-                       if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
-                       {
-                               Warning("OOM - VFS_AllocHandle");
-                               Threads_Exit(0, 0xFF);  // Terminate user
-                       }
-               }
-               memset( gaUserHandles, 0, size );
-       }
-       
-       // Restore handles
-       memcpy( gaUserHandles, handles, NumFDs * sizeof(tVFS_Handle) );
-       // Reference when copied
-       for( i = 0; i < NumFDs; i ++ )
-       {
-               tVFS_Handle     *h = &handles[i];
-       
-               if( !h->Node )
-                       continue ;
-               if( h->Node->Type && h->Node->Type->Reference )
-                       h->Node->Type->Reference( h->Node );
-       }
-}
-
-void VFS_FreeSavedHandles(int NumFDs, void *Handles)
-{
-       tVFS_Handle     *handles = Handles;
-        int    i;
-
-       // NULL = nothing to do
-       if( !Handles )
-               return ;        
-       
-       // Dereference all saved nodes
-       for( i = 0; i < NumFDs; i ++ )
-       {
-               tVFS_Handle     *h = &handles[i];
-       
-               if( !h->Node )
-                       continue ;
-               if( h->Node->Type && h->Node->Type->Close )
-                       h->Node->Type->Close( h->Node );
-       }
-       free( Handles );
-}
diff --git a/Kernel/vfs/io.c b/Kernel/vfs/io.c
deleted file mode 100644 (file)
index e7a2a06..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * AcessMicro VFS
- * - File IO Passthru's
- */
-#define DEBUG  0
-#include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
-
-// === CODE ===
-/**
- * \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
- * \brief Read data from a node (file)
- */
-Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
-{
-       tVFS_Handle     *h;
-       Uint64  ret;
-       
-       ENTER("iFD XLength pBuffer", FD, Length, Buffer);
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  LEAVE_RET('i', -1);
-       
-       if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
-               LEAVE_RET('i', -1);
-
-       if(!h->Node->Type || !h->Node->Type->Read)      LEAVE_RET('i', 0);
-       
-       ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
-       if(ret == -1)   LEAVE_RET('i', -1);
-       
-       h->Position += ret;
-       LEAVE('X', ret);
-       return ret;
-}
-
-/**
- * \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read data from a given offset (atomic)
- */
-Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tVFS_Handle     *h;
-       Uint64  ret;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-       
-       if( !(h->Mode & VFS_OPENFLAG_READ) )    return -1;
-       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
-
-       if( !h->Node->Type || !h->Node->Type->Read) {
-               Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
-               return 0;
-       }
-       ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
-       if(ret == -1)   return -1;
-       return ret;
-}
-
-/**
- * \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
- * \brief Read data from a node (file)
- */
-Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
-{
-       tVFS_Handle     *h;
-       Uint64  ret;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-       
-       if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
-       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
-
-       if( !h->Node->Type || !h->Node->Type->Write )   return 0;
-       
-       ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
-       if(ret == -1)   return -1;
-
-       h->Position += ret;
-       return ret;
-}
-
-/**
- * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
- * \brief Write data to a file at a given offset
- */
-Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tVFS_Handle     *h;
-       Uint64  ret;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-       
-       if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
-       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
-
-       if(!h->Node->Type || !h->Node->Type->Write)     return 0;
-       ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
-
-       if(ret == -1)   return -1;
-       return ret;
-}
-
-/**
- * \fn Uint64 VFS_Tell(int FD)
- * \brief Returns the current file position
- */
-Uint64 VFS_Tell(int FD)
-{
-       tVFS_Handle     *h;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-       
-       return h->Position;
-}
-
-/**
- * \fn int VFS_Seek(int FD, Sint64 Offset, int Whence)
- * \brief Seek to a new location
- * \param FD   File descriptor
- * \param Offset       Where to go
- * \param Whence       From where
- */
-int VFS_Seek(int FD, Sint64 Offset, int Whence)
-{
-       tVFS_Handle     *h;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-       
-       //Log_Debug("VFS", "VFS_Seek: (fd=0x%x, Offset=0x%llx, Whence=%i)",
-       //      FD, Offset, Whence);
-       
-       // Set relative to current position
-       if(Whence == 0) {
-               h->Position += Offset;
-               return 0;
-       }
-       
-       // Set relative to end of file
-       if(Whence < 0) {
-               if( h->Node->Size == -1 )       return -1;
-
-               h->Position = h->Node->Size - Offset;
-               return 0;
-       }
-       
-       // Set relative to start of file
-       h->Position = Offset;
-       return 0;
-}
-
-/**
- * \fn int VFS_IOCtl(int FD, int ID, void *Buffer)
- * \brief Call an IO Control on a file
- */
-int VFS_IOCtl(int FD, int ID, void *Buffer)
-{
-       tVFS_Handle     *h;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-
-       if(!h->Node->Type || !h->Node->Type->IOCtl)     return -1;
-       return h->Node->Type->IOCtl(h->Node, ID, Buffer);
-}
-
-/**
- * \fn int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
- * \brief Retrieve file information
- * \return Number of ACLs stored
- */
-int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
-{
-       tVFS_Handle     *h;
-        int    max;
-       
-       h = VFS_GetHandle(FD);
-       if(!h)  return -1;
-
-       if( h->Mount )
-               Dest->mount = h->Mount->Identifier;
-       else
-               Dest->mount = 0;
-       Dest->inode = h->Node->Inode;   
-       Dest->uid = h->Node->UID;
-       Dest->gid = h->Node->GID;
-       Dest->size = h->Node->Size;
-       Dest->atime = h->Node->ATime;
-       Dest->ctime = h->Node->MTime;
-       Dest->mtime = h->Node->CTime;
-       Dest->numacls = h->Node->NumACLs;
-       
-       Dest->flags = 0;
-       if(h->Node->Flags & VFS_FFLAG_DIRECTORY)        Dest->flags |= 0x10;
-       if(h->Node->Flags & VFS_FFLAG_SYMLINK)  Dest->flags |= 0x20;
-       
-       max = (MaxACLs < h->Node->NumACLs) ? MaxACLs : h->Node->NumACLs;
-       memcpy(&Dest->acls, h->Node->ACLs, max*sizeof(tVFS_ACL));
-       
-       return max;
-}
-
-// === EXPORTS ===
-EXPORT(VFS_Read);
-EXPORT(VFS_Write);
-EXPORT(VFS_ReadAt);
-EXPORT(VFS_WriteAt);
-EXPORT(VFS_IOCtl);
-EXPORT(VFS_Seek);
-EXPORT(VFS_Tell);
diff --git a/Kernel/vfs/main.c b/Kernel/vfs/main.c
deleted file mode 100644 (file)
index 5ff0e7c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* 
- * Acess 2
- * Virtual File System
- */
-#include <acess.h>
-#include <fs_sysfs.h>
-#include <threads.h>
-#include <vfs.h>
-#include <vfs_int.h>
-#include <vfs_ext.h>
-
-// === IMPORTS ===
-extern tVFS_Driver     gRootFS_Info;
-extern tVFS_Driver     gDevFS_Info;
-
-// === PROTOTYPES ===
-#if 0
- int   VFS_Init(void);
-char   *VFS_GetTruePath(const char *Path);
-void   VFS_GetMemPath(char *Dest, void *Base, Uint Length);
-tVFS_Driver    *VFS_GetFSByName(const char *Name);
- int   VFS_AddDriver(tVFS_Driver *Info);
-#endif
-void   VFS_UpdateDriverFile(void);
-
-// === EXPORTS ===
-EXPORT(VFS_AddDriver);
-
-// === GLOBALS ===
-tVFS_Node      NULLNode = {0};
-tShortSpinlock slDriverListLock;
-tVFS_Driver    *gVFS_Drivers = NULL;
-char   *gsVFS_DriverFile = NULL;
- int   giVFS_DriverFileID = 0;
-
-char   *gsVFS_MountFile = NULL;
- int   giVFS_MountFileID = 0;
-
-// === CODE ===
-/**
- * \fn int VFS_Init(void)
- * \brief Initialises the VFS for use by the kernel and user
- */
-int VFS_Init(void)
-{
-       // Core Drivers
-       gVFS_Drivers = &gRootFS_Info;
-       gVFS_Drivers->Next = &gDevFS_Info;
-       VFS_UpdateDriverFile();
-       
-       // Register with SysFS
-       giVFS_MountFileID = SysFS_RegisterFile("VFS/Mounts", NULL, 0);
-       giVFS_DriverFileID = SysFS_RegisterFile("VFS/Drivers", NULL, 0);
-       
-       if( VFS_Mount("root", "/", "rootfs", "") != 0 ) {
-               Log_KernelPanic("VFS", "Unable to mount root (Where the **** is rootfs?)");
-               return -1;
-       }
-       VFS_MkDir("/Devices");
-       VFS_MkDir("/Mount");
-       VFS_Mount("dev", "/Devices", "devfs", "");
-               
-       Log_Debug("VFS", "Setting max files");
-       *Threads_GetMaxFD() = 32;
-       return 0;
-}
-
-/**
- * \fn char *VFS_GetTruePath(const char *Path)
- * \brief Gets the true path (non-symlink) of a file
- */
-char *VFS_GetTruePath(const char *Path)
-{
-       tVFS_Node       *node;
-       char    *ret, *tmp;
-       
-       tmp = VFS_GetAbsPath(Path);
-       if(tmp == NULL) return NULL;
-       //Log(" VFS_GetTruePath: tmp = '%s'", tmp);
-       node = VFS_ParsePath(tmp, &ret, NULL);
-       free(tmp);
-       //Log(" VFS_GetTruePath: node=%p, ret='%s'", node, ret);
-       
-       if(!node)       return NULL;
-       if(node->Type->Close)   node->Type->Close(node);
-       
-       return ret;
-}
-
-/**
- * \fn void VFS_GetMemPath(char *Dest, void *Base, Uint Length)
- * \brief Create a VFS memory pointer path
- */
-void VFS_GetMemPath(char *Dest, void *Base, Uint Length)
-{
-       Dest[0] = '$';
-       itoa( &Dest[1], (tVAddr)Base, 16, BITS/4, '0' );
-       Dest[BITS/4+1] = ':';
-       itoa( &Dest[BITS/4+2], Length, 16, BITS/4, '0' );
-       Dest[BITS/2+2] = '\0';
-}
-
-/**
- * \fn tVFS_Driver *VFS_GetFSByName(const char *Name)
- * \brief Gets a filesystem structure given a name
- */
-tVFS_Driver *VFS_GetFSByName(const char *Name)
-{
-       tVFS_Driver     *drv = gVFS_Drivers;
-       
-       for(;drv;drv=drv->Next)
-       {
-//             Log("strcmp('%s' (%p), '%s') == 0?", drv->Name, drv->Name, Name);
-               if(strcmp(drv->Name, Name) == 0)
-                       return drv;
-       }
-       return NULL;
-}
-
-/**
- * \fn int VFS_AddDriver(tVFS_Driver *Info)
- */
-int VFS_AddDriver(tVFS_Driver *Info)
-{
-       if(!Info)       return  -1;
-       
-       SHORTLOCK( &slDriverListLock );
-       Info->Next = gVFS_Drivers;
-       gVFS_Drivers = Info;
-       SHORTREL( &slDriverListLock );
-       
-       VFS_UpdateDriverFile();
-       
-       return 0;
-}
-
-/**
- * \fn void VFS_UpdateDriverFile(void)
- * \brief Updates the driver list file
- */
-void VFS_UpdateDriverFile(void)
-{
-       tVFS_Driver     *drv;
-        int    len = 0;
-       char    *buf;
-       
-       // Format:
-       // <name>\n
-       for( drv = gVFS_Drivers; drv; drv = drv->Next )
-       {
-               len += 1 + strlen(drv->Name);
-       }
-       buf = malloc(len+1);
-       len = 0;
-       for( drv = gVFS_Drivers; drv; drv = drv->Next )
-       {
-               strcpy( &buf[len], drv->Name );
-               len += strlen(drv->Name);
-               buf[len++] = '\n';
-       }
-       buf[len] = '\0';
-       
-       SysFS_UpdateFile( giVFS_DriverFileID, buf, len );
-       if(gsVFS_DriverFile)    free(gsVFS_DriverFile);
-       gsVFS_DriverFile = buf;
-}
diff --git a/Kernel/vfs/memfile.c b/Kernel/vfs/memfile.c
deleted file mode 100644 (file)
index 14b3948..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* 
- * Acess 2
- * Virtual File System
- * - Memory Pseudo Files
- */
-#include <acess.h>
-#include <vfs.h>
-
-// === PROTOTYPES ===
-tVFS_Node      *VFS_MemFile_Create(const char *Path);
-void   VFS_MemFile_Close(tVFS_Node *Node);
-Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
-
-// === GLOBALS ===
-tVFS_NodeType  gVFS_MemFileType = {
-       .Close = VFS_MemFile_Close,
-       .Read = VFS_MemFile_Read,
-       .Write = VFS_MemFile_Write
-       };
-
-// === CODE ===
-/**
- * \fn tVFS_Node *VFS_MemFile_Create(const char *Path)
- */
-tVFS_Node *VFS_MemFile_Create(const char *Path)
-{
-       Uint    base, size;
-       const char      *str = Path;
-       tVFS_Node       *ret;
-       
-       str++;  // Eat '$'
-       
-       // Read Base address
-       base = 0;
-       for( ; ('0' <= *str && *str <= '9') || ('A' <= *str && *str <= 'F'); str++ )
-       {
-               base *= 16;
-               if('A' <= *str && *str <= 'F')
-                       base += *str - 'A' + 10;
-               else
-                       base += *str - '0';
-       }
-       
-       // Check separator
-       if(*str++ != ':')       return NULL;
-       
-       // Read buffer size
-       size = 0;
-       for( ; ('0' <= *str && *str <= '9') || ('A' <= *str && *str <= 'F'); str++ )
-       {
-               size *= 16;
-               if('A' <= *str && *str <= 'F')
-                       size += *str - 'A' + 10;
-               else
-                       size += *str - '0';
-       }
-       
-       // Check for NULL byte
-       if(*str != '\0')        return NULL;
-       
-       // Allocate and fill node
-       ret = malloc(sizeof(tVFS_Node));
-       memset(ret, 0, sizeof(tVFS_Node));
-       
-       // State
-       ret->ImplPtr = (void*)base;
-       ret->Size = size;
-       
-       // ACLs
-       ret->NumACLs = 1;
-       ret->ACLs = &gVFS_ACL_EveryoneRWX;
-       
-       // Functions
-       ret->Type = &gVFS_MemFileType;
-       
-       return ret;
-}
-
-/**
- * \fn void VFS_MemFile_Close(tVFS_Node *Node)
- * \brief Dereference and clean up a memory file
- */
-void VFS_MemFile_Close(tVFS_Node *Node)
-{
-       Node->ReferenceCount --;
-       if( Node->ReferenceCount == 0 ) {
-               Node->ImplPtr = NULL;
-               free(Node);
-       }
-}
-
-/**
- * \fn Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from a memory file
- */
-Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       // Check for use of free'd file
-       if(Node->ImplPtr == NULL)       return 0;
-       
-       // Check for out of bounds read
-       if(Offset > Node->Size) return 0;
-       
-       // Truncate data read if needed
-       if(Offset + Length > Node->Size)
-               Length = Node->Size - Offset;
-       
-       // Copy Data
-       memcpy(Buffer, (Uint8*)Node->ImplPtr + Offset, Length);
-       
-       return Length;
-}
-
-/**
- * \fn Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Write to a memory file
- */
-Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       // Check for use of free'd file
-       if(Node->ImplPtr == NULL)       return 0;
-       
-       // Check for out of bounds read
-       if(Offset > Node->Size) return 0;
-       
-       // Truncate data read if needed
-       if(Offset + Length > Node->Size)
-               Length = Node->Size - Offset;
-       
-       // Copy Data
-       memcpy((Uint8*)Node->ImplPtr + Offset, Buffer, Length);
-       
-       return Length;
-}
diff --git a/Kernel/vfs/mmap.c b/Kernel/vfs/mmap.c
deleted file mode 100644 (file)
index 9fe9282..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Acess2 Kernel VFS
- * - By John Hodge (thePowersGang)
- *
- * mmap.c
- * - VFS_MMap support
- */
-#define DEBUG  0
-#include <acess.h>
-#include <vfs.h>
-#include <vfs_ext.h>
-#include <vfs_int.h>
-
-#define MMAP_PAGES_PER_BLOCK   16
-
-// === STRUCTURES ===
-typedef struct sVFS_MMapPageBlock      tVFS_MMapPageBlock;
-struct sVFS_MMapPageBlock
-{
-       tVFS_MMapPageBlock      *Next;
-       Uint64  BaseOffset;     // Must be a multiple of MMAP_PAGES_PER_BLOCK*PAGE_SIZE
-       tPAddr  PhysAddrs[MMAP_PAGES_PER_BLOCK];
-};
-
-// === CODE ===
-void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset)
-{
-       tVFS_Handle     *h;
-       tVAddr  mapping_dest, mapping_base;
-        int    npages, pagenum;
-       tVFS_MMapPageBlock      *pb, *prev;
-
-       ENTER("pDestHint iLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset);
-
-       if( Flags & MMAP_MAP_ANONYMOUS )
-               Offset = (tVAddr)DestHint & 0xFFF;
-       
-       npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
-       pagenum = Offset / PAGE_SIZE;
-
-       mapping_base = (tVAddr)DestHint;
-       mapping_dest = mapping_base & ~(PAGE_SIZE-1);
-
-       // TODO: Locate space for the allocation
-
-       // Handle anonymous mappings
-       if( Flags & MMAP_MAP_ANONYMOUS )
-       {
-               size_t  ofs = 0;
-               LOG("%i pages anonymous to %p", npages, mapping_dest);
-               for( ; npages --; mapping_dest += PAGE_SIZE, ofs += PAGE_SIZE )
-               {
-                       if( MM_GetPhysAddr(mapping_dest) ) {
-                               // TODO: Set flags to COW if needed (well, if shared)
-                               MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
-                               LOG("clear from %p, %i bytes", (void*)(mapping_base + ofs),
-                                       PAGE_SIZE - (mapping_base & (PAGE_SIZE-1))
-                                       );
-                               memset( (void*)(mapping_base + ofs), 0, PAGE_SIZE - (mapping_base & (PAGE_SIZE-1)));
-                       }
-                       else {
-                               LOG("New empty page");
-                               // TODO: Map a COW zero page instead
-                               if( !MM_Allocate(mapping_dest) ) {
-                                       // TODO: Error
-                                       Log_Warning("VFS", "VFS_MMap: Anon alloc to %p failed", mapping_dest);
-                               }
-                               memset((void*)mapping_dest, 0, PAGE_SIZE);
-                               LOG("Anon map to %p", mapping_dest);
-                       }
-               }
-               LEAVE_RET('p', (void*)mapping_base);
-       }
-
-       h = VFS_GetHandle(FD);
-       if( !h || !h->Node )    LEAVE_RET('n', NULL);
-
-       LOG("h = %p", h);
-       
-       Mutex_Acquire( &h->Node->Lock );
-
-       // Search for existing mapping for each page
-       // - Sorted list of 16 page blocks
-       for(
-               pb = h->Node->MMapInfo, prev = NULL;
-               pb && pb->BaseOffset + MMAP_PAGES_PER_BLOCK < pagenum;
-               prev = pb, pb = pb->Next
-               );
-
-       LOG("pb = %p, pb->BaseOffset = %X", pb, pb ? pb->BaseOffset : 0);
-
-       // - Allocate a block if needed
-       if( !pb || pb->BaseOffset > pagenum )
-       {
-               void    *old_pb = pb;
-               pb = malloc( sizeof(tVFS_MMapPageBlock) );
-               if(!pb) {
-                       Mutex_Release( &h->Node->Lock );
-                       LEAVE_RET('n', NULL);
-               }
-               pb->Next = old_pb;
-               pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK;
-               memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
-               if(prev)
-                       prev->Next = pb;
-               else
-                       h->Node->MMapInfo = pb;
-       }
-
-       // - Map (and allocate) pages
-       while( npages -- )
-       {
-               if( MM_GetPhysAddr(mapping_dest) == 0 )
-               {
-                       if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
-                       {
-                               tVFS_NodeType   *nt = h->Node->Type;
-                               if( !nt ) 
-                               {
-                                       // TODO: error
-                               }
-                               else if( nt->MMap )
-                                       nt->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
-                               else
-                               {
-                                        int    read_len;
-                                       // Allocate pages and read data
-                                       if( MM_Allocate(mapping_dest) == 0 ) {
-                                               // TODO: Unwrap
-                                               Mutex_Release( &h->Node->Lock );
-                                               LEAVE('n');
-                                               return NULL;
-                                       }
-                                       // TODO: Clip read length
-                                       read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
-//                                     if( read_len != PAGE_SIZE ) {
-//                                             memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
-//                                     }
-                               }
-                               pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
-                               MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node );
-                               MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
-                               LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
-                                       pb->PhysAddrs[pagenum - pb->BaseOffset]);
-                       }
-                       else
-                       {
-                               MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] );
-                               MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
-                               LOG("Cached map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
-                                       pb->PhysAddrs[pagenum - pb->BaseOffset]);
-                       }
-                       h->Node->ReferenceCount ++;
-               
-                       // Set flags
-                       if( !(Protection & MMAP_PROT_WRITE) ) {
-                               MM_SetFlags(mapping_dest, MM_PFLAG_RO, MM_PFLAG_RO);
-                       }
-                       else {
-                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
-                       }
-                       
-                       if( Protection & MMAP_PROT_EXEC ) {
-                               MM_SetFlags(mapping_dest, MM_PFLAG_EXEC, MM_PFLAG_EXEC);
-                       }
-                       else {
-                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_EXEC);
-                       }
-               }
-               else
-               {
-                       LOG("Flag update on %p", mapping_dest);
-                       if( (MM_GetFlags(mapping_dest) & MM_PFLAG_RO) && (Protection & MMAP_PROT_WRITE) )
-                       {
-                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
-                       }
-               }
-               if( Flags & MMAP_MAP_PRIVATE )
-                       MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
-               pagenum ++;
-               mapping_dest += PAGE_SIZE;
-
-               // Roll on to next block if needed
-               if(pagenum - pb->BaseOffset == MMAP_PAGES_PER_BLOCK)
-               {
-                       if( pb->Next && pb->Next->BaseOffset == pagenum )
-                               pb = pb->Next;
-                       else
-                       {
-                               tVFS_MMapPageBlock      *oldpb = pb;
-                               pb = malloc( sizeof(tVFS_MMapPageBlock) );
-                               pb->Next = oldpb->Next;
-                               pb->BaseOffset = pagenum;
-                               memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
-                               oldpb->Next = pb;
-                       }
-                       pagenum = 0;
-               }
-       }
-       
-       Mutex_Release( &h->Node->Lock );
-
-       LEAVE('p', mapping_base);
-       return (void*)mapping_base;
-}
-
-int VFS_MUnmap(void *Addr, size_t Length)
-{
-       return 0;
-}
diff --git a/Kernel/vfs/mount.c b/Kernel/vfs/mount.c
deleted file mode 100644 (file)
index 1773218..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/* 
- * Acess Micro - VFS Server version 1
- */
-#include <acess.h>
-#include <vfs.h>
-#include <vfs_int.h>
-#include <fs_sysfs.h>
-
-// === IMPORTS ===
-extern int     giVFS_MountFileID;
-extern char    *gsVFS_MountFile;
-
-// === PROTOTYPES ===
-#if 0
- int   VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
-#endif
-void   VFS_UpdateMountFile(void);
-
-// === GLOBALS ===
-tMutex glVFS_MountList;
-tVFS_Mount     *gVFS_Mounts;
-tVFS_Mount     *gVFS_RootMount = NULL;
-Uint32 giVFS_NextMountIdent = 1;
-
-// === CODE ===
-/**
- * \brief Mount a device
- * \param Device       Device string to mount
- * \param MountPoint   Destination for the mount
- * \param Filesystem   Filesystem to use for the mount
- * \param Options              Options to be passed to the filesystem
- * \return -1 on Invalid FS, -2 on No Mem, 0 on success
- * 
- * Mounts the filesystem on \a Device at \a MountPoint using the driver
- * \a Filesystem. The options in the string \a Options is passed to the
- * driver's mount.
- */
-int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
-{
-       tVFS_Mount      *mnt;
-       tVFS_Driver     *fs;
-        int    deviceLen = strlen(Device);
-        int    mountLen = strlen(MountPoint);
-        int    argLen = strlen(Options);
-       
-       // Get the filesystem
-       fs = VFS_GetFSByName(Filesystem);
-       if(!fs) {
-               Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
-               return -1;
-       }
-       
-       // Create mount information
-       mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
-       if(!mnt) {
-               return -2;
-       }
-       
-       // HACK: Forces VFS_ParsePath to fall back on root  
-       if(mountLen == 1 && MountPoint[0] == '/')
-               mnt->MountPointLen = 0;
-       else
-               mnt->MountPointLen = mountLen;
-       
-       // Fill Structure
-       mnt->Filesystem = fs;
-       
-       mnt->Device = &mnt->StrData[0];
-       memcpy( mnt->Device, Device, deviceLen+1 );
-       
-       mnt->MountPoint = &mnt->StrData[deviceLen+1];
-       memcpy( mnt->MountPoint, MountPoint, mountLen+1 );
-       
-       mnt->Options = &mnt->StrData[deviceLen+1+mountLen+1];
-       memcpy( mnt->Options, Options, argLen+1 );
-       
-       // Initialise Volume
-       mnt->RootNode = fs->InitDevice(Device, NULL);   //&ArgString);
-       if(!mnt->RootNode) {
-               free(mnt);
-               return -2;
-       }
-
-       mnt->Identifier = giVFS_NextMountIdent++;
-       #if 0
-       // Ensure identifiers don't repeat
-       // - Only a problem if there have been 4 billion mounts
-       while( giVFS_NextMountIdent == 0 || VFS_GetMountByIdent(giVFS_NextMountIdent) )
-               giVFS_NextMountIdent ++;
-       #endif
-       
-       // Set root
-       if(!gVFS_RootMount)     gVFS_RootMount = mnt;
-       
-       // Add to mount list
-       Mutex_Acquire( &glVFS_MountList );
-       {
-               tVFS_Mount      *tmp;
-               mnt->Next = NULL;
-               if(gVFS_Mounts) {
-                       for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
-                       tmp->Next = mnt;
-               }
-               else {
-                       gVFS_Mounts = mnt;
-               }
-       }
-       Mutex_Release( &glVFS_MountList );
-       
-       Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
-       
-       VFS_UpdateMountFile();
-       
-       return 0;
-}
-
-/**
- * \brief Gets a mount point given the identifier
- */
-tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
-{
-       tVFS_Mount      *mnt;
-       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
-       {
-               if(mnt->Identifier == MountID)
-                       return mnt;
-       }
-       return NULL;
-}
-
-/**
- * \brief Updates the mount file buffer
- * 
- * Updates the ProcFS mounts file buffer to match the current mounts list.
- */
-void VFS_UpdateMountFile(void)
-{
-        int    len = 0;
-       char    *buf;
-       tVFS_Mount      *mnt;
-       
-       // Format:
-       // <device>\t<location>\t<type>\t<options>\n
-       
-       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
-       {
-               len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
-                       + strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
-       }
-       
-       buf = malloc( len + 1 );
-       len = 0;
-       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
-       {
-               strcpy( &buf[len], mnt->Device );
-               len += strlen(mnt->Device);
-               buf[len++] = '\t';
-               
-               strcpy( &buf[len], mnt->MountPoint );
-               len += strlen(mnt->MountPoint);
-               buf[len++] = '\t';
-               
-               strcpy( &buf[len], mnt->Filesystem->Name );
-               len += strlen(mnt->Filesystem->Name);
-               buf[len++] = '\t';
-               
-               strcpy( &buf[len], mnt->Options );
-               len += strlen(mnt->Options);
-               buf[len++] = '\n';
-       }
-       buf[len] = 0;
-       
-       SysFS_UpdateFile( giVFS_MountFileID, buf, len );
-       if( gsVFS_MountFile )   free( gsVFS_MountFile );
-       gsVFS_MountFile = buf;
-}
diff --git a/Kernel/vfs/nodecache.c b/Kernel/vfs/nodecache.c
deleted file mode 100644 (file)
index d2796c1..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * AcessMicro VFS
- * - File IO Passthru's
- */
-#include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
-
-// === TYPES ===
-typedef struct sCachedInode {
-       struct sCachedInode     *Next;
-       tVFS_Node       Node;
-} tCachedInode;
-typedef struct sInodeCache {
-       struct sInodeCache      *Next;
-        int    Handle;
-       tCachedInode    *FirstNode;     // Sorted List
-       Uint64  MaxCached;              // Speeds up Searching
-} tInodeCache;
-
-// === PROTOTYPES ===
-tInodeCache    *Inode_int_GetFSCache(int Handle);
-
-// === GLOBALS ===
- int   gVFS_NextInodeHandle = 1;
-tShortSpinlock glVFS_InodeCache;
-tInodeCache    *gVFS_InodeCache = NULL;
-
-// === CODE ===
-/**
- * \fn int Inode_GetHandle()
- */
-int Inode_GetHandle()
-{
-       tInodeCache     *ent;
-       
-       ent = malloc( sizeof(tInodeCache) );
-       ent->MaxCached = 0;
-       ent->Handle = gVFS_NextInodeHandle++;
-       ent->Next = NULL;       ent->FirstNode = NULL;
-       
-       // Add to list
-       SHORTLOCK( &glVFS_InodeCache );
-       ent->Next = gVFS_InodeCache;
-       gVFS_InodeCache = ent;
-       SHORTREL( &glVFS_InodeCache );
-       
-       return gVFS_NextInodeHandle-1;
-}
-
-/**
- * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
- * \brief Gets a node from the cache
- */
-tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
-{
-       tInodeCache     *cache;
-       tCachedInode    *ent;
-       
-       cache = Inode_int_GetFSCache(Handle);
-       if(!cache)      return NULL;
-       
-       if(Inode > cache->MaxCached)    return NULL;
-       
-       // Search Cache
-       ent = cache->FirstNode;
-       for( ; ent; ent = ent->Next )
-       {
-               if(ent->Node.Inode < Inode)     continue;
-               if(ent->Node.Inode > Inode)     return NULL;
-               ent->Node.ReferenceCount ++;
-               return &ent->Node;
-       }
-       
-       return NULL;    // Should never be reached
-}
-
-/**
- * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
- */
-tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
-{
-       tInodeCache     *cache;
-       tCachedInode    *newEnt, *ent, *prev;
-       
-       cache = Inode_int_GetFSCache(Handle);
-       if(!cache)      return NULL;
-       
-       if(Node->Inode > cache->MaxCached)
-               cache->MaxCached = Node->Inode;
-       
-       // Search Cache
-       ent = cache->FirstNode;
-       prev = (tCachedInode*) &cache->FirstNode;
-       for( ; ent; prev = ent, ent = ent->Next )
-       {
-               if(ent->Node.Inode < Node->Inode)       continue;
-               if(ent->Node.Inode == Node->Inode) {
-                       ent->Node.ReferenceCount ++;
-                       return &ent->Node;
-               }
-               break;
-       }
-       
-       // Create new entity
-       newEnt = malloc(sizeof(tCachedInode));
-       newEnt->Next = ent;
-       memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
-       prev->Next = newEnt;
-               
-       return &newEnt->Node;
-}
-
-/**
- * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
- * \brief Dereferences/Removes a cached node
- */
-void Inode_UncacheNode(int Handle, Uint64 Inode)
-{
-       tInodeCache     *cache;
-       tCachedInode    *ent, *prev;
-       
-       cache = Inode_int_GetFSCache(Handle);
-       if(!cache)      return ;
-       
-       if(Inode > cache->MaxCached)    return ;
-       
-       // Search Cache
-       ent = cache->FirstNode;
-       prev = (tCachedInode*) &cache->FirstNode;       // Special case removal
-       for( ; ent; prev = ent, ent = ent->Next )
-       {
-               if(ent->Node.Inode < Inode)     continue;
-               if(ent->Node.Inode > Inode)     return;
-               ent->Node.ReferenceCount --;
-               // Check if node needs to be freed
-               if(ent->Node.ReferenceCount == 0)
-               {
-                       prev->Next = ent->Next;
-                       if(ent->Node.Inode == cache->MaxCached)
-                       {
-                               if(ent != cache->FirstNode)
-                                       cache->MaxCached = prev->Node.Inode;
-                               else
-                                       cache->MaxCached = 0;
-                       }
-                               
-                       free(ent);
-               }
-               return ;
-       }
-       
-       return ;
-}
-
-/**
- * \fn void Inode_ClearCache(int Handle)
- * \brief Removes a cache
- */
-void Inode_ClearCache(int Handle)
-{
-       tInodeCache     *cache;
-       tInodeCache     *prev = NULL;
-       tCachedInode    *ent, *next;
-       
-       // Find the cache
-       for(
-               cache = gVFS_InodeCache;
-               cache && cache->Handle < Handle;
-               prev = cache, cache = cache->Next
-               );
-       if(!cache || cache->Handle != Handle)   return;
-       
-       // Search Cache
-       ent = cache->FirstNode;
-       while( ent )
-       {
-               ent->Node.ReferenceCount = 1;
-               next = ent->Next;
-               
-               if(ent->Node.Type && ent->Node.Type->Close)
-                       ent->Node.Type->Close( &ent->Node );
-               free(ent);
-               
-               ent = next;
-       }
-       
-       // Free Cache
-       if(prev == NULL)
-               gVFS_InodeCache = cache->Next;
-       else
-               prev->Next = cache->Next;
-       free(cache);
-}
-
-/**
- * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
- * \brief Gets a cache given it's handle
- */
-tInodeCache *Inode_int_GetFSCache(int Handle)
-{
-       tInodeCache     *cache = gVFS_InodeCache;
-       // Find Cache
-       for( ; cache; cache = cache->Next )
-       {
-               if(cache->Handle > Handle)      continue;
-               if(cache->Handle < Handle) {
-                       Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
-                       return NULL;
-               }
-               break;
-       }
-       if(!cache) {
-               Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
-               return NULL;
-       }
-       
-       return cache;
-}
diff --git a/Kernel/vfs/open.c b/Kernel/vfs/open.c
deleted file mode 100644 (file)
index 1536d1a..0000000
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
- * Acess2 VFS
- * - Open, Close and ChDir
- */
-#define DEBUG  0
-#include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
-#include "vfs_ext.h"
-#include <threads.h>
-
-// === CONSTANTS ===
-#define        OPEN_MOUNT_ROOT 1
-#define MAX_PATH_SLASHES       256
-#define MAX_NESTED_LINKS       4
-#define MAX_PATH_LEN   255
-
-// === IMPORTS ===
-extern tVFS_Mount      *gVFS_RootMount;
-extern int     VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode);
-extern tVFS_Node       *VFS_MemFile_Create(const char *Path);
-
-// === PROTOTYPES ===
- int   VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode );
-
-// === CODE ===
-/**
- * \fn char *VFS_GetAbsPath(const char *Path)
- * \brief Create an absolute path from a relative one
- */
-char *VFS_GetAbsPath(const char *Path)
-{
-       char    *ret;
-        int    pathLen = strlen(Path);
-       char    *pathComps[MAX_PATH_SLASHES];
-       char    *tmpStr;
-       int             iPos = 0;
-       int             iPos2 = 0;
-       const char      *chroot = *Threads_GetChroot();
-        int    chrootLen;
-       const char      *cwd = *Threads_GetCWD();
-        int    cwdLen;
-       
-       ENTER("sPath", Path);
-       
-       // Memory File
-       if(Path[0] == '$') {
-               ret = malloc(strlen(Path)+1);
-               if(!ret) {
-                       Log_Warning("VFS", "VFS_GetAbsPath: malloc() returned NULL");
-                       return NULL;
-               }
-               strcpy(ret, Path);
-               LEAVE('p', ret);
-               return ret;
-       }
-       
-       // - Fetch ChRoot
-       if( chroot == NULL )
-               chroot = "";
-       chrootLen = strlen(chroot);
-       
-       // Check if the path is already absolute
-       if(Path[0] == '/') {
-               ret = malloc(chrootLen + pathLen + 1);
-               if(!ret) {
-                       Log_Warning("VFS", "VFS_GetAbsPath: malloc() returned NULL");
-                       return NULL;
-               }
-               strcpy(ret + chrootLen, Path);
-       }
-       else {
-               if(cwd == NULL) {
-                       cwd = "/";
-                       cwdLen = 1;
-               }
-               else {
-                       cwdLen = strlen(cwd);
-               }
-               // Prepend the current directory
-               ret = malloc(chrootLen + cwdLen + 1 + pathLen + 1 );
-               strcpy(ret+chrootLen, cwd);
-               ret[cwdLen] = '/';
-               strcpy(ret+chrootLen+cwdLen+1, Path);
-               //Log("ret = '%s'", ret);
-       }
-       
-       // Parse Path
-       pathComps[iPos++] = tmpStr = ret+chrootLen+1;
-       while(*tmpStr)
-       {
-               if(*tmpStr++ == '/')
-               {
-                       pathComps[iPos++] = tmpStr;
-                       if(iPos == MAX_PATH_SLASHES) {
-                               LOG("Path '%s' has too many elements", Path);
-                               free(ret);
-                               LEAVE('n');
-                               return NULL;
-                       }
-               }
-       }
-       pathComps[iPos] = NULL;
-       
-       // Cleanup
-       iPos2 = iPos = 0;
-       while(pathComps[iPos])
-       {
-               tmpStr = pathComps[iPos];
-               // Always Increment iPos
-               iPos++;
-               // ..
-               if(tmpStr[0] == '.' && tmpStr[1] == '.' && (tmpStr[2] == '/' || tmpStr[2] == '\0') )
-               {
-                       if(iPos2 != 0)
-                               iPos2 --;
-                       continue;
-               }
-               // .
-               if(tmpStr[0] == '.' && (tmpStr[1] == '/' || tmpStr[1] == '\0') )
-               {
-                       continue;
-               }
-               // Empty
-               if(tmpStr[0] == '/' || tmpStr[0] == '\0')
-               {
-                       continue;
-               }
-               
-               // Set New Position
-               pathComps[iPos2] = tmpStr;
-               iPos2++;
-       }
-       pathComps[iPos2] = NULL;
-       
-       // Build New Path
-       iPos2 = chrootLen + 1;  iPos = 0;
-       ret[0] = '/';
-       while(pathComps[iPos])
-       {
-               tmpStr = pathComps[iPos];
-               while(*tmpStr && *tmpStr != '/')
-               {
-                       ret[iPos2++] = *tmpStr;
-                       tmpStr++;
-               }
-               ret[iPos2++] = '/';
-               iPos++;
-       }
-       if(iPos2 > 1)
-               ret[iPos2-1] = 0;
-       else
-               ret[iPos2] = 0;
-
-       // Prepend the chroot
-       if(chrootLen)
-               memcpy( ret, chroot, chrootLen );
-       
-       LEAVE('s', ret);
-//     Log_Debug("VFS", "VFS_GetAbsPath: RETURN '%s'", ret);
-       return ret;
-}
-
-/**
- * \fn char *VFS_ParsePath(const char *Path, char **TruePath)
- * \brief Parses a path, resolving sysmlinks and applying permissions
- */
-tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPoint)
-{
-       tVFS_Mount      *mnt, *longestMount;
-        int    cmp, retLength = 0;
-        int    ofs, nextSlash;
-        int    iNestedLinks = 0;
-       tVFS_Node       *curNode, *tmpNode;
-       char    *tmp;
-       char    path_buffer[MAX_PATH_LEN+1];
-       
-       ENTER("sPath pTruePath", Path, TruePath);
-       
-       // HACK: Memory File
-       if(Threads_GetUID() == 0 && Path[0] == '$') {
-               if(TruePath) {
-                       *TruePath = malloc(strlen(Path)+1);
-                       strcpy(*TruePath, Path);
-               }
-               curNode = VFS_MemFile_Create(Path);
-               if(MountPoint) {
-                       *MountPoint = NULL;
-               }
-               LEAVE('p', curNode);
-               return curNode;
-       }
-
-restart_parse: 
-       // For root we always fast return
-       if(Path[0] == '/' && Path[1] == '\0') {
-               if(TruePath) {
-                       *TruePath = malloc( gVFS_RootMount->MountPointLen+1 );
-                       strcpy(*TruePath, gVFS_RootMount->MountPoint);
-               }
-               if(MountPoint)  *MountPoint = gVFS_RootMount;
-               LEAVE('p', gVFS_RootMount->RootNode);
-               return gVFS_RootMount->RootNode;
-       }
-       
-       // Check if there is anything mounted
-       if(!gVFS_Mounts) {
-               Log_Error("VFS", "VFS_ParsePath - No filesystems mounted");
-               return NULL;
-       }
-       
-       // Find Mountpoint
-       longestMount = gVFS_RootMount;
-       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
-       {
-               // Quick Check
-               if( Path[mnt->MountPointLen] != '/' && Path[mnt->MountPointLen] != '\0')
-                       continue;
-               // Length Check - If the length is smaller than the longest match sofar
-               if(mnt->MountPointLen < longestMount->MountPointLen)    continue;
-               // String Compare
-               cmp = strcmp(Path, mnt->MountPoint);
-               
-               #if OPEN_MOUNT_ROOT
-               // Fast Break - Request Mount Root
-               if(cmp == 0) {
-                       if(TruePath) {
-                               *TruePath = malloc( mnt->MountPointLen+1 );
-                               strcpy(*TruePath, mnt->MountPoint);
-                       }
-                       if(MountPoint)
-                               *MountPoint = mnt;
-                       LEAVE('p', mnt->RootNode);
-                       return mnt->RootNode;
-               }
-               #endif
-               // Not a match, continue
-               if(cmp != '/')  continue;
-               longestMount = mnt;
-       }
-       
-       // Save to shorter variable
-       mnt = longestMount;
-       
-       LOG("mnt = {MountPoint:\"%s\"}", mnt->MountPoint);
-       
-       // Initialise String
-       if(TruePath)
-       {
-               // Assumes that the resultant path (here) will not be > strlen(Path) + 1
-               *TruePath = malloc( strlen(Path) + 1 );
-               strcpy(*TruePath, mnt->MountPoint);
-               retLength = mnt->MountPointLen;
-       }
-       
-       curNode = mnt->RootNode;
-       curNode->ReferenceCount ++;     
-       // Parse Path
-       ofs = mnt->MountPointLen+1;
-       for(; (nextSlash = strpos(&Path[ofs], '/')) != -1; ofs += nextSlash + 1)
-       {
-               char    pathEle[nextSlash+1];
-               
-               // Empty String
-               if(nextSlash == 0)      continue;
-               
-               memcpy(pathEle, &Path[ofs], nextSlash);
-               pathEle[nextSlash] = 0;
-       
-               // Check permissions on root of filesystem
-               if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
-                       //Log("Permissions fail on '%s'", Path);
-                       goto _error;
-               }
-               
-               // Check if the node has a FindDir method
-               if( !curNode->Type->FindDir )
-               {
-                       //Log("FindDir fail on '%s'", Path);
-                       goto _error;
-               }
-               LOG("FindDir{=%p}(%p, '%s')", curNode->Type->FindDir, curNode, pathEle);
-               // Get Child Node
-               tmpNode = curNode->Type->FindDir(curNode, pathEle);
-               LOG("tmpNode = %p", tmpNode);
-               _CloseNode( curNode );
-               curNode = tmpNode;
-               
-               // Error Check
-               if(!curNode) {
-                       LOG("Node '%s' not found in dir '%s'", pathEle, Path);
-                       goto _error;
-               }
-               
-               // Handle Symbolic Links
-               if(curNode->Flags & VFS_FFLAG_SYMLINK) {
-                       if(TruePath) {
-                               free(*TruePath);
-                               *TruePath = NULL;
-                       }
-                       if(!curNode->Type || !curNode->Type->Read) {
-                               Log_Warning("VFS", "VFS_ParsePath - Read of symlink node %p'%s' is NULL",
-                                       curNode, Path);
-                               goto _error;
-                       }
-                       
-                       if(iNestedLinks > MAX_NESTED_LINKS) {
-                               Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded");
-                               goto _error;
-                       }
-                       
-                       // Parse Symlink Path
-                       // - Just update the path variable and restart the function
-                       // > Count nested symlinks and limit to some value (counteracts loops)
-                       {
-                                int    remlen = strlen(Path) - (ofs + nextSlash);
-                               if( curNode->Size + remlen > MAX_PATH_LEN ) {
-                                       Log_Warning("VFS", "VFS_ParsePath - Symlinked path too long");
-                                       goto _error;
-                               }
-                               curNode->Type->Read( curNode, 0, curNode->Size, path_buffer );
-                               path_buffer[ curNode->Size ] = '\0';
-                               LOG("path_buffer = '%s'", path_buffer);
-                               strcat(path_buffer, Path + ofs+nextSlash);
-                               
-                               Path = path_buffer;
-//                             Log_Debug("VFS", "VFS_ParsePath: Symlink translated to '%s'", Path);
-                               iNestedLinks ++;
-                       }
-
-                       // EVIL: Goto :)
-                       LOG("Symlink -> '%s', restart", Path);
-                       goto restart_parse;
-               }
-               
-               // Handle Non-Directories
-               if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) )
-               {
-                       Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory");
-                       goto _error;
-               }
-               
-               // Check if path needs extending
-               if(!TruePath)   continue;
-               
-               // Increase buffer space
-               tmp = realloc( *TruePath, retLength + strlen(pathEle) + 1 + 1 );
-               // Check if allocation succeeded
-               if(!tmp) {
-                       Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer");
-                       goto _error;
-               }
-               *TruePath = tmp;
-               // Append to path
-               (*TruePath)[retLength] = '/';
-               strcpy(*TruePath+retLength+1, pathEle);
-               
-               LOG("*TruePath = '%s'", *TruePath);
-               
-               // - Extend Path
-               retLength += nextSlash + 1;
-       }
-
-       // Check final finddir call     
-       if( !curNode->Type || !curNode->Type->FindDir ) {
-               Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path);
-               goto _error;
-       }
-       
-       // Get last node
-       LOG("FindDir(%p, '%s')", curNode, &Path[ofs]);
-       tmpNode = curNode->Type->FindDir(curNode, &Path[ofs]);
-       LOG("tmpNode = %p", tmpNode);
-       // Check if file was found
-       if(!tmpNode) {
-               LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
-               goto _error;
-       }
-       _CloseNode( curNode );
-       
-       if(TruePath)
-       {
-               // Increase buffer space
-               tmp = realloc(*TruePath, retLength + strlen(&Path[ofs]) + 1 + 1);
-               // Check if allocation succeeded
-               if(!tmp) {
-                       Log_Warning("VFS", "VFS_ParsePath -  Unable to reallocate true path buffer");
-                       goto _error;
-               }
-               *TruePath = tmp;
-               // Append to path
-               (*TruePath)[retLength] = '/';
-               strcpy(*TruePath + retLength + 1, &Path[ofs]);
-               // - Extend Path
-               //retLength += strlen(tmpNode->Name) + 1;
-       }
-
-       if( MountPoint ) {
-               *MountPoint = mnt;
-       }
-       
-       LEAVE('p', tmpNode);
-       return tmpNode;
-
-_error:
-       _CloseNode( curNode );
-       
-       if(TruePath && *TruePath) {
-               free(*TruePath);
-               *TruePath = NULL;
-       }
-       LEAVE('n');
-       return NULL;
-}
-
-/**
- * \brief Create and return a handle number for the given node and mode
- */
-int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode )
-{
-        int    i;
-       
-       ENTER("pNode pMount xMode", Node, Mount, Mode);
-
-       i = 0;
-       i |= (Mode & VFS_OPENFLAG_EXEC) ? VFS_PERM_EXECUTE : 0;
-       i |= (Mode & VFS_OPENFLAG_READ) ? VFS_PERM_READ : 0;
-       i |= (Mode & VFS_OPENFLAG_WRITE) ? VFS_PERM_WRITE : 0;
-       
-       LOG("i = 0b%b", i);
-       
-       // Permissions Check
-       if( !VFS_CheckACL(Node, i) ) {
-               _CloseNode( Node );
-               Log_Log("VFS", "VFS_int_CreateHandle: Permissions Failed");
-               errno = EACCES;
-               LEAVE_RET('i', -1);
-       }
-       
-       i = VFS_AllocHandle( !!(Mode & VFS_OPENFLAG_USER), Node, Mode );
-       if( i < 0 ) {
-               Log_Notice("VFS", "VFS_int_CreateHandle: Out of handles");
-               errno = ENFILE;
-               LEAVE_RET('i', -1);
-       }
-
-       VFS_GetHandle(i)->Mount = Mount;
-
-       LEAVE_RET('x', i);
-}
-
-/**
- * \fn int VFS_Open(const char *Path, Uint Mode)
- * \brief Open a file
- */
-int VFS_Open(const char *Path, Uint Flags)
-{
-       return VFS_OpenEx(Path, Flags, 0);
-}
-
-int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
-{
-       tVFS_Node       *node;
-       tVFS_Mount      *mnt;
-       char    *absPath;
-       
-       ENTER("sPath xFlags oMode", Path, Flags);
-       
-       // Get absolute path
-       absPath = VFS_GetAbsPath(Path);
-       if(absPath == NULL) {
-               Log_Warning("VFS", "VFS_Open: Path expansion failed '%s'", Path);
-               LEAVE_RET('i', -1);
-       }
-       LOG("absPath = \"%s\"", absPath);
-       
-       // Parse path and get mount point
-       node = VFS_ParsePath(absPath, NULL, &mnt);
-       
-       // Create file if requested and it doesn't exist
-       if( !node && (Flags & VFS_OPENFLAG_CREATE) )
-       {
-               // TODO: Translate `Mode` into ACL and node flags
-               // Get parent, create node
-               VFS_MkNod(absPath, 0);
-               node = VFS_ParsePath(absPath, NULL, &mnt);
-       }
-       
-       // Free generated path
-       free(absPath);
-       
-       // Check for error
-       if(!node)
-       {
-               LOG("Cannot find node");
-               errno = ENOENT;
-               LEAVE_RET('i', -1);
-       }
-       
-       // Check for symlinks
-       if( !(Flags & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
-       {
-               char    tmppath[node->Size+1];
-               if( node->Size > MAX_PATH_LEN ) {
-                       Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size);
-                       LEAVE_RET('i', -1);
-               }
-               if( !node->Type || !node->Type->Read ) {
-                       Log_Warning("VFS", "VFS_Open - No read method on symlink");
-                       LEAVE_RET('i', -1);
-               }
-               // Read symlink's path
-               node->Type->Read( node, 0, node->Size, tmppath );
-               tmppath[ node->Size ] = '\0';
-               _CloseNode( node );
-               // Open the target
-               node = VFS_ParsePath(tmppath, NULL, &mnt);
-               if(!node) {
-                       LOG("Cannot find symlink target node (%s)", tmppath);
-                       errno = ENOENT;
-                       LEAVE_RET('i', -1);
-               }
-       }
-
-       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Flags));
-}
-
-
-/**
- * \brief Open a file from an open directory
- */
-int VFS_OpenChild(int FD, const char *Name, Uint Mode)
-{
-       tVFS_Handle     *h;
-       tVFS_Node       *node;
-       
-       ENTER("xFD sName xMode", FD, Name, Mode);
-
-       // Get handle
-       h = VFS_GetHandle(FD);
-       if(h == NULL) {
-               Log_Warning("VFS", "VFS_OpenChild - Invalid file handle 0x%x", FD);
-               errno = EINVAL;
-               LEAVE_RET('i', -1);
-       }
-       
-       // Check for directory
-       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
-               Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory");
-               errno = ENOTDIR;
-               LEAVE_RET('i', -1);
-       }
-
-       // Sanity check
-       if( !h->Node->Type || !h->Node->Type->FindDir ) {
-               Log_Error("VFS", "VFS_OpenChild - Node does not have a type/is missing FindDir");
-               errno = ENOTDIR;
-               LEAVE_RET('i', -1);
-       }
-       
-       // Find Child
-       node = h->Node->Type->FindDir(h->Node, Name);
-       if(!node) {
-               errno = ENOENT;
-               LEAVE_RET('i', -1);
-       }
-
-       LEAVE_RET('x', VFS_int_CreateHandle(node, h->Mount, Mode));
-}
-
-int VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode)
-{
-       tVFS_Mount      *mnt;
-       tVFS_Node       *node;
-
-       ENTER("iMount XInode xMode", Mount, Inode, Mode);
-       
-       // Get mount point
-       mnt = VFS_GetMountByIdent(Mount);
-       if( !mnt ) {
-               LOG("Mount point ident invalid");
-               errno = ENOENT;
-               LEAVE_RET('i', -1);
-       }
-       
-       // Does the filesystem support this?
-       if( !mnt->Filesystem->GetNodeFromINode ) {
-               LOG("Filesystem does not support inode accesses");
-               errno = ENOENT;
-               LEAVE_RET('i', -1);
-       }
-
-       // Get node
-       node = mnt->Filesystem->GetNodeFromINode(mnt->RootNode, Inode);
-       if( !node ) {
-               LOG("Unable to find inode");
-               errno = ENOENT;
-               LEAVE_RET('i', -1);
-       }
-       
-       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Mode));
-}
-
-/**
- * \fn void VFS_Close(int FD)
- * \brief Closes an open file handle
- */
-void VFS_Close(int FD)
-{
-       tVFS_Handle     *h;
-       
-       // Get handle
-       h = VFS_GetHandle(FD);
-       if(h == NULL) {
-               Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD);
-               return;
-       }
-       
-       #if VALIDATE_VFS_FUNCTIPONS
-       if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) {
-               Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)",
-                       h->Node, h->Node->Close);
-               return ;
-       }
-       #endif
-       
-       _CloseNode(h->Node);
-       
-       h->Node = NULL;
-}
-
-/**
- * \brief Change current working directory
- */
-int VFS_ChDir(const char *Dest)
-{
-       char    *buf;
-        int    fd;
-       tVFS_Handle     *h;
-       
-       // Create Absolute
-       buf = VFS_GetAbsPath(Dest);
-       if(buf == NULL) {
-               Log_Notice("VFS", "VFS_ChDir: Path expansion failed");
-               return -1;
-       }
-       
-       // Check if path exists
-       fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
-       if(fd == -1) {
-               Log_Notice("VFS", "VFS_ChDir: Path is invalid");
-               return -1;
-       }
-       
-       // Get node so we can check for directory
-       h = VFS_GetHandle(fd);
-       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
-               Log("VFS_ChDir: Path is not a directory");
-               VFS_Close(fd);
-               return -1;
-       }
-       
-       // Close file
-       VFS_Close(fd);
-       
-       {
-               char    **cwdptr = Threads_GetCWD();
-               // Free old working directory
-               if( *cwdptr )   free( *cwdptr );
-               // Set new
-               *cwdptr = buf;
-       }
-       
-       Log("Updated CWD to '%s'", buf);
-       
-       return 1;
-}
-
-/**
- * \fn int VFS_ChRoot(char *New)
- * \brief Change current root directory
- */
-int VFS_ChRoot(const char *New)
-{
-       char    *buf;
-        int    fd;
-       tVFS_Handle     *h;
-       
-       if(New[0] == '/' && New[1] == '\0')
-               return 1;       // What a useless thing to ask!
-       
-       // Create Absolute
-       buf = VFS_GetAbsPath(New);
-       if(buf == NULL) {
-               LOG("Path expansion failed");
-               return -1;
-       }
-       
-       // Check if path exists
-       fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
-       if(fd == -1) {
-               LOG("Path is invalid");
-               return -1;
-       }
-       
-       // Get node so we can check for directory
-       h = VFS_GetHandle(fd);
-       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
-               LOG("Path is not a directory");
-               VFS_Close(fd);
-               return -1;
-       }
-       
-       // Close file
-       VFS_Close(fd);
-
-       // Update       
-       {
-               char    **chroot_ptr = Threads_GetChroot();
-               if( *chroot_ptr )       free( *chroot_ptr );
-               *chroot_ptr = buf;
-       }
-       
-       LOG("Updated Root to '%s'", buf);
-       
-       return 1;
-}
-
-// === EXPORTS ===
-EXPORT(VFS_Open);
-EXPORT(VFS_Close);
diff --git a/Kernel/vfs/select.c b/Kernel/vfs/select.c
deleted file mode 100644 (file)
index 439afc0..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Acess2 VFS
- * - By thePowersGang (John Hodge)
- * 
- * select.c
- * - Implements the select() system call (and supporting code)
- *
- * TODO: Implment timeouts (via an alarm event?)
- * TODO: Remove malloc for read/write queues
- */
-#define DEBUG  0
-#include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
-#include "vfs_ext.h"
-#include <semaphore.h>
-#include <threads.h>
-#include <events.h>
-
-// === CONSTANTS ===
-#define        NUM_THREADS_PER_ALLOC   4
-
-// === IMPORTS ===
-extern tThread *Proc_GetCurThread(void);
-
-// === TYPES ===
-typedef struct sVFS_SelectListEnt      tVFS_SelectListEnt;
-
-// === STRUCTURES ===
-struct sVFS_SelectListEnt
-{
-       tVFS_SelectListEnt      *Next;
-       tThread *Threads[NUM_THREADS_PER_ALLOC];
-};
-
-// NOTE: Typedef is in vfs.h
-struct sVFS_SelectList
-{
-       tMutex  Lock;
-       tVFS_SelectListEnt      FirstEnt;
-};
-
-// === PROTOTYPES ===
-// int VFS_SelectNode(tVFS_Node *Node, enum eVFS_SelectTypes Type, tTime *Timeout);
-// int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
-// int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull);
-// int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable);
-// int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState);
- int   VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, int **Flag, int *WantedFlag, int *MaxAllowed);
- int   VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
- int   VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
- int   VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed);
-void   VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread);
-void   VFS_int_Select_SignalAll(tVFS_SelectList *List);
-
-// === GLOBALS ===
-
-// === FUNCTIONS ===
-int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *Name)
-{
-       tThread *thisthread = Proc_GetCurThread();
-        int    ret, type;
-       
-       ENTER("pNode iTypeFlags pTimeout sName", Node, TypeFlags, Timeout, Name);
-       
-       // Initialise
-       for( type = 0; type < 3; type ++ )
-       {
-               tVFS_SelectList **list;
-                int    *flag, wanted, maxAllowed;
-               if( !(TypeFlags & (1 << type)) )        continue;
-               if( VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed) ) {
-                       LEAVE('i', -1);
-                       return -1;
-               }
-       
-               // Alloc if needed
-               if( !*list )    *list = calloc(1, sizeof(tVFS_SelectList));
-       
-               VFS_int_Select_AddThread(*list, thisthread, maxAllowed);
-               if( *flag == wanted )
-               {
-                       VFS_int_Select_RemThread(*list, thisthread);
-                       LEAVE('i', 1);
-                       return 1;
-               }
-       }
-
-       // - Fast return for polling
-       if( Timeout && *Timeout == 0 )  return 0;
-
-       // Wait for things      
-       if( !Timeout || *Timeout > 0 )
-       {
-               LOG("Semaphore_Wait()");
-               // TODO: Actual timeout
-               Threads_WaitEvents( THREAD_EVENT_VFS );
-       }
-       
-       // Get return value
-       ret = 0;
-       for( type = 0; type < 3; type ++ )
-       {
-               tVFS_SelectList **list;
-                int    *flag, wanted, maxAllowed;
-               if( !(TypeFlags & (1 << type)) )        continue;
-               VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed);
-               LOG("VFS_int_Select_RemThread()");
-               VFS_int_Select_RemThread(*list, thisthread);
-               ret = ret || *flag == wanted;
-       }
-       
-       LEAVE('i', ret);
-       return ret;
-}
-
-int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel)
-{
-       tThread *thisthread = Proc_GetCurThread();
-        int    ret;
-       
-       ENTER("iMaxHandle pReadHandles pWriteHandles pErrHandles pTimeout bIsKernel",
-               MaxHandle, ReadHandles, WriteHandles, ErrHandles, Timeout, IsKernel);
-       
-       // Notes: The idea is to make sure we only enter wait (Threads_WaitEvents)
-       // if we are going to be woken up (either by an event at a later time,
-       // or by an event that happened while or before we were registering).
-       // Hence, register must happen _before_ we check the state flag
-       // (See VFS_int_Select_Register), that way either we pick up the flag,
-       // or the semaphore is incremeneted (or both, but never none)
-       
-       // Register with nodes
-       ret  = VFS_int_Select_Register(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
-       ret += VFS_int_Select_Register(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
-       ret += VFS_int_Select_Register(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
-       
-       LOG("Register ret = %i", ret);
-       
-       // If there were events waiting, de-register and return
-       if( ret > 0 )
-       {
-               ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
-               ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
-               ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
-               LEAVE('i', ret);
-               return ret;
-       }
-       
-       // TODO: Implement timeout
-       LOG("Timeout = %p", Timeout);
-       
-       // Wait (only if there is no timeout, or it is greater than zero
-       if( !Timeout || *Timeout > 0 )
-       {
-               // TODO: Timeout
-               // TODO: Allow extra events to be waited upon
-               Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
-       }
-       
-       // Fill output (modify *Handles)
-       // - Also, de-register
-       ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
-       ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
-       ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
-       LEAVE('i', ret);
-       return ret;
-}
-
-// Mark a node as having data ready for reading
-int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable)
-{
-       ENTER("pNode bIsDataAvaliable", Node, IsDataAvaliable);
-       Node->DataAvaliable = !!IsDataAvaliable;
-       if( Node->DataAvaliable )
-               VFS_int_Select_SignalAll(Node->ReadThreads);
-       LEAVE('i', 0);
-       return 0;
-}
-
-// Mark a node as having a full buffer
-int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
-{
-       ENTER("pNode bIsBufferFull", Node, IsBufferFull);
-       Node->BufferFull = !!IsBufferFull;
-       if( !Node->BufferFull )
-               VFS_int_Select_SignalAll(Node->WriteThreads);
-       LEAVE('i', 0);
-       return 0;
-}
-
-// Mark a node as errored
-int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState)
-{
-       ENTER("pNode bIsErrorState", Node, IsErrorState);
-       Node->ErrorOccurred = !!IsErrorState;
-       if( Node->ErrorOccurred )
-               VFS_int_Select_SignalAll(Node->ErrorThreads);
-       LEAVE('i', 0);
-       return 0;
-}
-
-// --- Internal ---
-int VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, int **Flag, int *WantedFlag, int *MaxAllowed)
-{
-       // Get the type of the listen
-       switch(Type)
-       {
-       case 0: // Read
-               if(List)        *List = &Node->ReadThreads;
-               if(Flag)        *Flag = &Node->DataAvaliable;
-               if(WantedFlag)  *WantedFlag = 1;
-               if(MaxAllowed)  *MaxAllowed = 1;        // Max of 1 for read
-               break;
-       case 1: // Write
-               if(List)        *List = &Node->WriteThreads;
-               if(Flag)        *Flag = &Node->BufferFull;
-               if(WantedFlag)  *WantedFlag = 0;
-               if(MaxAllowed)  *MaxAllowed = 1;        // Max of 1 for write
-               break;
-       case 2: // Error
-               if(List)        *List = &Node->ErrorThreads;
-               if(Flag)        *Flag = &Node->ErrorOccurred;
-               if(WantedFlag)  *WantedFlag = 1;
-               if(MaxAllowed)  *MaxAllowed = -1;       // No max for error listeners
-               break;
-       default:
-               Log_Error("VFS", "VFS_int_Select_GetType: BUG CHECK, Unknown Type %i", Type);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * \return Number of files with an action
- */
-int VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
-{
-        int    i, numFlagged = 0;
-       tVFS_SelectList **list;
-        int    *flag, wantedFlagValue;
-        int    maxAllowed;
-       
-       if( !Handles )  return 0;
-       
-       ENTER("pThread iMaxHandle pHandles iType iIsKernel", Thread, MaxHandle, Handles, Type, IsKernel);
-       
-       for( i = 0; i < MaxHandle; i ++ )
-       {
-               tVFS_Handle     *handle;
-               
-               // Is the descriptor set
-               if( !FD_ISSET(i, Handles) )     continue;
-               LOG("FD #%i", i);
-               
-               handle = VFS_GetHandle( i | (IsKernel?VFS_KERNEL_FLAG:0) );
-               // Is the handle valid?
-               if( !handle || !handle->Node )
-               {
-                       if( Type == 2 ) {       // Bad FD counts as an error
-                               numFlagged ++;
-                       }
-                       else {
-                               FD_CLR(i, Handles);
-                       }
-                       continue;
-               }
-       
-               // Get the type of the listen
-               if( VFS_int_Select_GetType(Type, handle->Node, &list, &flag, &wantedFlagValue, &maxAllowed) ) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               
-               // Alloc if needed
-               if( !*list ) {
-                       *list = calloc(1, sizeof(tVFS_SelectList));
-               }
-               
-               // Register
-               if( VFS_int_Select_AddThread(*list, Thread, maxAllowed ) )
-               {
-                       // Oops, error (or just no space)
-                       FD_CLR(i, Handles);
-               }
-               
-               // Check for the flag
-               if( !!*flag == !!wantedFlagValue )
-                       numFlagged ++;
-       }
-       
-       LEAVE('i', numFlagged);
-       
-       return numFlagged;
-}
-/**
- * \return Number of files with an action
- */
-int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
-{
-        int    i, numFlagged = 0;
-       tVFS_SelectList **list;
-        int    *flag, wantedFlagValue;
-       
-       if( !Handles )  return 0;
-       
-       ENTER("pThread iMaxHandle pHandles iType iIsKernel", Thread, MaxHandle, Handles, Type, IsKernel);
-       
-       for( i = 0; i < MaxHandle; i ++ )
-       {
-               tVFS_Handle     *handle;
-               
-               // Is the descriptor set
-               if( !FD_ISSET(i, Handles) )     continue;
-               LOG("FD #%i", i);
-               
-               handle = VFS_GetHandle( i | (IsKernel?VFS_KERNEL_FLAG:0) );
-               // Is the handle valid?
-               if( !handle || !handle->Node )
-               {
-                       if( Type == 2 ) {       // Bad FD counts as an error
-                               numFlagged ++;
-                       }
-                       else {
-                               FD_CLR(i, Handles);
-                       }
-                       continue;
-               }
-       
-               // Get the type of the listen
-       
-               // Get the type of the listen
-               if( VFS_int_Select_GetType(Type, handle->Node, &list, &flag, &wantedFlagValue, NULL) ) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               
-               // Remove
-               VFS_int_Select_RemThread(*list, Thread );
-               
-               // Check for the flag
-               if( !!*flag == !!wantedFlagValue ) {
-                       numFlagged ++;
-               }
-               else {
-                       FD_CLR(i, Handles);
-               }
-       }
-       
-       LEAVE('i', numFlagged);
-       
-       return numFlagged;
-}
-
-/**
- * \return Boolean failure
- */
-int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed)
-{
-        int    i, count = 0;
-       tVFS_SelectListEnt      *block, *prev;
-       
-       ENTER("pList pThread iMaxAllowed", List, Thread, MaxAllowed);
-       
-       // Lock to avoid concurrency issues
-       Mutex_Acquire(&List->Lock);
-       
-       block = &List->FirstEnt;
-       
-       // Look for free space
-       do
-       {
-               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
-               {
-                       if( block->Threads[i] == NULL )
-                       {
-                               block->Threads[i] = Thread;
-                               Mutex_Release(&List->Lock);
-                               LEAVE('i', 0);
-                               return 0;
-                       }
-                       count ++;
-                       if( MaxAllowed && count >= MaxAllowed ) {
-                               LEAVE('i', 1);
-                               return 1;
-                       }
-               }
-               
-               prev = block;
-               block = block->Next;
-       } while(block);
-       
-       LOG("New block");
-       
-       // Create new block
-       block = malloc( sizeof(tVFS_SelectListEnt) );
-       if( !block ) {
-               Log_Warning("VFS", "VFS_int_Select_AddThread: malloc() failed");
-               Mutex_Release(&List->Lock);
-               return -1;
-       }
-       block->Next = NULL;
-       block->Threads[0] = Thread;
-       for( i = 1; i < NUM_THREADS_PER_ALLOC; i ++ )
-       {
-               block->Threads[i] = NULL;
-       }
-       
-       // Add to list
-       prev->Next = block;
-       
-       // Release
-       Mutex_Release(&List->Lock);
-       
-       LEAVE('i', 0);
-       return 0;
-}
-
-void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
-{
-        int    i;
-       tVFS_SelectListEnt      *block, *prev = NULL;
-       
-       ENTER("pList pThread", List, Thread);
-       
-       // Lock to avoid concurrency issues
-       Mutex_Acquire(&List->Lock);
-       
-       block = &List->FirstEnt;
-       
-       // Look for the thread
-       do
-       {
-               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
-               {
-                       if( block->Threads[i] == Thread )
-                       {
-                               block->Threads[i] = NULL;
-                               
-                               // Check if this block is empty
-                               if( block != &List->FirstEnt )
-                               {
-                                       for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
-                                               if( block->Threads[i] )
-                                                       break;
-                                       // If empty, free it
-                                       if( i == NUM_THREADS_PER_ALLOC ) {
-                                               LOG("Deleting block");
-                                               prev->Next = block->Next;
-                                               free(block);
-                                       }
-                                       //TODO: If not empty, check if it can be merged downwards
-                               }
-                               
-                               Mutex_Release(&List->Lock);
-                               LEAVE('-');
-                               return ;
-                       }
-               }
-               
-               prev = block;
-               block = block->Next;
-       } while(block);
-       
-       // Not on list, is this an error?
-       
-       Mutex_Release(&List->Lock);
-       
-       LOG("Not on list");
-       LEAVE('-');
-}
-
-/**
- * \brief Signal all threads on a list
- */
-void VFS_int_Select_SignalAll(tVFS_SelectList *List)
-{
-        int    i;
-       tVFS_SelectListEnt      *block;
-       
-       if( !List )     return ;
-       
-       ENTER("pList", List);
-       
-       // Lock to avoid concurrency issues
-       Mutex_Acquire(&List->Lock);
-       
-       block = &List->FirstEnt;
-       
-       // Look for the thread
-       do
-       {
-               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
-               {
-                       if( block->Threads[i]  )
-                       {
-                               LOG("block(%p)->Threads[%i] = %p", block, i, block->Threads[i]);
-                               Threads_PostEvent( block->Threads[i], THREAD_EVENT_VFS );
-                       }
-               }
-               
-               block = block->Next;
-       } while(block);
-       
-       Mutex_Release(&List->Lock);
-       
-       LEAVE('-');
-}
diff --git a/Kernel/workqueue.c b/Kernel/workqueue.c
deleted file mode 100644 (file)
index b1a6385..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge (thePowersGang)
- *
- * workqueue.c
- * - Worker FIFO Queue (Single Consumer, Interrupt Producer)
- */
-#include <acess.h>
-#include <workqueue.h>
-#include <threads_int.h>
-
-// === CODE ===
-void Workqueue_Init(tWorkqueue *Queue, const char *Name, size_t NextOfset)
-{
-       Queue->Name = Name;
-       Queue->NextOffset = NextOfset;
-}
-
-void *Workqueue_GetWork(tWorkqueue *Queue)
-{
-       tThread *us;
-
-       for( ;; )
-       {
-               // Check for work
-               SHORTLOCK(&Queue->Protector);
-               if(Queue->Head)
-               {
-                       void *ret = Queue->Head;
-                       Queue->Head = *( (void**)ret + Queue->NextOffset/sizeof(void*) );
-                       if(Queue->Tail == ret)
-                               Queue->Tail = NULL;
-                       SHORTREL(&Queue->Protector);    
-                       return ret;
-               }
-               
-               // Go to sleep
-               SHORTLOCK(&glThreadListLock);
-               us = Threads_RemActive();
-               us->WaitPointer = Queue;
-               us->Status = THREAD_STAT_QUEUESLEEP;
-               Queue->Sleeper = us;
-               SHORTREL(&Queue->Protector);    
-               SHORTREL(&glThreadListLock);
-               
-               // Yield and sleep
-               Threads_Yield();
-               if(us->Status == THREAD_STAT_QUEUESLEEP) {
-                       // Why are we awake?!
-               }
-
-               us->WaitPointer = NULL;
-       }
-}
-
-void Workqueue_AddWork(tWorkqueue *Queue, void *Ptr)
-{
-       SHORTLOCK(&Queue->Protector);
-
-       if( Queue->Tail )
-               *( (void**)Queue->Tail + Queue->NextOffset/sizeof(void*) ) = Ptr;
-       else
-               Queue->Head = Ptr;
-       Queue->Tail = Ptr;
-       
-       if( Queue->Sleeper )
-       {       
-               if( Queue->Sleeper->Status != THREAD_STAT_ACTIVE )
-                       Threads_AddActive(Queue->Sleeper);
-               Queue->Sleeper = NULL;
-       }
-       SHORTREL(&Queue->Protector);
-}
diff --git a/KernelLand/Kernel/.gitignore b/KernelLand/Kernel/.gitignore
new file mode 100644 (file)
index 0000000..439ce3e
--- /dev/null
@@ -0,0 +1 @@
+*.BuildNum.*
diff --git a/KernelLand/Kernel/Doxyfile b/KernelLand/Kernel/Doxyfile
new file mode 100644 (file)
index 0000000..a474dd5
--- /dev/null
@@ -0,0 +1,1510 @@
+# Doxyfile 1.5.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = Acess2
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../SrcDoc/Kernel
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, 
+# Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses. 
+# With this tag you can assign which parser to use for a given extension. 
+# Doxygen has a built-in mapping, but you can override or extend it using this tag. 
+# The format is ext=language, where ext is a file extension, and language is one of 
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, 
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat 
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), 
+# use: inc=Fortran f=C
+
+EXTENSION_MAPPING      = 
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen to replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = YES
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penality. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will rougly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page. 
+# This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by 
+# doxygen. The layout file controls the global structure of the generated output files 
+# in an output format independent way. The create the layout file that represents 
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a 
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name 
+# of the layout file.
+
+LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = .
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = arch/archdoc.h
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output. 
+# If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis. 
+# Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match. 
+# The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code. 
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER 
+# are set, an additional index file will be generated that can be used as input for 
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated 
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = 
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. 
+# For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to FRAME, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature. Other possible values 
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories, 
+# and Class Hierarchy pages using a tree view instead of an ordered list; 
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which 
+# disables this behavior completely. For backwards compatibility with previous 
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE 
+# respectively.
+
+GENERATE_TREEVIEW      = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader. 
+# This is useful 
+# if you want to understand what is going on. 
+# On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#  
+# TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#  
+# TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links. 
+# Note that each tag file must have a unique name 
+# (where the name does NOT include the path) 
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
+# which can be done by putting it in a standard location or by setting the 
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif 
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Options related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/KernelLand/Kernel/Doxyfile.api b/KernelLand/Kernel/Doxyfile.api
new file mode 100644 (file)
index 0000000..6872e55
--- /dev/null
@@ -0,0 +1,1775 @@
+# Doxyfile 1.7.5.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = Acess2
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../APIDoc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+#INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = YES
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE.
+
+#CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = include/apidoc_mainpage.h \
+                         include/acess.h \
+                         include/hal_proc.h \
+                         include/binary.h \
+                         include/modules.h \
+                         include/vfs.h \
+                         include/vfs_ext.h \
+                         include/fs_devfs.h \
+                         include/fs_sysfs.h \
+                         include/iocache.h \
+                         arch/archdoc.h \
+                         include/apidoc/arch_x86.h \
+                         include/api_drv_common.h \
+                         include/api_drv_video.h \
+                         include/api_drv_terminal.h \
+                         include/api_drv_disk.h \
+                         include/api_drv_keyboard.h \
+                         include/api_drv_joystick.h \
+                         include/api_drv_network.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = api_drv_*.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to directory from which doxygen is run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is adviced to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NONE
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+#MATHJAX_EXTENSIONS     =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+#LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+#INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/KernelLand/Kernel/DoxygenLayout.xml b/KernelLand/Kernel/DoxygenLayout.xml
new file mode 100644 (file)
index 0000000..e8faa6d
--- /dev/null
@@ -0,0 +1,185 @@
+<doxygenlayout version="1.0">
+  <!-- Navigation index tabs for HTML output -->
+  <navindex>
+    <tab type="mainpage" visible="yes" title=""/>
+    <tab type="pages" visible="yes" title="" intro=""/>
+    <tab type="modules" visible="yes" title="" intro=""/>
+    <tab type="namespaces" visible="yes" title="">
+      <tab type="namespaces" visible="yes" title="" intro=""/>
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="classes" visible="yes" title="">
+      <tab type="classes" visible="yes" title="" intro=""/>
+      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
+      <tab type="classmembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="files" visible="yes" title="">
+      <tab type="files" visible="yes" title="" intro=""/>
+      <tab type="globals" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="dirs" visible="yes" title="" intro=""/>
+    <tab type="examples" visible="yes" title="" intro=""/>  
+  </navindex>
+
+  <!-- Layout definition for a class page -->
+  <class>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <inheritancegraph visible="$CLASS_GRAPH"/>
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+    <allmemberslink visible="yes"/>
+    <memberdecl>
+      <nestedclasses visible="yes" title=""/>
+      <publictypes title=""/>
+      <publicslots title=""/>
+      <signals title=""/>
+      <publicmethods title=""/>
+      <publicstaticmethods title=""/>
+      <publicattributes title=""/>
+      <publicstaticattributes title=""/>
+      <protectedtypes title=""/>
+      <protectedslots title=""/>
+      <protectedmethods title=""/>
+      <protectedstaticmethods title=""/>
+      <protectedattributes title=""/>
+      <protectedstaticattributes title=""/>
+      <packagetypes title=""/>
+      <packagemethods title=""/>
+      <packagestaticmethods title=""/>
+      <packageattributes title=""/>
+      <packagestaticattributes title=""/>
+      <properties title=""/>
+      <events title=""/>
+      <privatetypes title=""/>
+      <privateslots title=""/>
+      <privatemethods title=""/>
+      <privatestaticmethods title=""/>
+      <privateattributes title=""/>
+      <privatestaticattributes title=""/>
+      <friends title=""/>
+      <related title="" subtitle=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <typedefs title=""/>
+      <enums title=""/>
+      <constructors title=""/>
+      <functions title=""/>
+      <related title=""/>
+      <variables title=""/>
+      <properties title=""/>
+      <events title=""/>
+    </memberdef>
+    <usedfiles visible="$SHOW_USED_FILES"/>
+    <authorsection visible="yes"/>
+  </class>
+
+  <!-- Layout definition for a namespace page -->
+  <namespace>
+    <briefdescription visible="yes"/>
+    <memberdecl>
+      <nestednamespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </namespace>
+
+  <!-- Layout definition for a file page -->
+  <file>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <includegraph visible="$INCLUDE_GRAPH"/>
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+    <sourcelink visible="yes"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection/>
+  </file>
+
+  <!-- Layout definition for a group page -->
+  <group>
+    <briefdescription visible="yes"/>
+    <groupgraph visible="$GROUP_GRAPHS"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <dirs visible="yes" title=""/>
+      <nestedgroups visible="yes" title=""/>
+      <files visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <pagedocs/>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </group>
+
+  <!-- Layout definition for a directory page -->
+  <directory>
+    <briefdescription visible="yes"/>
+    <directorygraph visible="yes"/>
+    <memberdecl>
+      <dirs visible="yes"/>
+      <files visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+  </directory>
+</doxygenlayout>
diff --git a/KernelLand/Kernel/GenSyscalls.php b/KernelLand/Kernel/GenSyscalls.php
new file mode 100644 (file)
index 0000000..d451d1d
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+$gLines = file("syscalls.lst");
+
+$lSyscalls = array();
+$i = 0;
+foreach($gLines as $line)
+{
+       $line = trim($line);
+       if(empty($line))        continue;
+       
+       if( intVal($line) != 0)
+               $i = $line;
+       else
+               $lSyscalls[$i++] = explode("\t", $line, 3);
+}
+$lMax = $i;
+
+$lAsmInc = "; Acess2
+; System Calls List
+; 
+
+";
+$lHeader  = "/*
+ * AcessOS Microkernel Version
+ * syscalls.h
+ */
+#ifndef _SYSCALLS_H
+#define _SYSCALLS_H
+
+";
+$i = 0;
+foreach($lSyscalls as $num=>$call)
+{
+       if($i != $num)  {
+               $lHeader .= "\n";
+               $lAsmInc .= "\n";
+       }
+       
+       $lHeader .= "#define {$call[0]}\t{$num}";
+       $lHeader .= "\t// {$num} - {$call[1]}\n";
+       
+       $lAsmInc .= "%define {$call[0]}\t{$num}\t; {$call[1]}\n";
+       
+       
+       if($i != $num)
+               $i = $num+1;
+       else
+               $i ++;
+}
+$lHeader .= "#define NUM_SYSCALLS\t$i\n";
+$lHeader .= "#define SYS_DEBUG\t0x100  // 0x100 - Print a debug string\n";
+$lHeader .= "\n";
+$lHeader .= "#ifdef __GNUC__\n";
+$lHeader .= "static const char *cSYSCALL_NAMES[] = {\n\t";
+
+$j = 0;
+for($i=0;$i<$lMax;$i++)
+{
+       if(!isset($lSyscalls[$i]))
+               $lHeader .= "\"\",";
+       else
+               $lHeader .= "\"".$lSyscalls[$i][0]."\",";
+       $j ++;
+       if($j == 6) {
+               $lHeader .= "\n\t";
+               $j = 0;
+       }
+}
+$lHeader .= "\"\"\n};\n"
+$lHeader .= "#endif\n";
+$lHeader .= "#endif\n";
+
+$fp = fopen("include/syscalls.h", "w");        fwrite($fp, $lHeader);  fclose($fp);
+$fp = fopen("include/syscalls.inc.asm", "w");  fwrite($fp, $lAsmInc);  fclose($fp);
+
+?>
diff --git a/KernelLand/Kernel/GenSyscalls.pl b/KernelLand/Kernel/GenSyscalls.pl
new file mode 100755 (executable)
index 0000000..487ceca
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/perl
+#
+#
+
+open(FILE, "syscalls.lst");
+
+$num = 0;
+@calls = ();
+while($_ = <FILE>)
+{
+       if(/(\d+)/)
+       {
+               $num = $1;
+       }
+       elsif(/([A-Z_]+)\s+(.+)/)
+       {
+               push @calls, [$num, $1, $2];
+               $num ++;
+       }
+}
+
+close(FILE);
+
+# C header
+open(HEADER, ">include/syscalls.h");
+print HEADER "/*
+ * Acess2
+ * syscalls.h
+ * - System Call List
+ *
+ * NOTE: Generated from Kernel/syscalls.lst
+ */
+#ifndef _SYSCALLS_H
+#define _SYSCALLS_H
+
+";
+
+$lastid = -1;
+$i = 0;
+foreach my $call (@calls)
+{
+       print HEADER "#define ", $call->[1], "\t", $call->[0], "\t// ", $call->[2], "\n";
+       $i = $call->[0] + 1;
+}
+print HEADER "
+#define NUM_SYSCALLS   ",$i,"
+#define SYS_DEBUG      0x100
+
+#ifndef __ASSEMBLER__
+static const char *cSYSCALL_NAMES[] = {
+";
+
+$lastid = -1;
+foreach $call (@calls)
+{
+       while( $lastid + 1 < $call->[0] )
+       {
+               print HEADER "\t\"\",\n";
+               $lastid = $lastid + 1;
+       }
+       print HEADER "\t\"", $call->[1], "\",\n";
+       $lastid = $lastid + 1;
+}
+print HEADER  "
+\t\"\"
+};
+#endif
+
+#endif
+";
+
+close(HEADER);
+
+# Assembly Header
+open(ASM, ">include/syscalls.inc.asm");
+print ASM "; Acess2
+; System Calls List
+; 
+
+";
+foreach $call (@calls)
+{
+       print ASM "%define ", $call->[1], "\t", $call->[0], "\t ;", $call->[2], "\n";
+}
+close(ASM);
diff --git a/KernelLand/Kernel/Makefile b/KernelLand/Kernel/Makefile
new file mode 100644 (file)
index 0000000..d0c8dbf
--- /dev/null
@@ -0,0 +1,138 @@
+# Acess2 Kernel
+# Root Makefile
+# NOTE: Does some voodoo to allow differing architecture builds to co-exist
+# - The built objects and dependency files are suffixed with the arch name
+# - The final binary is Acess2.<ARCH>.bin
+
+-include ../Makefile.cfg
+
+-include arch/$(ARCHDIR)/Makefile
+
+-include Makefile.BuildNum.$(ARCH)
+
+ifeq ($(BUILD_NUM),)
+BUILD_NUM = 0
+endif
+
+KERNEL_VERSION = $(ACESS_VERSION)
+MAKEDEP                = $(CC) -M
+
+ifeq ($(AS_SUFFIX),)
+       AS_SUFFIX = S
+endif
+
+ASFLAGS         += -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
+CPPFLAGS       += -I./include -I./arch/$(ARCHDIR)/include -D_MODULE_NAME_=\"Kernel\"
+CPPFLAGS       += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D PLATFORM=\"$(PLATFORM)\" -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
+CPPFLAGS       += -D KERNEL_VERSION=$(KERNEL_VERSION)
+CFLAGS         += -Wall -fno-stack-protector -Wstrict-prototypes -g
+CFLAGS         += -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wuninitialized
+CFLAGS          += -O3
+LDFLAGS                += -T arch/$(ARCHDIR)/link.ld -g
+
+ifeq ($(PLATFORM),default)
+       OBJDIR := obj-$(ARCH)/
+       #OBJSUFFIX := .$(ARCH)
+       BIN := ../Acess2.$(ARCH).bin
+       GZBIN := ../Acess2.$(ARCH).gz
+else
+       OBJDIR := obj-$(ARCH)-$(PLATFORM)/
+       #OBJSUFFIX := .$(ARCH)-$(PLATFORM)
+       BIN := ../Acess2.$(ARCH)-$(PLATFORM).bin
+       GZBIN := ../Acess2.$(ARCH)-$(PLATFORM).gz
+endif
+
+ifeq ($(DEBUG_BUILD),yes)
+       LDFLAGS += -g
+       CFLAGS += -g
+endif
+
+BUILDINFO_OBJ := $(OBJDIR)buildinfo.o$(OBJSUFFIX)
+BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX)
+
+OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
+OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
+OBJ += messages.o modules.o syscalls.o system.o
+OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
+OBJ += drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
+OBJ += binary.o bin/elf.o bin/pe.o
+OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
+OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o
+OBJ += vfs/fs/root.o vfs/fs/devfs.o
+OBJ += $(addprefix drv/, $(addsuffix .o,$(DRIVERS)))
+
+OBJ := $(addsuffix $(OBJSUFFIX), $(OBJ))
+OBJ := $(addprefix $(OBJDIR), $(OBJ))
+
+MODS += $(addprefix ../Modules/, $(addsuffix .xo.$(ARCH),$(MODULES)))
+
+DEPFILES := $(OBJ:%$(OBJSUFFIX)=%.dep$(OBJSUFFIX))
+
+SRCFILES  = $(OBJ:$(OBJDIR)%.o$(OBJSUFFIX)=%.c)
+SRCFILES := $(SRCFILES:$(OBJDIR)%.ao$(OBJSUFFIX)=%.$(AS_SUFFIX))
+
+OBJ += $(BUILDINFO_OBJ)
+
+.PHONY: all clean install apidoc
+
+all: $(BIN)
+
+clean:
+       @$(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt
+       @$(RM) -r $(OBJDIR) $(OBJ) $(DEPFILES) $(BUILDINFO_SRC)
+
+install: $(BIN) 
+       @cp $(BIN) $(BIN)_
+       @$(STRIP) $(BIN)_
+       @gzip -c $(BIN)_ > $(GZBIN)
+       @$(RM) $(BIN)_
+       $(xCP) $(GZBIN) $(DISTROOT)
+
+apidoc:
+       doxygen Doxyfile.api
+
+$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile ../BuildConf/$(ARCH)/Makefile.cfg ../BuildConf/$(ARCH)/$(PLATFORM).mk
+       @echo --- LD -o $(BIN)
+       @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
+       @$(DISASM) -S $(BIN) > $(BIN).dsm
+       @wc -l $(SRCFILES) include/*.h > LineCounts.$(ARCH).txt
+       @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum.$(ARCH)
+       $(POSTBUILD)
+
+$(OBJDIR)%.ao$(OBJSUFFIX): %.$(AS_SUFFIX) Makefile
+       @echo --- AS -o $@
+       @mkdir -p $(dir $@)
+       @$(AS) $(ASFLAGS) $< -o $@
+ifeq ($(AS_SUFFIX),S)
+       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $<
+endif
+
+$(OBJDIR)%.o$(OBJSUFFIX): %.c Makefile
+#      if exists %*/Makefile
+#      @make -C %*/ all
+#      else
+       @echo --- CC -o $@
+       @mkdir -p $(dir $@)
+       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
+       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $<
+#      endif
+
+%.xo.$(ARCH):
+       @BUILDTYPE=static make -C $* all
+
+include/syscalls.h include/syscalls.inc.asm:   syscalls.lst Makefile GenSyscalls.pl
+       perl GenSyscalls.pl
+
+Makefile:      ../Makefile.cfg arch/$(ARCHDIR)/Makefile
+
+$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
+       @echo "#include <acess.h>" > $@
+       @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
+       @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@
+$(BUILDINFO_OBJ): $(BUILDINFO_SRC)
+       @echo --- CC -o $@
+       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
+
+# Dependency Files
+-include $(DEPFILES)
diff --git a/KernelLand/Kernel/adt.c b/KernelLand/Kernel/adt.c
new file mode 100644 (file)
index 0000000..ef2ae05
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Acess2 Kernel
+ * 
+ * adt.c
+ * - Complex data type code
+ */
+#include <acess.h>
+#include <adt.h>
+
+
+// === CODE ===
+// --- Ring Buffers ---
+tRingBuffer *RingBuffer_Create(size_t Space)
+{
+       tRingBuffer     *ret = malloc(sizeof(tRingBuffer)+Space);
+       ret->Start = 0;
+       ret->Length = 0;
+       ret->Space = Space;
+       return ret;
+}
+
+size_t RingBuffer_Read(void *Dest, tRingBuffer *Buffer, size_t Length)
+{
+       size_t  tmpLen;
+
+       tmpLen = Buffer->Length;        // Changed in Write, so cache it for our read
+
+       if(Length > tmpLen)     Length = tmpLen;
+       
+       if( Buffer->Start + Length > Buffer->Space )
+       {
+                int    endData = Buffer->Space - Buffer->Start;
+               memcpy(Dest, &Buffer->Data[Buffer->Start], endData);
+               memcpy((Uint8*)Dest + endData, Buffer->Data, Length - endData);
+       }
+       else
+       {
+               memcpy(Dest, &Buffer->Data[Buffer->Start], Length);
+       }
+
+       // Lock then modify
+       SHORTLOCK( &Buffer->Lock );
+       Buffer->Start += Length;
+       if( Buffer->Start > Buffer->Space )
+               Buffer->Start -= Buffer->Space;
+       Buffer->Length -= Length;
+       SHORTREL( &Buffer->Lock );
+
+       return Length;
+}
+
+size_t RingBuffer_Write(tRingBuffer *Buffer, const void *Source, size_t Length)
+{
+       size_t  bufEnd, endSpace;
+       size_t  tmpLen, tmpStart;
+       
+       // Cache Start and Length because _Read can change these
+       SHORTLOCK( &Buffer->Lock );
+       tmpStart = Buffer->Start;
+       tmpLen = Buffer->Length;
+       SHORTREL( &Buffer->Lock );
+
+       bufEnd = (tmpStart + Buffer->Length) % Buffer->Space;
+       endSpace = Buffer->Space - bufEnd;
+       
+       // Force to bounds
+       if(Length > Buffer->Space - tmpLen)     Length = Buffer->Space - tmpLen;
+       
+       if(endSpace < Length)
+       {
+               memcpy( &Buffer->Data[bufEnd], Source, endSpace );
+               memcpy( Buffer->Data, (Uint8*)Source + endSpace, Length - endSpace );
+       }
+       else
+       {
+               memcpy( &Buffer->Data[bufEnd], Source, Length );
+       }
+
+       // Lock then modify
+       SHORTLOCK( &Buffer->Lock );
+       Buffer->Length += Length;
+       SHORTREL( &Buffer->Lock );
+       
+       return Length;
+}
+
diff --git a/KernelLand/Kernel/arch/archdoc.h b/KernelLand/Kernel/arch/archdoc.h
new file mode 100644 (file)
index 0000000..ef3331f
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * \file archdoc.h
+ * \brief Documentation Definitions for the Acess 2 Architecture Interface
+ * \author John Hodge (thePowersGang)
+ * 
+ * Acess 2 allows different architecture builds to be made off almost
+ * the same source tree. The difference between the trees is the inclusion
+ * of a different directory from the "Kernel/arch/" directory that
+ * contains the architecture specific intialisation and management code.
+ * Each achitecture tree must provide all the definitions from this
+ * document in some form or another (usually in the most efficient way
+ * avaliable)
+ * The values and types used in this documentation are a guide only and
+ * will most probably be incorrect for most architectures.
+ */
+#ifndef _ARCHDOC_H_
+#define _ARCHDOC_H_
+
+/**
+ * \brief Maximum number of CPUs supported by this architecture driver
+ *        (in the current build)
+ */
+#define        MAX_CPUS        1
+/**
+ * \brief Number of bits in a machine word (Uint)
+ */
+#define        BITS    32
+/**
+ * \brief Number of valid bits in a \a tPAddr
+ */
+#define        PHYS_BITS       32
+
+/**
+ * \name Syncronisation Primitives
+ * \{
+ */
+/**
+ * \brief Spinlock type
+ */
+typedef volatile int   tSpinlock;
+/**
+ * \brief Acquire a spinlock
+ */
+#define LOCK(lockptr)  do{while(*(tSpinlock*)lockptr)Threads_Yield();*(tSpinlock*)lockptr=1;}while(0)
+/**
+ * \brief Release a held spinlock
+ */
+#define RELEASE(lockptr)       do{*(tSpinlock*)lockptr=0;}while(0)
+/**
+ * \}
+ */
+//#define      HALT()  __asm__ __volatile__ ("hlt")
+
+
+/**
+ * \name Atomic Types
+ * \{
+ */
+typedef unsigned int   Uint;   //!< Unsigned machine native integer
+typedef unsigned char  Uint8;  //!< Unsigned 8-bit integer
+typedef unsigned short Uint16; //!< Unsigned 16-bit integer
+typedef unsigned long  Uint32; //!< Unsigned 32-bit integer
+typedef unsigned long long     Uint64; //!< Unsigned 64-bit integer
+typedef signed int             Sint;   //!< Signed Machine Native integer
+typedef signed char            Sint8;  //!< Signed 8-bit integer
+typedef signed short   Sint16; //!< Signed 16-bit integer
+typedef signed long            Sint32; //!< Signed 32-bit integer
+typedef signed long long       Sint64; //!< Signed 16-bit integer
+/**
+ * \}
+ */
+
+typedef Uint   size_t; //!< Counter/Byte count type
+typedef Uint32 tVAddr; //!< Virtual address type
+typedef Uint32 tPAddr; //!< Physical Address type
+
+/**
+ * \brief Register state passed to the syscall handler
+ * 
+ * The \a tSyscallRegs structure allows the system call handler to read
+ * the user state to get the arguments for the call. It also allows the
+ * handler to alter specific parts of the user state to reflect the
+ * result of the call.
+ * \note The fields shown here are need only be present in the actual
+ *       structure, in any order. The implementation may also add more
+ *       fields for padding purposes.
+ */
+typedef struct {
+       Uint    Arg4;   //!< Fourth argument
+       Uint    Arg3;   //!< Third argument
+       Uint    Arg2;   //!< Second argument
+       union {
+               Uint    Arg1;   //!< First arugment
+               Uint    RetHi;  //!< High part of the return
+       };
+       union {
+               Uint    Num;    //!< Call Number
+               Uint    Return; //!< Low return value
+       };
+       
+       Uint    StackPointer;   //!< User stack pointer
+}      tSyscallRegs;
+
+/**
+ * \brief Opaque structure definining the MMU state for a task
+ */
+typedef struct sMemoryState    tMemoryState;
+
+/**
+ * \brief Opque structure defining the CPU state for a task
+ */
+typedef struct sTaskState      tTaskState;
+
+
+/**
+ * \name Memory Management
+ * \{
+ */
+/**
+ * \}
+ */
+
+
+#endif
diff --git a/KernelLand/Kernel/arch/armv7/Makefile b/KernelLand/Kernel/arch/armv7/Makefile
new file mode 100644 (file)
index 0000000..fad1b55
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Acess2 Kernel
+# arm7 Architecture Makefile
+# arch/arm7/Makefile
+
+CPPFLAGS       =
+CFLAGS         =
+ASFLAGS                =
+
+CPPFLAGS += -DMMU_PRESENT=1
+LDFLAGS += `$(CC) --print-libgcc-file-name`
+
+A_OBJ  = start.ao main.o lib.o lib.ao time.o pci.o debug.o
+A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
+
+#main.c: Makefile.BuildNum.$(ARCH)
+
+ifeq ($(PLATFORM),tegra2)
+       POSTBUILD = arm-elf-objcopy $(BIN) -O binary $(BIN)
+endif
diff --git a/KernelLand/Kernel/arch/armv7/debug.c b/KernelLand/Kernel/arch/armv7/debug.c
new file mode 100644 (file)
index 0000000..7b9e55d
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/debug.c
+ * - ARM7 Debug output
+ * NOTE: Currently designed for the realview-pb-a8 emulated by Qemu
+ */
+#include <acess.h>
+
+// === CONSTANTS ===
+//#define UART0_BASE   0x10009000
+#define UART0_BASE     0xF1000000      // Boot time mapped
+
+// === PROTOTYPES ===
+void   KernelPanic_SetMode(void);
+void   KernelPanic_PutChar(char Ch);
+void   StartupPrint(const char *str);
+
+// === GLOBALS ===
+ int   giDebug_SerialInitialised = 0;
+
+// === CODE ===
+void Debug_PutCharDebug(char ch)
+{
+       if(ch == '\n')
+               Debug_PutCharDebug('\r');
+
+       #if PLATFORM_is_tegra2
+       // Tegra2
+       while( !(*(volatile Uint32*)(UART0_BASE + 0x14) & (1 << 5)) )
+               ;
+       #endif
+       
+//     *(volatile Uint32*)(SERIAL_BASE + SERIAL_REG_DATA) = ch;
+       *(volatile Uint32*)(UART0_BASE) = ch;
+}
+
+void Debug_PutStringDebug(const char *str)
+{
+       for( ; *str; str++ )
+               Debug_PutCharDebug( *str );
+}
+
+void KernelPanic_SetMode(void)
+{
+}
+
+void KernelPanic_PutChar(char ch)
+{
+//     Debug_PutCharDebug(ch);
+}
+
+void StartupPrint(const char *str)
+{
+}
+
diff --git a/KernelLand/Kernel/arch/armv7/include/arch.h b/KernelLand/Kernel/arch/armv7/include/arch.h
new file mode 100644 (file)
index 0000000..837a5e1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Acess2
+ * ARM7 Architecture Header
+ */
+#ifndef _ARCH_H_
+#define _ARCH_H_
+
+// === CONSTANTS ===
+#define INVLPTR        ((void*)-1)
+#define BITS   32
+#define PAGE_SIZE      0x1000
+#define KERNEL_BASE    0x80000000      // 2GiB
+
+// === TYPES ===
+typedef unsigned int   Uint;
+typedef unsigned char  Uint8;
+typedef unsigned short Uint16;
+typedef unsigned long  Uint32;
+typedef unsigned long long     Uint64;
+typedef signed int     Sint;
+typedef signed char    Sint8;
+typedef signed short   Sint16;
+typedef signed long    Sint32;
+typedef signed long long       Sint64;
+
+typedef int    size_t;
+typedef char   BOOL;
+
+typedef Uint32 tVAddr;
+typedef Uint32 tPAddr;
+
+#include "lock.h"
+
+// --- Debug
+extern void    Debug_PutCharDebug(char Ch);
+extern void    Debug_PutStringDebug(const char *String);
+
+// This should be elsewhere, but CBF
+extern void    MM_SetupPhys(void);
+extern int     MM_InitialiseVirtual(void);
+
+#define NO_IO_BUS      1
+
+#endif
diff --git a/KernelLand/Kernel/arch/armv7/include/assembly.h b/KernelLand/Kernel/arch/armv7/include/assembly.h
new file mode 100644 (file)
index 0000000..0c5c57f
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Acess2 ARMv7
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/include/assembly.h
+ * - Assembly specific macros
+ */
+#ifndef _ASSEMBLY_H_
+#define _ASSEMBLY_H_
+
+#define PUSH_GPRS \
+       str r0, [sp,#-1*4];\
+       str r1, [sp,#-2*4];\
+       str r2, [sp,#-3*4];\
+       str r3, [sp,#-4*4];\
+       str r4, [sp,#-5*4];\
+       str r5, [sp,#-6*4];\
+       str r6, [sp,#-7*4];\
+       str r7, [sp,#-8*4];\
+       str r8, [sp,#-9*4];\
+       str r9, [sp,#-10*4];\
+       str r10, [sp,#-11*4];\
+       str r11, [sp,#-12*4];\
+       str r12, [sp,#-13*4];\
+       str sp, [sp,#-14*4];\
+       str lr, [sp,#-15*4];\
+       sub sp, #16*4
+
+#define POP_GPRS add sp, #16*4; \
+       ldr r0, [sp,#-1*4]; \
+       ldr r1, [sp,#-2*4]; \
+       ldr r2, [sp,#-3*4]; \
+       ldr r3, [sp,#-4*4]; \
+       ldr r4, [sp,#-5*4]; \
+       ldr r5, [sp,#-6*4]; \
+       ldr r6, [sp,#-7*4]; \
+       ldr r7, [sp,#-8*4]; \
+       ldr r8, [sp,#-9*4]; \
+       ldr r9, [sp,#-10*4]; \
+       ldr r10, [sp,#-11*4]; \
+       ldr r11, [sp,#-12*4]; \
+       ldr r12, [sp,#-13*4]; \
+       ldr lr, [sp,#-15*4];
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv7/include/lock.h b/KernelLand/Kernel/arch/armv7/include/lock.h
new file mode 100644 (file)
index 0000000..6688af4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Acess2
+ * ARM7 Architecture
+ *
+ * lock.h - Hardware level spinlocks
+ */
+#ifndef _LOCK_H_
+#define _LOCK_H_
+
+// === CODE ===
+struct sShortSpinlock {
+        int    Lock;
+};
+
+// --- Spinlocks ---
+static inline int IS_LOCKED(struct sShortSpinlock *Lock)
+{
+       return !!Lock->Lock;
+}
+
+static inline int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
+{
+       // TODO: Handle multiple CPUs
+       return !!Lock->Lock;
+}
+
+static inline int SHORTLOCK(struct sShortSpinlock *Lock)
+{
+       #if 0
+       // Coped from linux, yes, but I know what it does now :)
+       Uint    tmp;
+       __asm__ __volatile__ (
+       "1:     ldrex   %0, [%1]\n"     // Exclusive LOAD
+       "       teq     %0, #0\n"       // Check if zero
+       "       strexeq %0, %2, [%1]\n" // Set to one if it is zero (releasing lock on the memory)
+       "       teqeq   %0, #0\n"       // If the lock was avaliable, check if the write succeeded
+       "       bne     1b"     // If the lock was unavaliable, or the write failed, loop
+               : "=&r" (tmp)   // Temp
+               : "r" (&Lock->Lock), "r" (1)
+               : "cc"  // Condition codes clobbered
+               );
+       #elif 1
+       while( *(volatile int*)&Lock->Lock )    ;
+       Lock->Lock = 1;
+       #else
+        int    v = 1;
+       while( v )
+               __asm__ __volatile__ (
+                       "swp %0, %0, [%1]"
+                       : "=r" (v) : "r" (&Lock->Lock)
+                       : "cc"
+                       );
+       #endif
+       return 1;
+}
+
+static inline void SHORTREL(struct sShortSpinlock *Lock)
+{
+       Lock->Lock = 0;
+}
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv7/include/mm_virt.h b/KernelLand/Kernel/arch/armv7/include/mm_virt.h
new file mode 100644 (file)
index 0000000..c1f10de
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Acess2
+ * ARM7 Virtual Memory Manager Header
+ */
+#ifndef _MM_VIRT_H_
+#define _MM_VIRT_H_
+
+#include "options.h"
+
+#define USER_STACK_COMM    0x04000     // Pages to allocate up front
+#define USER_STACK_SIZE           0x10000      // Stack space
+#define USER_STACK_TOP 0x78000000
+
+#define MM_USER_MIN    0x00001000
+#define USER_LIB_MAX   0x70000000
+#define MM_PPD_HANDLES 0x7F800000
+#define MM_TABLE1USER  0x7FC00000      // 2 GiB - 4 MiB
+#define MM_TABLE0USER  0x7FE00000      // 2 GiB - 2 MiB
+#define MM_KSTACK_BASE 0x7FE00000
+#define MM_KSTACK_END  0x80000000
+
+// Page Blocks are 12-bits wide (12 address bits used)
+// Hence, the table is 16KiB large (and must be so aligned)
+// and each block addresses 1MiB of data
+
+// First level table is aligned to 16KiB (restriction of TTBR reg)
+// - VMSAv6 uses two TTBR regs, determined by bit 31
+
+//#define KERNEL_BASE  0x80000000      // 2GiB
+
+#define MM_KHEAP_BASE  0x80800000      // 8MiB of kernel code
+#define MM_KHEAP_MAX   0xC0000000      // ~1GiB of kernel heap
+
+#define MM_MODULE_MIN  0xC0000000      // - 0xD0000000
+#define MM_MODULE_MAX  0xCF000000
+
+#define MM_GLOBALSTACKS        0xCF000000      // Global stacks
+#define MM_GLOBALSTACKS_END    0xD0000000
+
+// PMM Data, giving it 256MiB is overkill, but it's unused atm
+#define MM_MAXPHYSPAGE (1024*1024)
+// 2^(32-12) max pages
+// 8.125 bytes per page (for bitmap allocation)
+// = 8.125 MiB
+#define MM_PMM_BASE    0xE0000000
+#define MM_PMM_END     0xF0000000
+
+#define MM_HWMAP_BASE  0xF0000000      // Ent 0xF00
+#define MM_HWMAP_END   0xFE000000
+#define MM_TMPMAP_BASE 0xFE000000
+#define MM_TMPMAP_END  0xFF000000
+
+#define MM_KERNEL_VFS  0xFF000000      // 
+#define MM_TABLE1KERN  0xFF800000      // - 0x???????? 4MiB
+//#define MM_TABLE0KERN        0xFFC00000      // - 0xFFE04000 16KiB
+
+#endif
diff --git a/KernelLand/Kernel/arch/armv7/include/options.h b/KernelLand/Kernel/arch/armv7/include/options.h
new file mode 100644 (file)
index 0000000..95345ed
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Acess2 ARMv7 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * options.h
+ * - C/ASM Shared constants
+ */
+#ifndef _ARMV7_OPTIONS_H_
+#define _ARMV7_OPTIONS_H_
+
+#define KERNEL_BASE    0x80000000
+
+//#define PCI_PADDR    0x60000000      // Realview (Non-PB)
+
+#if PLATFORM_is_realview_pb
+# define UART0_PADDR   0x10009000      // Realview
+# define GICI_PADDR    0x1e000000
+# define GICD_PADDR    0x1e001000
+# define PL110_BASE    0x10020000      // Integrator
+
+#endif
+
+#if PLATFORM_is_tegra2 // Tegra2
+# define UART0_PADDR   0x70006000
+# define GICD_PADDR    0x50041000
+# define GICI_PADDR    0x50040100
+//# define PL110_BASE  0x10020000      // Integrator
+#endif
+
+#define MM_KSTACK_SIZE 0x2000  // 2 Pages
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv7/include/proc.h b/KernelLand/Kernel/arch/armv7/include/proc.h
new file mode 100644 (file)
index 0000000..d6ef3d5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Acess2
+ * ARM7 Architecture
+ *
+ * proc.h - Arch-Dependent Process Management
+ */
+#ifndef _PROC_H_
+#define _PROC_H_
+
+#define MAX_CPUS       4
+#define USER_MAX       0x80000000
+
+// === STRUCTURES ===
+typedef struct {
+       Uint32  IP, SP;
+       Uint32  UserIP, UserSP;
+} tTaskState;
+
+typedef struct {
+       Uint32  Base;
+} tMemoryState;
+
+typedef struct {
+       union {
+               Uint32  Num;
+               Uint32  Error;
+       };
+       union {
+               Uint32  Arg1;
+               Uint32  Return;
+       };
+       union {
+               Uint32  Arg2;
+               Uint32  RetHi;
+       };
+       Uint32  Arg3;
+       Uint32  Arg4;
+       Uint32  Arg5;
+       Uint32  Arg6;   // R6
+} tSyscallRegs;
+
+// === MACROS ===
+#define HALT() do{}while(0)
+
+// === PROTOTYPES ===
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv7/lib.S b/KernelLand/Kernel/arch/armv7/lib.S
new file mode 100644 (file)
index 0000000..e2f0613
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Acess2 ARM
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/lib.S
+ * - Assembly editions of library functions
+ */
+#include "include/assembly.h"
+
+.globl __memcpy_byte
+__memcpy_byte:
+1:
+       tst r2, r2      @ Check counter
+       moveq pc, lr    @ Return if zero
+       ldrb r3, [r1],#1        @ Read
+       strb r3, [r0],#1        @ Write
+       sub r2, #1
+       b 1b
+
+@ 
+@ Pre-aligned memcpy (32-bit blocks)
+@ 
+.globl __memcpy_align4
+__memcpy_align4:
+       push {r4}
+       mvn r3, #3      @ Mask for checking length
+       
+       @ 4 byte chunk copies
+1:     tst r2, r3
+       ldrne r4, [r1],#4
+       strne r4, [r0],#4
+       subne r2, #4
+       bne 1b
+
+       @ single byte copies to finish off
+2:     tst r2, #3
+       beq 3f
+       ldrb r4, [r1],#1
+       strb r4, [r0],#1
+       sub r2, #1
+       b 2b
+
+3:     pop {r4}
+       mov pc, lr
+
+@
+@ Division
+@
+.globl __divmod32_asm
+__divmod32_asm:
+       push {r4}
+       mov r4, #0      @ Return value
+       mov r3, #1      @ add value
+
+       @ Scan up for first larger multiple of 2
+1:     cmp r0, r1      @ N < D
+       bmi 2f          @ ^^
+       lsl r1, r1, #1  @ D <<= 1
+       lsls r3, r3, #1 @ add <<= 1
+       beq .err        @ result is zero
+       b 1b
+       
+       @ Go back down
+2:     lsrs r3, r3, #1 @ add >>= 1
+       beq 3f          @ Done (value is zero)
+       lsr r1, r1, #1  @ D >>= 1
+       cmp r0, r1      @ N < D
+       bmi 2b
+       sub r0, r1      @ N -= D
+       add r4, r3      @ ret += add
+       b 2b
+3:
+       tst r2, r2      @ Remainder (if wanted)
+       strne r0,[r2]
+       mov r0, r4      @ Return value
+       pop {r4}
+       mov pc, lr
+.err:
+       mov r0, #0
+       tst r2, r2
+       strne r0, [r2]
+       pop {r4}
+       mov pc, lr
+
diff --git a/KernelLand/Kernel/arch/armv7/lib.c b/KernelLand/Kernel/arch/armv7/lib.c
new file mode 100644 (file)
index 0000000..5a6928e
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Acess2 ARM7 Port
+ *
+ * lib.c - Library Functions
+ */
+#include <acess.h>
+#include "../helpers.h"
+
+// === IMPORTS ===
+extern void    __memcpy_align4(void *_dest, const void *_src, size_t _length);
+extern void    __memcpy_byte(void *_dest, const void *_src, size_t _length);
+extern Uint32  __divmod32_asm(Uint32 Num, Uint32 Den, Uint32 *Rem);
+
+// === PROTOTYPES ===
+Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
+Uint32 __divmod32(Uint32 Num, Uint32 Den, Uint32 *Rem);
+Uint64 __udivdi3(Uint64 Num, Uint64 Den);
+Uint64 __umoddi3(Uint64 Num, Uint64 Den);
+Uint32 __udivsi3(Uint32 Num, Uint32 Den);
+Uint32 __umodsi3(Uint32 Num, Uint32 Den);
+Sint32 __divsi3(Sint32 Num, Sint32 Den);
+Sint32 __modsi3(Sint32 Num, Sint32 Den);
+
+// === CODE ===
+void *memcpy(void *_dest, const void *_src, size_t _length)
+{
+       Uint8   *dst8 = _dest;
+       const Uint8     *src8 = _src;
+
+       if( ((tVAddr)_dest & 3) == 0 && ((tVAddr)_src & 3) == 0 )
+       {
+               __memcpy_align4(_dest, _src, _length);
+               return _dest;
+       }
+
+       // Handle small copies / Non-aligned
+       if( _length < 4 || ((tVAddr)_dest & 3) != ((tVAddr)_src & 3) )
+       {
+               __memcpy_byte(_dest, _src, _length);
+               return _dest;
+       }
+
+       // Force alignment
+       while( (tVAddr)dst8 & 3 ) *dst8 ++ = *src8++, _length --;
+
+       __memcpy_align4(dst8, src8, _length);
+       
+       return _dest;
+}
+
+int memcmp(const void *_m1, const void *_m2, size_t _length)
+{
+       const Uint32    *m1, *m2;
+       const Uint8     *m1_8 = _m1, *m2_8 = _m2;
+
+       // Handle small copies / Non-aligned
+       if( _length < 4 || ((tVAddr)_m1 & 3) != ((tVAddr)_m1 & 3) )
+       {
+               for( ; _length--; m1_8++,m2_8++ ) {
+                       if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
+               }
+               return 0;
+       }
+
+       // Force alignment
+       for( ; (tVAddr)m1_8 & 3; m1_8 ++, m2_8 ++) {
+               if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
+       }
+       m1 = (void *)m1_8;      m2 = (void *)m2_8;
+
+       // DWORD copies
+       for( ; _length > 3; _length -= 4, m1++, m2++)
+               if(*m1 != *m2)  return *m1 - *m2;
+
+       // Trailing bytes
+       m1_8 = (void*)m1;       m2_8 = (void*)m2;
+       for( ; _length; _length --, m1_8++, m2_8++ )
+               if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
+       
+       return 0;
+}
+
+void *memset(void *_dest, int _value, size_t _length)
+{
+       Uint32  *dst, val32;
+       Uint8   *dst8 = _dest;
+
+       _value = (Uint8)_value;
+
+       // Handle small copies
+       if( _length < 4 )
+       {
+               for( ; _length--; dst8++ )
+                       *dst8 = _value;
+               return _dest;
+       }
+
+       val32 = _value;
+       val32 |= val32 << 8;
+       val32 |= val32 << 16;
+       
+       // Force alignment
+       while( (tVAddr)dst8 & 3 ) *dst8 ++ = _value;
+       dst = (void *)dst8;
+
+       // DWORD copies
+       for( ; _length > 3; _length -= 4)
+               *dst++ = val32;
+
+       // Trailing bytes
+       dst8 = (void*)dst;
+       for( ; _length; _length -- )
+               *dst8 ++ = _value;
+       
+       return _dest;
+}
+
+DEF_DIVMOD(64)
+DEF_DIVMOD(32)
+
+Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
+{
+       Uint64  ret;
+       if(Den == 0)    return 0;       // TODO: #div0
+       if(Num < Den) {
+               if(Rem) *Rem = Num;
+               return 0;
+       }
+       if(Num == 0) {
+               if(Rem) *Rem = 0;
+               return 0;
+       }
+       if(Den == 1) {
+               if(Rem) *Rem = 0;
+               return Num;
+       }
+       if(Den == 2) {
+               if(Rem) *Rem = Num & 1;
+               return Num >> 1;
+       }
+       if(Den == 16) {
+               if(Rem) *Rem = Num & 0xF;
+               return Num >> 4;
+       }
+       if(Den == 32) {
+               if(Rem) *Rem = Num & 0x1F;
+               return Num >> 5;
+       }
+       if(Den == 0x1000) {
+               if(Rem) *Rem = Num & 0xFFF;
+               return Num >> 12;
+       }
+       
+       if( !(Den >> 32) && !(Num >> 32) ) {
+               if(Rem) *Rem = 0;       // Clear high bits
+               return __divmod32_asm(Num, Den, (Uint32*)Rem);
+       }
+
+       ret = __divmod64(Num, Den, Rem);
+       return ret;
+}
+
+// Unsigned Divide 64-bit Integer
+Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+{
+       return DivMod64U(Num, Den, NULL);
+}
+
+// Unsigned Modulus 64-bit Integer
+Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+{
+       Uint64  ret = 0;
+       DivMod64U(Num, Den, &ret);
+       return ret;
+}
+
+Uint32 __udivsi3(Uint32 Num, Uint32 Den)
+{
+       return __divmod32_asm(Num, Den, NULL);
+}
+
+Uint32 __umodsi3(Uint32 Num, Uint32 Den)
+{
+       Uint32  rem;
+       __divmod32_asm(Num, Den, &rem);
+       return rem;
+}
+
+static inline Sint32 DivMod32S(Sint32 Num, Sint32 Den, Sint32 *Rem)
+{
+       Sint32  ret = 1;
+       if( Num < 0 ) {
+               ret = -ret;
+               Num = -Num;
+       }
+       if( Den < 0 ) {
+               ret = -ret;
+               Den = -Den;
+       }
+       if(ret < 0)
+               ret = -__divmod32(Num, Den, (Uint32*)Rem);
+       else
+               ret = __divmod32(Num, Den, (Uint32*)Rem);
+       return ret;
+}
+
+Sint32 __divsi3(Sint32 Num, Sint32 Den)
+{
+       return DivMod32S(Num, Den, NULL);
+}
+
+Sint32 __modsi3(Sint32 Num, Sint32 Den)
+{
+       Sint32  rem;
+       DivMod32S(Num, Den, &rem);
+       return rem;
+}
diff --git a/KernelLand/Kernel/arch/armv7/link.ld b/KernelLand/Kernel/arch/armv7/link.ld
new file mode 100644 (file)
index 0000000..d10dcc4
--- /dev/null
@@ -0,0 +1,55 @@
+ENTRY (_start)
+
+_kernel_base = 0x80000000;
+_usertext_vbase = 0xFFFFE000;
+
+SECTIONS
+{
+       . = 0;
+       .init :
+       {
+               *(.init)
+       }
+       . += _kernel_base;
+       .text : AT( ADDR(.text) - _kernel_base )
+       {
+               *(.text*)
+               *(.rodata*)
+       }
+                       
+
+       /* HACKS: User accesible .text section */
+       . = ALIGN(0x1000);
+       gUsertextPhysStart = . - _kernel_base;
+       . = _usertext_vbase;
+       .usertext : AT( gUsertextPhysStart )
+       {
+               *(.usertext)
+       }
+       . += gUsertextPhysStart + _kernel_base - _usertext_vbase;
+       
+       /* 0x4000 (4 pages) alignment needed for root table */
+       .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
+       {
+               *(.padata)
+               *(.data*)
+               
+               gKernelSymbols = .;
+               *(KEXPORT)
+               gKernelSymbolsEnd = .;
+               
+               gKernelModules = .;
+               *(KMODULES)
+               gKernelModulesEnd = .;
+       }
+       .bss : AT( ADDR(.bss) - _kernel_base )
+       {
+               bss_start = .;
+               *(.bss*)
+               *(COMMON*)
+               . = ALIGN(0x1000);
+               *(.pabss)
+               bss_end = .;
+       }
+       gKernelEnd = .;
+}
diff --git a/KernelLand/Kernel/arch/armv7/main.c b/KernelLand/Kernel/arch/armv7/main.c
new file mode 100644 (file)
index 0000000..248c17c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Acess2
+ *
+ * ARM7 Entrypoint
+ * arch/arm7/main.c
+ */
+#define DEBUG  0
+
+#include <acess.h>
+#include <modules.h>
+
+// === IMPORTS ===
+extern void    Interrupts_Setup(void);
+extern void    Arch_LoadBootModules(void);
+extern void    Heap_Install(void);
+extern void    Threads_Init(void);
+extern void    System_Init(const char *Commandline);
+
+// === PROTOTYPES ===
+ int   kmain(void);
+Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args);
+
+// === CODE ===
+int kmain(void)
+{
+       LogF("Acess2 ARMv7 v"EXPAND_STR(KERNEL_VERSION)"\n");
+       LogF(" Git Hash %s\n", gsGitHash);
+       LogF(" Build %i\n", BUILD_NUM);
+       
+       MM_SetupPhys();
+
+       LogF("Heap Setup...\n");
+       Heap_Install();
+
+       LogF("Threads Init...\n");
+       Threads_Init();
+       
+       LogF("VFS Init...\n");
+       VFS_Init();
+
+       // Boot modules?
+       Module_EnsureLoaded("armv7_GIC");
+
+       //
+       LogF("Moving to arch-independent init\n");
+       #if PLATFORM_is_tegra2
+       System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=Tegra2Vid");
+       #else
+       System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=PL110");
+       #endif
+//     System_Init("Acess2.armv7.bin /Acess=initrd:");
+       //TODO: 
+       LogF("End of kmain(), for(;;) Threads_Sleep();\n");
+       for(;;)
+               Threads_Sleep();
+}
+
+void Arch_LoadBootModules(void)
+{
+}
+
+Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args)
+{
+       Uint32  ret = -1, err = 0;
+       Uint32  addr;
+       ENTER("iNum xArgs[0] xArgs[1] xArgs[2] xArgs[3]",
+               Num, Args[0], Args[1], Args[2], Args[3]
+               );
+       switch(Num)
+       {
+       case 1:
+//             Log_Debug("ARMv7", "__clear_cache(%p, %p)", Args[0], Args[1]);
+               // Align
+               Args[0] &= ~0xFFF;
+               Args[1] += 0xFFF;       Args[1] &= ~0xFFF;
+               // Invalidate!
+               for( addr = Args[0]; addr < Args[1]; addr += 0x1000 )
+               {
+                       LOG("addr = %p", addr);
+                       __asm__ __volatile__ (
+                               "mcrlt p15, 0, %0, c7, c5, 1;\n\t"
+                               "mcrlt p15, 0, %0, c7, c6, 1;\n\t"
+                               :
+                               : "r" (addr)
+                               );
+               }
+               ret = 0;
+               break;
+       }
+       Args[0] = ret;  // RetLow
+       Args[1] = 0;    // RetHi
+       Args[2] = err;  // Errno
+       LEAVE('x', ret);
+       return ret;
+}
+
diff --git a/KernelLand/Kernel/arch/armv7/mm_phys.c b/KernelLand/Kernel/arch/armv7/mm_phys.c
new file mode 100644 (file)
index 0000000..5e4a242
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Acess2
+ *
+ * ARM7 Physical Memory Manager
+ * arch/arm7/mm_phys.c
+ */
+#define DEBUG  0
+
+#include <acess.h>
+#include <mm_virt.h>
+
+#define MM_NUM_RANGES  1       // Single range
+#define MM_RANGE_MAX   0
+#define TRACE_ALLOCS   0
+
+#define NUM_STATIC_ALLOC       4
+
+char   gStaticAllocPages[NUM_STATIC_ALLOC][PAGE_SIZE] __attribute__ ((section(".padata")));
+tPAddr gaiStaticAllocPages[NUM_STATIC_ALLOC] = {
+       (tPAddr)(&gStaticAllocPages[0]) - KERNEL_BASE,
+       (tPAddr)(&gStaticAllocPages[1]) - KERNEL_BASE,
+       (tPAddr)(&gStaticAllocPages[2]) - KERNEL_BASE,
+       (tPAddr)(&gStaticAllocPages[3]) - KERNEL_BASE
+};
+extern char    gKernelEnd[];
+
+
+#include <tpl_mm_phys_bitmap.h>
+
+//#define REALVIEW_LOWRAM_SIZE 0x10000000
+#define REALVIEW_LOWRAM_SIZE   (32*1024*1024)
+
+void MM_SetupPhys(void)
+{
+       LogF("MM_SetupPhys: ()\n");
+       MM_Tpl_InitPhys( REALVIEW_LOWRAM_SIZE/0x1000, NULL );
+}
+
+int MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length )
+{
+       switch(Index)
+       {
+       case 0:
+               *Start = ((tVAddr)&gKernelEnd - KERNEL_BASE + 0xFFF) & ~0xFFF;
+               *Length = REALVIEW_LOWRAM_SIZE - *Start;
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/**
+ * \brief Takes a physical address and returns the ID of its range
+ * \param Addr Physical address of page
+ * \return Range ID from eMMPhys_Ranges
+ */
+int MM_int_GetRangeID( tPAddr Addr )
+{
+       return MM_RANGE_MAX;    // ARM doesn't need ranges
+}
diff --git a/KernelLand/Kernel/arch/armv7/mm_virt.c b/KernelLand/Kernel/arch/armv7/mm_virt.c
new file mode 100644 (file)
index 0000000..460b334
--- /dev/null
@@ -0,0 +1,1078 @@
+/*
+ * Acess2
+ * 
+ * ARM7 Virtual Memory Manager
+ * - arch/arm7/mm_virt.c
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <mm_virt.h>
+#include <hal_proc.h>
+
+#define TRACE_MAPS     0
+
+#define AP_KRW_ONLY    1       // Kernel page
+#define AP_KRO_ONLY    5       // Kernel RO page
+#define AP_RW_BOTH     3       // Standard RW
+#define AP_RO_BOTH     7       // COW Page
+#define AP_RO_USER     2       // User RO Page
+#define PADDR_MASK_LVL1        0xFFFFFC00
+
+// === IMPORTS ===
+extern Uint32  kernel_table0[];
+
+// === TYPES ===
+typedef struct
+{
+       tPAddr  PhysAddr;
+       Uint8   Size;
+       Uint8   Domain;
+       BOOL    bExecutable;
+       BOOL    bGlobal;
+       BOOL    bShared;
+        int    AP;
+} tMM_PageInfo;
+
+//#define FRACTAL(table1, addr)        ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
+#define FRACTAL(table1, addr)  ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
+#define USRFRACTAL(addr)       (*((Uint32*)(0x7FDFF000) + ((addr)>>22)))
+#define TLBIALL()      __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
+#define TLBIMVA(addr)  __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1;dsb;isb" : : "r" ((addr)&~0xFFF):"memory")
+#define DCCMVAC(addr)  __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" ((addr)&~0xFFF))
+
+// === PROTOTYPES ===
+void   MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
+ int   MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
+ int   MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+ int   MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+tVAddr MM_NewUserStack(void);
+tPAddr MM_AllocateZero(tVAddr VAddr);
+tPAddr MM_AllocateRootTable(void);
+void   MM_int_CloneTable(Uint32 *DestEnt, int Table);
+tPAddr MM_Clone(void);
+tVAddr MM_NewKStack(int bGlobal);
+void   MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
+//void MM_DumpTables(tVAddr Start, tVAddr End);
+void   MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch);
+
+// === GLOBALS ===
+tPAddr giMM_ZeroPage;
+
+// === CODE ===
+int MM_InitialiseVirtual(void)
+{
+       return 0;
+}
+
+void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
+{
+       if(VAddr & 0x80000000) {
+               *Table0 = (void*)&kernel_table0;        // Level 0
+               *Table1 = (void*)MM_TABLE1KERN; // Level 1
+       }
+       else {
+               *Table0 = (void*)MM_TABLE0USER;
+               *Table1 = (void*)MM_TABLE1USER;
+       }
+}
+
+int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
+{
+       Uint32  *table0, *table1;
+       Uint32  *desc;
+       tPAddr  paddr;
+       
+       ENTER("xVAddr iDomain", VAddr, Domain);
+
+       MM_int_GetTables(VAddr, &table0, &table1);
+
+       VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
+
+       desc = &table0[ VAddr>>20];
+       LOG("desc = %p", desc);
+       
+       // table0: 4 bytes = 1 MiB
+
+       LOG("desc[0] = %x", desc[0]);
+       LOG("desc[1] = %x", desc[1]);
+       LOG("desc[2] = %x", desc[2]);
+       LOG("desc[3] = %x", desc[3]);
+
+       if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
+        || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
+       {
+               // Error?
+               LEAVE('i', 1);
+               return 1;
+       }
+
+       paddr = MM_AllocPhys();
+       if( !paddr )
+       {
+               // Error
+               LEAVE('i', 2);
+               return 2;
+       }
+       
+       *desc = paddr | (Domain << 5) | 1;
+       desc[1] = desc[0] + 0x400;
+       desc[2] = desc[0] + 0x800;
+       desc[3] = desc[0] + 0xC00;
+
+       if( VAddr < 0x80000000 ) {
+               USRFRACTAL(VAddr) = paddr | 0x13;
+       }
+       else {
+               FRACTAL(table1, VAddr) = paddr | 0x13;
+       }
+
+       // TLBIALL 
+       TLBIALL();
+       
+       memset( (void*)&table1[ (VAddr >> 12) & ~(1024-1) ], 0, 0x1000 );
+
+       LEAVE('i', 0);
+       return 0;
+}      
+
+int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
+{
+       Uint32  *table0, *table1;
+       Uint32  *desc;
+
+       ENTER("pVAddr ppi", VAddr, pi);
+
+       MM_int_GetTables(VAddr, &table0, &table1);
+
+       desc = &table0[ VAddr >> 20 ];
+       LOG("desc = %p", desc);
+
+       switch(pi->Size)
+       {
+       case 12:        // Small Page
+       case 16:        // Large Page
+               LOG("Page");
+               if( (*desc & 3) == 0 ) {
+                       MM_int_AllocateCoarse( VAddr, pi->Domain );
+               }
+               desc = &table1[ VAddr >> 12 ];
+               LOG("desc (2) = %p", desc);
+               if( pi->Size == 12 )
+               {
+                       // Small page
+                       // - Error if overwriting a large page
+                       if( (*desc & 3) == 1 )  LEAVE_RET('i', 1);
+                       if( pi->PhysAddr == 0 ) {
+                               *desc = 0;
+                               TLBIMVA( VAddr );
+                               DCCMVAC( (tVAddr) desc );
+                               #warning "HACK: TLBIALL"
+                               TLBIALL();
+                               LEAVE('i', 0);
+                               return 0;
+                       }
+
+                       *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
+                       if(!pi->bExecutable)    *desc |= 1;     // XN
+                       if(!pi->bGlobal)        *desc |= 1 << 11;       // nG
+                       if( pi->bShared)        *desc |= 1 << 10;       // S
+                       *desc |= (pi->AP & 3) << 4;     // AP
+                       *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
+                       TLBIMVA( VAddr );       
+                       #warning "HACK: TLBIALL"
+                       TLBIALL();
+                       DCCMVAC( (tVAddr) desc );
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               else
+               {
+                       // Large page
+                       Log_Warning("MMVirt", "TODO: Implement large pages in MM_int_SetPageInfo");
+               }
+               break;
+       case 20:        // Section or unmapped
+               Log_Warning("MMVirt", "TODO: Implement sections in MM_int_SetPageInfo");
+               break;
+       case 24:        // Supersection
+               // Error if not aligned
+               if( VAddr & 0xFFFFFF ) {
+                       LEAVE('i', 1);
+                       return 1;
+               }
+               if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
+               {
+                       if( pi->PhysAddr == 0 ) {
+                               *desc = 0;
+                       }
+                       else {
+                               // Apply
+                               *desc = pi->PhysAddr & 0xFF000000;
+//                             *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
+//                             *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
+                               *desc |= 2 | (1 << 18);
+                       }
+                       // TODO: Apply to all entries
+                       Log_Warning("MMVirt", "TODO: Apply changes to all entries of supersections");
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               // TODO: What here?
+               Log_Warning("MMVirt", "TODO: 24-bit not on supersection?");
+               LEAVE('i', 1);
+               return 1;
+       }
+
+       LEAVE('i', 1);
+       return 1;
+}
+
+int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
+{
+       Uint32  *table0, *table1;
+       Uint32  desc;
+
+//     LogF("MM_int_GetPageInfo: VAddr=%p, pi=%p\n", VAddr, pi);
+       
+       MM_int_GetTables(VAddr, &table0, &table1);
+
+       desc = table0[ VAddr >> 20 ];
+
+//     if( VAddr > 0x90000000)
+//             LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
+       
+       pi->bExecutable = 1;
+       pi->bGlobal = 0;
+       pi->bShared = 0;
+       pi->AP = 0;
+
+       switch( (desc & 3) )
+       {
+       // 0: Unmapped
+       case 0:
+               pi->PhysAddr = 0;
+               pi->Size = 20;
+               pi->Domain = 0;
+               return 1;
+
+       // 1: Coarse page table
+       case 1:
+               // Domain from top level table
+               pi->Domain = (desc >> 5) & 7;
+               // Get next level
+               desc = table1[ VAddr >> 12 ];
+//             LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
+               switch( desc & 3 )
+               {
+               // 0: Unmapped
+               case 0: 
+                       pi->Size = 12;
+                       return 1;
+               // 1: Large Page (64KiB)
+               case 1:
+                       pi->Size = 16;
+                       pi->PhysAddr = desc & 0xFFFF0000;
+                       pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
+                       pi->bExecutable = !(desc & 0x8000);
+                       pi->bShared = (desc >> 10) & 1;
+                       return 0;
+               // 2/3: Small page
+               case 2:
+               case 3:
+                       pi->Size = 12;
+                       pi->PhysAddr = desc & 0xFFFFF000;
+                       pi->bExecutable = !(desc & 1);
+                       pi->bGlobal = !(desc >> 11);
+                       pi->bShared = (desc >> 10) & 1;
+                       pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
+                       return 0;
+               }
+               return 1;
+       
+       // 2: Section (or Supersection)
+       case 2:
+               if( desc & (1 << 18) ) {
+                       // Supersection
+                       pi->PhysAddr = desc & 0xFF000000;
+                       pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
+                       pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
+                       pi->Size = 24;
+                       pi->Domain = 0; // Supersections default to zero
+                       pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
+                       return 0;
+               }
+               
+               // Section
+               pi->PhysAddr = desc & 0xFFF80000;
+               pi->Size = 20;
+               pi->Domain = (desc >> 5) & 7;
+               pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
+               return 0;
+
+       // 3: Reserved (invalid)
+       case 3:
+               pi->PhysAddr = 0;
+               pi->Size = 20;
+               pi->Domain = 0;
+               return 2;
+       }
+       return 2;
+}
+
+// --- Exports ---
+tPAddr MM_GetPhysAddr(tVAddr VAddr)
+{
+       tMM_PageInfo    pi;
+       if( MM_int_GetPageInfo(VAddr, &pi) )
+               return 0;
+       return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
+}
+
+Uint MM_GetFlags(tVAddr VAddr)
+{
+       tMM_PageInfo    pi;
+        int    ret;
+
+       if( MM_int_GetPageInfo(VAddr, &pi) )
+               return 0;
+
+       ret = 0;
+       
+       switch(pi.AP)
+       {
+       case 0:
+               break;
+       case AP_KRW_ONLY:
+               ret |= MM_PFLAG_KERNEL;
+               break;
+       case AP_KRO_ONLY:
+               ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
+               break;
+       case AP_RW_BOTH:
+               break;
+       case AP_RO_BOTH:
+               ret |= MM_PFLAG_COW;
+               break;
+       case AP_RO_USER:
+               ret |= MM_PFLAG_RO;
+               break;
+       }
+
+       if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
+       return ret;
+}
+
+void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
+{
+       tMM_PageInfo    pi;
+       Uint    curFlags;
+       
+       if( MM_int_GetPageInfo(VAddr, &pi) )
+               return ;
+       
+       curFlags = MM_GetFlags(VAddr);
+       if( (curFlags & Mask) == Flags )
+               return ;
+       curFlags &= ~Mask;
+       curFlags |= Flags;
+
+       if( curFlags & MM_PFLAG_COW )
+               pi.AP = AP_RO_BOTH;
+       else
+       {
+               switch(curFlags & (MM_PFLAG_KERNEL|MM_PFLAG_RO) )
+               {
+               case 0:
+                       pi.AP = AP_RW_BOTH;     break;
+               case MM_PFLAG_KERNEL:
+                       pi.AP = AP_KRW_ONLY;    break;
+               case MM_PFLAG_RO:
+                       pi.AP = AP_RO_USER;     break;
+               case MM_PFLAG_KERNEL|MM_PFLAG_RO:
+                       pi.AP = AP_KRO_ONLY;    break;
+               }
+       }
+       
+       pi.bExecutable = !!(curFlags & MM_PFLAG_EXEC);
+
+       MM_int_SetPageInfo(VAddr, &pi);
+}
+
+int MM_IsValidBuffer(tVAddr Addr, size_t Size)
+{
+       tMM_PageInfo    pi;
+        int    bUser = 0;
+       
+       Size += Addr & (PAGE_SIZE-1);
+       Addr &= ~(PAGE_SIZE-1);
+
+       if( MM_int_GetPageInfo(Addr, &pi) )     return 0;
+       Addr += PAGE_SIZE;
+
+       if(pi.AP != AP_KRW_ONLY && pi.AP != AP_KRO_ONLY)
+               bUser = 1;
+
+       while( Size >= PAGE_SIZE )
+       {
+               if( MM_int_GetPageInfo(Addr, &pi) )
+                       return 0;
+               if(bUser && (pi.AP == AP_KRW_ONLY || pi.AP == AP_KRO_ONLY))
+                       return 0;
+               Addr += PAGE_SIZE;
+               Size -= PAGE_SIZE;
+       }
+       
+       return 1;
+}
+
+int MM_Map(tVAddr VAddr, tPAddr PAddr)
+{
+       tMM_PageInfo    pi = {0};
+       #if TRACE_MAPS
+       Log("MM_Map %P=>%p", PAddr, VAddr);
+       #endif
+       
+       pi.PhysAddr = PAddr;
+       pi.Size = 12;
+       if(VAddr < USER_STACK_TOP)
+               pi.AP = AP_RW_BOTH;
+       else
+               pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
+       pi.bExecutable = 1;
+       if( MM_int_SetPageInfo(VAddr, &pi) ) {
+//             MM_DerefPhys(pi.PhysAddr);
+               return 0;
+       }
+       return pi.PhysAddr;
+}
+
+tPAddr MM_Allocate(tVAddr VAddr)
+{
+       tMM_PageInfo    pi = {0};
+       
+       ENTER("pVAddr", VAddr);
+
+       pi.PhysAddr = MM_AllocPhys();
+       if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
+       pi.Size = 12;
+       if(VAddr < USER_STACK_TOP)
+               pi.AP = AP_RW_BOTH;
+       else
+               pi.AP = AP_KRW_ONLY;
+       pi.bExecutable = 0;
+       if( MM_int_SetPageInfo(VAddr, &pi) ) {
+               MM_DerefPhys(pi.PhysAddr);
+               LEAVE('i', 0);
+               return 0;
+       }
+       LEAVE('x', pi.PhysAddr);
+       return pi.PhysAddr;
+}
+
+tPAddr MM_AllocateZero(tVAddr VAddr)
+{
+       if( !giMM_ZeroPage ) {
+               giMM_ZeroPage = MM_Allocate(VAddr);
+               MM_RefPhys(giMM_ZeroPage);
+               memset((void*)VAddr, 0, PAGE_SIZE);
+       }
+       else {
+               MM_RefPhys(giMM_ZeroPage);
+               MM_Map(VAddr, giMM_ZeroPage);
+       }
+       MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
+       return giMM_ZeroPage;
+}
+
+void MM_Deallocate(tVAddr VAddr)
+{
+       tMM_PageInfo    pi;
+       
+       if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
+       if( pi.PhysAddr == 0 )  return;
+       MM_DerefPhys(pi.PhysAddr);
+       
+       pi.PhysAddr = 0;
+       pi.AP = 0;
+       pi.bExecutable = 0;
+       MM_int_SetPageInfo(VAddr, &pi);
+}
+
+tPAddr MM_AllocateRootTable(void)
+{
+       tPAddr  ret;
+       
+       ret = MM_AllocPhysRange(2, -1);
+       if( ret & 0x1000 ) {
+               MM_DerefPhys(ret);
+               MM_DerefPhys(ret+0x1000);
+               ret = MM_AllocPhysRange(3, -1);
+               if( ret & 0x1000 ) {
+                       MM_DerefPhys(ret);
+                       ret += 0x1000;
+//                     Log("MM_AllocateRootTable: Second try not aligned, %P", ret);
+               }
+               else {
+                       MM_DerefPhys(ret + 0x2000);
+//                     Log("MM_AllocateRootTable: Second try aligned, %P", ret);
+               }
+       }
+//     else
+//             Log("MM_AllocateRootTable: Got it in one, %P", ret);
+       return ret;
+}
+
+void MM_int_CloneTable(Uint32 *DestEnt, int Table)
+{
+       tPAddr  table;
+       Uint32  *tmp_map;
+       Uint32  *cur = (void*)MM_TABLE1USER;
+//     Uint32  *cur = &FRACTAL(MM_TABLE1USER,0);
+        int    i;
+       
+       table = MM_AllocPhys();
+       if(!table)      return ;
+
+       cur += 256*Table;
+       
+       tmp_map = (void*)MM_MapTemp(table);
+       
+       for( i = 0; i < 1024; i ++ )
+       {
+//             Log_Debug("MMVirt", "cur[%i] (%p) = %x", Table*256+i, &cur[Table*256+i], cur[Table*256+i]);
+               switch(cur[i] & 3)
+               {
+               case 0: tmp_map[i] = 0; break;
+               case 1:
+                       tmp_map[i] = 0;
+                       Log_Error("MMVirt", "TODO: Support large pages in MM_int_CloneTable (%p)", (Table*256+i)*0x1000);
+                       // Large page?
+                       break;
+               case 2:
+               case 3:
+                       // Small page
+                       // - If full RW
+//                     Debug("%p cur[%i] & 0x230 = 0x%x", Table*256*0x1000, i, cur[i] & 0x230);
+                       if( (cur[i] & 0x230) == 0x010 )
+                       {
+                               void    *dst, *src;
+                               tPAddr  newpage;
+                               newpage = MM_AllocPhys();
+                               src = (void*)( (Table*256+i)*0x1000 );
+                               dst = (void*)MM_MapTemp(newpage);
+//                             Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF);
+                               memcpy(dst, src, PAGE_SIZE);
+                               MM_FreeTemp( (tVAddr)dst );
+                               tmp_map[i] = newpage | (cur[i] & 0xFFF);
+                       }
+                       else
+                       {
+                               if( (cur[i] & 0x230) == 0x030 )
+                                       cur[i] |= 0x200;        // Set to full RO (Full RO=COW, User RO = RO)
+                               tmp_map[i] = cur[i];
+                               MM_RefPhys( tmp_map[i] & ~0xFFF );
+                       }
+                       break;
+               }
+       }
+       MM_FreeTemp( (tVAddr) tmp_map );
+
+       DestEnt[0] = table + 0*0x400 + 1;
+       DestEnt[1] = table + 1*0x400 + 1;
+       DestEnt[2] = table + 2*0x400 + 1;
+       DestEnt[3] = table + 3*0x400 + 1;
+}
+
+tPAddr MM_Clone(void)
+{
+       tPAddr  ret;
+       Uint32  *new_lvl1_1, *new_lvl1_2, *cur;
+       Uint32  *tmp_map;
+        int    i;
+
+//     MM_DumpTables(0, KERNEL_BASE);
+       
+       ret = MM_AllocateRootTable();
+
+       cur = (void*)MM_TABLE0USER;
+       new_lvl1_1 = (void*)MM_MapTemp(ret);
+       new_lvl1_2 = (void*)MM_MapTemp(ret+0x1000);
+       tmp_map = new_lvl1_1;
+       for( i = 0; i < 0x800-4; i ++ )
+       {
+               // HACK! Ignore the original identity mapping
+               if( i == 0 && Threads_GetTID() == 0 ) {
+                       tmp_map[0] = 0;
+                       continue;
+               }
+               if( i == 0x400 )
+                       tmp_map = &new_lvl1_2[-0x400];
+               switch( cur[i] & 3 )
+               {
+               case 0: tmp_map[i] = 0; break;
+               case 1:
+                       MM_int_CloneTable(&tmp_map[i], i);
+                       i += 3; // Tables are alocated in blocks of 4
+                       break;
+               case 2:
+               case 3:
+                       Log_Error("MMVirt", "TODO: Support Sections/Supersections in MM_Clone (i=%i)", i);
+                       tmp_map[i] = 0;
+                       break;
+               }
+       }
+
+       // Allocate Fractal table
+       {
+                int    j, num;
+               tPAddr  tmp = MM_AllocPhys();
+               Uint32  *table = (void*)MM_MapTemp(tmp);
+               Uint32  sp;
+               register Uint32 __SP asm("sp");
+
+               // Map table to last 4MiB of user space
+               new_lvl1_2[0x3FC] = tmp + 0*0x400 + 1;
+               new_lvl1_2[0x3FD] = tmp + 1*0x400 + 1;
+               new_lvl1_2[0x3FE] = tmp + 2*0x400 + 1;
+               new_lvl1_2[0x3FF] = tmp + 3*0x400 + 1;
+               
+               tmp_map = new_lvl1_1;
+               for( j = 0; j < 512; j ++ )
+               {
+                       if( j == 256 )
+                               tmp_map = &new_lvl1_2[-0x400];
+                       if( (tmp_map[j*4] & 3) == 1 )
+                       {
+                               table[j] = tmp_map[j*4] & PADDR_MASK_LVL1;// 0xFFFFFC00;
+                               table[j] |= 0x813;      // nG, Kernel Only, Small page, XN
+                       }
+                       else
+                               table[j] = 0;
+               }
+               // Fractal
+               table[j++] = (ret + 0x0000) | 0x813;
+               table[j++] = (ret + 0x1000) | 0x813;
+               // Nuke the rest
+               for(      ; j < 1024; j ++ )
+                       table[j] = 0;
+               
+               // Get kernel stack bottom
+               sp = __SP & ~(MM_KSTACK_SIZE-1);
+               j = (sp / 0x1000) % 1024;
+               num = MM_KSTACK_SIZE/0x1000;
+
+//             Log("num = %i, sp = %p, j = %i", num, sp, j);
+               
+               // Copy stack pages
+               for(; num--; j ++, sp += 0x1000)
+               {
+                       tVAddr  page;
+                       void    *tmp_page;
+                       
+                       page = MM_AllocPhys();
+//                     Log("page = %P", page);
+                       table[j] = page | 0x813;
+
+                       tmp_page = (void*)MM_MapTemp(page);
+                       memcpy(tmp_page, (void*)sp, 0x1000);
+                       MM_FreeTemp( (tVAddr) tmp_page );
+               }
+
+               MM_FreeTemp( (tVAddr)table );
+       }
+
+       MM_FreeTemp( (tVAddr)new_lvl1_1 );
+       MM_FreeTemp( (tVAddr)new_lvl1_2 );
+
+//     Log("MM_Clone: ret = %P", ret);
+
+       return ret;
+}
+
+void MM_ClearUser(void)
+{
+        int    i, j;
+       const int       user_table_count = USER_STACK_TOP / (256*0x1000);
+       Uint32  *cur = (void*)MM_TABLE0USER;
+       Uint32  *tab;
+       
+//     MM_DumpTables(0, 0x80000000);
+
+//     Log("user_table_count = %i (as opposed to %i)", user_table_count, 0x800-4);
+
+       for( i = 0; i < user_table_count; i ++ )
+       {
+               switch( cur[i] & 3 )
+               {
+               case 0: break;  // Already unmapped
+               case 1: // Sub pages
+                       tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
+                       for( j = 0; j < 1024; j ++ )
+                       {
+                               switch( tab[j] & 3 )
+                               {
+                               case 0: break;  // Unmapped
+                               case 1:
+                                       Log_Error("MMVirt", "TODO: Support large pages in MM_ClearUser");
+                                       break;
+                               case 2:
+                               case 3:
+                                       MM_DerefPhys( tab[j] & ~(PAGE_SIZE-1) );
+                                       break;
+                               }
+                       }
+                       MM_DerefPhys( cur[i] & ~(PAGE_SIZE-1) );
+                       cur[i+0] = 0;
+                       cur[i+1] = 0;
+                       cur[i+2] = 0;
+                       i += 3;
+                       break;
+               case 2:
+               case 3:
+                       Log_Error("MMVirt", "TODO: Implement sections/supersections in MM_ClearUser");
+                       break;
+               }
+               cur[i] = 0;
+       }
+       
+       // Final block of 4 tables are KStack
+       i = 0x800 - 4;
+       
+       // Clear out unused stacks
+       {
+               register Uint32 __SP asm("sp");
+                int    cur_stack_base = ((__SP & ~(MM_KSTACK_SIZE-1)) / PAGE_SIZE) % 1024;
+
+               tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
+               
+               // First 512 is the Table1 mapping + 2 for Table0 mapping
+               for( j = 512+2; j < 1024; j ++ )
+               {
+                       // Skip current stack
+                       if( j == cur_stack_base ) {
+                               j += (MM_KSTACK_SIZE / PAGE_SIZE) - 1;
+                               continue ;
+                       }
+                       if( !(tab[j] & 3) )     continue;
+                       ASSERT( (tab[j] & 3) == 2 );
+                       MM_DerefPhys( tab[j] & ~(PAGE_SIZE) );
+                       tab[j] = 0;
+               }
+       }
+       
+
+//     MM_DumpTables(0, 0x80000000);
+}
+
+tVAddr MM_MapTemp(tPAddr PAddr)
+{
+       tVAddr  ret;
+       tMM_PageInfo    pi;
+
+       for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
+       {
+               if( MM_int_GetPageInfo(ret, &pi) == 0 )
+                       continue;
+
+//             Log("MapTemp %P at %p by %p", PAddr, ret, __builtin_return_address(0));
+               MM_RefPhys(PAddr);      // Counter the MM_Deallocate in FreeTemp
+               MM_Map(ret, PAddr);
+               
+               return ret;
+       }
+       Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
+       return 0;
+}
+
+void MM_FreeTemp(tVAddr VAddr)
+{
+       if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
+               Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
+               return ;
+       }
+       
+       MM_Deallocate(VAddr);
+}
+
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
+{
+       tVAddr  ret;
+        int    i;
+       tMM_PageInfo    pi;
+
+       ENTER("xPAddr iNPages", PAddr, NPages);
+
+       // Scan for a location
+       for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
+       {
+//             LOG("checking %p", ret);
+               // Check if there is `NPages` free pages
+               for( i = 0; i < NPages; i ++ )
+               {
+                       if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
+                               break;
+               }
+               // Nope, jump to after the used page found and try again
+//             LOG("i = %i, ==? %i", i, NPages);
+               if( i != NPages ) {
+                       ret += i * PAGE_SIZE;
+                       continue ;
+               }
+       
+               // Map the pages        
+               for( i = 0; i < NPages; i ++ )
+                       MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAGE_SIZE);
+               // and return
+               LEAVE('p', ret);
+               return ret;
+       }
+       Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
+       LEAVE('p', 0);
+       return 0;
+}
+
+tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
+{
+       tPAddr  phys;
+       tVAddr  ret;
+
+       phys = MM_AllocPhysRange(Pages, MaxBits);
+       if(!phys) {
+               Log_Warning("MMVirt", "No space left for a %i page block (MM_AllocDMA)", Pages);
+               return 0;
+       }
+       
+       ret = MM_MapHWPages(phys, Pages);
+       *PAddr = phys;
+
+       return ret;
+}
+
+void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
+{
+       Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
+}
+
+tVAddr MM_NewKStack(int bShared)
+{
+       tVAddr  min_addr, max_addr;
+       tVAddr  addr, ofs;
+
+       if( bShared ) {
+               min_addr = MM_GLOBALSTACKS;
+               max_addr = MM_GLOBALSTACKS_END;
+       }
+       else {
+               min_addr = MM_KSTACK_BASE;
+               max_addr = MM_KSTACK_END;
+       }
+
+       // Locate a free slot
+       for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
+       {
+               tMM_PageInfo    pi;
+               if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) )    break;
+       }
+
+       // Check for an error   
+       if(addr >= max_addr) {
+               return 0;
+       }
+
+       // 1 guard page
+       for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
+       {
+               if( MM_Allocate(addr + ofs) == 0 )
+               {
+                       while(ofs)
+                       {
+                               ofs -= PAGE_SIZE;
+                               MM_Deallocate(addr + ofs);
+                       }
+                       Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
+                       return 0;
+               }
+       }
+       return addr + ofs;
+}
+
+tVAddr MM_NewUserStack(void)
+{
+       tVAddr  addr, ofs;
+
+       addr = USER_STACK_TOP - USER_STACK_SIZE;
+       if( MM_GetPhysAddr(addr + PAGE_SIZE) ) {
+               Log_Error("MMVirt", "Unable to create initial user stack, addr %p taken",
+                       addr + PAGE_SIZE
+                       );
+               return 0;
+       }
+
+       // 1 guard page
+       for( ofs = PAGE_SIZE; ofs < USER_STACK_SIZE; ofs += PAGE_SIZE )
+       {
+               tPAddr  rv;
+               if(ofs >= USER_STACK_SIZE - USER_STACK_COMM)
+                       rv = MM_Allocate(addr + ofs);
+               else
+                       rv = MM_AllocateZero(addr + ofs);
+               if(rv == 0)
+               {
+                       while(ofs)
+                       {
+                               ofs -= PAGE_SIZE;
+                               MM_Deallocate(addr + ofs);
+                       }
+                       Log_Warning("MMVirt", "MM_NewUserStack: Unable to allocate");
+                       return 0;
+               }
+               MM_SetFlags(addr+ofs, 0, MM_PFLAG_KERNEL);
+       }
+//     Log("Return %p", addr + ofs);
+//     MM_DumpTables(0, 0x80000000);
+       return addr + ofs;
+}
+
+void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
+{
+       if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
+       {
+               Debug("%p => %8s - 0x%7x %i %x %s",
+                       Start, "ZERO", Len,
+                       Info->Domain, Info->AP,
+                       Info->bGlobal ? "G" : "nG"
+                       );
+       }
+       else
+       {
+               Debug("%p => %8x - 0x%7x %i %x %s",
+                       Start, Info->PhysAddr-Len, Len,
+                       Info->Domain, Info->AP,
+                       Info->bGlobal ? "G" : "nG"
+                       );
+       }
+}
+
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+       tVAddr  range_start = 0, addr;
+       tMM_PageInfo    pi, pi_old;
+        int    i = 0, inRange=0;
+       
+       memset(&pi_old, 0, sizeof(pi_old));
+
+       Debug("Page Table Dump (%p to %p):", Start, End);
+       range_start = Start;
+       for( addr = Start; i == 0 || (addr && addr < End); i = 1 )
+       {
+                int    rv;
+//             Log("addr = %p", addr);
+               rv = MM_int_GetPageInfo(addr, &pi);
+               if( rv
+                || pi.Size != pi_old.Size
+                || pi.Domain != pi_old.Domain
+                || pi.AP != pi_old.AP
+                || pi.bGlobal != pi_old.bGlobal
+                || pi_old.PhysAddr != pi.PhysAddr )
+               {
+                       if(inRange) {
+                               MM_int_DumpTableEnt(range_start, addr - range_start, &pi_old);
+                       }
+                       addr &= ~((1 << pi.Size)-1);
+                       range_start = addr;
+               }
+               
+               pi_old = pi;
+               // Handle the zero page
+               if( !giMM_ZeroPage || pi_old.Size != 12 || pi_old.PhysAddr != giMM_ZeroPage )
+                       pi_old.PhysAddr += 1 << pi_old.Size;
+               addr += 1 << pi_old.Size;
+               inRange = (rv == 0);
+       }
+       if(inRange)
+               MM_int_DumpTableEnt(range_start, addr - range_start, &pi);
+       Debug("Done");
+}
+
+// NOTE: Runs in abort context, not much difference, just a smaller stack
+void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
+{
+        int    rv;
+       tMM_PageInfo    pi;
+       
+       rv = MM_int_GetPageInfo(Addr, &pi);
+       
+       // Check for COW
+       if( rv == 0 &&  pi.AP == AP_RO_BOTH )
+       {
+               pi.AP = AP_RW_BOTH;
+               if( giMM_ZeroPage && pi.PhysAddr == giMM_ZeroPage )
+               {
+                       tPAddr  newpage;
+                       newpage = MM_AllocPhys();
+                       if( !newpage ) {
+                               Log_Error("MMVirt", "Unable to allocate new page for COW of ZERO");
+                               for(;;);
+                       }
+                       
+                       #if TRACE_COW
+                       Log_Notice("MMVirt", "COW %p caused by %p, ZERO duped to %P (RefCnt(%i)--)", Addr, PC,
+                               newpage, MM_GetRefCount(pi.PhysAddr));
+                       #endif
+
+                       MM_DerefPhys(pi.PhysAddr);
+                       pi.PhysAddr = newpage;
+                       pi.AP = AP_RW_BOTH;
+                       MM_int_SetPageInfo(Addr, &pi);
+                       
+                       memset( (void*)(Addr & ~(PAGE_SIZE-1)), 0, PAGE_SIZE );
+
+                       return ;
+               }
+               else if( MM_GetRefCount(pi.PhysAddr) > 1 )
+               {
+                       // Duplicate the page
+                       tPAddr  newpage;
+                       void    *dst, *src;
+                       
+                       newpage = MM_AllocPhys();
+                       if(!newpage) {
+                               Log_Error("MMVirt", "Unable to allocate new page for COW");
+                               for(;;);
+                       }
+                       dst = (void*)MM_MapTemp(newpage);
+                       src = (void*)(Addr & ~(PAGE_SIZE-1));
+                       memcpy( dst, src, PAGE_SIZE );
+                       MM_FreeTemp( (tVAddr)dst );
+                       
+                       #if TRACE_COW
+                       Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
+                               pi.PhysAddr, newpage, MM_GetRefCount(pi.PhysAddr));
+                       #endif
+
+                       MM_DerefPhys(pi.PhysAddr);
+                       pi.PhysAddr = newpage;
+               }
+               #if TRACE_COW
+               else {
+                       Log_Notice("MMVirt", "COW %p caused by %p, took last reference to %P",
+                               Addr, PC, pi.PhysAddr);
+               }
+               #endif
+               // Unset COW
+               pi.AP = AP_RW_BOTH;
+               MM_int_SetPageInfo(Addr, &pi);
+               return ;
+       }
+       
+
+       Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR,
+               (bPrefetch ? " - Prefetch" : "")
+               );
+       if( Addr < 0x80000000 )
+               MM_DumpTables(0, 0x80000000);
+       else
+               MM_DumpTables(0x80000000, -1);
+       for(;;);
+}
+
diff --git a/KernelLand/Kernel/arch/armv7/pci.c b/KernelLand/Kernel/arch/armv7/pci.c
new file mode 100644 (file)
index 0000000..2e674bb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *
+ */
+#include <acess.h>
+#include <drv_pci_int.h>
+
+// Realview
+//#define PCI_BASE     0x60000000
+
+//#define PCI_BASE     0xF0400000      // VMM Mapping
+#define PCI_BASE       0
+
+// === CODE ===
+void PCI_CfgWriteDWord(Uint32 Addr, Uint32 Data)
+{
+       #if PCI_BASE
+       Uint32  address = PCI_BASE | Addr;
+       *(Uint32*)(address) = Data;
+       #else
+       #endif
+}
+
+Uint32 PCI_CfgReadDWord(Uint32 Addr)
+{
+       #if PCI_BASE
+       Uint32  address = PCI_BASE | Addr;
+       return *(Uint32*)address;
+       #else
+       return 0xFFFFFFFF;
+       #endif
+}
+
diff --git a/KernelLand/Kernel/arch/armv7/proc.S b/KernelLand/Kernel/arch/armv7/proc.S
new file mode 100644 (file)
index 0000000..531de29
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Acess2 ARM
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/proc.S
+ * - Process management assembly
+ */
+
+#include "include/assembly.h"
+
+.globl KernelThreadHeader
+@ SP+12: Argument 1
+@ SP+8: Argument Count
+@ SP+4: Function
+@ SP+0: Thread Pointer
+KernelThreadHeader:
+       ldr r0, [sp],#4
+       @ TODO: Do something with the thread pointer
+       
+       ldr r4, [sp],#4 @ Function
+       @ Get argument
+       ldr r0, [sp],#4
+
+       blx r4
+       
+       ldr r0, =0
+       bl Threads_Exit
+       b .
+
+.globl SwitchTask
+@ R0: New stack
+@ R1: Pointer to where to save old stack
+@ R2: New IP
+@ R3: Pointer to save old IP
+@ SP+0: New address space
+SwitchTask:
+       push {r4-r12,lr}
+
+       @ Save IP       
+       ldr r4, =.return
+       str r4, [r3]
+       @ Save SP
+       str sp, [r1]
+
+       @ Only update TTBR0 if the task has an explicit address space
+       ldr r1, [sp,#4*10]
+       tst r1, r1
+       mcrne p15, 0, r1, c2, c0, 0     @ Set TTBR0 to r0
+       mov r1, #0
+       mcrne p15, 0, r1, c8, c7, 0     @ TLBIALL - Invalidate all
+
+       @ Restore SP
+       mov sp, r0
+
+       bx r2
+
+.return:
+       pop {r4-r12,pc}
+
+.extern MM_Clone
+.extern MM_DumpTables
+.globl Proc_CloneInt
+Proc_CloneInt:
+       @ R0: SP Destination
+       @ R1: Mem Destination
+       push {r4-r12,lr}
+       mov r4, r1      @ Save mem destination
+       str sp, [r0]    @ Save SP to SP dest
+
+       bl MM_Clone
+       str r0, [r4]    @ Save clone return to Mem Dest
+
+       ldr r0, =Proc_CloneInt_new
+       pop {r4-r12,pc}
+Proc_CloneInt_new:
+       mov r0, #0
+       pop {r4-r12,pc}
+
+@ R0: New user SP
+@ Return: Old user SP
+.globl Proc_int_SwapUserSP
+Proc_int_SwapUserSP:
+       cps #31 @ Go to system mode
+       mov r1, sp
+       tst r0, r0      @ Only update if non-zero
+       movne sp, r0
+       mov r0, r1
+       cps #19
+       mov pc, lr
+
+.section .usertext, "ax"
+.globl Proc_int_DropToUser
+@ R0: User IP
+@ R1: User SP
+Proc_int_DropToUser:
+       cps #16
+       mov sp, r1
+       mov pc, r0
+
+.section .rodata
+csProc_CloneInt_NewTaskMessage:
+       .asciz "New task PC=%p, R4=%p, sp=%p"
+csProc_CloneInt_OldTaskMessage:
+       .asciz "Parent task PC=%p, R4=%p, SP=%p"
diff --git a/KernelLand/Kernel/arch/armv7/proc.c b/KernelLand/Kernel/arch/armv7/proc.c
new file mode 100644 (file)
index 0000000..cd998f2
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/proc.c
+ * - ARM7 Process Switching
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <hal_proc.h>
+
+// === IMPORTS ===
+extern tThread gThreadZero;
+extern tProcess        gProcessZero;
+extern void    SwitchTask(Uint32 NewSP, Uint32 *OldSP, Uint32 NewIP, Uint32 *OldIP, Uint32 MemPtr);
+extern void    KernelThreadHeader(void);       // Actually takes args on stack
+extern void    Proc_int_DropToUser(Uint32 IP, Uint32 SP) NORETURN __attribute__((long_call));
+extern Uint32  Proc_int_SwapUserSP(Uint32 NewSP);
+extern Uint32  Proc_CloneInt(Uint32 *SP, Uint32 *MemPtr);
+extern tVAddr  MM_NewKStack(int bGlobal);      // TODO: Move out into a header
+extern tVAddr  MM_NewUserStack(void);
+extern char    kernel_table0[];
+
+// === PROTOTYPES ===
+void   Proc_IdleThread(void *unused);
+
+// === GLOBALS ===
+tThread        *gpCurrentThread = &gThreadZero;
+tThread *gpIdleThread = NULL;
+
+// === CODE ===
+void ArchThreads_Init(void)
+{
+       gProcessZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
+}
+
+void Proc_IdleThread(void *unused)
+{
+       Threads_SetPriority(gpIdleThread, -1);
+       for(;;) {
+               Proc_Reschedule();
+               __asm__ __volatile__ ("wfi");
+       }
+}
+
+void Proc_Start(void)
+{
+       tTID    tid;
+
+       tid = Proc_NewKThread( Proc_IdleThread, NULL );
+       gpIdleThread = Threads_GetThread(tid);
+       gpIdleThread->ThreadName = (char*)"Idle Thread";
+}
+
+int GetCPUNum(void)
+{
+       return 0;
+}
+
+tThread *Proc_GetCurThread(void)
+{
+       return gpCurrentThread;
+}
+
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
+{
+       Uint32  *usr_sp;
+        int    i;
+       const char      **envp;
+       tVAddr  delta;
+
+//     Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
+//             Entrypoint, Base, ArgC, ArgV, DataSize);
+
+       // Write data to the user's stack
+       usr_sp = (void*)MM_NewUserStack();
+       usr_sp -= (DataSize+3)/4;
+       memcpy(usr_sp, ArgV, DataSize);
+       free(ArgV);
+
+       // Adjust user's copy of the arguments
+       delta = (tVAddr)usr_sp -  (tVAddr)ArgV;
+       ArgV = (void*)usr_sp;
+       for(i = 0; ArgV[i]; i ++)       ArgV[i] += delta;
+       envp = &ArgV[i+1];
+       for(i = 0; envp[i]; i ++)       envp[i] += delta;
+       
+       *--usr_sp = (Uint32)envp;
+       *--usr_sp = (Uint32)ArgV;
+       *--usr_sp = (Uint32)ArgC;
+       *--usr_sp = Base;
+       
+       // Drop to user code
+       Log_Debug("Proc", "Proc_int_DropToUser(%p, %p)", Entrypoint, usr_sp);
+       Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
+}
+
+void Proc_ClearProcess(tProcess *Process)
+{
+       Log_Warning("Proc", "TODO: Nuke address space etc");
+}
+
+void Proc_ClearThread(tThread *Thread)
+{
+}
+
+tTID Proc_Clone(Uint Flags)
+{
+       tThread *new;
+       Uint32  pc, sp, mem;
+
+       new = Threads_CloneTCB(Flags);
+       if(!new)        return -1;
+
+       // Actual clone magic
+       pc = Proc_CloneInt(&sp, &mem);
+       if(pc == 0) {
+               Log("Proc_Clone: In child");
+               return 0;
+       }
+       
+       new->SavedState.IP = pc;
+       new->SavedState.SP = sp;
+       new->SavedState.UserSP = Proc_int_SwapUserSP(0);
+       new->SavedState.UserIP = Proc_GetCurThread()->SavedState.UserIP;
+       new->Process->MemState.Base = mem;
+
+       Threads_AddActive(new);
+
+       return new->TID;
+}
+
+int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+{
+       tThread *new;
+       Uint32  sp;
+
+       new = Threads_CloneThreadZero();
+       if(!new)        return -1;
+       if(new->ThreadName)     free(new->ThreadName);
+       new->ThreadName = NULL;
+
+       new->KernelStack = MM_NewKStack(1);
+       if(!new->KernelStack) {
+               // TODO: Delete thread
+               Log_Error("Proc", "Unable to allocate kernel stack");
+               return -1;
+       }       
+
+       sp = new->KernelStack;
+       
+       *(Uint32*)(sp -= 4) = (Uint)Ptr;
+       *(Uint32*)(sp -= 4) = (Uint)Fnc;
+       *(Uint32*)(sp -= 4) = (Uint)new;
+
+       new->SavedState.SP = sp;
+       new->SavedState.IP = (Uint)KernelThreadHeader;
+
+       Threads_AddActive(new);
+
+       return new->TID;
+}
+
+tTID Proc_NewKThread( void (*Fnc)(void*), void *Ptr )
+{
+       tThread *new;
+       Uint32  sp;
+
+       new = Threads_CloneTCB(0);
+       if(!new)        return -1;
+       free(new->ThreadName);
+       new->ThreadName = NULL;
+
+       // TODO: Non-shared stack
+       new->KernelStack = MM_NewKStack(1);
+       if(!new->KernelStack) {
+               // TODO: Delete thread
+               Log_Error("Proc", "Unable to allocate kernel stack");
+               return -1;
+       }       
+
+       sp = new->KernelStack;
+       
+       *(Uint32*)(sp -= 4) = (Uint)Ptr;
+       *(Uint32*)(sp -= 4) = (Uint)Fnc;
+       *(Uint32*)(sp -= 4) = (Uint)new;
+
+       new->SavedState.SP = sp;
+       new->SavedState.IP = (Uint)KernelThreadHeader;
+
+       Threads_AddActive(new);
+
+       return new->TID;
+}
+
+void Proc_CallFaultHandler(tThread *Thread)
+{
+
+}
+
+void Proc_Reschedule(void)
+{
+       tThread *cur, *next;
+
+       cur = gpCurrentThread;
+
+       next = Threads_GetNextToRun(0, cur);
+       if(!next)       next = gpIdleThread;
+       if(!next || next == cur)        return;
+
+       Log("Switching to %p (%i %s) IP=%p SP=%p TTBR0=%p UsrSP=%p",
+               next, next->TID, next->ThreadName,
+               next->SavedState.IP, next->SavedState.SP, next->Process->MemState.Base,
+               next->SavedState.UserSP
+               );
+
+       Log("Requested by %p", __builtin_return_address(0));
+       
+       gpCurrentThread = next;
+
+       cur->SavedState.UserSP = Proc_int_SwapUserSP( next->SavedState.UserSP );
+
+       SwitchTask(
+               next->SavedState.SP, &cur->SavedState.SP,
+               next->SavedState.IP, &cur->SavedState.IP,
+               next->Process->MemState.Base
+               );
+       
+}
+
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       
+}
+
diff --git a/KernelLand/Kernel/arch/armv7/start.S b/KernelLand/Kernel/arch/armv7/start.S
new file mode 100644 (file)
index 0000000..8d9f3e4
--- /dev/null
@@ -0,0 +1,367 @@
+
+#include "include/assembly.h"
+#include "include/options.h"
+
+@
+@ Exception defs taken from ARM DDI 0406B
+@ 
+.section .init
+interrupt_vector_table:
+ivt_reset:     b _start        @ 0x00 Reset
+ivt_undef:     b Undef_Handler @ 0x04 #UD
+ivt_svc:       b SVC_Handler   @ 0x08 SVC (used to be called SWI)
+ivt_prefetch:  b PrefetchAbort @ 0x0C Prefetch abort
+ivt_data:      b DataAbort     @ 0x10 Data abort
+ivt_unused:    b .             @ 0x14 Not Used
+ivt_irq:       b IRQHandler    @ 0x18 IRQ
+ivt_fiq:       b .             @ 0x1C FIQ (Fast interrupt)
+
+.globl _start
+_start:
+       ldr r2, =UART0_PADDR
+       mov r1, #'A'
+       str r1, [r2]    
+
+       ldr r0, =kernel_table0-KERNEL_BASE
+       mcr p15, 0, r0, c2, c0, 1       @ Set TTBR1 to r0
+       mcr p15, 0, r0, c2, c0, 0       @ Set TTBR0 to r0 too (for identity)
+
+       mov r1, #'c'
+       str r1, [r2]    
+
+       mov r0, #1
+       mcr p15, 0, r0, c2, c0, 2       @ Set TTCR to 1 (50/50 split)
+
+       mov r1, #'e'
+       str r1, [r2]    
+       
+       mov r0, #3
+       mcr p15, 0, r0, c3, c0, 0       @ Set Domain 0 to Manager
+
+       mov r1, #'s'
+       str r1, [r2]    
+
+       @ Enable VMSA
+       mrc p15, 0, r0, c1, c0, 0
+       orr r0, r0, #1
+       orr r0, r0, #1 << 23
+       mvn r1, #1 << 2
+       and r0, r0, r1
+       mcr p15, 0, r0, c1, c0, 0
+
+       @ HACK! Disable caching
+       mrc p15, 0, r1, c1, c0, 0
+
+       ldr r2, =0xF1000000
+       mov r1, #'s'
+       str r1, [r2]    
+
+       @ Enable access faults on domains 0 & 1
+       mov r0, #0x55   @ 01010101b
+       mcr p15, 0, r0, c3, c0, 0
+
+       mov r1, #'2'
+       str r1, [r2]    
+
+       @
+       @ Check for security extensions
+       @
+       mrc p15, 0, r0, c0, c1, 1
+       and r0, #0xF0
+       @ - Present
+       ldrne r0,=KERNEL_BASE
+       mcrne p15, 0, r0, c12, c0, 0    @ Set the VBAR (brings exceptions into high memory)
+       @ - Absent
+       mrceq p15, 0, r0, c1, c0, 0     @ Set SCTLR.V
+       orreq r0, #0x2000
+       mcreq p15, 0, r0, c1, c0, 0
+
+       mov r1, #'-'
+       str r1, [r2]    
+
+       @ Prepare for interrupts
+       cps #18 @ IRQ Mode
+       ldr sp, =irqstack+0x1000        @ Set up stack
+       cps #23 @ Abort Mode
+       ldr sp, =abortstack+0x1000
+       cps #19
+
+       mov r1, #'a'
+       str r1, [r2]    
+       mov r1, #'r'
+       str r1, [r2]    
+       mov r1, #'m'
+       str r1, [r2]    
+       mov r1, #13
+       str r1, [r2]    
+       mov r1, #10
+       str r1, [r2]    
+
+.extern bss_start
+.extern bss_size_div_4
+.zero_bss:
+       ldr r0, =bss_start
+       ldr r1, =bss_end
+       mov r3, #0
+.zero_bss_loop:
+       str r3, [r0],#4
+       cmp r0, r1
+       bls .zero_bss_loop
+
+.goto_c:
+       ldr sp, =0x80000000-8   @ Set up stack (top of user range)
+       ldr r0, =kmain
+       mov pc, r0
+1:     b 1b    @ Infinite loop
+
+.comm irqstack, 0x1000 @ ; 4KiB Stack
+.comm abortstack, 0x1000       @ ; 4KiB Stack
+
+.extern SyscallHandler
+SVC_Handler:
+@      sub lr, #4
+       srsdb sp!, #19  @ Save state to stack
+       cpsie ifa, #19  @ Ensure we're in supervisor with interrupts enabled (should already be there)
+       push {r0-r12}
+
+       ldr r4, [lr,#-4]
+       mvn r5, #0xFF000000
+       and r4, r5
+
+       tst r4, #0x1000 
+       bne .arm_specifics
+
+       push {r4}
+
+       mov r0, sp
+       ldr r4, =SyscallHandler
+       blx r4
+       
+@      ldr r0, =csSyscallPrintRetAddr
+@      ldr r1, [sp,#9*4+5*4]
+@      ldr r4, =Log
+@      blx r4
+       
+       pop {r2}        @ errno
+       pop {r0,r1}     @ Ret/RetHi
+       add sp, #2*4    @ Saved r2/r3
+
+       pop {r4-r12}
+       rfeia sp!       @ Pop state (actually RFEFD)
+.arm_specifics:
+       and r4, #0xFF
+       mov r0, r4      @ Number
+       mov r1, sp      @ Arguments
+       
+       ldr r4, =ARMv7_int_HandleSyscalls
+       blx r4
+
+       add sp, #4*4
+       pop {r4-r12}
+       rfeia sp!
+
+
+.globl gpIRQHandler
+gpIRQHandler:  .long   0
+IRQ_saved_sp:  .long   0
+IRQ_saved_lr:  .long   0
+.globl IRQHandler
+IRQHandler:
+       sub lr, #4      @ Adjust LR to the correct value
+       srsdb sp!, #19  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+       cps #19
+
+       PUSH_GPRS
+
+@      ldr r0, =csIRQ_Tag
+@      ldr r1, =csIRQ_Fmt
+@      ldr r4, =Log_Debug
+@      blx r4
+       
+       @ Call the registered handler
+       ldr r0, gpIRQHandler
+       blx r0
+
+       @ Restore CPU state
+       POP_GPRS
+       cpsie i
+       rfeia sp!       @ Pop state (actually RFEFD)
+       bx lr
+
+.globl DataAbort
+DataAbort:
+       sub lr, #8      @ Adjust LR to the correct value
+       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+@      cpsid ifa, #19
+       PUSH_GPRS
+
+       mov r3, #0      @ not a prefetch abort
+       mrc p15, 0, r2, c5, c0, 0       @ Read DFSR (Data Fault Status Register) to R2
+       mrc p15, 0, r1, c6, c0, 0       @ Read DFAR (Data Fault Address Register) into R1
+       mov r0, lr      @ PC
+       ldr r4, =MM_PageFault
+       blx r4
+
+       POP_GPRS
+       rfeia sp!       @ Pop state (actually RFEFD)
+
+.globl PrefetchAbort
+PrefetchAbort:
+       sub lr, #4      @ Adjust LR to the correct value
+       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+@      cpsid ifa, #19
+       PUSH_GPRS
+
+       ldr r0, =csAbort_Tag
+       ldr r1, =csPrefetchAbort_Fmt
+#      mov r2, lr
+       mrc p15, 0, r2, c6, c0, 2       @ Read IFAR (Instruction Fault Address Register) into R3
+       mrc p15, 0, r3, c5, c0, 1       @ Read IFSR (Instruction Fault Status Register) into R3
+       ldr r5, =Log_Error
+       blx r5
+
+.loop:
+       wfi
+       b .loop
+.globl Undef_Handler
+Undef_Handler:
+       wfi
+       b Undef_Handler
+
+
+
+.section .rodata
+csIRQ_Tag:
+csAbort_Tag:
+       .asciz "ARMv7"
+csIRQ_Fmt:
+       .asciz "IRQ"
+csDataAbort_Fmt:
+       .asciz "Data Abort - %p accessed %p, DFSR=%x Unk:%x Unk:%x"
+csPrefetchAbort_Fmt:
+       .asciz "Prefetch Abort at %p, IFSR=%x"
+csSyscallPrintRetAddr:
+       .asciz "Syscall ret to %p"
+
+.section .padata
+.globl kernel_table0
+
+kernel_table0:
+       .long 0x00000402        @ Identity map the first 1 MiB
+       .rept 0x7FC - 1
+               .long 0
+       .endr
+       .long user_table1_map + 0x000 - KERNEL_BASE + 1 @ 0x7FC00000
+       .long user_table1_map + 0x400 - KERNEL_BASE + 1 @ 0x7FD00000
+       .long user_table1_map + 0x800 - KERNEL_BASE + 1 @ KStacks
+       .long user_table1_map + 0xC00 - KERNEL_BASE + 1
+       @ 0x80000000 - User/Kernel split
+       .long 0x00000402        @ Map first 4 MiB to 2GiB (KRW only)
+       .long 0x00100402        @ 
+       .long 0x00200402        @ 
+       .long 0x00300402        @ 
+       .rept 0xF00 - 0x800 - 4
+               .long 0
+       .endr
+#if PCI_PADDR
+       .long PCI_PADDR +  0*(1 << 20) + 0x402  @ Map PCI config space
+       .long PCI_PADDR +  1*(1 << 20) + 0x402
+       .long PCI_PADDR +  2*(1 << 20) + 0x402
+       .long PCI_PADDR +  3*(1 << 20) + 0x402
+       .long PCI_PADDR +  4*(1 << 20) + 0x402
+       .long PCI_PADDR +  5*(1 << 20) + 0x402
+       .long PCI_PADDR +  6*(1 << 20) + 0x402
+       .long PCI_PADDR +  7*(1 << 20) + 0x402
+       .long PCI_PADDR +  8*(1 << 20) + 0x402
+       .long PCI_PADDR +  9*(1 << 20) + 0x402
+       .long PCI_PADDR + 10*(1 << 20) + 0x402
+       .long PCI_PADDR + 11*(1 << 20) + 0x402
+       .long PCI_PADDR + 12*(1 << 20) + 0x402
+       .long PCI_PADDR + 13*(1 << 20) + 0x402
+       .long PCI_PADDR + 14*(1 << 20) + 0x402
+       .long PCI_PADDR + 15*(1 << 20) + 0x402
+#else
+       .rept 16
+               .long 0
+       .endr
+#endif
+       .long hwmap_table_0 + 0x000 - KERNEL_BASE + 1
+       .long hwmap_table_0 + 0x400 - KERNEL_BASE + 1
+       .long hwmap_table_0 + 0x800 - KERNEL_BASE + 1
+       .long hwmap_table_0 + 0xC00 - KERNEL_BASE + 1
+       .rept 0xFF8 - 0xF00 - 16 - 4
+               .long 0
+       .endr
+       @ Page fractals
+       .long kernel_table1_map + 0x000 - KERNEL_BASE + 1
+       .long kernel_table1_map + 0x400 - KERNEL_BASE + 1
+       .long kernel_table1_map + 0x800 - KERNEL_BASE + 1
+       .long kernel_table1_map + 0xC00 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0x000 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0x400 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0x800 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0xC00 - KERNEL_BASE + 1
+
+@ PID0 user table
+.globl user_table1_map
+@ User table1 data table (only the first half is needed)
+@ - Abused to provide kernel stacks in the unused half of the table
+user_table1_map:       @ Size = 4KiB (only 2KiB used)
+       .rept 0x800/4-1
+               .long 0
+       .endr
+       .long user_table1_map - KERNEL_BASE + 0x13      @ ...1FF000 = 0x7FDFF000
+       @ Kernel stack zone
+       .long kernel_table0 + 0x0000 - KERNEL_BASE + 0x13       @ ...200000 = 0x7FE00000
+       .long kernel_table0 + 0x1000 - KERNEL_BASE + 0x13       @ ...201000 = 0x7FE01000
+       .rept (0x800/4)-(MM_KSTACK_SIZE/0x1000)-2
+               .long 0
+       .endr
+       #if MM_KSTACK_SIZE != 0x2000
+       #error Kernel stack size not changed in start.S
+       #endif
+       .long stack + 0x0000 - KERNEL_BASE + 0x13       @ Kernel Stack
+       .long stack + 0x1000 - KERNEL_BASE + 0x13       @ 
+
+.globl kernel_table1_map
+kernel_table1_map:     @ Size = 4KiB
+       .rept (0xF00+16)/4
+               .long 0
+       .endr
+       .long hwmap_table_0 - KERNEL_BASE + 0x13
+       .rept 0xFF8/4 - (0xF00+16)/4 - 1
+               .long 0
+       .endr
+       .long kernel_table1_map - KERNEL_BASE + 0x13
+       .long kernel_exception_map - KERNEL_BASE + 0x13
+
+@ Hardware mappings 
+.globl hwmap_table_0
+hwmap_table_0:
+       .long UART0_PADDR + 0x13        @ UART0
+       .rept 1024 - 1
+               .long 0
+       .endr
+.globl kernel_exception_map
+kernel_exception_map:
+       @ Padding
+       .rept 1024-256
+               .long 0
+       .endr
+       @ Align to nearly the end
+       .rept 256-16
+               .long   0
+       .endr
+       .long 0x212     @ Map first page for exceptions (Kernel RO, Execute)
+       .rept 16-1-2
+               .long 0
+       .endr
+       .long gUsertextPhysStart + 0x22 @ User .text (User RO, Kernel RW, because both is COW)
+       .long 0
+       
+.section .padata
+stack:
+       .space MM_KSTACK_SIZE, 0        @ Original kernel stack
+
+// vim: ts=8 ft=armv7
+
diff --git a/KernelLand/Kernel/arch/armv7/time.c b/KernelLand/Kernel/arch/armv7/time.c
new file mode 100644 (file)
index 0000000..d4ae4fa
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Acess2
+ *
+ * ARM7 Time code
+ * arch/arm7/time.c
+ */
+#include <acess.h>
+
+// === GLOBALS ===
+tTime  giTimestamp;
+
+// === CODE ===
+tTime now(void)
+{
+       return giTimestamp;
+}
diff --git a/KernelLand/Kernel/arch/helpers.h b/KernelLand/Kernel/arch/helpers.h
new file mode 100644 (file)
index 0000000..4d85fcb
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/helpers.h
+ * - Misc helper functions for the arch code
+ */
+#ifndef _ARCH_HELPERS_H_
+#define _ARCH_HELPERS_H_
+
+// Divide
+// - Find what power of two times Den is > Num
+// - Iterate down in bit significance
+//  > If the `N` value is greater than `D`, we can set this bit
+#define DEF_DIVMOD(s) Uint##s __divmod##s(Uint##s N, Uint##s D, Uint##s*Rem){\
+       Uint##s ret=0,add=1;\
+       while(N>=D&&add) {D<<=1;add<<=1;}\
+       while(add>1){\
+               add>>=1;D>>=1;\
+               if(N>=D){ret+=add;N-=D;}\
+       }\
+       if(Rem)*Rem = N;\
+       return ret;\
+}
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/m68k/Makefile b/KernelLand/Kernel/arch/m68k/Makefile
new file mode 100644 (file)
index 0000000..4caea1e
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Acess2 Kernel
+# m68k Architecture Makefile
+# arch/m68k/Makefile
+
+CFLAGS = 
+
+A_OBJ = main.o debug.o lib.o time.o proc.o mm_virt.o mm_phys.o
+
+LDFLAGS += `$(CC) --print-libgcc-file-name`
+
diff --git a/KernelLand/Kernel/arch/m68k/debug.c b/KernelLand/Kernel/arch/m68k/debug.c
new file mode 100644 (file)
index 0000000..8c7de3b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/debug.c
+ * - Debugging output
+ */
+#include <acess.h>
+
+// === PROTOTYPES ===
+void   StartupPrint(const char *Str);
+void   KernelPanic_SetMode(void);
+void   KernelPanic_PutChar(char ch);
+
+// === CODE ===
+void StartupPrint(const char *Str)
+{
+}
+
+void KernelPanic_SetMode(void)
+{
+}
+
+void KernelPanic_PutChar(char ch)
+{
+}
+
diff --git a/KernelLand/Kernel/arch/m68k/include/arch.h b/KernelLand/Kernel/arch/m68k/include/arch.h
new file mode 100644 (file)
index 0000000..0b2dc5b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Acess2 M68000 port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/include/arch.h
+ * - Architectre config
+ */
+#ifndef _M68K_ARCH_H_
+#define _M68K_ARCH_H_
+
+#define INVLPTR        ((void*)-1)
+#define BITS   32
+
+typedef unsigned long long     Uint64;
+typedef unsigned long  Uint32;
+typedef unsigned short Uint16;
+typedef unsigned char  Uint8;
+
+typedef signed long long       Sint64;
+typedef signed long    Sint32;
+typedef signed short   Sint16;
+typedef signed char    Sint8;
+
+typedef unsigned int   Uint;
+typedef unsigned int   size_t;
+
+typedef char   BOOL;
+
+typedef Uint32 tVAddr;
+typedef Uint32 tPAddr;
+
+struct sShortSpinlock
+{
+       int v;
+};
+
+// Non preemptive and no SMP, no need for these
+#define SHORTLOCK(lock)        do{}while(0)
+#define SHORTREL(lock) do{}while(0)
+#define IS_LOCKED(lock)        (0)
+#define CPU_HAS_LOCK(lock)     (0)
+
+#define Debug_PutCharDebug(ch) do{}while(0)
+#define Debug_PutStringDebug(ch)       do{}while(0)
+
+#define HALT() do{}while(0)
+
+#define USER_MAX       0
+
+#define        PAGE_SIZE       0x1000
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/m68k/include/mm_virt.h b/KernelLand/Kernel/arch/m68k/include/mm_virt.h
new file mode 100644 (file)
index 0000000..01480b9
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Acess2 M68000 port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/include/mm_virt.h
+ * - Virtual memory addresses
+ */
+#ifndef _M68K_MM_VIRT_H_
+#define _M68K_MM_VIRT_H_
+
+#define MM_KHEAP_BASE  0
+#define MM_KHEAP_MAX   0
+
+#define MM_USER_MIN    0
+#define USER_LIB_MAX   0
+#define MM_MODULE_MIN  0
+#define MM_MODULE_MAX  0
+
+#define MM_PPD_HANDLES 0
+#define MM_KERNEL_VFS  0
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/m68k/include/proc.h b/KernelLand/Kernel/arch/m68k/include/proc.h
new file mode 100644 (file)
index 0000000..8cf6aa0
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Acess2 M68000 port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/include/proc.h
+ * - Task management defs
+ */
+#ifndef _M68K_PROC_H_
+#define _M68K_PROC_H_
+
+#define MAX_CPUS       1
+
+typedef int    tMemoryState;   // Unused
+
+typedef struct {
+       Uint32  IP;
+       Uint32  SP;
+} tTaskState;
+
+typedef struct {
+       Uint32  Num;
+       union {
+               Uint32  Arg1;
+               Uint32  Return;
+       };
+       union {
+               Uint32  Arg2;
+               Uint32  RetHi;
+       };
+       union {
+               Uint32  Arg3;
+               Uint32  Error;
+       };
+       Uint32  Arg4;
+       Uint32  Arg5;
+       Uint32  Arg6;
+} tSyscallRegs;
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/m68k/lib.c b/KernelLand/Kernel/arch/m68k/lib.c
new file mode 100644 (file)
index 0000000..2888a31
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/lib.c
+ * - Library functions
+ */
+#include <acess.h>
+#include "../helpers.h"
+#include <drv_pci_int.h>
+
+Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
+Uint64 __udivdi3(Uint64 Num, Uint64 Den);
+Uint64 __umoddi3(Uint64 Num, Uint64 Den);
+
+// === CODE ===
+void *memcpy(void *__dest, const void *__src, size_t __len)
+{
+       register Uint8  *dest = __dest;
+       register const Uint8 *src = __src;
+
+       while(__len --)
+               *dest++ = *src++;
+
+       return __dest;
+}
+
+void *memset(void *__dest, int __val, size_t __count)
+{
+       register Uint8  *dest = __dest;
+       
+       while(__count --)
+               *dest = __val;
+       
+       return __dest;
+}
+
+int memcmp(const void *__p1, const void *__p2, size_t __maxlen)
+{
+       const char      *m1 = __p1, *m2 = __p2;
+       while( __maxlen-- )
+       {
+               if(*m1 != *m2)  return *m1 - *m2;
+       }
+       return 0;
+}
+
+DEF_DIVMOD(64)
+
+Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
+{
+       Uint64  ret;
+       if(Den == 0)    return 0;       // TODO: #div0
+       if(Num < Den) {
+               if(Rem) *Rem = Num;
+               return 0;
+       }
+       if(Num == 0) {
+               if(Rem) *Rem = 0;
+               return 0;
+       }
+       if(Den == 1) {
+               if(Rem) *Rem = 0;
+               return Num;
+       }
+       if(Den == 2) {
+               if(Rem) *Rem = Num & 1;
+               return Num >> 1;
+       }
+       if(Den == 16) {
+               if(Rem) *Rem = Num & 0xF;
+               return Num >> 4;
+       }
+       if(Den == 32) {
+               if(Rem) *Rem = Num & 0x1F;
+               return Num >> 5;
+       }
+       if(Den == 0x1000) {
+               if(Rem) *Rem = Num & 0xFFF;
+               return Num >> 12;
+       }
+       
+       if( !(Den >> 32) && !(Num >> 32) ) {
+               if(Rem) *Rem = (Uint32)Num % (Uint32)Den;       // Clear high bits
+               return (Uint32)Num / (Uint32)Den;
+       }
+
+       ret = __divmod64(Num, Den, Rem);
+       return ret;
+}
+
+// Unsigned Divide 64-bit Integer
+Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+{
+       return DivMod64U(Num, Den, NULL);
+}
+
+// Unsigned Modulus 64-bit Integer
+Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+{
+       Uint64  ret = 0;
+       DivMod64U(Num, Den, &ret);
+       return ret;
+}
+
+// ---- PCI (stubbed)
+Uint32 PCI_CfgReadDWord(Uint32 Addr)
+{
+       return 0xFFFFFFFF;
+}
+void PCI_CfgWriteDWord(Uint32 Addr, Uint32 Data)
+{
+}
+
diff --git a/KernelLand/Kernel/arch/m68k/link.ld b/KernelLand/Kernel/arch/m68k/link.ld
new file mode 100644 (file)
index 0000000..c0b0c9d
--- /dev/null
@@ -0,0 +1,40 @@
+ENTRY (_start)
+
+_kernel_base = 0x0;
+
+SECTIONS
+{
+       . = 0;
+       .init :
+       {
+               *(.init)
+       }
+       . += _kernel_base;
+       .text : AT( ADDR(.text) - _kernel_base )
+       {
+               *(.text*)
+               *(.rodata*)
+       }
+       /* 0x4000 (4 pages) alignment needed for root table */
+       .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
+       {
+               *(.padata)
+               *(.data*)
+               
+               gKernelSymbols = .;
+               *(KEXPORT)
+               gKernelSymbolsEnd = .;
+               
+               gKernelModules = .;
+               *(KMODULES)
+               gKernelModulesEnd = .;
+       }
+       .bss : AT( ADDR(.bss) - _kernel_base )
+       {
+               *(.bss*)
+               *(COMMON*)
+               . = ALIGN(0x1000);
+               *(.pabss)
+       }
+       gKernelEnd = .;
+}
diff --git a/KernelLand/Kernel/arch/m68k/main.c b/KernelLand/Kernel/arch/m68k/main.c
new file mode 100644 (file)
index 0000000..3f78e4b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/main.c
+ * - C entrypoint
+ */
+#include <acess.h>
+#include <init.h>
+
+// === PROTOTYPES ===
+void   kmain(void);
+
+// === CODE ===
+void kmain(void)
+{
+       LogF("Acess2 m68k v"EXPAND_STR(KERNEL_VERSION)"\n");
+       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+       
+}
+
+void Arch_LoadBootModules(void)
+{
+       
+}
+
diff --git a/KernelLand/Kernel/arch/m68k/mm_phys.c b/KernelLand/Kernel/arch/m68k/mm_phys.c
new file mode 100644 (file)
index 0000000..24fd1f2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/mm_phys.c
+ * - Stubbed physical memory management
+ */
+#include <acess.h>
+
+// === CODE ===
+void MM_RefPhys(tPAddr Page)
+{
+       // TODO: Refcount pages
+       Log_Warning("MMPhys", "TODO: Implement MM_RefPhys");
+}
+
+int MM_SetPageNode(tPAddr Page, void *Node)
+{
+       Log_Warning("MMPhys", "TODO: Implement MM_SetPageNode");
+       return -1;
+}
+
diff --git a/KernelLand/Kernel/arch/m68k/mm_virt.c b/KernelLand/Kernel/arch/m68k/mm_virt.c
new file mode 100644 (file)
index 0000000..88990a1
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/mm_virt.c
+ * - Stubbed virtual memory management (no MMU)
+ */
+#include <acess.h>
+#include <mm_virt.h>
+#include <hal_proc.h>
+
+// === CODE ===
+tPAddr MM_GetPhysAddr(tVAddr Addr)
+{
+       return Addr;
+}
+
+void MM_SetFlags(tVAddr Addr, Uint Val, Uint Mask)
+{
+       return ;
+}
+
+Uint MM_GetFlags(tVAddr Addr)
+{
+       return 0;
+}
+
+int MM_Map(tVAddr Dest, tPAddr Src)
+{
+       Dest &= (PAGE_SIZE-1);
+       Src &= (PAGE_SIZE-1);
+       if(Dest != Src)
+               memcpy((void*)Dest, (void*)Src, PAGE_SIZE);
+       return 0;
+}
+
+tPAddr MM_Allocate(tVAddr Dest)
+{
+       return Dest;
+}
+
+void MM_Deallocate(tVAddr Addr)
+{
+}
+
+void MM_ClearUser(void)
+{
+}
+
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+
+}
+
diff --git a/KernelLand/Kernel/arch/m68k/proc.c b/KernelLand/Kernel/arch/m68k/proc.c
new file mode 100644 (file)
index 0000000..c148bff
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/proc.c
+ * - Multithreading
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <hal_proc.h>
+
+// === IMPORTS ===
+extern tThread gThreadZero;
+
+// === GLOBALS ===
+tThread        *gpCurrentThread = &gThreadZero;
+
+// === CODE ===
+void ArchThreads_Init(void)
+{
+}
+
+void Proc_Start(void)
+{      
+}
+
+tThread *Proc_GetCurThread(void)
+{
+       return gpCurrentThread;
+}
+
+int GetCPUNum(void)
+{
+       return 0;
+}
+
+tTID Proc_Clone(Uint Flags)
+{
+       UNIMPLEMENTED();
+       return -1;
+}
+
+tTID Proc_NewKThread(tThreadFunction Fcn, void *Arg)
+{
+       UNIMPLEMENTED();
+       return -1;
+}
+
+tTID Proc_SpawnWorker(tThreadFunction Fcn, void *Arg)
+{
+       UNIMPLEMENTED();
+       return -1;
+}
+
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+{
+       Log_KernelPanic("Proc", "TODO: Implement Proc_StartUser");
+       for(;;);
+}
+
+void Proc_CallFaultHandler(tThread *Thread)
+{
+       
+}
+
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       
+}
+
+void Proc_Reschedule(void)
+{
+       Log_Notice("Proc", "TODO: Implement Proc_Reschedule");
+}
+
diff --git a/KernelLand/Kernel/arch/m68k/time.c b/KernelLand/Kernel/arch/m68k/time.c
new file mode 100644 (file)
index 0000000..0fffaf6
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Acess2 M68K port
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/m68k/time.c
+ * - Timekeeping
+ */
+#include <acess.h>
+
+// === CODE ===
+Sint64 now(void)
+{
+       return 0;
+}
diff --git a/KernelLand/Kernel/arch/x86/Makefile b/KernelLand/Kernel/arch/x86/Makefile
new file mode 100644 (file)
index 0000000..c83a5af
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Acess2 Kernel
+# i386 Architecture Makefile
+# arch/i386/Makefile
+
+AS_SUFFIX = asm
+
+CPPFLAGS       =
+CFLAGS         =
+ASFLAGS                = -f elf
+
+USE_MP=0
+
+ifeq ($(PLATFORM),default)
+       USE_MP=0
+else ifeq ($(PLATFORM),smp)
+       USE_MP=1
+endif
+
+ASFLAGS += -D USE_MP=$(USE_MP)
+CPPFLAGS += -DUSE_MP=$(USE_MP)
+
+A_OBJ  = start.ao main.o lib.o desctab.ao errors.o irq.o
+A_OBJ += mm_phys.o mm_virt.o
+A_OBJ += proc.o proc.ao time.o vm8086.o
+A_OBJ += kpanic.o pci.o
diff --git a/KernelLand/Kernel/arch/x86/desctab.asm b/KernelLand/Kernel/arch/x86/desctab.asm
new file mode 100644 (file)
index 0000000..6eaa651
--- /dev/null
@@ -0,0 +1,327 @@
+; AcessOS Microkernel Version
+;
+; desctab.asm
+[BITS 32]
+
+
+[section .data]
+; IDT
+ALIGN 8
+[global gIDT]
+gIDT:
+       ; CS = 0x08, Type = 32-bit Interrupt (0xE = 1 110)
+       times   256     dd      0x00080000,0x00000E00
+[global gIDTPtr]
+gIDTPtr:
+       dw      256 * 16 - 1    ; Limit
+       dd      gIDT            ; Base
+
+[section .text]
+
+[global Desctab_Install]
+Desctab_Install:
+       ; Set up IDT
+       ; Helper Macros
+       ; - Set an IDT entry to an ISR
+%macro SETISR  1
+       mov eax, Isr%1
+       mov     WORD [gIDT + %1*8], ax
+       shr eax, 16
+       mov     WORD [gIDT + %1*8+6], ax
+       ; Enable
+       mov     ax, WORD [gIDT + %1*8 + 4]
+       or ax, 0x8000
+       mov     WORD [gIDT + %1*8 + 4], ax
+%endmacro
+       ; Enable user calling of an ISR
+%macro SET_USER        1
+       or WORD [gIDT + %1*8 + 4], 0x6000
+%endmacro
+       ; Set an ISR as a trap (leaves interrupts enabled when invoked)
+%macro SET_TRAP        1
+       or WORD [gIDT + %1*8 + 4], 0x0100
+%endmacro
+
+       ; Error handlers
+       %assign i       0
+       %rep 32
+       SETISR  i
+       %assign i i+1
+       %endrep
+       
+       ; User Syscall
+       SETISR  0xAC
+       SET_USER        0xAC
+       SET_TRAP        0xAC    ; Interruptable
+       
+       ; MP ISRs
+       %if USE_MP
+       SETISR  0xED    ; 0xED Inter-processor HALT
+       SETISR  0xEE    ; 0xEE Timer
+       SETISR  0xEF    ; 0xEF Spurious Interrupt
+       %endif
+
+       ; IRQs
+       %assign i       0xF0
+       %rep 16
+       SETISR  i
+       %assign i i+1
+       %endrep
+
+       ; Load IDT
+       lidt [gIDTPtr]
+
+       ; Remap PIC
+       push edx        ; Save EDX
+       mov dx, 0x20
+       mov al, 0x11
+       out dx, al      ;       Init Command
+       mov dx, 0x21
+       mov al, 0xF0
+       out dx, al      ;       Offset (Start of IDT Range)
+       mov al, 0x04
+       out dx, al      ;       IRQ connected to Slave (00000100b) = IRQ2
+       mov al, 0x01
+       out dx, al      ;       Set Mode
+       mov al, 0x00
+       out dx, al      ;       Set Mode
+       
+       mov dx, 0xA0
+       mov al, 0x11
+       out dx, al      ;       Init Command
+       mov dx, 0xA1
+       mov al, 0xF8
+       out dx, al      ;       Offset (Start of IDT Range)
+       mov al, 0x02
+       out dx, al      ;       IRQ Line connected to master
+       mov al, 0x01
+       out dx, al      ;       Set Mode
+       mov dl, 0x00
+       out dx, al      ;       Set Mode
+       pop edx
+       
+       ret
+
+
+; ===============
+; = Define ISRs =
+; ===============
+%macro ISR_ERRNO       1
+[global Isr%1]
+Isr%1:
+       ;xchg bx, bx
+       push    %1
+       jmp     ErrorCommon
+%endmacro
+%macro ISR_NOERR       1
+[global Isr%1]
+Isr%1:
+       ;xchg bx, bx
+       push    0
+       push    %1
+       jmp     ErrorCommon
+%endmacro
+
+%macro DEF_SYSCALL     1
+[global Isr%1]
+Isr%1:
+       push    0
+       push    %1
+       jmp     SyscallCommon
+%endmacro
+
+%macro DEF_IRQ 1
+[global Isr%1]
+Isr%1:
+       push    0
+       push    %1
+       jmp     IRQCommon
+%endmacro
+
+ISR_NOERR      0;  0: Divide By Zero Exception
+ISR_NOERR      1;  1: Debug Exception
+ISR_NOERR      2;  2: Non Maskable Interrupt Exception
+ISR_NOERR      3;  3: Int 3 Exception
+ISR_NOERR      4;  4: INTO Exception
+ISR_NOERR      5;  5: Out of Bounds Exception
+ISR_NOERR      6;  6: Invalid Opcode Exception
+ISR_NOERR      7;  7: Coprocessor Not Available Exception
+ISR_ERRNO      8;  8: Double Fault Exception (With Error Code!)
+ISR_NOERR      9;  9: Coprocessor Segment Overrun Exception
+ISR_ERRNO      10; 10: Bad TSS Exception (With Error Code!)
+ISR_ERRNO      11; 11: Segment Not Present Exception (With Error Code!)
+ISR_ERRNO      12; 12: Stack Fault Exception (With Error Code!)
+ISR_ERRNO      13; 13: General Protection Fault Exception (With Error Code!)
+ISR_ERRNO      14; 14: Page Fault Exception (With Error Code!)
+ISR_NOERR      15; 15: Reserved Exception
+ISR_NOERR      16; 16: Floating Point Exception
+ISR_NOERR      17; 17: Alignment Check Exception
+ISR_NOERR      18; 18: Machine Check Exception
+ISR_NOERR      19; 19: Reserved
+ISR_NOERR      20; 20: Reserved
+ISR_NOERR      21; 21: Reserved
+ISR_NOERR      22; 22: Reserved
+ISR_NOERR      23; 23: Reserved
+ISR_NOERR      24; 24: Reserved
+ISR_NOERR      25; 25: Reserved
+ISR_NOERR      26; 26: Reserved
+ISR_NOERR      27; 27: Reserved
+ISR_NOERR      28; 28: Reserved
+ISR_NOERR      29; 29: Reserved
+ISR_NOERR      30; 30: Reserved
+ISR_NOERR      31; 31: Reserved
+
+DEF_SYSCALL    0xAC    ; Acess System Call
+
+%if USE_MP
+[global Isr0xED]
+; 0xED - Interprocessor HALT
+Isr0xED:
+       cli
+.jmp:  hlt
+       jmp .jmp
+
+[global Isr0xEE]
+[extern SchedulerBase]
+; AP's Timer Interrupt
+Isr0xEE:
+       push eax        ; Line up with interrupt number
+       mov eax, dr1    ; CPU Number
+       push eax
+       mov eax, [esp+4]        ; Load EAX back
+       jmp SchedulerBase
+; Spurious Interrupt
+[global Isr0xEF]
+Isr0xEF:
+       xchg bx, bx     ; MAGIC BREAK
+       iret
+%endif
+
+; IRQs
+; - Timer
+[global Isr240]
+[global Isr240.jmp]
+[extern SchedulerBase]
+[extern SetAPICTimerCount]
+Isr240:
+       push 0  ; Line up with Argument in errors
+       push 0  ; CPU Number
+       ;xchg bx, bx    ; MAGIC BREAK
+Isr240.jmp:
+       %if USE_MP
+       jmp SetAPICTimerCount   ; This is reset once the bus speed has been calculated
+       %else
+       jmp SchedulerBase
+       %endif
+; - Assignable
+%assign i      0xF1
+%rep 16
+       DEF_IRQ i
+%assign i i+1
+%endrep
+
+; ---------------------
+; Common error handling
+; ---------------------
+[extern ErrorHandler]
+ErrorCommon:
+       ;xchg bx, bx    ; MAGIC BREAK
+       
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+
+       ; Clear TF      
+;      pushf
+;      and WORD [esp], 0xFEFF
+;      popf
+
+       mov ax, 0x10
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       push esp
+       call ErrorHandler
+       add esp, 4
+       
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       popa
+       add esp, 8      ; Error Code and ID
+       iret
+
+; --------------------------
+; Common System Call Handler
+; --------------------------
+[extern SyscallHandler]
+SyscallCommon:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       push esp
+       call SyscallHandler
+       add esp, 4
+       
+       ; Pass changes to TF on to the user
+       ; EFLAGS is stored at ESP[4+8+2+2]
+       ; 4 Segment Registers
+       ; 8 GPRs
+       ; 2 Error Code / Interrupt ID
+       ; 2 CS/EIP
+       pushf
+       pop eax
+       and eax, 0x100  ; 0x100 = Trace Flag
+       and WORD [esp+(4+8+2+2)*4], ~0x100      ; Clear
+       or DWORD [esp+(4+8+2+2)*4], eax ; Set for user
+       
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       popa
+       add esp, 8      ; Error Code and ID
+       iret
+
+; ------------
+; IRQ Handling
+; ------------
+[extern IRQ_Handler]
+[global IRQCommon]
+[global IRQCommon_handled]
+IRQCommon_handled equ IRQCommon.handled
+IRQCommon:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       mov ax, 0x10
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       push esp
+       call IRQ_Handler
+.handled:
+       add esp, 4
+       
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       popa
+       add esp, 8      ; Error Code and ID
+       iret
+
+; vim: ft=nasm ts=8
diff --git a/KernelLand/Kernel/arch/x86/errors.c b/KernelLand/Kernel/arch/x86/errors.c
new file mode 100644 (file)
index 0000000..d2d2cef
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Acess2 - x86 Architecture
+ * arch/x86/errors.c
+ * - CPU Error Handler
+ */
+#include <acess.h>
+#include <proc.h>
+#include <mm_virt.h>
+
+// === CONSTANTS ===
+#define        MAX_BACKTRACE   8       //!< Maximum distance to trace the stack backwards
+
+// === IMPORTS ===
+extern void    MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
+extern void    VM8086_GPF(tRegs *Regs);
+extern void    Threads_Dump(void);
+extern void    Threads_Fault(int Num);
+extern int     GetCPUNum(void);
+extern void    MM_DumpTables(tVAddr, tVAddr);
+extern void    Proc_EnableSSE(void);
+extern void    Proc_RestoreSSE(Uint32 Data);
+
+// === PROTOTYPES ===
+void   __stack_chk_fail(void);
+void   ErrorHandler(tRegs *Regs);
+void   Proc_PrintBacktrace(void);
+void   Error_Backtrace(Uint eip, Uint ebp);
+void   StartupPrint(char *Str);
+
+// === GLOBALS ===
+const char *csaERROR_NAMES[] = {
+       "Divide By Zero", "Debug", "NMI Exception", "INT3",
+       "INTO Instr - Overflow", "BOUND Instr - Out of Bounds", "Invalid Opcode", "Coprocessor not avaliable",
+       "Double Fault", "Coprocessor Segment Overrun", "Bad TSS", "Segment Not Present",
+       "Stack Fault Exception", "GPF", "#PF", "Reserved",
+       "Floating Point Exception", "Alignment Check Exception", "Machine Check Exception",     "Reserved",
+       "Reserved", "Reserved", "Reserved", "Reserved",
+       "Reserved", "Reserved", "Reserved", "Reserved",
+       "Reserved", "Reserved", "Reserved", "Reserved"
+       };
+
+// === CODE ===
+/**
+ * \brief Keeps GCC happy
+ */
+void __stack_chk_fail(void)
+{
+       Panic("FATAL ERROR: Stack Check Failed\n");
+       for(;;);
+}
+
+/**
+ * \fn void ErrorHandler(tRegs *Regs)
+ * \brief General Error Handler
+ * \param Regs Register state at error
+ */
+void ErrorHandler(tRegs *Regs)
+{
+       Uint    cr;
+       
+       //if( Regs && !(Regs->int_num == 13 && Regs->eflags & 0x20000) )
+       //      __asm__ __volatile__ ("xchg %bx, %bx");
+       //Log_Debug("X86", "Regs = %p", Regs);
+       //Log_Debug("X86", "Error %i at 0x%08x", Regs->int_num, Regs->eip);
+       
+       __asm__ __volatile__ ("cli");
+       
+       // Debug exception (used for single-stepping)
+       if(Regs->int_num == 1)
+       {
+               static Uint32   lastEIP = 0;
+               tThread *thread = Proc_GetCurThread();
+               if( Regs->eip == lastEIP )
+                       return;
+               Log("%p(%i %s) IP=%08x", thread, thread->TID, thread->ThreadName, Regs->eip);
+               lastEIP = Regs->eip;
+               return ;
+       }
+       
+       // Page Fault
+       if(Regs->int_num == 14)
+       {
+               __asm__ __volatile__ ("sti");   // Should be OK, TODO: Test
+               __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
+               MM_PageFault( cr, Regs->err_code, Regs );
+               return ;
+       }
+
+       // #NM - Coprocessor unavaliable
+       if(Regs->int_num == 7)
+       {
+               tThread *thread = Proc_GetCurThread();
+               if(!thread->SavedState.bSSEModified)
+               {
+                       Proc_EnableSSE();
+                       if(!thread->SavedState.SSE)
+                               thread->SavedState.SSE = malloc(sizeof(tSSEState) + 0xF);
+                       else
+                               Proc_RestoreSSE( ((Uint)thread->SavedState.SSE + 0xF) & ~0xF );
+                       thread->SavedState.bSSEModified = 1;
+                       __asm__ __volatile__ ("sti");
+                       return ;
+               }
+               // oops, SSE enabled but a #NM, bad news
+       }
+       
+       // VM8086 GPF
+       if(Regs->int_num == 13 && Regs->eflags & 0x20000)
+       {
+               VM8086_GPF(Regs);
+               return ;
+       }
+       
+       // Check if it's a user mode fault
+       if( (Regs->cs & 3) == 3 ) {
+               Log_Warning("Arch", "User Fault -  %s, Code: 0x%x",
+                       csaERROR_NAMES[Regs->int_num], Regs->err_code);
+               Log_Warning("Arch", "at CS:EIP %04x:%08x",
+                       Regs->cs, Regs->eip);
+               MM_DumpTables(0, KERNEL_BASE);
+               switch( Regs->int_num )
+               {
+               // Division by Zero
+               case  0:        Threads_Fault(FAULT_DIV0);      break;
+               // Invalid opcode
+               case  6:        Threads_Fault(FAULT_OPCODE);    break;
+               // GPF
+               case 13:        Threads_Fault(FAULT_ACCESS);    break;
+               // Floating Point Exception
+               case 16:        Threads_Fault(FAULT_FLOAT);     break;
+               
+               default:        Threads_Fault(FAULT_MISC);      break;
+               }
+               return ;
+       }
+       
+       Debug_KernelPanic();
+       
+       LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x\n",
+               GetCPUNum(),
+               Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code,
+               Regs->eip);
+       
+       //Warning("CPU Error %i - %s, Code: 0x%x",
+       //      Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code);
+       //Warning(" CS:EIP = 0x%04x:%08x", Regs->cs, Regs->eip);
+       __ASM__ ("xchg %bx, %bx");
+       if(Regs->cs == 0x08)
+               Warning(" SS:ESP = 0x0010:%08x", (Uint)Regs+sizeof(tRegs));
+       else
+               Warning(" SS:ESP = 0x%04x:%08x", Regs->ss, Regs->esp);
+       Warning(" EFLAGS = 0x%08x", Regs->eflags);
+       Warning(" EAX %08x ECX %08x EDX %08x EBX %08x",
+               Regs->eax, Regs->ecx, Regs->edx, Regs->ebx);
+       Warning(" ESP %08x EBP %08x ESI %08x EDI %08x",
+               Regs->esp, Regs->ebp, Regs->esi, Regs->edi);
+       Warning(" DS %04x ES %04x FS %04x GS %04x",
+               Regs->ds, Regs->es, Regs->fs, Regs->gs);
+       
+       // Control Registers
+       __asm__ __volatile__ ("mov %%cr0, %0":"=r"(cr));
+       Warning(" CR0 0x%08x", cr);
+       __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
+       Warning(" CR2 0x%08x", cr);
+       __asm__ __volatile__ ("mov %%cr3, %0":"=r"(cr));
+       Warning(" CR3 0x%08x", cr);
+       
+       switch( Regs->int_num )
+       {
+       case 6: // #UD
+               Warning(" Offending bytes: %02x %02x %02x %02x",
+                       *(Uint8*)(Regs->eip+0), *(Uint8*)(Regs->eip+1),
+                       *(Uint8*)(Regs->eip+2), *(Uint8*)(Regs->eip+3));
+               break;
+       }
+       
+       // Print Stack Backtrace
+       Error_Backtrace(Regs->eip, Regs->ebp);
+       
+       // Dump running threads
+       Threads_Dump();
+       
+       for(;;) __asm__ __volatile__ ("hlt");
+}
+
+void Proc_PrintBacktrace(void)
+{
+       Uint32  ebp;
+       __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (ebp));
+       Error_Backtrace( *(Uint32*)(ebp+4), *(Uint32*)ebp );
+}
+
+/**
+ * \fn void Error_Backtrace(Uint eip, Uint ebp)
+ * \brief Unrolls the stack to trace execution
+ * \param eip  Current Instruction Pointer
+ * \param ebp  Current Base Pointer (Stack Frame)
+ */
+void Error_Backtrace(Uint eip, Uint ebp)
+{
+        int    i = 0;
+//     Uint    delta = 0;
+//     char    *str = NULL;
+       
+       //if(eip < 0xC0000000 && eip > 0x1000)
+       //{
+       //      LogF("Backtrace: User - 0x%x\n", eip);
+       //      return;
+       //}
+
+       #if 0   
+       if(eip > 0xE0000000)
+       {
+               LogF("Backtrace: Data Area - 0x%x\n", eip);
+               return;
+       }
+       
+       if(eip > 0xC8000000)
+       {
+               LogF("Backtrace: Kernel Module - 0x%x\n", eip);
+               return;
+       }
+       #endif  
+
+       //str = Debug_GetSymbol(eip, &delta);
+//     if(str == NULL)
+               LogF("Backtrace: 0x%x", eip);
+//     else
+//             LogF("Backtrace: %s+0x%x", str, delta);
+       if(!MM_GetPhysAddr(ebp))
+       {
+               LogF("\nBacktrace: Invalid EBP, stopping\n");
+               return;
+       }
+       
+       
+       while( MM_GetPhysAddr(ebp) && i < MAX_BACKTRACE )
+       {
+               if( ebp >= MM_KERNEL_STACKS_END )       break;
+               //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
+//             if(str == NULL)
+                       LogF(" >> 0x%x", *(Uint*)(ebp+4));
+//             else
+//                     LogF(" >> %s+0x%x", str, delta);
+               ebp = *(Uint*)ebp;
+               i++;
+       }
+       LogF("\n");
+}
+
+/**
+ * \fn void StartupPrint(char *Str)
+ * \brief Str  String to print
+ * \note WHY IS THIS HERE?!?!
+ */
+void StartupPrint(char *Str)
+{
+       Uint16  *buf = (void*)0xC00B8000;
+        int    i = 0;
+       static int      line = 0;
+       while(*Str)
+       {
+               buf[line*80 + i++] = *Str | 0x0700;
+               Str ++;
+       }
+       
+       // Clear the rest of the line
+       while(i < 80)
+               buf[line*80 + i++] = 0x0720;
+       
+       line ++;
+       if(line == 25)
+       {
+               line --;
+               memcpy(buf, &buf[80], 80*24*2);
+               memset(&buf[80*24], 0, 80*2);
+       }
+}
+
+// === EXPORTS ===
+EXPORT(__stack_chk_fail);
diff --git a/KernelLand/Kernel/arch/x86/include/arch.h b/KernelLand/Kernel/arch/x86/include/arch.h
new file mode 100644 (file)
index 0000000..8a98705
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Acess2
+ * - x86 Architecture
+ * arch/x86/include/arch.h
+ */
+#ifndef _ARCH_H_
+#define _ARCH_H_
+
+// - Base Defintions
+#define        KERNEL_BASE     0xC0000000
+#define BITS   32
+#define PAGE_SIZE      0x1000
+
+#define INVLPTR        ((void*)-1)
+
+// Allow nested spinlocks?
+#define LOCK_DISABLE_INTS      1
+
+// - Processor/Machine Specific Features
+#if ARCH != x86 && ARCH != x86_smp
+# error "Unknown architecture '" #ARCH "'"
+#endif
+
+#if USE_MP
+# define       MAX_CPUS        8
+#else
+# define       MAX_CPUS        1
+#endif
+
+#if USE_PAE
+# define       PHYS_BITS       48
+#else
+# define       PHYS_BITS       32
+#endif
+
+#define __ASM__        __asm__ __volatile__
+
+// === Spinlocks ===
+/**
+ * \brief Short Spinlock structure
+ */
+struct sShortSpinlock {
+       volatile int    Lock;   //!< Lock value
+       
+       #if LOCK_DISABLE_INTS
+        int    IF;     //!< Interrupt state on call to SHORTLOCK
+       #endif
+};
+
+// === MACROS ===
+/**
+ * \brief Halt the CPU (shorter version of yield)
+ */
+#if 1
+#define        HALT()  do { \
+       Uint32  flags; \
+       __asm__ __volatile__ ("pushf;pop %0" : "=a"(flags)); \
+       if( !(flags & 0x200) )  Panic("HALT called with interrupts disabled"); \
+       __asm__ __volatile__ ("hlt"); \
+} while(0)
+#else
+#define        HALT()  __asm__ __volatile__ ("hlt")
+#endif
+/**
+ * \brief Fire a magic breakpoint (bochs)
+ */
+#define        MAGIC_BREAK()   __asm__ __volatile__ ("xchg %bx, %bx")
+
+// === TYPES ===
+typedef unsigned int   Uint;   // Unsigned machine native integer
+typedef unsigned char  Uint8;
+typedef unsigned short Uint16;
+typedef unsigned long  Uint32;
+typedef unsigned long long     Uint64;
+typedef signed int             Sint;   // Signed Machine Native integer
+typedef signed char            Sint8;
+typedef signed short   Sint16;
+typedef signed long            Sint32;
+typedef signed long long       Sint64;
+typedef Uint   size_t;
+typedef char   BOOL;
+
+typedef Uint32 tPAddr;
+typedef Uint32 tVAddr;
+
+typedef struct {
+       Uint32  gs, fs, es, ds;
+       Uint32  edi, esi, ebp, kesp;
+       Uint32  ebx, edx, ecx, eax;
+       Uint32  int_num, err_code;
+       Uint32  eip, cs;
+       Uint32  eflags, esp, ss;
+} tRegs;
+
+typedef struct {
+       Uint    Resvd1[4];      // GS, FS, ES, DS
+       Uint    Arg4, Arg5;     // EDI, ESI
+       Uint    Arg6;   // EBP
+       Uint    Resvd2[1];      // Kernel ESP
+       union {
+               Uint    Arg1;
+               Uint    Error;
+       };      // EBX
+       union {
+               Uint    Arg3;
+               Uint    RetHi;  // High 32 bits of ret
+       };      // EDX
+       Uint    Arg2;   // ECX
+       union {
+               Uint    Num;
+               Uint    Return;
+       };      // EAX
+       Uint    Resvd3[5];      // Int, Err, Eip, CS, ...
+       Uint    StackPointer;   // ESP
+       Uint    Resvd4[1];      // SS
+} tSyscallRegs;
+
+// === FUNCTIONS ===
+extern void    Debug_PutCharDebug(char ch);
+extern void    Debug_PutStringDebug(const char *String);
+
+extern int     IS_LOCKED(struct sShortSpinlock *Lock);
+extern int     CPU_HAS_LOCK(struct sShortSpinlock *Lock);
+extern void    SHORTLOCK(struct sShortSpinlock *Lock);
+extern void    SHORTREL(struct sShortSpinlock *Lock);
+
+#endif // !defined(_ARCH_H_)
diff --git a/KernelLand/Kernel/arch/x86/include/arch_int.h b/KernelLand/Kernel/arch/x86/include/arch_int.h
new file mode 100644 (file)
index 0000000..81ea2d7
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * x86 Arch - Internal Definitions
+ * - arch/x86/include/arch_int.h
+ */
+#ifndef _ARCH_INT_H_
+#define _ARCH_INT_H_
+
+/**
+ * \brief Spinlock primative atomic set-if-zero loop
+ */
+extern void    __AtomicTestSetLoop(Uint *Ptr, Uint Value);
+
+/**
+ * \brief Clear and free an address space
+ */
+extern void    MM_ClearSpace(Uint32 CR3);
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/x86/include/desctab.h b/KernelLand/Kernel/arch/x86/include/desctab.h
new file mode 100644 (file)
index 0000000..47a462a
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ */
+#ifndef _DESCTAB_H_
+#define _DESCTAB_H_
+
+typedef struct {
+       Uint16  LimitLow;
+       Uint16  BaseLow;
+       Uint8   BaseMid;
+       Uint8   Access;
+       struct {
+               unsigned LimitHi:       4;
+               unsigned Flags:         4;
+       } __attribute__ ((packed));
+       Uint8   BaseHi;
+} __attribute__ ((packed)) tGDT;
+
+typedef struct {
+       Uint16  OffsetLo;
+       Uint16  CS;
+       Uint16  Flags;
+       Uint16  OffsetHi;
+} __attribute__ ((packed)) tIDT;
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/include/mm_phys.h b/KernelLand/Kernel/arch/x86/include/mm_phys.h
new file mode 100644 (file)
index 0000000..96d3e64
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * AcessOS Microkernel Version
+ * mm_phys.h
+ */
+#ifndef _MM_PHYS_H
+#define _MM_PHYS_H
+
+// === FUNCTIONS ===
+//extern tPAddr        MM_AllocPhys(void);
+//extern tPAddr        MM_AllocPhysRange(int Pages, int MaxBits);
+//extern void  MM_RefPhys(tPAddr PAddr);
+//extern void  MM_DerefPhys(tPAddr PAddr);
+//extern int   MM_GetRefCount(tPAddr Addr);
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/include/mm_virt.h b/KernelLand/Kernel/arch/x86/include/mm_virt.h
new file mode 100644 (file)
index 0000000..d84c965
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Acess2
+ * - Virtual Memory Manager (Header)
+ */
+#ifndef _MM_VIRT_H
+#define _MM_VIRT_H
+
+// NOTES:
+// - 1PD is 0x400000
+
+// - Memory Layout
+#define        MM_USER_MIN     0x00200000
+#define        USER_STACK_SZ   0x00020000      // 128 KiB
+#define        USER_STACK_TOP  0x00800000
+#define USER_LIB_MAX   0xBC000000
+#define        MM_USER_MAX     0xBC000000      // Top load address for user libraries
+#define        MM_PPD_MIN      0xBC000000      // Per-Process Data base
+#define        MM_PPD_HANDLES  0xBC000000      // - VFS Handles (Practically unlimited)
+#define        MM_PPD_MMAP     0xBD000000      // - MMap Entries (24b each = 0x2AAAA max)
+#define        MM_PPD_UNALLOC  0xBE000000      //
+#define MM_PPD_CFG     0xBFFFF000      // - Per-process config entries 
+#define        MM_PPD_MAX      0xC0000000      // 
+
+#define        MM_KHEAP_BASE   0xC0400000      // C+4MiB
+#define        MM_KHEAP_MAX    0xCF000000      //
+#define MM_KERNEL_VFS  0xCF000000      // 
+#define MM_KUSER_CODE  0xCFFF0000      // 16 Pages
+#define        MM_MODULE_MIN   0xD0000000      // Lowest Module Address
+#define MM_MODULE_MAX  0xE0000000      // 128 MiB
+
+// Page Info (Which VFS node owns each physical page)
+// 2^32/2^12*16
+// = 2^24 = 16 MiB = 0x4000000
+// 256 items per page
+#define MM_PAGENODE_BASE       0xE0000000
+
+// Needs (2^32/2^12*4 bytes)
+// - 2^22 bytes max = 4 MiB = 0x1000000
+// 1024 items per page
+#define        MM_REFCOUNT_BASE        0xE4000000
+
+#define MM_KERNEL_STACKS       0xF0000000
+#define        MM_KERNEL_STACK_SIZE    0x00008000
+#define MM_KERNEL_STACKS_END   0xFC000000
+
+// === FUNCTIONS ===
+extern void    MM_FinishVirtualInit(void);
+extern void    MM_SetCR3(Uint CR3);
+extern tPAddr  MM_Clone(int bCloneUser);
+extern tVAddr  MM_NewKStack(void);
+extern tVAddr  MM_NewWorkerStack(Uint *InitialStack, size_t StackSize);
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/include/mp.h b/KernelLand/Kernel/arch/x86/include/mp.h
new file mode 100644 (file)
index 0000000..0dd5a1e
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ */
+#ifndef _MP_H
+#define _MP_H
+
+#define MPPTR_IDENT    ('_'|('M'<<8)|('P'<<16)|('_'<<24))
+#define MPTABLE_IDENT  ('P'|('C'<<8)|('M'<<16)|('P'<<24))
+
+typedef struct sMPInfo {
+       Uint32  Sig;    // '_MP_'
+       Uint32  MPConfig;
+       Uint8   Length;
+       Uint8   Version;
+       Uint8   Checksum;
+       Uint8   Features[5];    // 2-4 are unused
+} tMPInfo;
+
+typedef union uMPTable_Ent {
+       Uint8   Type;
+       struct {
+               Uint8   Type;
+               Uint8   APICID;
+               Uint8   APICVer;
+               Uint8   CPUFlags;       // bit 0: Enabled, bit 1: Boot Processor
+               Uint32  CPUSignature;   // Stepping, Model, Family
+               Uint32  FeatureFlags;
+               Uint32  Reserved[2];
+       } __attribute__((packed))       Proc;   // 0x00
+       struct {
+               Uint8   Type;
+               Uint8   ID;
+               char    TypeString[6];
+       } __attribute__((packed))       Bus;    // 0x01
+       struct {
+               Uint8   Type;
+               Uint8   ID;
+               Uint8   Version;
+               Uint8   Flags;  // bit 0: Enabled
+               Uint32  Addr;
+       } __attribute__((packed))       IOAPIC; // 0x02
+       struct {
+               Uint8   Type;
+               Uint8   IntType;
+               Uint16  Flags;  // 0,1: Polarity, 2,3: Trigger Mode
+               Uint8   SourceBusID;
+               Uint8   SourceBusIRQ;
+               Uint8   DestAPICID;
+               Uint8   DestAPICIRQ;
+       } __attribute__((packed))       IOInt;
+       struct {
+               Uint8   Type;
+               Uint8   IntType;
+               Uint16  Flags;  // 0,1: Polarity, 2,3: Trigger Mode
+               Uint8   SourceBusID;
+               Uint8   SourceBusIRQ;
+               Uint8   DestLocalAPICID;
+               Uint8   DestLocalAPICIRQ;
+       } __attribute__((packed))       LocalInt;
+} __attribute__((packed)) tMPTable_Ent;
+
+typedef struct sMPTable {
+       Uint32  Sig;
+       Uint16  BaseTableLength;
+       Uint8   SpecRev;
+       Uint8   Checksum;
+       
+       char    OemID[8];
+       char    ProductID[12];
+       
+       Uint32  OEMTablePtr;
+       Uint16  OEMTableSize;
+       Uint16  EntryCount;
+       
+       Uint32  LocalAPICMemMap;        //!< Address used to access the local APIC
+       Uint16  ExtendedTableLen;
+       Uint8   ExtendedTableChecksum;
+       Uint8   Reserved;
+       
+       tMPTable_Ent    Entries[];
+} tMPTable;
+
+typedef volatile struct {
+       Uint32  Addr;
+       Uint32  Resvd1[3];
+       union {
+               Uint8   Byte;
+               Uint16  Word;
+               Uint32  DWord;
+       }       Value;
+       Uint32  Resvd2[3];
+}      tIOAPIC;
+
+typedef struct {
+       Uint32  Val;
+       Uint32  Padding[3];
+} volatile     tReg;
+
+typedef volatile struct {
+       tReg    _unused1[2];
+       tReg    ID;
+       tReg    Version;
+       tReg    _unused2[4];
+       tReg    TPR;    // Task Priority Register
+       tReg    APR;    // Arbitration Priority Register (RO)
+       tReg    PPR;    // Processor Priority Register (RO)
+       tReg    EOI;    // EOI Register (Write Only)
+       tReg    _unused3[1];
+       tReg    LogDest;        // Logical Destination Register
+       tReg    DestFmt;        // Destination Format Register (0-27: RO, 28-31: RW)
+       tReg    SIV;    // Spurious Interrupt Vector Register (0-8: RW, 9-31: RO)
+       tReg    ISR[8]; // In-Service Register - Total 256 Bits (RO)
+       tReg    TMR[8]; // Trigger Mode Register - Total 256 Bits (RO)
+       tReg    IRR[8]; // Interrupt Request Register - Total 256 Bits (RO)
+       tReg    ErrorStatus;    // Error Status Register (RO)
+       tReg    _unused4[6];
+       tReg    LVTCMI; // LVT CMI Registers
+       // 0x300
+       tReg    ICR[2]; // Interrupt Command Register (RW)
+       // LVT Registers (Controls Local Vector Table)
+       // Structure:
+       // 0-7:   Vector - IDT Vector for the interrupt
+       // 12:    Delivery Status (0: Idle, 1: Send Pending)
+       // 16:    Mask (0: Enabled, 1: Disabled)
+       // 0x320
+       tReg    LVTTimer;       // LVT Timer Register (RW)
+       tReg    LVTThermalSensor;       // LVT Thermal Sensor Register (RW)
+       tReg    LVTPerfMonCounters;     // LVT Performance Monitor Counters Register (RW)
+       tReg    LVTLInt0;       // LVT Local Interrupt (LINT) #0 Register (RW);
+       tReg    LVTLInt1;       // LVT Local Interrupt (LINT) #1 Register (RW);
+       tReg    LVTError;       // LVT Error Register (RW);
+       // 0x380
+       tReg    InitialCount;   // Initial Count Register (Used for the timer) (RW)
+       tReg    CurrentCount;   // Current Count Register (Used for the timer) (RW)
+       tReg    _unused5[4];
+       // 0x3E0
+       tReg    DivideConifg;   // Divide Configuration Register (RW)
+       tReg    _unused6[1];
+} volatile     tAPIC;
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/include/multiboot2.h b/KernelLand/Kernel/arch/x86/include/multiboot2.h
new file mode 100644 (file)
index 0000000..735109a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Acess 2
+ * By John Hodge (thePowersGang)
+ *
+ * multiboot2.h
+ * - Multiboot 2 Header
+ */
+#ifndef _MULTIBOOT2_H_
+#define _MULTIBOOT2_H_
+
+#define MULTIBOOT2_MAGIC       0x36D76289
+
+typedef struct sMultiboot2Info
+{
+       Uint32  TotalSize;
+       Uint32  Reserved;       // SBZ
+}      tMultiboot2Info;
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/include/proc.h b/KernelLand/Kernel/arch/x86/include/proc.h
new file mode 100644 (file)
index 0000000..9ecd98b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * AcessOS Microkernel Version
+ * proc.h
+ */
+#ifndef _PROC_H
+#define _PROC_H
+
+// === TYPES ==
+typedef struct sTSS {
+       Uint32  Link;
+       Uint32  ESP0, SS0;
+       Uint32  ESP1, SS1;
+       Uint32  ESP2, SS2;
+       Uint32  CR3;
+       Uint32  EIP;
+       Uint32  EFLAGS;
+       Uint32  EAX, ECX, EDX, EBX;
+       Uint32  ESP, EBP, ESI, EDI;
+       Uint32  ES, CS, DS, SS, FS, GS;
+       Uint32  LDTR;
+       Uint16  Resvd, IOPB;    // IO Permissions Bitmap
+} __attribute__((packed)) tTSS;
+
+typedef struct {
+       #if USE_PAE
+       Uint    PDPT[4];
+       #else
+       Uint32  CR3;
+       #endif
+} tMemoryState;
+
+// 512 bytes, 16 byte aligned
+typedef struct sSSEState
+{
+       char    data[512];
+} tSSEState;
+
+typedef struct {
+       Uint    EIP, ESP;
+       Uint32  UserCS, UserEIP;
+       tSSEState       *SSE;
+        int    bSSEModified;
+} tTaskState;
+
+#include <threads_int.h>
+
+#define USER_MAX       KERNEL_BASE
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/include/vm8086.h b/KernelLand/Kernel/arch/x86/include/vm8086.h
new file mode 100644 (file)
index 0000000..7c8dd47
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Acess2 VM8086 BIOS Interface
+ * - By John Hodge (thePowersGang)
+ *
+ * vm8086.h
+ * - Core Header
+ */
+#ifndef _VM80806_H_
+#define _VM80806_H_
+
+// === TYPES ===
+/**
+ * \note Semi-opaque - Past \a .IP, the implementation may add any data
+ *       it needs to the state.
+ */
+typedef struct sVM8086
+{
+       Uint16  AX, CX, DX, BX;
+       Uint16  BP, SP, SI, DI;
+       
+       Uint16  SS, DS, ES;
+       
+       Uint16  CS, IP;
+       
+       struct sVM8086_InternalData     *Internal;
+}      tVM8086;
+
+// === FUNCTIONS ===
+/**
+ * \brief Create an instance of the VM8086 Emulator
+ * \note Do not free this pointer with ::free, instead use ::VM8086_Free
+ * \return Pointer to a tVM8086 structure, this structure may be larger than
+ *         tVM8086 due to internal data.
+ */
+extern tVM8086 *VM8086_Init(void);
+/**
+ * \brief Free an allocated tVM8086 structure
+ * \param State        Emulator state to free
+ */
+extern void    VM8086_Free(tVM8086 *State);
+/**
+ * \brief Allocate a piece of memory in the emulated address space and
+ *        return a host and emulated pointer to it.
+ * \param State        Emulator state
+ * \param Size Size of memory block
+ * \param Segment      Pointer to location to store the allocated memory's segment
+ * \param Offset       Pointet to location to store the allocated memory's offset
+ * \return Host pointer to the allocated memory
+ */
+extern void    *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset);
+/**
+ * \brief Gets a pointer to a piece of emulated memory
+ * \todo Only 1 machine page is garenteed to be contiguous
+ * \param State        Emulator State
+ * \param Segment      Source Segment
+ * \param Offset       Source Offset
+ * \return Host pointer to the emulated memory
+ */
+extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset);
+/**
+ * \brief Calls a real-mode interrupt described by the current state of the IVT.
+ * \param State        Emulator State
+ * \param Interrupt    BIOS Interrupt to call
+ */
+extern void    VM8086_Int(tVM8086 *State, Uint8 Interrupt);
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86/irq.c b/KernelLand/Kernel/arch/x86/irq.c
new file mode 100644 (file)
index 0000000..e2dcf0e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * AcessOS Microkernel Version
+ * irq.c
+ */
+#include <acess.h>
+
+// === CONSTANTS ===
+#define        MAX_CALLBACKS_PER_IRQ   4
+#define TRACE_IRQS     0
+
+// === TYPES ===
+typedef void (*tIRQ_Callback)(int, void *);
+
+// === PROTOTYPES ===
+void   IRQ_Handler(tRegs *Regs);
+
+// === GLOBALS ===
+tIRQ_Callback  gIRQ_Handlers[16][MAX_CALLBACKS_PER_IRQ];
+void   *gaIRQ_DataPointers[16][MAX_CALLBACKS_PER_IRQ];
+
+// === CODE ===
+/**
+ * \fn void IRQ_Handler(tRegs *Regs)
+ * \brief Handle an IRQ
+ */
+void IRQ_Handler(tRegs *Regs)
+{
+        int    i, irq = Regs->int_num - 0xF0;
+
+       //Log("IRQ_Handler: (Regs={int_num:%i})", Regs->int_num);
+
+       for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
+       {
+               if( gIRQ_Handlers[irq][i] ) {
+                       gIRQ_Handlers[irq][i](irq, gaIRQ_DataPointers[irq][i]);
+                       #if TRACE_IRQS
+                       if( irq != 8 )
+                               Log("IRQ %i: Call %p", Regs->int_num, gIRQ_Handlers[Regs->int_num][i]);
+                       #endif
+               }
+       }
+
+       //Log(" IRQ_Handler: Resetting");
+       if(irq >= 8)
+               outb(0xA0, 0x20);       // ACK IRQ (Secondary PIC)
+       outb(0x20, 0x20);       // ACK IRQ
+       //Log("IRQ_Handler: RETURN");
+}
+
+/**
+ * \fn int IRQ_AddHandler( int Num, void (*Callback)(int) )
+ */
+int IRQ_AddHandler( int Num, void (*Callback)(int, void*), void *Ptr )
+{
+        int    i;
+       for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
+       {
+               if( gIRQ_Handlers[Num][i] == NULL ) {
+                       Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
+                       gIRQ_Handlers[Num][i] = Callback;
+                       gaIRQ_DataPointers[Num][i] = Ptr;
+                       return 1;
+               }
+       }
+
+       Log_Warning("IRQ", "No free callbacks on IRQ%i", Num);
+       return 0;
+}
diff --git a/KernelLand/Kernel/arch/x86/kpanic.c b/KernelLand/Kernel/arch/x86/kpanic.c
new file mode 100644 (file)
index 0000000..9300c69
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Acess 2 Kernel
+ * - By John Hodge (thePowersGang)
+ * 
+ * kpanic.c
+ * - x86 Kernel Panic Handler
+ */
+
+#include <acess.h>
+#include <proc.h>
+
+// === CONSTANTS ===
+#define        FB      ((Uint16 *)(KERNEL_BASE|0xB8000))
+#define BGC    0x4F00  // White on Red
+//#define BGC  0xC000  // Black on Bright Red
+//#define BGC  0x1F00  // White on Blue (BSOD!)
+
+// === IMPORTS ===
+extern Uint32  GetEIP(void);
+extern void    Error_Backtrace(Uint32 eip, Uint32 ebp);
+#if USE_MP
+extern void    MP_SendIPIVector(int CPU, Uint8 Vector);
+extern int     giNumCPUs;
+extern int     GetCPUNum(void);
+#endif
+
+// === PROTOTYPES ===
+void   KernelPanic_SetMode(void);
+void   KernelPanic_PutChar(char Ch);
+
+// === CONSTANTS ===
+const struct {
+       Uint16  IdxPort;
+       Uint16  DatPort;
+       Uint8   Index;
+       Uint8   Value;
+}      caRegValues[] = {
+       //{0x3C0, 0x3C0, 0x10, 0x0C},   // Mode Control (Blink Enabled)
+       {0x3C0, 0x3C0, 0x10, 0x04},     // Mode Control (Blink Disabled)
+       {0x3C0, 0x3C0, 0x11, 0x00},     // Overscan Register
+       {0x3C0, 0x3C0, 0x12, 0x0F},     // Color Plane Enable
+       {0x3C0, 0x3C0, 0x13, 0x08},     // Horizontal Panning
+       {0x3C0, 0x3C0, 0x14, 0x00},     // Color Select
+       {0    , 0x3C2, 0   , 0x67},     // Miscellaneous Output Register
+       {0x3C4, 0x3C5, 0x01, 0x00},     // Clock Mode Register
+       {0x3C4, 0x3C5, 0x03, 0x00},     // Character select
+       {0x3C4, 0x3C5, 0x04, 0x07},     // Memory Mode Register
+       {0x3CE, 0x3CF, 0x05, 0x10},     // Mode Register
+       {0x3CE, 0x3CF, 0x06, 0x0E},     // Miscellaneous Register
+       {0x3D4, 0x3D5, 0x00, 0x5F},     // Horizontal Total
+       {0x3D4, 0x3D5, 0x01, 0x4F},     // Horizontal Display Enable End
+       {0x3D4, 0x3D5, 0x02, 0x50},     // Horizontal Blank Start
+       {0x3D4, 0x3D5, 0x03, 0x82},     // Horizontal Blank End
+       {0x3D4, 0x3D5, 0x04, 0x55},     // Horizontal Retrace Start
+       {0x3D4, 0x3D5, 0x05, 0x81},     // Horizontal Retrace End
+       {0x3D4, 0x3D5, 0x06, 0xBF},     // Vertical Total
+       {0x3D4, 0x3D5, 0x07, 0x1F},     // Overflow Register
+       {0x3D4, 0x3D5, 0x08, 0x00},     // Preset row scan
+       {0x3D4, 0x3D5, 0x09, 0x4F},     // Maximum Scan Line
+       {0x3D4, 0x3D5, 0x10, 0x9C},     // Vertical Retrace Start
+       {0x3D4, 0x3D5, 0x11, 0x8E},     // Vertical Retrace End
+       {0x3D4, 0x3D5, 0x12, 0x8F},     // Vertical Display Enable End
+       {0x3D4, 0x3D5, 0x13, 0x28},     // Logical Width
+       {0x3D4, 0x3D5, 0x14, 0x1F},     // Underline Location
+       {0x3D4, 0x3D5, 0x15, 0x96},     // Vertical Blank Start
+       {0x3D4, 0x3D5, 0x16, 0xB9},     // Vertical Blank End
+       {0x3D4, 0x3D5, 0x17, 0xA3}      // CRTC Mode Control
+};
+#define        NUM_REGVALUES   (sizeof(caRegValues)/sizeof(caRegValues[0]))
+
+// === GLOBALS ===
+ int   giKP_Pos = 0;
+
+// === CODE ===
+/**
+ * \brief Sets the screen mode for a kernel panic
+ */
+void KernelPanic_SetMode(void)
+{
+        int    i;
+       
+       // This function is called by Panic(), but MM_PageFault and the
+       // CPU exception handers also call it, so let's not clear the screen
+       // twice
+       if( giKP_Pos )  return ;
+       
+       // Restore VGA 0xB8000 text mode
+       #if 1
+       for( i = 0; i < NUM_REGVALUES; i++ )
+       {
+               // Reset Flip-Flop
+               if( caRegValues[i].IdxPort == 0x3C0 )   inb(0x3DA);
+               
+               if( caRegValues[i].IdxPort )
+                       outb(caRegValues[i].IdxPort, caRegValues[i].Index);
+               outb(caRegValues[i].DatPort, caRegValues[i].Value);
+       }
+       
+       inb(0x3DA);
+       outb(0x3C0, 0x20);
+       #endif
+
+       #if USE_MP
+       // Send halt to all processors
+       for( i = 0; i < giNumCPUs; i ++ )
+       {
+               if(i == GetCPUNum())    continue ;
+               FB[i] = BGC|('A'+i);
+               MP_SendIPIVector(i, 0xED);
+       }
+       #endif
+       
+       // Clear Screen
+       for( i = 0; i < 80*25; i++ )
+       {
+               FB[i] = BGC;
+       }
+       
+       {
+               Uint32  eip = GetEIP();
+               Uint32  ebp;
+               __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (ebp));
+               Error_Backtrace(eip, ebp);
+       }
+}
+
+void KernelPanic_PutChar(char Ch)
+{
+       if( giKP_Pos > 80*25 )  return ;
+       switch(Ch)
+       {
+       case '\t':
+               do {
+                       FB[giKP_Pos] &= 0xFF00;
+                       FB[giKP_Pos++] |= ' ';
+               } while(giKP_Pos & 7);
+               break;
+       
+       case '\n':
+               giKP_Pos += 80;
+       case '\r':
+               giKP_Pos -= giKP_Pos % 80;
+               break;
+       
+       default:
+               if(' ' <= Ch && Ch < 0x7F)
+               {
+                       FB[giKP_Pos] &= 0xFF00;
+                       FB[giKP_Pos] |= Ch;
+               }
+               giKP_Pos ++;
+               break;
+       }
+}
diff --git a/KernelLand/Kernel/arch/x86/lib.c b/KernelLand/Kernel/arch/x86/lib.c
new file mode 100644 (file)
index 0000000..175f9a5
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Acess2
+ *
+ * arch/x86/lib.c
+ * - General arch-specific stuff
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <arch_int.h>
+#include <hal_proc.h>  // GetCPUNum
+
+#define TRACE_LOCKS    0
+
+#define DEBUG_TO_E9    1
+#define DEBUG_TO_SERIAL        1
+#define        SERIAL_PORT     0x3F8
+#define        GDB_SERIAL_PORT 0x2F8
+
+// === IMPRORTS ===
+#if TRACE_LOCKS
+extern struct sShortSpinlock   glDebug_Lock;
+extern tMutex  glPhysAlloc;
+#define TRACE_LOCK_COND        (Lock != &glDebug_Lock && Lock != &glThreadListLock && Lock != &glPhysAlloc.Protector)
+//#define TRACE_LOCK_COND      (Lock != &glDebug_Lock && Lock != &glPhysAlloc.Protector)
+#endif
+
+// === PROTOTYPES ==
+Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
+Uint64 __udivdi3(Uint64 Num, Uint64 Den);
+Uint64 __umoddi3(Uint64 Num, Uint64 Den);
+
+// === GLOBALS ===
+ int   gbDebug_SerialSetup = 0;
+ int   gbGDB_SerialSetup = 0;
+
+// === CODE ===
+/**
+ * \brief Determine if a short spinlock is locked
+ * \param Lock Lock pointer
+ */
+int IS_LOCKED(struct sShortSpinlock *Lock)
+{
+       return !!Lock->Lock;
+}
+
+/**
+ * \brief Check if the current CPU has the lock
+ * \param Lock Lock pointer
+ */
+int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
+{
+       return Lock->Lock == GetCPUNum() + 1;
+}
+
+void __AtomicTestSetLoop(Uint *Ptr, Uint Value)
+{
+       __ASM__(
+               "1:\n\t"
+               "xor %%eax, %%eax;\n\t"
+               "lock cmpxchgl %0, (%1);\n\t"
+               "jnz 1b;\n\t"
+               :: "r"(Value), "r"(Ptr)
+               : "eax" // EAX clobbered
+               );
+}
+/**
+ * \brief Acquire a Short Spinlock
+ * \param Lock Lock pointer
+ * 
+ * This type of mutex should only be used for very short sections of code,
+ * or in places where a Mutex_* would be overkill, such as appending
+ * an element to linked list (usually two assignement lines in C)
+ * 
+ * \note This type of lock halts interrupts, so ensure that no timing
+ * functions are called while it is held. As a matter of fact, spend as
+ * little time as possible with this lock held
+ * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
+ */
+void SHORTLOCK(struct sShortSpinlock *Lock)
+{
+        int    IF;
+        int    cpu = GetCPUNum() + 1;
+       
+       // Save interrupt state
+       __ASM__ ("pushf;\n\tpop %0" : "=r"(IF));
+       IF &= 0x200;    // AND out all but the interrupt flag
+       
+       #if TRACE_LOCKS
+       if( TRACE_LOCK_COND )
+       {
+               //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
+               Debug("%i %p obtaining %p (Called by %p)", cpu-1,  __builtin_return_address(0), Lock, __builtin_return_address(1));
+       }
+       #endif
+       
+       __ASM__("cli");
+       
+       // Wait for another CPU to release
+       __AtomicTestSetLoop( (Uint*)&Lock->Lock, cpu );
+       Lock->IF = IF;
+       
+       #if TRACE_LOCKS
+       if( TRACE_LOCK_COND )
+       {
+               //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
+               Debug("%i %p locked by %p\t%p", cpu-1, Lock, __builtin_return_address(0), __builtin_return_address(1));
+//             Debug("got it");
+       }
+       #endif
+}
+/**
+ * \brief Release a short lock
+ * \param Lock Lock pointer
+ */
+void SHORTREL(struct sShortSpinlock *Lock)
+{      
+       #if TRACE_LOCKS
+       if( TRACE_LOCK_COND )
+       {
+               //Log_Log("LOCK", "%p released by %p", Lock, __builtin_return_address(0));
+               Debug("Lock %p released by %p\t%p", Lock, __builtin_return_address(0), __builtin_return_address(1));
+       }
+       #endif
+       
+       // Lock->IF can change anytime once Lock->Lock is zeroed
+       if(Lock->IF) {
+               Lock->Lock = 0;
+               __ASM__ ("sti");
+       }
+       else {
+               Lock->Lock = 0;
+       }
+}
+
+// === DEBUG IO ===
+#if USE_GDB_STUB
+int putDebugChar(char ch)
+{
+       if(!gbGDB_SerialSetup) {
+               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
+               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
+               outb(GDB_SERIAL_PORT + 1, 0x00);    //  (base is         (hi byte)
+               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit (8N1)
+               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
+               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+               gbGDB_SerialSetup = 1;
+       }
+       while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
+       outb(GDB_SERIAL_PORT, ch);
+       return 0;
+}
+int getDebugChar(void)
+{
+       if(!gbGDB_SerialSetup) {
+               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
+               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
+               outb(GDB_SERIAL_PORT + 1, 0x00);    //                   (hi byte)
+               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
+               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
+               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+               gbGDB_SerialSetup = 1;
+       }
+       while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0)     ;
+       return inb(GDB_SERIAL_PORT);
+}
+#endif /* USE_GDB_STUB */
+
+void Debug_PutCharDebug(char ch)
+{
+       #if DEBUG_TO_E9
+       __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
+       #endif
+       
+       #if DEBUG_TO_SERIAL
+       if(!gbDebug_SerialSetup) {
+               outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
+               outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+               outb(SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
+               outb(SERIAL_PORT + 1, 0x00);    //                   (hi byte)
+               outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
+               outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
+               outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+               gbDebug_SerialSetup = 1;
+       }
+       while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
+       outb(SERIAL_PORT, ch);
+       #endif
+}
+
+void Debug_PutStringDebug(const char *String)
+{
+       while(*String)
+               Debug_PutCharDebug(*String++);
+}
+
+// === IO Commands ===
+void outb(Uint16 Port, Uint8 Data)
+{
+       __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
+}
+void outw(Uint16 Port, Uint16 Data)
+{
+       __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
+}
+void outd(Uint16 Port, Uint32 Data)
+{
+       __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
+}
+Uint8 inb(Uint16 Port)
+{
+       Uint8   ret;
+       __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
+       return ret;
+}
+Uint16 inw(Uint16 Port)
+{
+       Uint16  ret;
+       __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
+       return ret;
+}
+Uint32 ind(Uint16 Port)
+{
+       Uint32  ret;
+       __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
+       return ret;
+}
+
+/**
+ * \fn void *memset(void *Dest, int Val, size_t Num)
+ * \brief Do a byte granuality set of Dest
+ */
+void *memset(void *Dest, int Val, size_t Num)
+{
+       Uint32  val = Val&0xFF;
+       val |= val << 8;
+       val |= val << 16;
+       __asm__ __volatile__ (
+               "rep stosl;\n\t"
+               "mov %3, %%ecx;\n\t"
+               "rep stosb"
+               :: "D" (Dest), "a" (val), "c" (Num/4), "r" (Num&3));
+       return Dest;
+}
+/**
+ * \brief Set double words
+ */
+void *memsetd(void *Dest, Uint32 Val, size_t Num)
+{
+       __asm__ __volatile__ ("rep stosl" :: "D" (Dest), "a" (Val), "c" (Num));
+       return Dest;
+}
+
+/**
+ * \fn int memcmp(const void *m1, const void *m2, size_t Num)
+ * \brief Compare two pieces of memory
+ */
+int memcmp(const void *m1, const void *m2, size_t Num)
+{
+       const Uint8     *d1 = m1;
+       const Uint8     *d2 = m2;
+       if( Num == 0 )  return 0;       // No bytes are always identical
+       
+       while(Num--)
+       {
+               if(*d1 != *d2)
+                       return *d1 - *d2;
+               d1 ++;
+               d2 ++;
+       }
+       return 0;
+}
+
+/**
+ * \fn void *memcpy(void *Dest, const void *Src, size_t Num)
+ * \brief Copy \a Num bytes from \a Src to \a Dest
+ */
+void *memcpy(void *Dest, const void *Src, size_t Num)
+{
+       tVAddr  dst = (tVAddr)Dest;
+       tVAddr  src = (tVAddr)Src;
+       if( (dst & 3) != (src & 3) )
+       {
+               __asm__ __volatile__ ("rep movsb" :: "D" (dst), "S" (src), "c" (Num));
+//             Debug("\nmemcpy:Num=0x%x by %p (UA)", Num, __builtin_return_address(0));
+       }
+       #if 1
+       else if( Num > 128 && (dst & 15) == (src & 15) )
+       {
+               char    tmp[16+15];     // Note, this is a hack to save/restor xmm0
+                int    count = 16 - (dst & 15);
+//             Debug("\nmemcpy:Num=0x%x by %p (SSE)", Num, __builtin_return_address(0));
+               if( count < 16 )
+               {
+                       Num -= count;
+                       __asm__ __volatile__ ("rep movsb" : "=D"(dst),"=S"(src): "0"(dst), "1"(src), "c"(count));
+               }
+               
+               count = Num / 16;
+               __asm__ __volatile__ (
+                       "movdqa 0(%5), %%xmm0;\n\t"
+                       "1:\n\t"
+                       "movdqa 0(%1), %%xmm0;\n\t"
+                       "movdqa %%xmm0, 0(%0);\n\t"
+                       "add $16,%0;\n\t"
+                       "add $16,%1;\n\t"
+                       "loop 1b;\n\t"
+                       "movdqa %%xmm0, 0(%5);\n\t"
+                       : "=r"(dst),"=r"(src)
+                       : "0"(dst), "1"(src), "c"(count), "r" (((tVAddr)tmp+15)&~15)
+                       );
+
+               count = Num & 15;
+               if(count)
+                       __asm__ __volatile__ ("rep movsb" :: "D"(dst), "S"(src), "c"(count));
+       }
+       #endif
+       else
+       {
+//             Debug("\nmemcpy:Num=0x%x by %p", Num, __builtin_return_address(0));
+               __asm__ __volatile__ (
+                       "rep movsl;\n\t"
+                       "mov %3, %%ecx;\n\t"
+                       "rep movsb"
+                       :: "D" (Dest), "S" (Src), "c" (Num/4), "r" (Num&3));
+       }
+       return Dest;
+}
+
+/**
+ * \fn void *memcpyd(void *Dest, const void *Src, size_t Num)
+ * \brief Copy \a Num DWORDs from \a Src to \a Dest
+ */
+void *memcpyd(void *Dest, const void *Src, size_t Num)
+{
+       __asm__ __volatile__ ("rep movsl" :: "D" (Dest), "S" (Src), "c" (Num));
+       return Dest;
+}
+
+#include "../helpers.h"
+
+DEF_DIVMOD(64);
+
+Uint64 DivMod64U(Uint64 Num, Uint64 Div, Uint64 *Rem)
+{
+       if( Div < 0x100000000ULL && Num < 0xFFFFFFFF * Div ) {
+               Uint32  rem, ret_32;
+               __asm__ __volatile__(
+                       "div %4"
+                       : "=a" (ret_32), "=d" (rem)
+                       : "a" ( (Uint32)(Num & 0xFFFFFFFF) ), "d" ((Uint32)(Num >> 32)), "r" (Div)
+                       );
+               if(Rem) *Rem = rem;
+               return ret_32;
+       }
+
+       return __divmod64(Num, Div, Rem);
+}
+
+/**
+ * \fn Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+ * \brief Divide two 64-bit integers
+ */
+Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+{
+       if(Den == 0) {
+               __asm__ __volatile__ ("int $0x0");
+               return -1;
+       }
+       // Common speedups
+       if(Num <= 0xFFFFFFFF && Den <= 0xFFFFFFFF)
+               return (Uint32)Num / (Uint32)Den;
+       if(Den == 1)    return Num;
+       if(Den == 2)    return Num >> 1;        // Speed Hacks
+       if(Den == 4)    return Num >> 2;        // Speed Hacks
+       if(Den == 8)    return Num >> 3;        // Speed Hacks
+       if(Den == 16)   return Num >> 4;        // Speed Hacks
+       if(Den == 32)   return Num >> 5;        // Speed Hacks
+       if(Den == 1024) return Num >> 10;       // Speed Hacks
+       if(Den == 2048) return Num >> 11;       // Speed Hacks
+       if(Den == 4096) return Num >> 12;
+       if(Num < Den)   return 0;
+       if(Num < Den*2) return 1;
+       if(Num == Den*2)        return 2;
+
+       return __divmod64(Num, Den, NULL);
+}
+
+/**
+ * \fn Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+ * \brief Get the modulus of two 64-bit integers
+ */
+Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+{
+       Uint64  ret = 0;
+       if(Den == 0) {
+               __asm__ __volatile__ ("int $0x0");      // Call Div by Zero Error
+               return -1;
+       }
+       if(Den == 1)    return 0;       // Speed Hacks
+       if(Den == 2)    return Num & 1; // Speed Hacks
+       if(Den == 4)    return Num & 3; // Speed Hacks
+       if(Den == 8)    return Num & 7; // Speed Hacks
+       if(Den == 16)   return Num & 15;        // Speed Hacks
+       if(Den == 32)   return Num & 31;        // Speed Hacks
+       if(Den == 1024) return Num & 1023;      // Speed Hacks
+       if(Den == 2048) return Num & 2047;      // Speed Hacks
+       if(Den == 4096) return Num & 4095;      // Speed Hacks
+       
+       if(Num >> 32 == 0 && Den >> 32 == 0)
+               return (Uint32)Num % (Uint32)Den;
+       
+       __divmod64(Num, Den, &ret);
+       return ret;
+}
+
+
+// --- EXPORTS ---
+EXPORT(memcpy);        EXPORT(memset);
+EXPORT(memcmp);
+//EXPORT(memcpyw);     EXPORT(memsetw);
+EXPORT(memcpyd);       EXPORT(memsetd);
+EXPORT(inb);   EXPORT(inw);    EXPORT(ind);
+EXPORT(outb);  EXPORT(outw);   EXPORT(outd);
+EXPORT(__udivdi3);     EXPORT(__umoddi3);
+
+EXPORT(SHORTLOCK);
+EXPORT(SHORTREL);
+EXPORT(IS_LOCKED);
diff --git a/KernelLand/Kernel/arch/x86/link.ld b/KernelLand/Kernel/arch/x86/link.ld
new file mode 100644 (file)
index 0000000..a09b29a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * AcessMicro Kernel
+ * Linker Script
+ */
+
+lowStart = start - 0xC0000000;
+ENTRY(lowStart)
+OUTPUT_FORMAT(elf32-i386)
+
+SECTIONS {
+       . = 0x100000;
+       __load_addr = .;
+       .multiboot : AT(ADDR(.multiboot)) {
+               *(.multiboot)
+       }
+       
+       . += 0xC0000000;
+       
+       .text ALIGN(0x1000): AT(ADDR(.text) - 0xC0000000) {
+               *(.text)
+       }
+       
+       .usertext ALIGN(0x1000): AT(ADDR(.usertext) - 0xC0000000) {
+               _UsertextBase = .;
+               *(.usertext)
+       }
+       _UsertextEnd = .;
+       
+       .rodata ALIGN(0x1000): AT(ADDR(.rodata) - 0xC0000000) {
+               *(.initpd)
+               *(.rodata)
+               *(.rdata)
+               gKernelModules = .;
+               *(KMODULES)
+               gKernelModulesEnd = .;
+               . = ALIGN(4);
+               gKernelSymbols = .;
+               *(KEXPORT)
+               gKernelSymbolsEnd = .;
+
+
+       }
+       /*
+       .debug_abbrev : { *(.debug_abbrev) }
+       .debug_info : { *(.debug_info) }
+       .debug_line : { *(.debug_line) }
+       .debug_loc : { *(.debug_loc) }
+       .debug_pubnames : { *(.debug_pubnames) }
+       .debug_aranges : { *(.debug_aranges) }
+       .debug_ranges : { *(.debug_ranges) }
+       .debug_str : { *(.debug_str) }
+       .debug_frame : { *(.debug_frame) }
+       */
+       
+       .padata ALIGN (0x1000) : AT(ADDR(.padata) - 0xC0000000) {
+               *(.padata)
+       }
+       
+       .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
+               *(.data)
+       }
+
+       __bss_start = .;
+       .bss : AT(ADDR(.bss) - 0xC0000000) {
+               _sbss = .;
+               *(COMMON)
+               *(.bss)
+               _ebss = .;
+       }
+       gKernelEnd = (. + 0xFFF)&0xFFFFF000;
+}
diff --git a/KernelLand/Kernel/arch/x86/main.c b/KernelLand/Kernel/arch/x86/main.c
new file mode 100644 (file)
index 0000000..2106b6a
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Acess 2
+ * x86 Kernel Main
+ * arch/x86/main.c
+ */
+#include <acess.h>
+#include <mboot.h>
+#include <multiboot2.h>
+#include <init.h>
+#include <mm_virt.h>
+#include <mp.h>
+
+#define        VGA_ERRORS      0
+
+#define MAX_ARGSTR_POS (0x400000-0x2000)
+
+// === IMPORTS ===
+extern void    Heap_Install(void);
+extern void    Desctab_Install(void);
+extern void    MM_PreinitVirtual(void);
+extern void    MM_Install(tMBoot_Info *MBoot);
+extern void    MM_InstallVirtual(void);
+extern void    Threads_Init(void);
+extern int     Time_Setup(void);
+// --- Core ---
+extern void    System_Init(char *Commandline);
+
+// === PROTOTYPES ===
+ int   kmain(Uint MbMagic, void *MbInfoPtr);
+
+// === GLOBALS ===
+char   *gsBootCmdLine = NULL;
+struct {
+       Uint32  PBase;
+       void    *Base;
+       Uint    Size;
+       char    *ArgString;
+}      *gaArch_BootModules;
+ int   giArch_NumBootModules = 0;
+
+// === CODE ===
+int kmain(Uint MbMagic, void *MbInfoPtr)
+{
+        int    i;
+       tMBoot_Module   *mods;
+       tMBoot_Info     *mbInfo;
+
+       LogF("Acess2 x86-"PLATFORM" v"EXPAND_STR(KERNEL_VERSION)"\n");
+       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+       
+       Log("MbMagic = %08x, MbInfoPtr = %p", MbMagic, MbInfoPtr);
+       
+       // Set up non-boot info dependent stuff
+       Desctab_Install();      // Set up GDT and IDT
+       MM_PreinitVirtual();    // Initialise virtual mappings
+       
+       switch(MbMagic)
+       {
+       // Multiboot 1
+       case MULTIBOOT_MAGIC:
+               // Adjust Multiboot structure address
+               mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
+               gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE);
+               
+               MM_Install( mbInfo );   // Set up physical memory manager
+               break;
+       
+       // Multiboot 2
+       case MULTIBOOT2_MAGIC:
+               Panic("Multiboot 2 not yet supported");
+               //MM_InstallMBoot2( MbInfo );   // Set up physical memory manager
+               return 0;
+               break;
+       
+       default:
+               Panic("Multiboot magic invalid %08x, expected %08x or %08x\n",
+                       MbMagic, MULTIBOOT_MAGIC, MULTIBOOT2_MAGIC);
+               return 0;
+       }
+       
+       MM_InstallVirtual();    // Clean up virtual address space
+       Heap_Install();         // Create initial heap
+       
+       // Start Multitasking
+       Threads_Init();
+       
+       // Start Timers
+       Time_Setup();
+       
+       Log_Log("Arch", "Starting VFS...");
+       // Load Virtual Filesystem
+       VFS_Init();
+       
+       // Load initial modules
+       mods = (void*)( mbInfo->Modules + KERNEL_BASE );
+       giArch_NumBootModules = mbInfo->ModuleCount;
+       gaArch_BootModules = malloc( giArch_NumBootModules * sizeof(*gaArch_BootModules) );
+       for( i = 0; i < mbInfo->ModuleCount; i ++ )
+       {
+                int    ofs;
+       
+               Log_Log("Arch", "Multiboot Module at 0x%08x, 0x%08x bytes (String at 0x%08x)",
+                       mods[i].Start, mods[i].End-mods[i].Start, mods[i].String);
+       
+               gaArch_BootModules[i].PBase = mods[i].Start;
+               gaArch_BootModules[i].Size = mods[i].End - mods[i].Start;
+       
+               // Always HW map the module data        
+               ofs = mods[i].Start&0xFFF;
+               gaArch_BootModules[i].Base = (void*)( MM_MapHWPages(mods[i].Start,
+                       (gaArch_BootModules[i].Size+ofs+0xFFF) / 0x1000
+                       ) + ofs );
+               
+               // Only map the string if needed
+               if( (tVAddr)mods[i].String > MAX_ARGSTR_POS )
+               {
+                       // Assumes the string is < 4096 bytes long)
+                       gaArch_BootModules[i].ArgString = (void*)(
+                               MM_MapHWPages(mods[i].String, 2) + (mods[i].String&0xFFF)
+                               );
+               }
+               else
+                       gaArch_BootModules[i].ArgString = (char *)mods[i].String + KERNEL_BASE;
+       }
+       
+       // Pass on to Independent Loader
+       Log_Log("Arch", "Starting system");
+       System_Init(gsBootCmdLine);
+       
+       // Sleep forever (sleeping beauty)
+       for(;;)
+               Threads_Sleep();
+       return 0;
+}
+
+void Arch_LoadBootModules(void)
+{
+        int    i, j, numPages;
+       for( i = 0; i < giArch_NumBootModules; i ++ )
+       {
+               Log_Log("Arch", "Loading '%s'", gaArch_BootModules[i].ArgString);
+               
+               if( !Module_LoadMem( gaArch_BootModules[i].Base, gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString ) )
+               {
+                       Log_Warning("Arch", "Unable to load module");
+               }
+               
+               // Unmap and free
+               numPages = (gaArch_BootModules[i].Size + ((Uint)gaArch_BootModules[i].Base&0xFFF) + 0xFFF) >> 12;
+               MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].Base, numPages );
+               
+               for( j = 0; j < numPages; j++ )
+                       MM_DerefPhys( gaArch_BootModules[i].PBase + (j << 12) );
+               
+               if( (tVAddr) gaArch_BootModules[i].ArgString > MAX_ARGSTR_POS )
+                       MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].ArgString, 2 );
+       }
+       Log_Log("Arch", "Boot modules loaded");
+       free( gaArch_BootModules );
+}
diff --git a/KernelLand/Kernel/arch/x86/mm_phys.c b/KernelLand/Kernel/arch/x86/mm_phys.c
new file mode 100644 (file)
index 0000000..aa1b260
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Acess2
+ * - Physical memory manager
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <mboot.h>
+#include <mm_virt.h>
+
+//#define USE_STACK    1
+#define TRACE_ALLOCS   0       // Print trace messages on AllocPhys/DerefPhys
+
+
+// === IMPORTS ===
+extern char    gKernelEnd[];
+extern void    Proc_PrintBacktrace(void);
+
+// === PROTOTYPES ===
+void   MM_Install(tMBoot_Info *MBoot);
+//tPAddr       MM_AllocPhys(void);
+//tPAddr       MM_AllocPhysRange(int Pages, int MaxBits);
+//void MM_RefPhys(tPAddr PAddr);
+//void MM_DerefPhys(tPAddr PAddr);
+// int MM_GetRefCount(tPAddr PAddr);
+
+// === GLOBALS ===
+tMutex glPhysAlloc;
+Uint64 giPhysAlloc = 0;        // Number of allocated pages
+Uint64 giPageCount = 0;        // Total number of pages
+Uint64 giLastPossibleFree = 0; // Last possible free page (before all pages are used)
+
+Uint32 gaSuperBitmap[1024];    // Blocks of 1024 Pages
+Uint32 gaPageBitmap[1024*1024/32];     // Individual pages
+ int   *gaPageReferences;
+void   **gaPageNodes = (void*)MM_PAGENODE_BASE;
+#define REFENT_PER_PAGE        (0x1000/sizeof(gaPageReferences[0]))
+
+// === CODE ===
+void MM_Install(tMBoot_Info *MBoot)
+{
+       Uint    kernelPages, num;
+       Uint    i;
+       Uint64  maxAddr = 0;
+       tMBoot_Module   *mods;
+       tMBoot_MMapEnt  *ent;
+       
+       // --- Find largest address
+       MBoot->MMapAddr |= KERNEL_BASE;
+       ent = (void *)( MBoot->MMapAddr );
+       while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
+       {
+               // Adjust for size
+               ent->Size += 4;
+               
+               // If entry is RAM and is above `maxAddr`, change `maxAddr`
+               if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
+                       maxAddr = ent->Base + ent->Length;
+               // Go to next entry
+               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+       }
+       
+       if(maxAddr == 0) {      
+               giPageCount = (MBoot->HighMem >> 2) + 256;      // HighMem is a kByte value
+       }
+       else {
+               giPageCount = maxAddr >> 12;
+       }
+       giLastPossibleFree = giPageCount - 1;
+       
+       memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
+       
+       // Set up allocateable space
+       ent = (void *)( MBoot->MMapAddr );
+       while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
+       {               
+               memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) );
+               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+       }
+       
+       // Get used page count (Kernel)
+       kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
+       kernelPages += 0xFFF;   // Page Align
+       kernelPages >>= 12;
+       
+       // Fill page bitmap
+       num = kernelPages/32;
+       memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num );
+       gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1;
+       
+       // Fill Superpage bitmap
+       num = kernelPages/(32*32);
+       memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num );
+       gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1;
+       
+       // Mark Multiboot's pages as taken
+       // - Structure
+       MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
+       // - Module List
+       for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
+               MM_RefPhys( MBoot->Modules + (i << 12) );
+       // - Modules
+       mods = (void*)(MBoot->Modules + KERNEL_BASE);
+       for(i = 0; i < MBoot->ModuleCount; i++)
+       {
+               num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
+               while(num--)
+                       MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
+       }
+
+       gaPageReferences = (void*)MM_REFCOUNT_BASE;
+
+       Log_Log("PMem", "Physical memory set up");
+}
+
+/**
+ * \fn tPAddr MM_AllocPhys(void)
+ * \brief Allocates a physical page from the general pool
+ */
+tPAddr MM_AllocPhys(void)
+{
+       // int  a, b, c;
+        int    indx = -1;
+       tPAddr  ret;
+       
+       ENTER("");
+       
+       Mutex_Acquire( &glPhysAlloc );
+       
+       // Classful scan
+       #if 1
+       {
+       const int addrClasses[] = {0,16,20,24,32,64};
+       const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
+        int    i;
+        int    first, last;
+       for( i = numAddrClasses; i -- > 1; )
+       {
+               first = 1UL << (addrClasses[i-1] - 12);
+               last = (1UL << (addrClasses[i] - 12)) - 1;
+               // Range is above the last free page
+               if( first > giLastPossibleFree )
+                       continue;
+               // Last possible free page is in the range
+               if( last > giLastPossibleFree )
+                       last = giLastPossibleFree;
+                       
+               // Scan the range
+               for( indx = first; indx < last; )
+               {
+                       if( gaSuperBitmap[indx>>10] == -1 ) {
+                               indx += 1024;
+                               continue;
+                       }
+                       
+                       if( gaPageBitmap[indx>>5] == -1 ) {
+                               indx += 32;
+                               continue;
+                       }
+                       
+                       if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
+                               indx ++;
+                               continue;
+                       }
+                       break;
+               }
+               if( indx < last )       break;
+               
+               giLastPossibleFree = first;     // Well, we couldn't find any in this range
+       }
+       // Out of memory?
+       if( i <= 1 )    indx = -1;
+       }
+       #elif 0
+       // Find free page
+       // Scan downwards
+       LOG("giLastPossibleFree = %i", giLastPossibleFree);
+       for( indx = giLastPossibleFree; indx >= 0; )
+       {
+               if( gaSuperBitmap[indx>>10] == -1 ) {
+                       indx -= 1024;
+                       continue;
+               }
+               
+               if( gaPageBitmap[indx>>5] == -1 ) {
+                       indx -= 32;
+                       continue;
+               }
+               
+               if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
+                       indx --;
+                       continue;
+               }
+               break;
+       }
+       if( indx >= 0 )
+               giLastPossibleFree = indx;
+       LOG("indx = %i", indx);
+       #else
+       c = giLastPossibleFree % 32;
+       b = (giLastPossibleFree / 32) % 32;
+       a = giLastPossibleFree / 1024;
+       
+       LOG("a=%i,b=%i,c=%i", a, b, c);
+       for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
+       if(a < 0) {
+               Mutex_Release( &glPhysAlloc );
+               Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used",
+                       __builtin_return_address(0), giPhysAlloc, giPageCount);
+               LEAVE('i', 0);
+               return 0;
+       }
+       for( ; gaSuperBitmap[a] & (1<<b); b-- );
+       for( ; gaPageBitmap[a*32+b] & (1<<c); c-- );
+       LOG("a=%i,b=%i,c=%i", a, b, c);
+       indx = (a << 10) | (b << 5) | c;
+       if( indx >= 0 )
+               giLastPossibleFree = indx;
+       #endif
+       
+       if( indx < 0 ) {
+               Mutex_Release( &glPhysAlloc );
+               Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used (indx = %x)",
+                       __builtin_return_address(0), giPhysAlloc, giPageCount, indx);
+               Log_Debug("PMem", "giLastPossibleFree = %lli", giLastPossibleFree);
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       if( indx > 0xFFFFF ) {
+               Panic("The fuck? Too many pages! (indx = 0x%x)", indx);
+       }
+       
+       if( indx >= giPageCount ) {
+               Mutex_Release( &glPhysAlloc );
+               Log_Error("PMem", "MM_AllocPhys - indx(%i) > giPageCount(%i)", indx, giPageCount);
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Mark page used
+       if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
+               gaPageReferences[indx] = 1;
+       gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
+       
+       giPhysAlloc ++;
+       
+       // Get address
+       ret = indx << 12;
+       
+       // Mark used block
+       if(gaPageBitmap[ indx>>5 ] == -1) {
+               gaSuperBitmap[indx>>10] |= 1 << ((indx>>5)&31);
+       }
+
+       // Release Spinlock
+       Mutex_Release( &glPhysAlloc );
+       
+       LEAVE('X', ret);
+       #if TRACE_ALLOCS
+       if( now() > 4000 ) {
+       Log_Debug("PMem", "MM_AllocPhys: RETURN %P (%i free)", ret, giPageCount-giPhysAlloc);
+       Proc_PrintBacktrace();
+       }
+       #endif
+       return ret;
+}
+
+/**
+ * \fn tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
+ * \brief Allocate a range of physical pages
+ * \param Pages        Number of pages to allocate
+ * \param MaxBits      Maximum number of address bits to use
+ */
+tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
+{
+        int    a, b;
+        int    i, idx, sidx;
+       tPAddr  ret;
+       
+       ENTER("iPages iMaxBits", Pages, MaxBits);
+       
+       // Sanity Checks
+       if(MaxBits < 0) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       if(MaxBits > PHYS_BITS) MaxBits = PHYS_BITS;
+       
+       // Lock
+       Mutex_Acquire( &glPhysAlloc );
+       
+       // Set up search state
+       if( giLastPossibleFree > ((tPAddr)1 << (MaxBits-12)) ) {
+               sidx = (tPAddr)1 << (MaxBits-12);
+       }
+       else {
+               sidx = giLastPossibleFree;
+       }
+       idx = sidx / 32;
+       sidx %= 32;
+       b = idx % 32;
+       a = idx / 32;
+       
+       #if 0
+       LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
+       
+       // Find free page
+       for( ; gaSuperBitmap[a] == -1 && a --; )        b = 31;
+       if(a < 0) {
+               Mutex_Release( &glPhysAlloc );
+               Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
+               LEAVE('i', 0);
+               return 0;
+       }
+       LOG("a = %i", a);
+       for( ; gaSuperBitmap[a] & (1 << b); b-- )       sidx = 31;
+       LOG("b = %i", b);
+       idx = a * 32 + b;
+       for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
+               LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
+       
+       LOG("idx = %i, sidx = %i", idx, sidx);
+       #else
+       
+       #endif
+       
+       // Check if the gap is large enough
+       while( idx >= 0 )
+       {
+               // Find a free page
+               for( ; ; )
+               {
+                       // Bulk Skip
+                       if( gaPageBitmap[idx] == -1 ) {
+                               idx --;
+                               sidx = 31;
+                               continue;
+                       }
+                       
+                       if( gaPageBitmap[idx] & (1 << sidx) ) {
+                               sidx --;
+                               if(sidx < 0) {  sidx = 31;      idx --; }
+                               if(idx < 0)     break;
+                               continue;
+                       }
+                       break;
+               }
+               if( idx < 0 )   break;
+               
+               // Check if it is a free range
+               for( i = 0; i < Pages; i++ )
+               {
+                       // Used page? break
+                       if( gaPageBitmap[idx] & (1 << sidx) )
+                               break;
+                       
+                       sidx --;
+                       if(sidx < 0) {  sidx = 31;      idx --; }
+                       if(idx < 0)     break;
+               }
+               
+               if( i == Pages )
+                       break;
+       }
+       
+       // Check if an address was found
+       if( idx < 0 ) {
+               Mutex_Release( &glPhysAlloc );
+               Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Mark pages used
+       for( i = 0; i < Pages; i++ )
+       {
+               if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[idx*32+sidx] ) )
+                       gaPageReferences[idx*32+sidx] = 1;
+               gaPageBitmap[ idx ] |= 1 << sidx;
+               sidx ++;
+               giPhysAlloc ++;
+               if(sidx == 32) { sidx = 0;      idx ++; }
+       }
+       
+       // Get address
+       ret = (idx << 17) | (sidx << 12);
+       
+       // Mark used block
+       if(gaPageBitmap[ idx ] == -1)   gaSuperBitmap[idx/32] |= 1 << (idx%32);
+
+       // Release Spinlock
+       Mutex_Release( &glPhysAlloc );
+       
+       LEAVE('X', ret);
+       #if TRACE_ALLOCS
+       Log_Debug("PMem", "MM_AllocPhysRange: RETURN 0x%llx-0x%llx (%i free)",
+               ret, ret + (1<<Pages)-1, giPageCount-giPhysAlloc);
+       #endif
+       return ret;
+}
+
+/**
+ * \fn void MM_RefPhys(tPAddr PAddr)
+ */
+void MM_RefPhys(tPAddr PAddr)
+{
+       // Get page number
+       PAddr >>= 12;
+
+       // We don't care about non-ram pages
+       if(PAddr >= giPageCount)        return;
+       
+       // Lock Structures
+       Mutex_Acquire( &glPhysAlloc );
+       
+       // Reference the page
+       if( gaPageReferences )
+       {
+               if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+               {
+                        int    i, base;
+                       tVAddr  addr = ((tVAddr)&gaPageReferences[PAddr]) & ~0xFFF;
+//                     Log_Debug("PMem", "MM_RefPhys: Allocating info for %X", PAddr);
+                       Mutex_Release( &glPhysAlloc );
+                       if( MM_Allocate( addr ) == 0 ) {
+                               Log_KernelPanic("PMem", "MM_RefPhys: Out of physical memory allocating info for %X", PAddr*PAGE_SIZE);
+                       }
+                       Mutex_Acquire( &glPhysAlloc );
+                       
+                       base = PAddr & ~(1024-1);
+                       for( i = 0; i < 1024; i ++ ) {
+                               gaPageReferences[base + i] = (gaPageBitmap[(base+i)/32] & (1 << (base+i)%32)) ? 1 : 0;
+                       }
+               }
+               gaPageReferences[ PAddr ] ++;
+       }
+       
+       // Mark as used
+       gaPageBitmap[ PAddr / 32 ] |= 1 << (PAddr&31);
+       
+       // Mark used block
+       if(gaPageBitmap[ PAddr / 32 ] == -1)
+               gaSuperBitmap[PAddr/1024] |= 1 << ((PAddr/32)&31);
+       
+       // Release Spinlock
+       Mutex_Release( &glPhysAlloc );
+}
+
+/**
+ * \fn void MM_DerefPhys(tPAddr PAddr)
+ * \brief Dereferences a physical page
+ */
+void MM_DerefPhys(tPAddr PAddr)
+{
+       // Get page number
+       PAddr >>= 12;
+
+       // We don't care about non-ram pages
+       if(PAddr >= giPageCount)        return;
+       
+       // Check if it is freed
+       if( !(gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ) {
+               Log_Warning("MMVirt", "MM_DerefPhys - Non-referenced memory dereferenced");
+               return;
+       }
+       
+       // Lock Structures
+       Mutex_Acquire( &glPhysAlloc );
+       
+       if( giLastPossibleFree < PAddr )
+               giLastPossibleFree = PAddr;
+
+       // Dereference
+       if( !MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
+       {
+               #if TRACE_ALLOCS
+               Log_Debug("PMem", "MM_DerefPhys: Free'd %P (%i free)", PAddr<<12, giPageCount-giPhysAlloc);
+               Proc_PrintBacktrace();
+               #endif
+               //LOG("Freed 0x%x by %p\n", PAddr<<12, __builtin_return_address(0));
+               giPhysAlloc --;
+               gaPageBitmap[ PAddr / 32 ] &= ~(1 << (PAddr&31));
+               if(gaPageBitmap[ PAddr / 32 ] == 0)
+                       gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
+
+               if( MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) )
+               {
+                       gaPageNodes[PAddr] = NULL;
+                       // TODO: Free Node Page when fully unused
+               }
+       }
+
+       // Release spinlock
+       Mutex_Release( &glPhysAlloc );
+}
+
+/**
+ * \fn int MM_GetRefCount(tPAddr Addr)
+ */
+int MM_GetRefCount(tPAddr PAddr)
+{
+       // Get page number
+       PAddr >>= 12;
+       
+       // We don't care about non-ram pages
+       if(PAddr >= giPageCount)        return -1;
+
+       if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+               return (gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ? 1 : 0;
+       
+       // Check if it is freed
+       return gaPageReferences[ PAddr ];
+}
+
+int MM_SetPageNode(tPAddr PAddr, void *Node)
+{
+       tVAddr  block_addr;
+       
+       if( MM_GetRefCount(PAddr) == 0 )        return 1;
+        
+       PAddr /= PAGE_SIZE;
+
+       block_addr = (tVAddr) &gaPageNodes[PAddr];
+       block_addr &= ~(PAGE_SIZE-1);
+       
+       if( !MM_GetPhysAddr( block_addr ) )
+       {
+               if( !MM_Allocate( block_addr ) ) {
+                       Log_Warning("PMem", "Unable to allocate Node page");
+                       return -1;
+               }
+               memset( (void*)block_addr, 0, PAGE_SIZE );
+       }
+
+       gaPageNodes[PAddr] = Node;
+//     Log("gaPageNodes[0x%x] = %p", PAddr, Node);
+       return 0;
+}
+
+int MM_GetPageNode(tPAddr PAddr, void **Node)
+{
+       if( MM_GetRefCount(PAddr) == 0 )        return 1;
+       
+       PAddr /= PAGE_SIZE;
+       if( !MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) ) {
+               *Node = NULL;
+               return 0;
+       }
+       *Node = gaPageNodes[PAddr];
+       return 0;
+}
+
diff --git a/KernelLand/Kernel/arch/x86/mm_virt.c b/KernelLand/Kernel/arch/x86/mm_virt.c
new file mode 100644 (file)
index 0000000..bd7b1df
--- /dev/null
@@ -0,0 +1,1151 @@
+/*
+ * AcessOS Microkernel Version
+ * mm_virt.c
+ * 
+ * Memory Map
+ * 0xE0 - Kernel Base
+ * 0xF0 - Kernel Stacks
+ * 0xFD - Fractals
+ * 0xFE - Unused
+ * 0xFF - System Calls / Kernel's User Code
+ */
+#define DEBUG  0
+#define SANITY 1
+#include <acess.h>
+#include <mm_virt.h>
+#include <mm_phys.h>
+#include <proc.h>
+#include <hal_proc.h>
+#include <arch_int.h>
+
+#define TAB    22
+
+#define WORKER_STACKS          0x00100000      // Thread0 Only!
+#define        WORKER_STACK_SIZE       MM_KERNEL_STACK_SIZE
+#define WORKER_STACKS_END      0xB0000000
+#define        NUM_WORKER_STACKS       ((WORKER_STACKS_END-WORKER_STACKS)/WORKER_STACK_SIZE)
+
+#define PAE_PAGE_TABLE_ADDR    0xFC000000      // 16 MiB
+#define PAE_PAGE_DIR_ADDR      0xFCFC0000      // 16 KiB
+#define PAE_PAGE_PDPT_ADDR     0xFCFC3F00      // 32 bytes
+#define PAE_TMP_PDPT_ADDR      0xFCFC3F20      // 32 bytes
+#define PAE_TMP_DIR_ADDR       0xFCFE0000      // 16 KiB
+#define PAE_TMP_TABLE_ADDR     0xFD000000      // 16 MiB
+
+#define PAGE_TABLE_ADDR        0xFC000000
+#define PAGE_DIR_ADDR  0xFC3F0000
+#define PAGE_CR3_ADDR  0xFC3F0FC0
+#define TMP_CR3_ADDR   0xFC3F0FC4      // Part of core instead of temp
+#define TMP_DIR_ADDR   0xFC3F1000      // Same
+#define TMP_TABLE_ADDR 0xFC400000
+
+#define HW_MAP_ADDR            0xFE000000
+#define        HW_MAP_MAX              0xFFEF0000
+#define        NUM_HW_PAGES    ((HW_MAP_MAX-HW_MAP_ADDR)/0x1000)
+#define        TEMP_MAP_ADDR   0xFFEF0000      // Allows 16 "temp" pages
+#define        NUM_TEMP_PAGES  16
+#define LAST_BLOCK_ADDR        0xFFFF0000      // Free space for kernel provided user code/ *(-1) protection
+
+#define        PF_PRESENT      0x1
+#define        PF_WRITE        0x2
+#define        PF_USER         0x4
+#define PF_GLOBAL      0x80
+#define        PF_COW          0x200
+#define        PF_NOPAGE       0x400
+
+#define INVLPG(addr)   __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
+
+#define GET_TEMP_MAPPING(cr3) do { \
+       __ASM__("cli"); \
+       __AtomicTestSetLoop( (Uint *)gpTmpCR3, cr3 | 3 ); \
+} while(0)
+#define REL_TEMP_MAPPING() do { \
+       *gpTmpCR3 = 0; \
+       __ASM__("sti"); \
+} while(0)
+
+typedef Uint32 tTabEnt;
+
+// === IMPORTS ===
+extern char    _UsertextEnd[], _UsertextBase[];
+extern Uint32  gaInitPageDir[1024];
+extern Uint32  gaInitPageTable[1024];
+extern void    Threads_SegFault(tVAddr Addr);
+extern void    Error_Backtrace(Uint eip, Uint ebp);
+
+// === PROTOTYPES ===
+void   MM_PreinitVirtual(void);
+void   MM_InstallVirtual(void);
+void   MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
+//void MM_DumpTables(tVAddr Start, tVAddr End);
+//void MM_ClearUser(void);
+tPAddr MM_DuplicatePage(tVAddr VAddr);
+
+// === GLOBALS ===
+#define gaPageTable    ((tTabEnt*)PAGE_TABLE_ADDR)
+#define gaPageDir      ((tTabEnt*)PAGE_DIR_ADDR)
+#define gaTmpTable     ((tTabEnt*)TMP_TABLE_ADDR)
+#define gaTmpDir       ((tTabEnt*)TMP_DIR_ADDR)
+#define gpPageCR3      ((tTabEnt*)PAGE_CR3_ADDR)
+#define gpTmpCR3       ((tTabEnt*)TMP_CR3_ADDR)
+
+#define gaPAE_PageTable        ((tTabEnt*)PAE_PAGE_TABLE_ADDR)
+#define gaPAE_PageDir  ((tTabEnt*)PAE_PAGE_DIR_ADDR)
+#define gaPAE_MainPDPT ((tTabEnt*)PAE_PAGE_PDPT_ADDR)
+#define gaPAE_TmpTable ((tTabEnt*)PAE_TMP_DIR_ADDR)
+#define gaPAE_TmpDir   ((tTabEnt*)PAE_TMP_DIR_ADDR)
+#define gaPAE_TmpPDPT  ((tTabEnt*)PAE_TMP_PDPT_ADDR)
+ int   gbUsePAE = 0;
+tMutex glTempMappings;
+tMutex glTempFractal;
+Uint32 gWorkerStacks[(NUM_WORKER_STACKS+31)/32];
+ int   giLastUsedWorker = 0;
+struct sPageInfo {
+       void    *Node;
+       tVAddr  Base;
+       Uint64  Offset;
+        int    Length;
+        int    Flags;
+}      *gaMappedRegions;       // sizeof = 24 bytes
+
+// === CODE ===
+/**
+ * \fn void MM_PreinitVirtual(void)
+ * \brief Maps the fractal mappings
+ */
+void MM_PreinitVirtual(void)
+{
+       gaInitPageDir[ PAGE_TABLE_ADDR >> 22 ] = ((tTabEnt)&gaInitPageDir - KERNEL_BASE) | 3;
+       INVLPG( PAGE_TABLE_ADDR );
+}
+
+/**
+ * \fn void MM_InstallVirtual(void)
+ * \brief Sets up the constant page mappings
+ */
+void MM_InstallVirtual(void)
+{
+        int    i;
+       
+       // --- Pre-Allocate kernel tables
+       for( i = KERNEL_BASE>>22; i < 1024; i ++ )
+       {
+               if( gaPageDir[ i ] )    continue;
+               // Skip stack tables, they are process unique
+               if( i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) {
+                       gaPageDir[ i ] = 0;
+                       continue;
+               }
+               // Preallocate table
+               gaPageDir[ i ] = MM_AllocPhys() | 3;
+               INVLPG( &gaPageTable[i*1024] );
+               memset( &gaPageTable[i*1024], 0, 0x1000 );
+       }
+       
+       // Unset kernel on the User Text pages
+       for( i = ((tVAddr)&_UsertextEnd-(tVAddr)&_UsertextBase+0xFFF)/4096; i--; ) {
+               MM_SetFlags( (tVAddr)&_UsertextBase + i*4096, 0, MM_PFLAG_KERNEL );
+       }
+       
+       *gpTmpCR3 = 0;
+}
+
+/**
+ * \brief Cleans up the SMP required mappings
+ */
+void MM_FinishVirtualInit(void)
+{
+       gaInitPageDir[ 0 ] = 0;
+}
+
+/**
+ * \fn void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
+ * \brief Called on a page fault
+ */
+void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
+{
+       //ENTER("xAddr bErrorCode", Addr, ErrorCode);
+       
+       // -- Check for COW --
+       if( gaPageDir  [Addr>>22] & PF_PRESENT  && gaPageTable[Addr>>12] & PF_PRESENT
+        && gaPageTable[Addr>>12] & PF_COW )
+       {
+               tPAddr  paddr;
+               if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
+               {
+                       gaPageTable[Addr>>12] &= ~PF_COW;
+                       gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
+               }
+               else
+               {
+                       //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr);
+                       paddr = MM_DuplicatePage( Addr );
+                       MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
+                       gaPageTable[Addr>>12] &= PF_USER;
+                       gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
+               }
+               
+//             Log_Debug("MMVirt", "COW for %p (%P)", Addr, gaPageTable[Addr>>12]);
+               
+               INVLPG( Addr & ~0xFFF );
+               return;
+       }
+
+       // Disable instruction tracing  
+       __ASM__("pushf; andw $0xFEFF, 0(%esp); popf");
+       Proc_GetCurThread()->bInstrTrace = 0;
+
+       // If it was a user, tell the thread handler
+       if(ErrorCode & 4) {
+               Log_Warning("MMVirt", "User %s %s memory%s",
+                       (ErrorCode&2?"write to":"read from"),
+                       (ErrorCode&1?"bad/locked":"non-present"),
+                       (ErrorCode&16?" (Instruction Fetch)":"")
+                       );
+               Log_Warning("MMVirt", "Instruction %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr);
+               __ASM__("sti"); // Restart IRQs
+               #if 1
+               Error_Backtrace(Regs->eip, Regs->ebp);
+               #endif
+               Threads_SegFault(Addr);
+               return ;
+       }
+       
+       Debug_KernelPanic();
+       
+       // -- Check Error Code --
+       if(ErrorCode & 8)
+               Warning("Reserved Bits Trashed!");
+       else
+       {
+               Warning("Kernel %s %s memory%s",
+                       (ErrorCode&2?"write to":"read from"),
+                       (ErrorCode&1?"bad/locked":"non-present"),
+                       (ErrorCode&16?" (Instruction Fetch)":"")
+                       );
+       }
+       
+       Log("CPU %i - Code at %p accessed %p", GetCPUNum(), Regs->eip, Addr);
+       // Print Stack Backtrace
+       Error_Backtrace(Regs->eip, Regs->ebp);
+
+       #if 0   
+       Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]);
+       if( gaPageDir[Addr>>22] & PF_PRESENT )
+               Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]);
+       #endif
+       //MM_DumpTables(0, -1); 
+       
+       // Register Dump
+       Log("EAX %08x ECX %08x EDX %08x EBX %08x", Regs->eax, Regs->ecx, Regs->edx, Regs->ebx);
+       Log("ESP %08x EBP %08x ESI %08x EDI %08x", Regs->esp, Regs->ebp, Regs->esi, Regs->edi);
+       //Log("SS:ESP %04x:%08x", Regs->ss, Regs->esp);
+       Log("CS:EIP %04x:%08x", Regs->cs, Regs->eip);
+       Log("DS %04x ES %04x FS %04x GS %04x", Regs->ds, Regs->es, Regs->fs, Regs->gs);
+       {
+               Uint    dr0, dr1;
+               __ASM__ ("mov %%dr0, %0":"=r"(dr0):);
+               __ASM__ ("mov %%dr1, %0":"=r"(dr1):);
+               Log("DR0 %08x DR1 %08x", dr0, dr1);
+       }
+       
+       Panic("Page Fault at 0x%x (Accessed 0x%x)", Regs->eip, Addr);
+}
+
+/**
+ * \fn void MM_DumpTables(tVAddr Start, tVAddr End)
+ * \brief Dumps the layout of the page tables
+ */
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+       tVAddr  rangeStart = 0;
+       tPAddr  expected = 0;
+       void    *expected_node = NULL, *tmpnode = NULL;
+       tVAddr  curPos;
+       Uint    page;
+       const tPAddr    MASK = ~0xF78;
+       
+       Start >>= 12;   End >>= 12;
+       
+       #if 0
+       Log("Directory Entries:");
+       for(page = Start >> 10;
+               page < (End >> 10)+1;
+               page ++)
+       {
+               if(gaPageDir[page])
+               {
+                       Log(" 0x%08x-0x%08x :: 0x%08x",
+                               page<<22, ((page+1)<<22)-1,
+                               gaPageDir[page]&~0xFFF
+                               );
+               }
+       }
+       #endif
+       
+       Log("Table Entries:");
+       for(page = Start, curPos = Start<<12;
+               page < End;
+               curPos += 0x1000, page++)
+       {
+               if( !(gaPageDir[curPos>>22] & PF_PRESENT)
+               ||  !(gaPageTable[page] & PF_PRESENT)
+               ||  (gaPageTable[page] & MASK) != expected
+               ||  (tmpnode=NULL,MM_GetPageNode(expected, &tmpnode), tmpnode != expected_node))
+               {
+                       if(expected) {
+                               tPAddr  orig = gaPageTable[rangeStart>>12];
+                               Log(" 0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s) %p",
+                                       rangeStart,
+                                       orig & ~0xFFF,
+                                       curPos - rangeStart,
+                                       (orig & PF_NOPAGE ? "P" : "-"),
+                                       (orig & PF_COW ? "C" : "-"),
+                                       (orig & PF_GLOBAL ? "G" : "-"),
+                                       (orig & PF_USER ? "U" : "-"),
+                                       (orig & PF_WRITE ? "W" : "-"),
+                                       expected_node
+                                       );
+                               expected = 0;
+                       }
+                       if( !(gaPageDir[curPos>>22] & PF_PRESENT) )     continue;
+                       if( !(gaPageTable[curPos>>12] & PF_PRESENT) )   continue;
+                       
+                       expected = (gaPageTable[page] & MASK);
+                       MM_GetPageNode(expected, &expected_node);
+                       rangeStart = curPos;
+               }
+               if(expected)    expected += 0x1000;
+       }
+       
+       if(expected) {
+               tPAddr  orig = gaPageTable[rangeStart>>12];
+               Log("0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s) %p",
+                       rangeStart,
+                       orig & ~0xFFF,
+                       curPos - rangeStart,
+                       (orig & PF_NOPAGE ? "p" : "-"),
+                       (orig & PF_COW ? "C" : "-"),
+                       (orig & PF_GLOBAL ? "G" : "-"),
+                       (orig & PF_USER ? "U" : "-"),
+                       (orig & PF_WRITE ? "W" : "-"),
+                       expected_node
+                       );
+               expected = 0;
+       }
+}
+
+/**
+ * \fn tPAddr MM_Allocate(tVAddr VAddr)
+ */
+tPAddr MM_Allocate(tVAddr VAddr)
+{
+       tPAddr  paddr;
+       //ENTER("xVAddr", VAddr);
+       //__ASM__("xchg %bx,%bx");
+       // Check if the directory is mapped
+       if( gaPageDir[ VAddr >> 22 ] == 0 )
+       {
+               // Allocate directory
+               paddr = MM_AllocPhys();
+               if( paddr == 0 ) {
+                       Warning("MM_Allocate - Out of Memory (Called by %p)", __builtin_return_address(0));
+                       //LEAVE('i',0);
+                       return 0;
+               }
+               // Map and mark as user (if needed)
+               gaPageDir[ VAddr >> 22 ] = paddr | 3;
+               if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
+               
+               INVLPG( &gaPageDir[ VAddr >> 22 ] );
+               memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
+       }
+       // Check if the page is already allocated
+       else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
+               Warning("MM_Allocate - Allocating to used address (%p)", VAddr);
+               //LEAVE('X', gaPageTable[ VAddr >> 12 ] & ~0xFFF);
+               return gaPageTable[ VAddr >> 12 ] & ~0xFFF;
+       }
+       
+       // Allocate
+       paddr = MM_AllocPhys();
+       //LOG("paddr = 0x%llx", paddr);
+       if( paddr == 0 ) {
+               Warning("MM_Allocate - Out of Memory when allocating at %p (Called by %p)",
+                       VAddr, __builtin_return_address(0));
+               //LEAVE('i',0);
+               return 0;
+       }
+       // Map
+       gaPageTable[ VAddr >> 12 ] = paddr | 3;
+       // Mark as user
+       if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
+       // Invalidate Cache for address
+       INVLPG( VAddr & ~0xFFF );
+       
+       //LEAVE('X', paddr);
+       return paddr;
+}
+
+/**
+ * \fn void MM_Deallocate(tVAddr VAddr)
+ */
+void MM_Deallocate(tVAddr VAddr)
+{
+       if( gaPageDir[ VAddr >> 22 ] == 0 ) {
+               Warning("MM_Deallocate - Directory not mapped");
+               return;
+       }
+       
+       if(gaPageTable[ VAddr >> 12 ] == 0) {
+               Warning("MM_Deallocate - Page is not allocated");
+               return;
+       }
+       
+       // Dereference page
+       MM_DerefPhys( gaPageTable[ VAddr >> 12 ] & ~0xFFF );
+       // Clear page
+       gaPageTable[ VAddr >> 12 ] = 0;
+}
+
+/**
+ * \fn tPAddr MM_GetPhysAddr(tVAddr Addr)
+ * \brief Checks if the passed address is accesable
+ */
+tPAddr MM_GetPhysAddr(tVAddr Addr)
+{
+       if( !(gaPageDir[Addr >> 22] & 1) )
+               return 0;
+       if( !(gaPageTable[Addr >> 12] & 1) )
+               return 0;
+       return (gaPageTable[Addr >> 12] & ~0xFFF) | (Addr & 0xFFF);
+}
+
+/**
+ * \fn void MM_SetCR3(Uint CR3)
+ * \brief Sets the current process space
+ */
+void MM_SetCR3(Uint CR3)
+{
+       __ASM__("mov %0, %%cr3"::"r"(CR3));
+}
+
+/**
+ * \fn int MM_Map(tVAddr VAddr, tPAddr PAddr)
+ * \brief Map a physical page to a virtual one
+ */
+int MM_Map(tVAddr VAddr, tPAddr PAddr)
+{
+       //ENTER("xVAddr xPAddr", VAddr, PAddr);
+       // Sanity check
+       if( PAddr & 0xFFF || VAddr & 0xFFF ) {
+               Log_Warning("MM_Virt", "MM_Map - Physical or Virtual Addresses are not aligned");
+               //LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Align addresses
+       PAddr &= ~0xFFF;        VAddr &= ~0xFFF;
+       
+       // Check if the directory is mapped
+       if( gaPageDir[ VAddr >> 22 ] == 0 )
+       {
+               tPAddr  tmp = MM_AllocPhys();
+               if( tmp == 0 )
+                       return 0;
+               gaPageDir[ VAddr >> 22 ] = tmp | 3;
+               
+               // Mark as user
+               if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
+               
+               INVLPG( &gaPageTable[ (VAddr >> 12) & ~0x3FF ] );
+               memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
+       }
+       // Check if the page is already allocated
+       else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
+               Warning("MM_Map - Allocating to used address");
+               //LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Map
+       gaPageTable[ VAddr >> 12 ] = PAddr | 3;
+       // Mark as user
+       if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
+       
+       //LOG("gaPageTable[ 0x%x ] = (Uint)%p = 0x%x",
+       //      VAddr >> 12, &gaPageTable[ VAddr >> 12 ], gaPageTable[ VAddr >> 12 ]);
+       
+       // Reference
+       MM_RefPhys( PAddr );
+       
+       //LOG("INVLPG( 0x%x )", VAddr);
+       INVLPG( VAddr );
+       
+       //LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \brief Clear user's address space
+ */
+void MM_ClearUser(void)
+{
+       Uint    i, j;
+       
+       for( i = 0; i < (MM_USER_MAX>>22); i ++ )
+       {
+               // Check if directory is not allocated
+               if( !(gaPageDir[i] & PF_PRESENT) ) {
+                       gaPageDir[i] = 0;
+                       continue;
+               }
+               
+               // Deallocate tables
+               for( j = 0; j < 1024; j ++ )
+               {
+                       if( gaPageTable[i*1024+j] & 1 )
+                               MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF );
+                       gaPageTable[i*1024+j] = 0;
+               }
+               
+               // Deallocate directory
+               MM_DerefPhys( gaPageDir[i] & ~0xFFF );
+               gaPageDir[i] = 0;
+               INVLPG( &gaPageTable[i*1024] );
+       }
+       INVLPG( gaPageDir );
+}
+
+/**
+ * \brief Deallocate an address space
+ */
+void MM_ClearSpace(Uint32 CR3)
+{
+        int    i, j;
+       
+       if(CR3 == (*gpPageCR3 & ~0xFFF)) {
+               Log_Error("MMVirt", "Can't clear current address space");
+               return ;
+       }
+
+       if( MM_GetRefCount(CR3) > 1 ) {
+               MM_DerefPhys(CR3);
+               Log_Log("MMVirt", "CR3 %P is still referenced, not cleaning (but dereferenced)", CR3);
+               return ;
+       }
+
+       Log_Debug("MMVirt", "Clearing out address space 0x%x from 0x%x", CR3, *gpPageCR3);
+       
+       GET_TEMP_MAPPING(CR3);
+       INVLPG( gaTmpDir );
+
+       for( i = 0; i < 1024; i ++ )
+       {
+               Uint32  *table = &gaTmpTable[i*1024];
+               if( !(gaTmpDir[i] & PF_PRESENT) )
+                       continue ;
+
+               INVLPG( table );        
+
+               if( i < 768 || (i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) )
+               {
+                       for( j = 0; j < 1024; j ++ )
+                       {
+                               if( !(table[j] & 1) )
+                                       continue;
+                               MM_DerefPhys( table[j] & ~0xFFF );
+                       }
+               }
+
+               if( i != (PAGE_TABLE_ADDR >> 22) )
+               {               
+                       MM_DerefPhys( gaTmpDir[i] & ~0xFFF );
+               }
+       }
+
+
+       MM_DerefPhys( CR3 );
+
+       REL_TEMP_MAPPING();
+}
+
+/**
+ * \fn tPAddr MM_Clone(void)
+ * \brief Clone the current address space
+ */
+tPAddr MM_Clone(int bNoUserCopy)
+{
+       Uint    i, j;
+       tPAddr  ret;
+       Uint    page = 0;
+       tVAddr  kStackBase = Proc_GetCurThread()->KernelStack - MM_KERNEL_STACK_SIZE;
+       void    *tmp;
+       
+       // Create Directory Table
+       ret = MM_AllocPhys();
+       if( ret == 0 ) {
+               return 0;
+       }
+       
+       // Map
+       GET_TEMP_MAPPING( ret );
+       INVLPG( gaTmpDir );
+       memsetd( gaTmpDir, 0, 1024 );
+       
+       if( Threads_GetPID() != 0 && !bNoUserCopy )
+       {       
+               // Copy Tables
+               for( i = 0; i < 768; i ++)
+               {
+                       // Check if table is allocated
+                       if( !(gaPageDir[i] & PF_PRESENT) ) {
+                               gaTmpDir[i] = 0;
+                               page += 1024;
+                               continue;
+                       }
+                       
+                       // Allocate new table
+                       gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7);
+                       INVLPG( &gaTmpTable[page] );
+                       // Fill
+                       for( j = 0; j < 1024; j ++, page++ )
+                       {
+                               if( !(gaPageTable[page] & PF_PRESENT) ) {
+                                       gaTmpTable[page] = 0;
+                                       continue;
+                               }
+                               
+                               // Refrence old page
+                               MM_RefPhys( gaPageTable[page] & ~0xFFF );
+                               // Add to new table
+                               if(gaPageTable[page] & PF_WRITE) {
+                                       gaTmpTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
+                                       gaPageTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
+                                       INVLPG( page << 12 );
+                               }
+                               else
+                                       gaTmpTable[page] = gaPageTable[page];
+                       }
+               }
+       }
+       
+       // Map in kernel tables (and make fractal mapping)
+       for( i = 768; i < 1024; i ++ )
+       {
+               // Fractal
+               if( i == (PAGE_TABLE_ADDR >> 22) ) {
+                       gaTmpDir[ PAGE_TABLE_ADDR >> 22 ] = *gpTmpCR3;
+                       continue;
+               }
+               if( i == (TMP_TABLE_ADDR >> 22) ) {
+                       gaTmpDir[ TMP_TABLE_ADDR >> 22 ] = 0;
+                       continue ;
+               }
+               
+               if( gaPageDir[i] == 0 ) {
+                       gaTmpDir[i] = 0;
+                       continue;
+               }
+               
+               //LOG("gaPageDir[%x/4] = 0x%x", i*4, gaPageDir[i]);
+               MM_RefPhys( gaPageDir[i] & ~0xFFF );
+               gaTmpDir[i] = gaPageDir[i];
+       }
+       
+       // Allocate kernel stack
+       for(i = MM_KERNEL_STACKS >> 22; i < MM_KERNEL_STACKS_END >> 22; i ++ )
+       {
+               // Check if directory is allocated
+               if( (gaPageDir[i] & 1) == 0 ) {
+                       gaTmpDir[i] = 0;
+                       continue;
+               }               
+               
+               // We don't care about other kernel stacks, just the current one
+               if( i != kStackBase >> 22 ) {
+                       MM_DerefPhys( gaPageDir[i] & ~0xFFF );
+                       gaTmpDir[i] = 0;
+                       continue;
+               }
+               
+               // Create a copy
+               gaTmpDir[i] = MM_AllocPhys() | 3;
+               INVLPG( &gaTmpTable[i*1024] );
+               for( j = 0; j < 1024; j ++ )
+               {
+                       // Is the page allocated? If not, skip
+                       if( !(gaPageTable[i*1024+j] & 1) ) {
+                               gaTmpTable[i*1024+j] = 0;
+                               continue;
+                       }
+                       
+                       // We don't care about other kernel stacks
+                       if( ((i*1024+j)*4096 & ~(MM_KERNEL_STACK_SIZE-1)) != kStackBase ) {
+                               gaTmpTable[i*1024+j] = 0;
+                               continue;
+                       }
+                       
+                       // Allocate page
+                       gaTmpTable[i*1024+j] = MM_AllocPhys() | 3;
+                       
+                       MM_RefPhys( gaTmpTable[i*1024+j] & ~0xFFF );
+                       
+                       tmp = (void *) MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
+                       memcpy( tmp, (void *)( (i*1024+j)*0x1000 ), 0x1000 );
+                       MM_FreeTemp( (Uint)tmp );
+               }
+       }
+       
+       REL_TEMP_MAPPING();
+       
+       //LEAVE('x', ret);
+       return ret;
+}
+
+/**
+ * \fn tVAddr MM_NewKStack(void)
+ * \brief Create a new kernel stack
+ */
+tVAddr MM_NewKStack(void)
+{
+       tVAddr  base;
+       Uint    i;
+       for(base = MM_KERNEL_STACKS; base < MM_KERNEL_STACKS_END; base += MM_KERNEL_STACK_SIZE)
+       {
+               // Check if space is free
+               if(MM_GetPhysAddr(base) != 0)   continue;
+               // Allocate
+               //for(i = MM_KERNEL_STACK_SIZE; i -= 0x1000 ; )
+               for(i = 0; i < MM_KERNEL_STACK_SIZE; i += 0x1000 )
+               {
+                       if( MM_Allocate(base+i) == 0 )
+                       {
+                               // On error, print a warning and return error
+                               Warning("MM_NewKStack - Out of memory");
+                               // - Clean up
+                               //for( i += 0x1000 ; i < MM_KERNEL_STACK_SIZE; i += 0x1000 )
+                               //      MM_Deallocate(base+i);
+                               return 0;
+                       }
+               }
+               // Success
+//             Log("MM_NewKStack - Allocated %p", base + MM_KERNEL_STACK_SIZE);
+               return base+MM_KERNEL_STACK_SIZE;
+       }
+       // No stacks left
+       Log_Warning("MMVirt", "MM_NewKStack - No address space left");
+       return 0;
+}
+
+/**
+ * \fn tVAddr MM_NewWorkerStack()
+ * \brief Creates a new worker stack
+ */
+tVAddr MM_NewWorkerStack(Uint *StackContents, size_t ContentsSize)
+{
+       Uint    base, addr;
+       tVAddr  tmpPage;
+       tPAddr  page;
+       
+       // TODO: Thread safety
+       // Find a free worker stack address
+       for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++)
+       {
+               // Used block
+               if( gWorkerStacks[base/32] == -1 ) {
+                       base += 31;     base &= ~31;
+                       base --;        // Counteracted by the base++
+                       continue;
+               }
+               // Used stack
+               if( gWorkerStacks[base/32] & (1 << base) ) {
+                       continue;
+               }
+               break;
+       }
+       if(base >= NUM_WORKER_STACKS) {
+               Warning("Uh-oh! Out of worker stacks");
+               return 0;
+       }
+       
+       // It's ours now!
+       gWorkerStacks[base/32] |= (1 << base);
+       // Make life easier for later calls
+       giLastUsedWorker = base;
+       // We have one
+       base = WORKER_STACKS + base * WORKER_STACK_SIZE;
+       //Log(" MM_NewWorkerStack: base = 0x%x", base);
+       
+       // Set the temp fractals to TID0's address space
+       GET_TEMP_MAPPING( ((Uint)gaInitPageDir - KERNEL_BASE) );
+       INVLPG( gaTmpDir );
+       
+       // Check if the directory is mapped (we are assuming that the stacks
+       // will fit neatly in a directory)
+       //Log(" MM_NewWorkerStack: gaTmpDir[ 0x%x ] = 0x%x", base>>22, gaTmpDir[ base >> 22 ]);
+       if(gaTmpDir[ base >> 22 ] == 0) {
+               gaTmpDir[ base >> 22 ] = MM_AllocPhys() | 3;
+               INVLPG( &gaTmpTable[ (base>>12) & ~0x3FF ] );
+       }
+       
+       // Mapping Time!
+       for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 )
+       {
+               page = MM_AllocPhys();
+               gaTmpTable[ (base + addr) >> 12 ] = page | 3;
+       }
+
+       // Release temporary fractal
+       REL_TEMP_MAPPING();
+
+       // NOTE: Max of 1 page
+       // `page` is the last allocated page from the previious for loop
+       tmpPage = MM_MapTemp( page );
+       memcpy( (void*)( tmpPage + (0x1000 - ContentsSize) ), StackContents, ContentsSize);
+       MM_FreeTemp(tmpPage);   
+       
+       //Log("MM_NewWorkerStack: RETURN 0x%x", base);
+       return base + WORKER_STACK_SIZE;
+}
+
+/**
+ * \fn void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
+ * \brief Sets the flags on a page
+ */
+void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
+{
+       tTabEnt *ent;
+       if( !(gaPageDir[VAddr >> 22] & 1) )     return ;
+       if( !(gaPageTable[VAddr >> 12] & 1) )   return ;
+       
+       ent = &gaPageTable[VAddr >> 12];
+       
+       // Read-Only
+       if( Mask & MM_PFLAG_RO )
+       {
+               if( Flags & MM_PFLAG_RO ) {
+                       *ent &= ~PF_WRITE;
+               }
+               else {
+                       gaPageDir[VAddr >> 22] |= PF_WRITE;
+                       *ent |= PF_WRITE;
+               }
+       }
+       
+       // Kernel
+       if( Mask & MM_PFLAG_KERNEL )
+       {
+               if( Flags & MM_PFLAG_KERNEL ) {
+                       *ent &= ~PF_USER;
+               }
+               else {
+                       gaPageDir[VAddr >> 22] |= PF_USER;
+                       *ent |= PF_USER;
+               }
+       }
+       
+       // Copy-On-Write
+       if( Mask & MM_PFLAG_COW )
+       {
+               if( Flags & MM_PFLAG_COW ) {
+                       *ent &= ~PF_WRITE;
+                       *ent |= PF_COW;
+               }
+               else {
+                       *ent &= ~PF_COW;
+                       *ent |= PF_WRITE;
+               }
+       }
+       
+       //Log("MM_SetFlags: *ent = 0x%08x, gaPageDir[%i] = 0x%08x",
+       //      *ent, VAddr >> 22, gaPageDir[VAddr >> 22]);
+}
+
+/**
+ * \brief Get the flags on a page
+ */
+Uint MM_GetFlags(tVAddr VAddr)
+{
+       tTabEnt *ent;
+       Uint    ret = 0;
+       
+       // Validity Check
+       if( !(gaPageDir[VAddr >> 22] & 1) )     return 0;
+       if( !(gaPageTable[VAddr >> 12] & 1) )   return 0;
+       
+       ent = &gaPageTable[VAddr >> 12];
+       
+       // Read-Only
+       if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
+       // Kernel
+       if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
+       // Copy-On-Write
+       if( *ent & PF_COW )     ret |= MM_PFLAG_COW;
+       
+       return ret;
+}
+
+/**
+ * \brief Check if the provided buffer is valid
+ * \return Boolean valid
+ */
+int MM_IsValidBuffer(tVAddr Addr, size_t Size)
+{
+        int    bIsUser;
+        int    dir, tab;
+
+       Size += Addr & (PAGE_SIZE-1);
+       Addr &= ~(PAGE_SIZE-1);
+
+       dir = Addr >> 22;
+       tab = Addr >> 12;
+       
+//     Debug("Addr = %p, Size = 0x%x, dir = %i, tab = %i", Addr, Size, dir, tab);
+
+       if( !(gaPageDir[dir] & 1) )     return 0;
+       if( !(gaPageTable[tab] & 1) )   return 0;
+       
+       bIsUser = !!(gaPageTable[tab] & PF_USER);
+
+       while( Size >= PAGE_SIZE )
+       {
+               if( (tab & 1023) == 0 )
+               {
+                       dir ++;
+                       if( !(gaPageDir[dir] & 1) )     return 0;
+               }
+               
+               if( !(gaPageTable[tab] & 1) )   return 0;
+               if( bIsUser && !(gaPageTable[tab] & PF_USER) )  return 0;
+
+               tab ++;
+               Size -= PAGE_SIZE;
+       }
+       return 1;
+}
+
+/**
+ * \fn tPAddr MM_DuplicatePage(tVAddr VAddr)
+ * \brief Duplicates a virtual page to a physical one
+ */
+tPAddr MM_DuplicatePage(tVAddr VAddr)
+{
+       tPAddr  ret;
+       Uint    temp;
+        int    wasRO = 0;
+       
+       //ENTER("xVAddr", VAddr);
+       
+       // Check if mapped
+       if( !(gaPageDir  [VAddr >> 22] & PF_PRESENT) )  return 0;
+       if( !(gaPageTable[VAddr >> 12] & PF_PRESENT) )  return 0;
+       
+       // Page Align
+       VAddr &= ~0xFFF;
+       
+       // Allocate new page
+       ret = MM_AllocPhys();
+       if( !ret ) {
+               return 0;
+       }
+       
+       // Write-lock the page (to keep data constistent), saving its R/W state
+       wasRO = (gaPageTable[VAddr >> 12] & PF_WRITE ? 0 : 1);
+       gaPageTable[VAddr >> 12] &= ~PF_WRITE;
+       INVLPG( VAddr );
+       
+       // Copy Data
+       temp = MM_MapTemp(ret);
+       memcpy( (void*)temp, (void*)VAddr, 0x1000 );
+       MM_FreeTemp(temp);
+       
+       // Restore Writeable status
+       if(!wasRO)      gaPageTable[VAddr >> 12] |= PF_WRITE;
+       INVLPG(VAddr);
+       
+       //LEAVE('X', ret);
+       return ret;
+}
+
+/**
+ * \fn Uint MM_MapTemp(tPAddr PAddr)
+ * \brief Create a temporary memory mapping
+ * \todo Show Luigi Barone (C Lecturer) and see what he thinks
+ */
+tVAddr MM_MapTemp(tPAddr PAddr)
+{
+        int    i;
+       
+       //ENTER("XPAddr", PAddr);
+       
+       PAddr &= ~0xFFF;
+       
+       //LOG("glTempMappings = %i", glTempMappings);
+       
+       for(;;)
+       {
+               Mutex_Acquire( &glTempMappings );
+               
+               for( i = 0; i < NUM_TEMP_PAGES; i ++ )
+               {
+                       // Check if page used
+                       if(gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] & 1)        continue;
+                       // Mark as used
+                       gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] = PAddr | 3;
+                       INVLPG( TEMP_MAP_ADDR + (i << 12) );
+                       //LEAVE('p', TEMP_MAP_ADDR + (i << 12));
+                       Mutex_Release( &glTempMappings );
+                       return TEMP_MAP_ADDR + (i << 12);
+               }
+               Mutex_Release( &glTempMappings );
+               Threads_Yield();        // TODO: Use a sleep queue here instead
+       }
+}
+
+/**
+ * \fn void MM_FreeTemp(tVAddr PAddr)
+ * \brief Free's a temp mapping
+ */
+void MM_FreeTemp(tVAddr VAddr)
+{
+        int    i = VAddr >> 12;
+       //ENTER("xVAddr", VAddr);
+       
+       if(i >= (TEMP_MAP_ADDR >> 12))
+               gaPageTable[ i ] = 0;
+       
+       //LEAVE('-');
+}
+
+/**
+ * \fn tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
+ * \brief Allocates a contigous number of pages
+ */
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
+{
+        int    i, j;
+       
+       PAddr &= ~0xFFF;
+       
+       // Scan List
+       for( i = 0; i < NUM_HW_PAGES; i ++ )
+       {               
+               // Check if addr used
+               if( gaPageTable[ (HW_MAP_ADDR >> 12) + i ] & 1 )
+                       continue;
+               
+               // Check possible region
+               for( j = 0; j < Number && i + j < NUM_HW_PAGES; j ++ )
+               {
+                       // If there is an allocated page in the region we are testing, break
+                       if( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] & 1 )    break;
+               }
+               // Is it all free?
+               if( j == Number )
+               {
+                       // Allocate
+                       for( j = 0; j < Number; j++ ) {
+                               MM_RefPhys( PAddr + (j<<12) );
+                               gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = (PAddr + (j<<12)) | 3;
+                       }
+                       return HW_MAP_ADDR + (i<<12);
+               }
+       }
+       // If we don't find any, return NULL
+       return 0;
+}
+
+/**
+ * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
+ * \brief Allocates DMA physical memory
+ * \param Pages        Number of pages required
+ * \param MaxBits      Maximum number of bits the physical address can have
+ * \param PhysAddr     Pointer to the location to place the physical address allocated
+ * \return Virtual address allocate
+ */
+tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
+{
+       tPAddr  maxCheck = (1 << MaxBits);
+       tPAddr  phys;
+       tVAddr  ret;
+       
+       ENTER("iPages iMaxBits pPhysAddr", Pages, MaxBits, PhysAddr);
+       
+       // Sanity Check
+       if(MaxBits < 12 || !PhysAddr) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Bound
+       if(MaxBits >= PHYS_BITS)        maxCheck = -1;
+       
+       // Fast Allocate
+       if(Pages == 1 && MaxBits >= PHYS_BITS)
+       {
+               phys = MM_AllocPhys();
+               if( !phys ) {
+                       *PhysAddr = 0;
+                       LEAVE_RET('i', 0);
+               }
+               *PhysAddr = phys;
+               ret = MM_MapHWPages(phys, 1);
+               if(ret == 0) {
+                       MM_DerefPhys(phys);
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               LEAVE('x', ret);
+               return ret;
+       }
+       
+       // Slow Allocate
+       phys = MM_AllocPhysRange(Pages, MaxBits);
+       // - Was it allocated?
+       if(phys == 0) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Allocated successfully, now map
+       ret = MM_MapHWPages(phys, Pages);
+       if( ret == 0 ) {
+               // If it didn't map, free then return 0
+               for(;Pages--;phys+=0x1000)
+                       MM_DerefPhys(phys);
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       *PhysAddr = phys;
+       LEAVE('x', ret);
+       return ret;
+}
+
+/**
+ * \fn void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
+ * \brief Unmap a hardware page
+ */
+void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
+{
+        int    i, j;
+       
+       //Log_Debug("VirtMem", "MM_UnmapHWPages: (VAddr=0x%08x, Number=%i)", VAddr, Number);
+       
+       // Sanity Check
+       if(VAddr < HW_MAP_ADDR || VAddr+Number*0x1000 > HW_MAP_MAX)     return;
+       
+       i = VAddr >> 12;
+       
+       Mutex_Acquire( &glTempMappings );       // Temp and HW share a directory, so they share a lock
+       
+       for( j = 0; j < Number; j++ )
+       {
+               MM_DerefPhys( gaPageTable[ i + j ] & ~0xFFF );
+               gaPageTable[ i + j ] = 0;
+       }
+       
+       Mutex_Release( &glTempMappings );
+}
+
diff --git a/KernelLand/Kernel/arch/x86/pci.c b/KernelLand/Kernel/arch/x86/pci.c
new file mode 100644 (file)
index 0000000..7a0a2c1
--- /dev/null
@@ -0,0 +1,22 @@
+/*\r
+ * Acess2\r
+ * arch/x86/pci.h - x86 PCI Bus Access\r
+ */\r
+#define DEBUG  0\r
+#include <acess.h>\r
+#include <drv_pci_int.h>\r
+\r
+// === CODE ===\r
+Uint32 PCI_CfgReadDWord(Uint32 Address)\r
+{\r
+       Address |= 0x80000000;\r
+       outd(0xCF8, Address);\r
+       return ind(0xCFC);\r
+}\r
+\r
+void PCI_CfgWriteDWord(Uint32 Address, Uint32 Data)\r
+{\r
+       Address |= 0x80000000;\r
+       outd(0xCF8, Address);\r
+       outd(0xCFC, Data);\r
+}\r
diff --git a/KernelLand/Kernel/arch/x86/proc.asm b/KernelLand/Kernel/arch/x86/proc.asm
new file mode 100644 (file)
index 0000000..8da7971
--- /dev/null
@@ -0,0 +1,375 @@
+; AcessOS Microkernel Version
+; Start.asm
+
+[bits 32]
+
+%define SAVEFLAG_FPU   0x1
+
+KERNEL_BASE    equ 0xC0000000
+
+KSTACK_USERSTATE_SIZE  equ     (4+8+1+5)*4     ; SRegs, GPRegs, CPU, IRET
+
+[section .text]
+
+[global NewTaskHeader]
+NewTaskHeader:
+       mov eax, [esp]
+       mov dr0, eax
+
+       mov eax, [esp+4]
+       add esp, 12     ; Thread, Function, Arg Count
+       call eax
+       
+       push eax        ; Ret val
+       push 0          ; 0 = This Thread
+       call Threads_Exit
+
+[extern MM_Clone]
+[global Proc_CloneInt]
+Proc_CloneInt:
+       pusha
+       ; Save RSP
+       mov eax, [esp+0x20+4]
+       mov [eax], esp
+       push DWORD [esp+0x20+12]
+       call MM_Clone
+       add esp, 4
+       ; Save CR3
+       mov esi, [esp+0x20+8]
+       mov [esi], eax
+       ; Undo the pusha
+       add esp, 0x20
+       mov eax, .newTask
+       ret
+.newTask:
+       popa
+       xor eax, eax
+       ret
+
+[global SwitchTasks]
+; + 4 = New RSP
+; + 8 = Old RSP save loc
+; +12 = New RIP
+; +16 = Old RIP save loc
+; +20 = CR3
+SwitchTasks:
+       pusha
+       
+       ; Old IP
+       mov eax, [esp+0x20+16]
+       test eax, eax
+       jz .nosave
+       mov DWORD [eax], .restore
+       ; Old SP
+       mov eax, [esp+0x20+8]
+       mov [eax], esp
+
+.nosave:
+       mov ecx, [esp+0x20+12]  ; New IP
+       mov eax, [esp+0x20+20]  ; New CR3
+       mov esp, [esp+0x20+ 4]  ; New SP
+       
+       test eax, eax
+       jz .setState
+       mov cr3, eax
+       invlpg [esp]
+       invlpg [esp+0x1000]
+.setState:
+       jmp ecx
+
+.restore:
+       popa
+       xor eax, eax
+       ret
+
+[global Proc_InitialiseSSE]
+Proc_InitialiseSSE:
+       mov eax, cr4
+       or eax, (1 << 9)|(1 << 10)      ; Set OSFXSR and OSXMMEXCPT
+       mov cr4, eax
+       mov eax, cr0
+       and ax, ~(1 << 2)       ; Clear EM
+       or eax, (1 << 1)        ; Set MP
+       mov eax, cr0
+       ret
+[global Proc_DisableSSE]
+Proc_DisableSSE:
+       mov eax, cr0
+       or ax, 1 << 3   ; Set TS
+       mov cr0, eax
+       ret
+[global Proc_EnableSSE]
+Proc_EnableSSE:
+       mov eax, cr0
+       and ax, ~(1 << 3)       ; Clear TS
+       mov cr0, eax
+       ret
+
+[global Proc_SaveSSE]
+Proc_SaveSSE:
+       mov eax, [esp+4]
+       fxsave [eax]
+       ret
+[global Proc_RestoreSSE]
+Proc_RestoreSSE:
+       mov eax, [esp+4]
+       fxrstor [eax]
+       ret
+
+%if USE_MP
+[extern giMP_TimerCount]
+[extern gpMP_LocalAPIC]
+[extern Isr240.jmp]
+[global SetAPICTimerCount]
+SetAPICTimerCount:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       mov ax, 0x10
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       mov eax, [gpMP_LocalAPIC]
+       mov ecx, [eax+0x320]
+       test ecx, 0x00010000
+       jz .setTime
+       mov DWORD [eax+0x380], 0xFFFFFFFF       ; Set Initial Count
+       mov DWORD [eax+0x320], 0x000000F0       ; Enable the timer on IVT#0xEF (One Shot)
+       jmp .ret
+
+.setTime:      
+       ; Get Timer Count
+       mov ecx, 0xFFFFFFFF
+       sub ecx, [eax+0x390]
+       mov DWORD [giMP_TimerCount], ecx
+       ; Disable APIC Timer
+       mov DWORD [eax+0x320], 0x000100EF
+       mov DWORD [eax+0x380], 0
+
+       ; Update Timer IRQ to the IRQ code
+       mov eax, SchedulerBase
+       sub eax, Isr240.jmp+5
+       mov DWORD [Isr240.jmp+1], eax
+
+       ;xchg bx, bx    ; MAGIC BREAK
+.ret:
+       mov dx, 0x20
+       mov al, 0x20
+       out dx, al              ; ACK IRQ
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       popa
+       add esp, 8      ; CPU ID / Error Code
+       iret
+%endif
+; --------------
+; Task Scheduler
+; --------------
+[extern Proc_Scheduler]
+[global SchedulerBase]
+SchedulerBase:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       pushf
+       and BYTE [esp+1], 0xFE  ; Clear Trap Flag
+       popf
+       
+       mov eax, dr0
+       push eax        ; Debug Register 0, Current Thread
+       
+       mov ax, 0x10
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       %if USE_MP
+       call GetCPUNum
+       mov ebx, eax
+       push eax        ; Push as argument
+       %else
+       push 0
+       %endif
+       
+       call Proc_Scheduler
+[global scheduler_return]
+scheduler_return:      ; Used by some hackery in Proc_DumpThreadCPUState
+       
+       add esp, 4      ; Remove CPU Number (thread is poped later)
+
+       %if USE_MP
+       test ebx, ebx
+       jnz .sendEOI
+       %endif
+       
+       mov al, 0x20
+       out 0x20, al            ; ACK IRQ
+       %if USE_MP
+       jmp .ret
+       
+.sendEOI:
+       mov eax, DWORD [gpMP_LocalAPIC]
+       mov DWORD [eax+0x0B0], 0
+       %endif
+.ret:
+       pop eax ; Debug Register 0, Current Thread
+       mov dr0, eax
+
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       
+       popa
+       add esp, 4*2    ; CPU ID + Dummy error code
+       ; No Error code / int num
+       iret
+
+[extern Proc_Clone]
+[extern Threads_Exit]
+[global SpawnTask]
+SpawnTask:
+       ; Call Proc_Clone with Flags=0
+       xor eax, eax
+;      push eax
+       push eax
+       call Proc_Clone
+       add esp, 8      ; Remove arguments from stack
+       
+       test eax, eax
+       jnz .parent
+       
+       ; In child, so now set up stack frame
+       mov ebx, [esp+4]        ; Child Function
+       mov edx, [esp+8]        ; Argument
+       ; Child Function
+       push edx        ; Argument
+       call ebx        ; Function
+       ; Kill thread once done
+       push eax        ; Exit Code
+       push   0        ; Kill this thread
+       call Threads_Exit       ; Kill Thread
+       
+.parent:
+       ret
+
+; void Proc_ReturnToUser(void *Method, Uint Parameter, tVAddr KernelStack)
+; Calls a user fault handler
+;
+[global Proc_ReturnToUser]
+[extern Proc_GetCurThread]
+Proc_ReturnToUser:
+       push ebp
+       mov ebp, esp
+       ; [EBP+8]: handler to use
+       ; [EBP+12]: parameter
+       ; [EBP+16]: kernel stack top
+       
+       ; Get kernel stack      
+       mov eax, [ebp+16]
+       sub eax, KSTACK_USERSTATE_SIZE
+       
+       ;
+       ; NOTE: This can cause corruption if the signal happens while the user
+       ;       has called a kernel operation.
+       ; Good thing this can only be called on a user fault.
+       ;
+       
+       ; Validate user ESP
+       ; - Page Table
+       mov edx, [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4
+       mov ecx, edx
+       shr ecx, 22
+       test BYTE [0xFC3F0000+ecx*4], 1
+       jnz .justKillIt
+       ; - Page
+       mov ecx, edx
+       shr ecx, 12
+       test BYTE [0xFC000000+ecx*4], 1
+       jnz .justKillIt
+       ; Adjust
+       sub edx, 8
+       ; - Page Table
+       mov ecx, edx
+       shr ecx, 22
+       test BYTE [0xFC3F0000+ecx*4], 1
+       jnz .justKillIt
+       ; - Page
+       mov ecx, edx
+       shr ecx, 12
+       test BYTE [0xFC000000+ecx*4], 1
+       jnz .justKillIt
+       
+       ; Get and alter User SP
+       mov edi, edx
+       mov edx, [ebp+12]       ; Get parameter
+       mov [edi+4], edx        ; save to user stack
+       mov [edi], DWORD User_Syscall_RetAndExit        ; Return Address
+       
+       ; Restore Segment Registers
+       mov ax, 0x23
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       push 0x23       ; SS
+       push edi        ; ESP
+       push 0x202      ; EFLAGS (IP and Rsvd)
+       push 0x1B       ; CS
+       mov eax, [ebp+8]        ; Method to call
+       push eax        ; EIP
+       
+       iret
+       
+       ; Just kill the bleeding thing
+       ; (I know it calls int 0xAC in kernel mode, but meh)
+.justKillIt:
+       xor eax, eax
+       xor ebx, ebx
+       dec ebx ; EBX = -1
+       int 0xAC
+
+[global GetCPUNum]
+GetCPUNum:     ; TODO: Store in debug registers
+       mov eax, dr1
+       ret
+
+[extern GetEIP]
+[global GetEIP_Sched]
+[global GetEIP_Sched_ret]
+GetEIP_Sched_ret equ GetEIP_Sched.ret
+GetEIP_Sched:
+       call GetEIP
+GetEIP_Sched.ret:
+       ret
+
+; Usermode code exported by the kernel
+[section .usertext]
+; Export a place for the user to jump to to call a syscall
+; - Allows the kernel to change the method easily
+User_Syscall:
+       xchg bx, bx     ; MAGIC BREAKPOINT
+       int 0xAC
+
+; A place to return to and exit
+User_Syscall_RetAndExit:
+       push eax
+       call User_Syscall_Exit
+User_Syscall_Exit:
+       xor eax, eax
+       mov ebx, [esp+4]
+       int 0xAC
+
+; vim: ft=nasm ts=8
diff --git a/KernelLand/Kernel/arch/x86/proc.c b/KernelLand/Kernel/arch/x86/proc.c
new file mode 100644 (file)
index 0000000..82a3f40
--- /dev/null
@@ -0,0 +1,1025 @@
+/*
+ * AcessOS Microkernel Version
+ * proc.c
+ */
+#include <acess.h>
+#include <threads.h>
+#include <proc.h>
+#include <desctab.h>
+#include <mm_virt.h>
+#include <errno.h>
+#if USE_MP
+# include <mp.h>
+#endif
+#include <hal_proc.h>
+#include <arch_int.h>
+
+// === FLAGS ===
+#define DEBUG_TRACE_SWITCH     0
+#define DEBUG_DISABLE_DOUBLEFAULT      1
+#define DEBUG_VERY_SLOW_PERIOD 0
+
+// === CONSTANTS ===
+// Base is 1193182
+#define TIMER_BASE      1193182
+#if DEBUG_VERY_SLOW_PERIOD
+# define TIMER_DIVISOR 1193    //~10Hz switch, with 10 quantum = 1s per thread
+#else
+# define TIMER_DIVISOR 11932   //~100Hz
+#endif
+
+// === TYPES ===
+typedef struct sCPU
+{
+       Uint8   APICID;
+       Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
+       Uint16  Resvd;
+       tThread *Current;
+}      tCPU;
+
+// === IMPORTS ===
+extern tGDT    gGDT[];
+extern tIDT    gIDT[];
+extern void    APWait(void);   // 16-bit AP pause code
+extern void    APStartup(void);        // 16-bit AP startup code
+extern Uint    GetEIP(void);   // start.asm
+extern Uint    GetEIP_Sched(void);     // proc.asm
+extern void    NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...);      // Actually takes cdecl args
+extern Uint    Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
+extern Uint32  gaInitPageDir[1024];    // start.asm
+extern char    Kernel_Stack_Top[];
+extern int     giNumCPUs;
+extern int     giNextTID;
+extern tThread gThreadZero;
+extern tProcess        gProcessZero;
+extern void    Isr8(void);     // Double Fault
+extern void    Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
+extern char    scheduler_return[];     // Return address in SchedulerBase
+extern char    IRQCommon[];    // Common IRQ handler code
+extern char    IRQCommon_handled[];    // IRQCommon call return location
+extern char    GetEIP_Sched_ret[];     // GetEIP call return location
+extern void    SwitchTasks(Uint NewSP, Uint *OldSP, Uint NewIP, Uint *OldIO, Uint CR3);
+extern void    Proc_InitialiseSSE(void);
+extern void    Proc_SaveSSE(Uint DestPtr);
+extern void    Proc_DisableSSE(void);
+
+// === PROTOTYPES ===
+//void ArchThreads_Init(void);
+#if USE_MP
+void   MP_StartAP(int CPU);
+void   MP_SendIPIVector(int CPU, Uint8 Vector);
+void   MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
+#endif
+void   Proc_IdleThread(void *Ptr);
+//void Proc_Start(void);
+//tThread      *Proc_GetCurThread(void);
+void   Proc_ChangeStack(void);
+// int Proc_NewKThread(void (*Fcn)(void*), void *Data);
+// int Proc_Clone(Uint *Err, Uint Flags);
+Uint   Proc_MakeUserStack(void);
+//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
+void   Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NORETURN;
+ int   Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
+//void Proc_CallFaultHandler(tThread *Thread);
+//void Proc_DumpThreadCPUState(tThread *Thread);
+void   Proc_Scheduler(int CPU);
+
+// === GLOBALS ===
+// --- Multiprocessing ---
+#if USE_MP
+volatile int   giNumInitingCPUs = 0;
+tMPInfo        *gMPFloatPtr = NULL;
+volatile Uint32        giMP_TimerCount;        // Start Count for Local APIC Timer
+tAPIC  *gpMP_LocalAPIC = NULL;
+Uint8  gaAPIC_to_CPU[256] = {0};
+ int   giProc_BootProcessorID = 0;
+tTSS   gaTSSs[MAX_CPUS];       // TSS Array
+#endif
+tCPU   gaCPUs[MAX_CPUS] = {
+       {.Current = &gThreadZero}
+       };
+tTSS   *gTSSs = NULL;  // Pointer to TSS array
+tTSS   gTSS0 = {0};
+// --- Error Recovery ---
+char   gaDoubleFaultStack[1024] __attribute__ ((section(".padata")));
+tTSS   gDoubleFault_TSS = {
+       .ESP0 = (Uint)&gaDoubleFaultStack[1024],
+       .SS0 = 0x10,
+       .CR3 = (Uint)gaInitPageDir - KERNEL_BASE,
+       .EIP = (Uint)Isr8,
+       .ESP = (Uint)&gaDoubleFaultStack[1024],
+       .CS = 0x08,     .SS = 0x10,
+       .DS = 0x10,     .ES = 0x10,
+       .FS = 0x10,     .GS = 0x10,
+};
+
+// === CODE ===
+/**
+ * \fn void ArchThreads_Init(void)
+ * \brief Starts the process scheduler
+ */
+void ArchThreads_Init(void)
+{
+       Uint    pos = 0;
+       
+       #if USE_MP
+       tMPTable        *mptable;
+       
+       // Mark BSP as active
+       gaCPUs[0].State = 2;
+       
+       // -- Initialise Multiprocessing
+       // Find MP Floating Table
+       // - EBDA/Last 1Kib (640KiB)
+       for(pos = KERNEL_BASE|0x9F000; pos < (KERNEL_BASE|0xA0000); pos += 16) {
+               if( *(Uint*)(pos) == MPPTR_IDENT ) {
+                       Log("Possible %p", pos);
+                       if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
+                       gMPFloatPtr = (void*)pos;
+                       break;
+               }
+       }
+       // - Last KiB (512KiB base mem)
+       if(!gMPFloatPtr) {
+               for(pos = KERNEL_BASE|0x7F000; pos < (KERNEL_BASE|0x80000); pos += 16) {
+                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
+                               Log("Possible %p", pos);
+                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
+                               gMPFloatPtr = (void*)pos;
+                               break;
+                       }
+               }
+       }
+       // - BIOS ROM
+       if(!gMPFloatPtr) {
+               for(pos = KERNEL_BASE|0xE0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
+                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
+                               Log("Possible %p", pos);
+                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
+                               gMPFloatPtr = (void*)pos;
+                               break;
+                       }
+               }
+       }
+       
+       // If the MP Table Exists, parse it
+       if(gMPFloatPtr)
+       {
+                int    i;
+               tMPTable_Ent    *ents;
+               #if DUMP_MP_TABLE
+               Log("gMPFloatPtr = %p", gMPFloatPtr);
+               Log("*gMPFloatPtr = {");
+               Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig);
+               Log("\t.MPConfig = 0x%08x", gMPFloatPtr->MPConfig);
+               Log("\t.Length = 0x%02x", gMPFloatPtr->Length);
+               Log("\t.Version = 0x%02x", gMPFloatPtr->Version);
+               Log("\t.Checksum = 0x%02x", gMPFloatPtr->Checksum);
+               Log("\t.Features = [0x%02x,0x%02x,0x%02x,0x%02x,0x%02x]",
+                       gMPFloatPtr->Features[0],       gMPFloatPtr->Features[1],
+                       gMPFloatPtr->Features[2],       gMPFloatPtr->Features[3],
+                       gMPFloatPtr->Features[4]
+                       );
+               Log("}");
+               #endif          
+
+               mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig );
+               #if DUMP_MP_TABLE
+               Log("mptable = %p", mptable);
+               Log("*mptable = {");
+               Log("\t.Sig = 0x%08x", mptable->Sig);
+               Log("\t.BaseTableLength = 0x%04x", mptable->BaseTableLength);
+               Log("\t.SpecRev = 0x%02x", mptable->SpecRev);
+               Log("\t.Checksum = 0x%02x", mptable->Checksum);
+               Log("\t.OEMID = '%8c'", mptable->OemID);
+               Log("\t.ProductID = '%8c'", mptable->ProductID);
+               Log("\t.OEMTablePtr = %p'", mptable->OEMTablePtr);
+               Log("\t.OEMTableSize = 0x%04x", mptable->OEMTableSize);
+               Log("\t.EntryCount = 0x%04x", mptable->EntryCount);
+               Log("\t.LocalAPICMemMap = 0x%08x", mptable->LocalAPICMemMap);
+               Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen);
+               Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum);
+               Log("}");
+               #endif
+               
+               gpMP_LocalAPIC = (void*)MM_MapHWPages(mptable->LocalAPICMemMap, 1);
+               
+               ents = mptable->Entries;
+               giNumCPUs = 0;
+               
+               for( i = 0; i < mptable->EntryCount; i ++ )
+               {
+                        int    entSize = 0;
+                       switch( ents->Type )
+                       {
+                       case 0: // Processor
+                               entSize = 20;
+                               #if DUMP_MP_TABLE
+                               Log("%i: Processor", i);
+                               Log("\t.APICID = %i", ents->Proc.APICID);
+                               Log("\t.APICVer = 0x%02x", ents->Proc.APICVer);
+                               Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags);
+                               Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature);
+                               Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags);
+                               #endif
+                               
+                               if( !(ents->Proc.CPUFlags & 1) ) {
+                                       Log("DISABLED");
+                                       break;
+                               }
+                               
+                               // Check if there is too many processors
+                               if(giNumCPUs >= MAX_CPUS) {
+                                       giNumCPUs ++;   // If `giNumCPUs` > MAX_CPUS later, it will be clipped
+                                       break;
+                               }
+                               
+                               // Initialise CPU Info
+                               gaAPIC_to_CPU[ents->Proc.APICID] = giNumCPUs;
+                               gaCPUs[giNumCPUs].APICID = ents->Proc.APICID;
+                               gaCPUs[giNumCPUs].State = 0;
+                               giNumCPUs ++;
+                               
+                               // Set BSP Variable
+                               if( ents->Proc.CPUFlags & 2 ) {
+                                       giProc_BootProcessorID = giNumCPUs-1;
+                               }
+                               
+                               break;
+                       
+                       #if DUMP_MP_TABLE >= 2
+                       case 1: // Bus
+                               entSize = 8;
+                               Log("%i: Bus", i);
+                               Log("\t.ID = %i", ents->Bus.ID);
+                               Log("\t.TypeString = '%6C'", ents->Bus.TypeString);
+                               break;
+                       case 2: // I/O APIC
+                               entSize = 8;
+                               Log("%i: I/O APIC", i);
+                               Log("\t.ID = %i", ents->IOAPIC.ID);
+                               Log("\t.Version = 0x%02x", ents->IOAPIC.Version);
+                               Log("\t.Flags = 0x%02x", ents->IOAPIC.Flags);
+                               Log("\t.Addr = 0x%08x", ents->IOAPIC.Addr);
+                               break;
+                       case 3: // I/O Interrupt Assignment
+                               entSize = 8;
+                               Log("%i: I/O Interrupt Assignment", i);
+                               Log("\t.IntType = %i", ents->IOInt.IntType);
+                               Log("\t.Flags = 0x%04x", ents->IOInt.Flags);
+                               Log("\t.SourceBusID = 0x%02x", ents->IOInt.SourceBusID);
+                               Log("\t.SourceBusIRQ = 0x%02x", ents->IOInt.SourceBusIRQ);
+                               Log("\t.DestAPICID = 0x%02x", ents->IOInt.DestAPICID);
+                               Log("\t.DestAPICIRQ = 0x%02x", ents->IOInt.DestAPICIRQ);
+                               break;
+                       case 4: // Local Interrupt Assignment
+                               entSize = 8;
+                               Log("%i: Local Interrupt Assignment", i);
+                               Log("\t.IntType = %i", ents->LocalInt.IntType);
+                               Log("\t.Flags = 0x%04x", ents->LocalInt.Flags);
+                               Log("\t.SourceBusID = 0x%02x", ents->LocalInt.SourceBusID);
+                               Log("\t.SourceBusIRQ = 0x%02x", ents->LocalInt.SourceBusIRQ);
+                               Log("\t.DestLocalAPICID = 0x%02x", ents->LocalInt.DestLocalAPICID);
+                               Log("\t.DestLocalAPICIRQ = 0x%02x", ents->LocalInt.DestLocalAPICIRQ);
+                               break;
+                       default:
+                               Log("%i: Unknown (%i)", i, ents->Type);
+                               break;
+                       #endif
+                       }
+                       ents = (void*)( (Uint)ents + entSize );
+               }
+               
+               if( giNumCPUs > MAX_CPUS ) {
+                       Warning("Too many CPUs detected (%i), only using %i of them", giNumCPUs, MAX_CPUS);
+                       giNumCPUs = MAX_CPUS;
+               }
+               gTSSs = gaTSSs;
+       }
+       else {
+               Log("No MP Table was found, assuming uniprocessor\n");
+               giNumCPUs = 1;
+               gTSSs = &gTSS0;
+       }
+       #else
+       giNumCPUs = 1;
+       gTSSs = &gTSS0;
+       #endif
+       
+       #if !DEBUG_DISABLE_DOUBLEFAULT
+       // Initialise Double Fault TSS
+       gGDT[5].BaseLow = (Uint)&gDoubleFault_TSS & 0xFFFF;
+       gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16;
+       gGDT[5].BaseHi = (Uint)&gDoubleFault_TSS >> 24;
+       
+       // Set double fault IDT to use the new TSS
+       gIDT[8].OffsetLo = 0;
+       gIDT[8].CS = 5<<3;
+       gIDT[8].Flags = 0x8500;
+       gIDT[8].OffsetHi = 0;
+       #endif
+       
+       // Set timer frequency
+       outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
+       outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
+       outb(0x40, (TIMER_DIVISOR>>8)&0xFF);    // High Byte
+       
+       Log_Debug("Proc", "PIT Frequency %i.%03i Hz",
+               TIMER_BASE/TIMER_DIVISOR,
+               ((Uint64)TIMER_BASE*1000/TIMER_DIVISOR)%1000
+               );
+       
+       #if USE_MP
+       // Get the count setting for APIC timer
+       Log("Determining APIC Count");
+       __asm__ __volatile__ ("sti");
+       while( giMP_TimerCount == 0 )   __asm__ __volatile__ ("hlt");
+       __asm__ __volatile__ ("cli");
+       Log("APIC Count %i", giMP_TimerCount);
+       {
+               Uint64  freq = giMP_TimerCount;
+               freq *= TIMER_BASE;
+               freq /= TIMER_DIVISOR;
+               if( (freq /= 1000) < 2*1000)
+                       Log("Bus Frequency %i KHz", freq);
+               else if( (freq /= 1000) < 2*1000)
+                       Log("Bus Frequency %i MHz", freq);
+               else if( (freq /= 1000) < 2*1000)
+                       Log("Bus Frequency %i GHz", freq);
+               else
+                       Log("Bus Frequency %i THz", freq);
+       }
+       
+       // Initialise Normal TSS(s)
+       for(pos=0;pos<giNumCPUs;pos++)
+       {
+       #else
+       pos = 0;
+       #endif
+               gTSSs[pos].SS0 = 0x10;
+               gTSSs[pos].ESP0 = 0;    // Set properly by scheduler
+               gGDT[6+pos].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
+               gGDT[6+pos].BaseMid = ((Uint)(&gTSSs[pos]) >> 16) & 0xFFFF;
+               gGDT[6+pos].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
+       #if USE_MP
+       }
+       #endif
+       
+       // Load the BSP's TSS
+       __asm__ __volatile__ ("ltr %%ax"::"a"(0x30));
+       // Set Current Thread and CPU Number in DR0 and DR1
+       __asm__ __volatile__ ("mov %0, %%db0"::"r"(&gThreadZero));
+       __asm__ __volatile__ ("mov %0, %%db1"::"r"(0));
+       
+       gaCPUs[0].Current = &gThreadZero;
+       gThreadZero.CurCPU = 0;
+       
+       gProcessZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
+       
+       // Create Per-Process Data Block
+       if( !MM_Allocate(MM_PPD_CFG) )
+       {
+               Panic("OOM - No space for initial Per-Process Config");
+       }
+
+       // Initialise SSE support
+       Proc_InitialiseSSE();
+       
+       // Change Stacks
+       Proc_ChangeStack();
+}
+
+#if USE_MP
+/**
+ * \brief Start an AP
+ */
+void MP_StartAP(int CPU)
+{
+       Log_Log("Proc", "Starting AP %i (APIC %i)", CPU, gaCPUs[CPU].APICID);
+       
+       // Set location of AP startup code and mark for a warm restart
+       *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APWait - (KERNEL_BASE|0xFFFF0);
+       *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
+       outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Set warm reset flag
+       MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);   // Init IPI
+       
+       // Delay
+       inb(0x80); inb(0x80); inb(0x80); inb(0x80);
+       
+       // TODO: Use a better address, preferably registered with the MM
+       // - MM_AllocDMA mabye?
+       // Create a far jump
+       *(Uint8*)(KERNEL_BASE|0x11000) = 0xEA;  // Far JMP
+       *(Uint16*)(KERNEL_BASE|0x11001) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0);     // IP
+       *(Uint16*)(KERNEL_BASE|0x11003) = 0xFFFF;       // CS
+       // Send a Startup-IPI to make the CPU execute at 0x11000 (which we
+       // just filled)
+       MP_SendIPI(gaCPUs[CPU].APICID, 0x11, 6);        // StartupIPI
+       
+       giNumInitingCPUs ++;
+}
+
+void MP_SendIPIVector(int CPU, Uint8 Vector)
+{
+       MP_SendIPI(gaCPUs[CPU].APICID, Vector, 0);
+}
+
+/**
+ * \brief Send an Inter-Processor Interrupt
+ * \param APICID       Processor's Local APIC ID
+ * \param Vector       Argument of some kind
+ * \param DeliveryMode Type of signal
+ * \note 3A 10.5 "APIC/Handling Local Interrupts"
+ */
+void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
+{
+       Uint32  val;
+       
+       // Hi
+       val = (Uint)APICID << 24;
+//     Log("%p = 0x%08x", &gpMP_LocalAPIC->ICR[1], val);
+       gpMP_LocalAPIC->ICR[1].Val = val;
+       // Low (and send)
+       val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
+//     Log("%p = 0x%08x", &gpMP_LocalAPIC->ICR[0], val);
+       gpMP_LocalAPIC->ICR[0].Val = val;
+}
+#endif
+
+void Proc_IdleThread(void *Ptr)
+{
+       tCPU    *cpu = &gaCPUs[GetCPUNum()];
+       cpu->Current->ThreadName = strdup("Idle Thread");
+       Threads_SetPriority( cpu->Current, -1 );        // Never called randomly
+       cpu->Current->Quantum = 1;      // 1 slice quantum
+       for(;;) {
+               __asm__ __volatile__ ("sti");   // Make sure interrupts are enabled
+               __asm__ __volatile__ ("hlt");   // Make sure interrupts are enabled
+               Proc_Reschedule();
+       }
+}
+
+/**
+ * \fn void Proc_Start(void)
+ * \brief Start process scheduler
+ */
+void Proc_Start(void)
+{
+        int    tid;
+       #if USE_MP
+        int    i;
+       #endif
+       
+       #if USE_MP
+       // Start APs
+       for( i = 0; i < giNumCPUs; i ++ )
+       {
+               if(i)   gaCPUs[i].Current = NULL;
+               
+               // Create Idle Task
+               tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
+               
+               // Start the AP
+               if( i != giProc_BootProcessorID ) {
+                       MP_StartAP( i );
+               }
+       }
+       
+       // BSP still should run the current task
+       gaCPUs[0].Current = &gThreadZero;
+       
+       // Start interrupts and wait for APs to come up
+       Log_Debug("Proc", "Waiting for APs to come up");
+       __asm__ __volatile__ ("sti");
+       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
+       #else
+       // Create Idle Task
+       tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
+//     gaCPUs[0].IdleThread = Threads_GetThread(tid);
+       
+       // Set current task
+       gaCPUs[0].Current = &gThreadZero;
+
+       // Start Interrupts (and hence scheduler)
+       __asm__ __volatile__("sti");
+       #endif
+       MM_FinishVirtualInit();
+}
+
+/**
+ * \fn tThread *Proc_GetCurThread(void)
+ * \brief Gets the current thread
+ */
+tThread *Proc_GetCurThread(void)
+{
+       #if USE_MP
+       return gaCPUs[ GetCPUNum() ].Current;
+       #else
+       return gaCPUs[ 0 ].Current;
+       #endif
+}
+
+/**
+ * \fn void Proc_ChangeStack(void)
+ * \brief Swaps the current stack for a new one (in the proper stack reigon)
+ */
+void Proc_ChangeStack(void)
+{
+       Uint    esp, ebp;
+       Uint    tmpEbp, oldEsp;
+       Uint    curBase, newBase;
+
+       __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
+       __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
+
+       oldEsp = esp;
+
+       // Create new KStack
+       newBase = MM_NewKStack();
+       // Check for errors
+       if(newBase == 0) {
+               Panic("What the?? Unable to allocate space for initial kernel stack");
+               return;
+       }
+
+       curBase = (Uint)&Kernel_Stack_Top;
+       
+       LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
+
+       // Get ESP as a used size
+       esp = curBase - esp;
+       LOG("memcpy( %p, %p, 0x%x )", (void*)(newBase - esp), (void*)(curBase - esp), esp );
+       // Copy used stack
+       memcpy( (void*)(newBase - esp), (void*)(curBase - esp), esp );
+       // Get ESP as an offset in the new stack
+       esp = newBase - esp;
+       // Adjust EBP
+       ebp = newBase - (curBase - ebp);
+
+       // Repair EBPs & Stack Addresses
+       // Catches arguments also, but may trash stack-address-like values
+       for(tmpEbp = esp; tmpEbp < newBase; tmpEbp += 4)
+       {
+               if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < curBase)
+                       *(Uint*)tmpEbp += newBase - curBase;
+       }
+       
+       Proc_GetCurThread()->KernelStack = newBase;
+       
+       __asm__ __volatile__ ("mov %0, %%esp"::"r"(esp));
+       __asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
+}
+
+void Proc_ClearProcess(tProcess *Process)
+{
+       MM_ClearSpace(Process->MemState.CR3);
+}
+
+void Proc_ClearThread(tThread *Thread)
+{
+       if(Thread->SavedState.SSE) {
+               free(Thread->SavedState.SSE);
+               Thread->SavedState.SSE = NULL;
+       }
+}
+
+tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
+{
+       Uint    esp;
+       tThread *newThread, *cur;
+       
+       cur = Proc_GetCurThread();
+       newThread = Threads_CloneTCB(0);
+       if(!newThread)  return -1;
+       
+       // Create new KStack
+       newThread->KernelStack = MM_NewKStack();
+       // Check for errors
+       if(newThread->KernelStack == 0) {
+               free(newThread);
+               return -1;
+       }
+
+       esp = newThread->KernelStack;
+       *(Uint*)(esp-=4) = (Uint)Data;  // Data (shadowed)
+       *(Uint*)(esp-=4) = 1;   // Number of params
+       *(Uint*)(esp-=4) = (Uint)Fcn;   // Function to call
+       *(Uint*)(esp-=4) = (Uint)newThread;     // Thread ID
+       
+       newThread->SavedState.ESP = esp;
+       newThread->SavedState.EIP = (Uint)&NewTaskHeader;
+       newThread->SavedState.SSE = NULL;
+//     Log("New (KThread) %p, esp = %p", newThread->SavedState.EIP, newThread->SavedState.ESP);
+       
+//     MAGIC_BREAK();  
+       Threads_AddActive(newThread);
+
+       return newThread->TID;
+}
+
+/**
+ * \fn int Proc_Clone(Uint *Err, Uint Flags)
+ * \brief Clone the current process
+ */
+tPID Proc_Clone(Uint Flags)
+{
+       tThread *newThread;
+       tThread *cur = Proc_GetCurThread();
+       Uint    eip;
+
+       // Sanity, please
+       if( !(Flags & CLONE_VM) ) {
+               Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
+               return -1;
+       }
+       
+       // New thread
+       newThread = Threads_CloneTCB(Flags);
+       if(!newThread)  return -1;
+
+       newThread->KernelStack = cur->KernelStack;
+
+       // Clone state
+       eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
+       if( eip == 0 ) {
+               return 0;
+       }
+       newThread->SavedState.EIP = eip;
+       newThread->SavedState.SSE = NULL;
+       newThread->SavedState.bSSEModified = 0;
+       
+       // Check for errors
+       if( newThread->Process->MemState.CR3 == 0 ) {
+               Log_Error("Proc", "Proc_Clone: MM_Clone failed");
+               Threads_Delete(newThread);
+               return -1;
+       }
+
+       // Add the new thread to the run queue
+       Threads_AddActive(newThread);
+       return newThread->TID;
+}
+
+/**
+ * \fn int Proc_SpawnWorker(void)
+ * \brief Spawns a new worker thread
+ */
+int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+{
+       tThread *new;
+       Uint    stack_contents[4];
+       
+       // Create new thread
+       new = Threads_CloneThreadZero();
+       if(!new) {
+               Warning("Proc_SpawnWorker - Out of heap space!\n");
+               return -1;
+       }
+
+       // Create the stack contents
+       stack_contents[3] = (Uint)Data;
+       stack_contents[2] = 1;
+       stack_contents[1] = (Uint)Fcn;
+       stack_contents[0] = (Uint)new;
+       
+       // Create a new worker stack (in PID0's address space)
+       new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
+
+       // Save core machine state
+       new->SavedState.ESP = new->KernelStack - sizeof(stack_contents);
+       new->SavedState.EIP = (Uint)NewTaskHeader;
+       new->SavedState.SSE = NULL;
+       new->SavedState.bSSEModified = 0;
+       
+       // Mark as active
+       new->Status = THREAD_STAT_PREINIT;
+       Threads_AddActive( new );
+       
+       return new->TID;
+}
+
+/**
+ * \fn Uint Proc_MakeUserStack(void)
+ * \brief Creates a new user stack
+ */
+Uint Proc_MakeUserStack(void)
+{
+        int    i;
+       Uint    base = USER_STACK_TOP - USER_STACK_SZ;
+       
+       // Check Prospective Space
+       for( i = USER_STACK_SZ >> 12; i--; )
+               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+                       break;
+       
+       if(i != -1)     return 0;
+       
+       // Allocate Stack - Allocate incrementally to clean up MM_Dump output
+       for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
+       {
+               if( !MM_Allocate( base + (i<<12) ) )
+               {
+                       Warning("OOM: Proc_MakeUserStack");
+                       return 0;
+               }
+       }
+       
+       return base + USER_STACK_SZ;
+}
+
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
+{
+       Uint    *stack;
+        int    i;
+       const char      **envp = NULL;
+       Uint16  ss, cs;
+       
+       // Copy data to the user stack and free original buffer
+       stack = (void*)Proc_MakeUserStack();
+       stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
+       memcpy( stack, ArgV, DataSize );
+       free(ArgV);
+       
+       // Adjust Arguments and environment
+       if( DataSize )
+       {
+               Uint delta = (Uint)stack - (Uint)ArgV;
+               ArgV = (const char**)stack;
+               for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
+               envp = &ArgV[i+1];
+               for( i = 0; envp[i]; i++ )      envp[i] += delta;
+       }
+       
+       // User Mode Segments
+       ss = 0x23;      cs = 0x1B;
+       
+       // Arguments
+       *--stack = (Uint)envp;
+       *--stack = (Uint)ArgV;
+       *--stack = (Uint)ArgC;
+       *--stack = Base;
+       
+       Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
+}
+
+void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
+{
+       Uint    *stack = (void*)Stack;
+       *--stack = SS;          //Stack Segment
+       *--stack = Stack;       //Stack Pointer
+       *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
+       *--stack = CS;          //Code Segment
+       *--stack = IP;  //EIP
+       //PUSHAD
+       *--stack = 0xAAAAAAAA;  // eax
+       *--stack = 0xCCCCCCCC;  // ecx
+       *--stack = 0xDDDDDDDD;  // edx
+       *--stack = 0xBBBBBBBB;  // ebx
+       *--stack = 0xD1D1D1D1;  // edi
+       *--stack = 0x54545454;  // esp - NOT POPED
+       *--stack = 0x51515151;  // esi
+       *--stack = 0xB4B4B4B4;  // ebp
+       //Individual PUSHs
+       *--stack = SS;  // ds
+       *--stack = SS;  // es
+       *--stack = SS;  // fs
+       *--stack = SS;  // gs
+       
+       __asm__ __volatile__ (
+       "mov %%eax,%%esp;\n\t"  // Set stack pointer
+       "pop %%gs;\n\t"
+       "pop %%fs;\n\t"
+       "pop %%es;\n\t"
+       "pop %%ds;\n\t"
+       "popa;\n\t"
+       "iret;\n\t" : : "a" (stack));
+       for(;;);
+}
+
+/**
+ * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
+ * \brief Demotes a process to a lower permission level
+ * \param Err  Pointer to user's errno
+ * \param Dest New Permission Level
+ * \param Regs Pointer to user's register structure
+ */
+int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
+{
+        int    cpl = Regs->cs & 3;
+       // Sanity Check
+       if(Dest > 3 || Dest < 0) {
+               *Err = -EINVAL;
+               return -1;
+       }
+       
+       // Permission Check
+       if(cpl > Dest) {
+               *Err = -EACCES;
+               return -1;
+       }
+       
+       // Change the Segment Registers
+       Regs->cs = (((Dest+1)<<4) | Dest) - 8;
+       Regs->ss = ((Dest+1)<<4) | Dest;
+       // Check if the GP Segs are GDT, then change them
+       if(!(Regs->ds & 4))     Regs->ds = ((Dest+1)<<4) | Dest;
+       if(!(Regs->es & 4))     Regs->es = ((Dest+1)<<4) | Dest;
+       if(!(Regs->fs & 4))     Regs->fs = ((Dest+1)<<4) | Dest;
+       if(!(Regs->gs & 4))     Regs->gs = ((Dest+1)<<4) | Dest;
+       
+       return 0;
+}
+
+/**
+ * \brief Calls a signal handler in user mode
+ * \note Used for signals
+ */
+void Proc_CallFaultHandler(tThread *Thread)
+{
+       // Rewinds the stack and calls the user function
+       // Never returns
+       Proc_ReturnToUser( Thread->FaultHandler, Thread->CurFaultNum, Thread->KernelStack );
+       for(;;);
+}
+
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       if( Thread->CurCPU > -1 )
+       {
+                int    maxBacktraceDistance = 6;
+               tRegs   *regs = NULL;
+               Uint32  *stack;
+               
+               if( Thread->CurCPU != GetCPUNum() ) {
+                       Log("  Currently running");
+                       return ;
+               }
+               
+               // Backtrace to find the IRQ entrypoint
+               // - This will usually only be called by an IRQ, so this should
+               //   work
+               __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
+               while( maxBacktraceDistance -- )
+               {
+                       // [ebp] = oldEbp
+                       // [ebp+4] = retaddr
+                       
+                       if( stack[1] == (tVAddr)&IRQCommon_handled ) {
+                               regs = (void*)stack[2];
+                               break;
+                       }
+                       
+                       stack = (void*)stack[0];
+               }
+               
+               if( !regs ) {
+                       Log("  Unable to find IRQ Entry");
+                       return ;
+               }
+               
+               Log("  at %04x:%08x", regs->cs, regs->eip);
+               return ;
+       }
+       
+       tVAddr  diffFromScheduler = Thread->SavedState.EIP - (tVAddr)SwitchTasks;
+       tVAddr  diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_CloneInt;
+       tVAddr  diffFromSpawn = Thread->SavedState.EIP - (tVAddr)NewTaskHeader;
+       
+       if( diffFromClone > 0 && diffFromClone < 40 )   // When I last checked, .newTask was at .+27
+       {
+               Log("  Creating process");
+               return ;
+       }
+       
+       if( diffFromSpawn == 0 )
+       {
+               Log("  Creating thread");
+               return ;
+       }
+       
+       if( diffFromScheduler > 0 && diffFromScheduler < 128 )  // When I last checked, GetEIP was at .+0x30
+       {
+               // Scheduled out
+               Log("  At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
+               return ;
+       }
+       
+       Log("  Just created (unknown %p)", Thread->SavedState.EIP);
+}
+
+void Proc_Reschedule(void)
+{
+       tThread *nextthread, *curthread;
+        int    cpu = GetCPUNum();
+
+       // TODO: Wait for the lock?
+       if(IS_LOCKED(&glThreadListLock))        return;
+       
+       curthread = Proc_GetCurThread();
+
+       nextthread = Threads_GetNextToRun(cpu, curthread);
+
+       if(!nextthread || nextthread == curthread)
+               return ;
+
+       #if DEBUG_TRACE_SWITCH
+       // HACK: Ignores switches to the idle threads
+       if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
+       {
+               LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
+                       GetCPUNum(),
+                       nextthread, nextthread->TID, nextthread->ThreadName,
+                       nextthread->Process->MemState.CR3,
+                       nextthread->SavedState.EIP,
+                       nextthread->SavedState.ESP
+                       );
+               LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
+       }
+       #endif
+
+       // Update CPU state
+       gaCPUs[cpu].Current = nextthread;
+       gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
+       __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
+
+       // Save FPU/MMX/XMM/SSE state
+       if( curthread && curthread->SavedState.SSE )
+       {
+               Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
+               curthread->SavedState.bSSEModified = 0;
+               Proc_DisableSSE();
+       }
+
+       if( curthread )
+       {
+               SwitchTasks(
+                       nextthread->SavedState.ESP, &curthread->SavedState.ESP,
+                       nextthread->SavedState.EIP, &curthread->SavedState.EIP,
+                       nextthread->Process->MemState.CR3
+                       );
+       }
+       else
+       {
+               SwitchTasks(
+                       nextthread->SavedState.ESP, 0,
+                       nextthread->SavedState.EIP, 0,
+                       nextthread->Process->MemState.CR3
+                       );
+       }
+
+       return ;
+}
+
+/**
+ * \fn void Proc_Scheduler(int CPU)
+ * \brief Swap current thread and clears dead threads
+ */
+void Proc_Scheduler(int CPU)
+{
+#if 0
+       tThread *thread;
+       
+       // If the spinlock is set, let it complete
+       if(IS_LOCKED(&glThreadListLock))        return;
+       
+       // Get current thread
+       thread = gaCPUs[CPU].Current;
+       
+       if( thread )
+       {
+               tRegs   *regs;
+               Uint    ebp;
+               // Reduce remaining quantum and continue timeslice if non-zero
+               if( thread->Remaining-- )
+                       return;
+               // Reset quantum for next call
+               thread->Remaining = thread->Quantum;
+               
+               // TODO: Make this more stable somehow
+               __asm__ __volatile__("mov %%ebp, %0" : "=r" (ebp));
+               regs = (tRegs*)(ebp+(2+2)*4);   // EBP,Ret + CPU,CurThread
+               thread->SavedState.UserCS = regs->cs;
+               thread->SavedState.UserEIP = regs->eip;
+               
+               if(thread->bInstrTrace) {
+                       regs->eflags |= 0x100;  // Set TF
+                       Log("%p De-scheduled", thread);
+               }
+               else
+                       regs->eflags &= ~0x100; // Clear TF
+       }
+
+       // TODO: Ack timer?
+       #if USE_MP
+       if( GetCPUNum() )
+               gpMP_LocalAPIC->EOI.Val = 0;
+       else
+       #endif
+               outb(0x20, 0x20);
+       __asm__ __volatile__ ("sti");
+       Proc_Reschedule();
+#endif
+}
+
+// === EXPORTS ===
+EXPORT(Proc_SpawnWorker);
diff --git a/KernelLand/Kernel/arch/x86/start.asm b/KernelLand/Kernel/arch/x86/start.asm
new file mode 100644 (file)
index 0000000..b6026de
--- /dev/null
@@ -0,0 +1,285 @@
+; AcessOS Microkernel Version
+; Start.asm
+
+[bits 32]
+
+KERNEL_BASE    equ 0xC0000000
+%define MAX_CPUS       16
+
+[extern __load_addr]
+[extern __bss_start]
+[extern gKernelEnd]
+[section .multiboot]
+mboot:
+       ; Multiboot macros to make a few lines later more readable
+       MULTIBOOT_PAGE_ALIGN    equ 1<<0
+       MULTIBOOT_MEMORY_INFO   equ 1<<1
+       MULTIBOOT_HEADER_MAGIC  equ 0x1BADB002
+       MULTIBOOT_HEADER_FLAGS  equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
+       MULTIBOOT_CHECKSUM      equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+       
+       ; This is the GRUB Multiboot header. A boot signature
+       dd MULTIBOOT_HEADER_MAGIC
+       dd MULTIBOOT_HEADER_FLAGS
+       dd MULTIBOOT_CHECKSUM
+       dd mboot; - KERNEL_BASE ;Location of Multiboot Header
+       
+; Multiboot 2 Header
+;mboot2:
+;      MULTIBOOT2_HEADER_MAGIC equ 0xE85250D6
+;      MULTIBOOT2_HEADER_ARCH  equ 0
+;      MULTIBOOT2_HEADER_LENGTH        equ (mboot2_end-mboot2)
+;      MULTIBOOT2_CHECKSUM     equ -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_HEADER_ARCH + MULTIBOOT2_HEADER_LENGTH)
+;      
+;      dd MULTIBOOT2_HEADER_MAGIC
+;      dd MULTIBOOT2_HEADER_ARCH
+;      dd MULTIBOOT2_HEADER_LENGTH
+;      dd MULTIBOOT2_CHECKSUM
+;      ; MBoot2 Address Header
+;      dw      2, 0
+;      dd      8 + 16
+;      dd      mboot2  ; Location of Multiboot Header
+;      dd      __load_addr - KERNEL_BASE       ; Kernel Load base
+;      dd      __bss_start - KERNEL_BASE       ; Kernel Data End
+;      dd      gKernelEnd - KERNEL_BASE        ; Kernel BSS End
+;      ; MBoot2 Entry Point Tag
+;      dw      3, 0
+;      dd      8 + 4
+;      dd      start - KERNEL_BASE
+;      ; MBoot2 Module Alignment Tag
+;      dw      6, 0
+;      dd      12      ; ???
+;      dd      0       ; Search me, seems it wants padding
+;      ; Terminator
+;      dw      0, 0
+;      dd      8
+;mboot2_end:
+       
+[section .text]
+[extern kmain]
+[global start]
+start:
+       ; Just show we're here
+       mov WORD [0xB8000], 0x0741      ; 'A'
+       
+       ; Set up stack
+       mov esp, Kernel_Stack_Top
+       
+       ; Start Paging
+       mov ecx, gaInitPageDir - KERNEL_BASE
+       mov cr3, ecx
+       mov ecx, cr0
+       or ecx, 0x80010000      ; PG and WP
+       mov cr0, ecx
+       
+       mov WORD [0xB8002], 0x0763      ; 'c'
+       
+       ; Set GDT
+       lgdt [gGDTPtr]
+       mov cx, 0x10    ; PL0 Data
+       mov ss, cx
+       mov ds, cx
+       mov es, cx
+       mov gs, cx
+       mov fs, cx
+       mov WORD [0xB8004], 0x0765      ; 'e'
+       jmp 0x08:.higher_half
+.higher_half:
+       
+       mov WORD [0xB8006], 0x0773      ; 's'
+       mov WORD [0xB8008], 0x0773      ; 's'
+
+       ; Call the kernel
+       push ebx        ; Multiboot Info
+       push eax        ; Multiboot Magic Value
+       mov WORD [0xB800A], 0x0732      ; '2'
+       call kmain
+
+       ; Halt the Machine
+       cli
+.hlt:
+       hlt
+       jmp .hlt
+
+; 
+; Multiprocessing AP Startup Code (Must be within 0 - 0x10FFF0)
+;
+%if USE_MP
+[extern gIDTPtr]
+[extern gpMP_LocalAPIC]
+[extern giMP_TimerCount]
+[extern gaAPIC_to_CPU]
+[extern gaCPUs]
+[extern giNumInitingCPUs]
+[extern MM_NewKStack]
+[extern Proc_InitialiseSSE]
+
+lGDTPtr:       ; Local GDT Pointer
+       dw      3*8-1
+       dd      gGDT-KERNEL_BASE
+
+[bits 16]
+[global APWait]
+APWait:
+       ;xchg bx, bx
+.hlt:
+       ;hlt
+       jmp .hlt
+[extern Proc_Reschedule]
+[global APStartup]
+APStartup:
+       ;xchg bx, bx    ; MAGIC BREAK!
+       ; Load initial GDT
+       mov ax, 0xFFFF
+       mov ds, ax
+       lgdt [DWORD ds:lGDTPtr-KERNEL_BASE-0xFFFF0]
+       ; Enable PMode in CR0
+       mov eax, cr0
+       or al, 1
+       mov cr0, eax
+       ; Jump into PMode
+       jmp 08h:DWORD .ProtectedMode-KERNEL_BASE
+[bits 32]
+.ProtectedMode:
+       ; Load segment registers
+       mov ax, 0x10
+       mov ss, ax
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       ; Start Paging
+       mov eax, gaInitPageDir - KERNEL_BASE
+       mov cr3, eax
+       mov eax, cr0
+       or eax, 0x80010000      ; PG and WP
+       mov cr0, eax
+       ; Jump to higher half
+       lea eax, [.higherHalf]
+       jmp eax
+.higherHalf:
+       ; Load True GDT & IDT
+       lgdt [gGDTPtr]
+       lidt [gIDTPtr]
+
+       mov ebp, [gpMP_LocalAPIC]
+       mov ebx, [ebp+0x20]     ; Read ID
+       shr ebx, 24
+       ;xchg bx, bx    ; MAGIC BREAK
+       ; BL is now local APIC ID
+       mov cl, BYTE [gaAPIC_to_CPU+ebx]
+       xor ebx, ebx
+       mov bl, cl
+       ; BL is now the CPU ID
+       mov dr1, ebx    ; Save the CPU number to a debug register
+       ; Mark the CPU as up
+       mov BYTE [gaCPUs+ebx*8+1], 1
+       ; Decrement the remaining CPU count
+       dec DWORD [giNumInitingCPUs]
+       
+       ; Create a stack
+       lea edx, [ebx+1]
+       shl edx, 5+2    ; *32 *4
+       lea esp, [gInitAPStacks+edx]
+       call MM_NewKStack
+       mov esp, eax
+       
+       ; Set TSS
+       lea ecx, [ebx*8+0x30]
+       ltr cx
+       
+       ;xchg bx, bx    ; MAGIC_BREAK
+       ; Enable Local APIC
+       mov DWORD [ebp+0x0F0], 0x000001EF       ; Spurious Interrupt Vector (0xEF)
+       mov ecx, DWORD [giMP_TimerCount]
+       mov DWORD [ebp+0x380], ecx      ; Set Initial Count
+       mov DWORD [ebp+0x320], 0x000200EE       ; Enable timer on IVT#0xEE
+       mov DWORD [ebp+0x330], 0x000100E0       ; ##Enable thermal sensor on IVT#0xE0
+       mov DWORD [ebp+0x340], 0x000100D0       ; ##Enable performance counters on IVT#0xD0
+       mov DWORD [ebp+0x350], 0x000100D1       ; ##Enable LINT0 on IVT#0xD1
+       mov DWORD [ebp+0x360], 0x000100D2       ; ##Enable LINT1 on IVT#0xD2
+       mov DWORD [ebp+0x370], 0x000100E1       ; ##Enable Error on IVT#0xE1
+       mov DWORD [ebp+0x0B0], 0        ; Send an EOI (just in case)
+
+       ; Initialise SSE support
+       call Proc_InitialiseSSE
+       
+       ; CPU is now marked as initialised
+
+.hlt:
+       sti
+       call Proc_Reschedule    
+       hlt
+       jmp .hlt
+%endif
+
+[global GetEIP]
+GetEIP:
+       mov eax, [esp]
+       ret
+
+; int CallWithArgArray(void *Ptr, int NArgs, Uint *Args)
+; Call a function passing the array as arguments
+[global CallWithArgArray]
+CallWithArgArray:
+       push ebp
+       mov ebp, esp
+       mov ecx, [ebp+12]       ; Get NArgs
+       mov edx, [ebp+16]
+
+.top:
+       mov eax, [edx+ecx*4-4]
+       push eax
+       loop .top
+       
+       mov eax, [ebp+8]
+       call eax
+       lea esp, [ebp]
+       pop ebp
+       ret
+
+[section .data]
+; GDT
+GDT_SIZE       equ     (1+2*2+1+MAX_CPUS)*8
+[global gGDT]
+gGDT:
+       ; PL0 - Kernel
+       ; PL3 - User
+       dd 0x00000000, 0x00000000       ; 00 NULL Entry
+       dd 0x0000FFFF, 0x00CF9A00       ; 08 PL0 Code
+       dd 0x0000FFFF, 0x00CF9200       ; 10 PL0 Data
+       dd 0x0000FFFF, 0x00CFFA00       ; 18 PL3 Code
+       dd 0x0000FFFF, 0x00CFF200       ; 20 PL3 Data
+       dd 26*4-1, 0x00408900   ; 28 Double Fault TSS
+       times MAX_CPUS  dd 26*4-1, 0x00408900   ; 30+ TSSes
+[global gGDTPtr]
+gGDTPtr:
+       dw      GDT_SIZE-1
+       dd      gGDT
+
+[section .initpd]
+[global gaInitPageDir]
+[global gaInitPageTable]
+align 4096
+gaInitPageDir:
+       dd      gaInitPageTable-KERNEL_BASE+3   ; 0x000 - Low kernel
+       times 0x300-0x000-1     dd      0
+       dd      gaInitPageTable-KERNEL_BASE+3   ; 0xC00 - High kernel
+       times 0x3F0-0x300-1     dd      0
+       dd      gaInitPageDir-KERNEL_BASE+3     ; 0xFC0 - Fractal
+       times 0x400-0x3F0-1     dd      0
+align 4096
+gaInitPageTable:
+       %assign i 0
+       %rep 1024
+       dd      i*0x1000+3
+       %assign i i+1
+       %endrep
+[global Kernel_Stack_Top]
+ALIGN 4096
+       times 1024      dd      0
+Kernel_Stack_Top:
+gInitAPStacks:
+       times 32*MAX_CPUS       dd      0
+
+; vim: ft=nasm ts=8    
diff --git a/KernelLand/Kernel/arch/x86/time.c b/KernelLand/Kernel/arch/x86/time.c
new file mode 100644 (file)
index 0000000..9b59b30
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Acess2 Kernel
+ * Timekeeping
+ * arch/x86/time.c
+ */
+#include <acess.h>
+
+// === MACROS ===
+#define        TIMER_QUANTUM   100
+// 2^(15-rate), 14: 2Hz, 5: 1024Hz, 2: 8192Hz
+// (Max: 14, Min: 2) - 14 = 2Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
+//#define TIMER_RATE   10      // 32 Hz
+//#define TIMER_RATE   12      // 8 Hz
+#define TIMER_RATE     14      // 2 Hz - Lowest
+#define TIMER_FREQ     (0x8000>>TIMER_RATE)    //Hz
+#define MS_PER_TICK_WHOLE      (1000/(TIMER_FREQ))
+#define MS_PER_TICK_FRACT      ((0x80000000*(1000%TIMER_FREQ))/TIMER_FREQ)
+
+// === IMPORTS ===
+extern volatile Sint64 giTimestamp;
+extern volatile Uint64 giTicks;
+extern volatile Uint64 giPartMiliseconds;
+extern void    Timer_CallTimers(void);
+
+// === GLOBALS ===
+volatile Uint64        giTime_TSCAtLastTick = 0;
+volatile Uint64        giTime_TSCPerTick = 0;
+
+// === PROTOTYPES ===
+//Sint64       now(void);
+ int   Time_Setup(void);
+void   Time_Interrupt(int IRQ, void *Ptr);
+Uint64 Time_ReadTSC(void);
+
+// === CODE ===
+/**
+ * \fn Sint64 now()
+ * \brief Return the current timestamp
+ */
+Sint64 now(void)
+{
+       Uint64  tsc = Time_ReadTSC();
+       tsc -= giTime_TSCAtLastTick;
+       tsc *= MS_PER_TICK_WHOLE;
+       if( giTime_TSCPerTick ) {
+               tsc /= giTime_TSCPerTick;
+       }
+       else
+               tsc = 0;
+       return giTimestamp + tsc;
+}
+
+/**
+ * \fn int Time_Setup(void)
+ * \brief Sets the system time from the Realtime-Clock
+ */
+int Time_Setup(void)
+{
+       Uint8   val;
+       
+       Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
+               TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
+       
+       outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
+       __asm__ __volatile__ ("cli");   // Disable normal interrupts
+       
+       // Set IRQ8 firing rate
+       outb(0x70, 0x0A);       // Set the index to register A
+       val = inb(0x71); // Get the current value of register A
+       val &= 0xF0;
+       val |= TIMER_RATE+1;
+       outb(0x70, 0x0A); // Reset index to A
+       outb(0x71, val);        // Update the timer rate
+               
+       // Enable IRQ8
+       outb(0x70, 0x0B);       // Set the index to register B
+       val = inb(0x71);        // Read the current value of register B
+       outb(0x70, 0x0B);       // Set the index again (a read will reset the index to register D)
+       outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
+       
+       __asm__ __volatile__ ("sti");   // Re-enable normal interrupts
+       outb(0x70, inb(0x70)|0x80);     // Re-enable NMIs
+       
+       // Install IRQ Handler
+       IRQ_AddHandler(8, Time_Interrupt, NULL);
+       
+       // Make sure the RTC actually fires
+       outb(0x70, 0x0C); // Select register C
+       inb(0x71);      // Just throw away contents.
+       
+       return 0;
+}
+
+/**
+ * \brief Called on the timekeeping IRQ
+ */
+void Time_Interrupt(int IRQ, void *Ptr)
+{
+       Uint64  curTSC = Time_ReadTSC();
+       
+       if( giTime_TSCAtLastTick )
+       {
+               giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
+       }
+       giTime_TSCAtLastTick = curTSC;
+       
+       giTicks ++;
+       giTimestamp += MS_PER_TICK_WHOLE;
+       giPartMiliseconds += MS_PER_TICK_FRACT;
+       if(giPartMiliseconds > 0x80000000) {
+               giTimestamp ++;
+               giPartMiliseconds -= 0x80000000;
+       }
+       
+       Timer_CallTimers();
+
+       // Make sure the RTC Fires again
+       outb(0x70, 0x0C); // Select register C
+       inb(0x71);      // Just throw away contents.
+}
+
+Uint64 Time_ReadTSC(void)
+{
+       Uint32  a, d;
+       __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
+       return ((Uint64)d << 32) | a;
+}
diff --git a/KernelLand/Kernel/arch/x86/vm8086.c b/KernelLand/Kernel/arch/x86/vm8086.c
new file mode 100644 (file)
index 0000000..6134862
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Acess2 VM8086 Driver
+ * - By John Hodge (thePowersGang)
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <vm8086.h>
+#include <modules.h>
+#include <hal_proc.h>
+#include <semaphore.h>
+
+// === CONSTANTS ===
+#define VM8086_MAGIC_CS        0xFFFF
+#define VM8086_MAGIC_IP        0x0010
+#define VM8086_STACK_SEG       0x9F00
+#define VM8086_STACK_OFS       0x0AFE
+enum eVM8086_Opcodes
+{
+       VM8086_OP_PUSHF   = 0x9C,
+       VM8086_OP_POPF    = 0x9D,
+       VM8086_OP_INT_I   = 0xCD,
+       VM8086_OP_IRET    = 0xCF,
+       VM8086_OP_IN_AD   = 0xEC,
+       VM8086_OP_IN_ADX  = 0xED,
+       VM8086_OP_OUT_AD  = 0xEE,
+       VM8086_OP_OUT_ADX = 0xEF
+};
+#define VM8086_PAGES_PER_INST  4
+
+#define VM8086_BLOCKSIZE       128
+#define VM8086_BLOCKCOUNT      ((0x9F000-0x10000)/VM8086_BLOCKSIZE)
+
+// === TYPES ===
+struct sVM8086_InternalData
+{
+       struct {
+               Uint32  Bitmap; // 32 sections = 128 byte blocks
+               tVAddr  VirtBase;
+               tPAddr  PhysAddr;
+       }       AllocatedPages[VM8086_PAGES_PER_INST];
+};
+
+// === PROTOTYPES ===
+ int   VM8086_Install(char **Arguments);
+void   VM8086_GPF(tRegs *Regs);
+//tVM8086      *VM8086_Init(void);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL);
+tMutex glVM8086_Process;
+tSemaphore     gVM8086_TaskComplete;
+tSemaphore     gVM8086_TasksToDo;
+tPID   gVM8086_WorkerPID;
+tTID   gVM8086_CallingThread;
+tVM8086        volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions
+Uint32 gaVM8086_MemBitmap[VM8086_BLOCKCOUNT/32];
+
+// === FUNCTIONS ===
+int VM8086_Install(char **Arguments)
+{
+       tPID    pid;    
+
+       Semaphore_Init(&gVM8086_TasksToDo, 0, 10, "VM8086", "TasksToDo");
+       
+       // Lock to avoid race conditions
+       Mutex_Acquire( &glVM8086_Process );
+       
+       // Create BIOS Call process
+       pid = Proc_Clone(CLONE_VM);
+       Log_Debug("VM8086", "pid = %i", pid);
+       if(pid == -1)
+       {
+               Log_Error("VM8086", "Unable to clone kernel into VM8086 worker");
+               return MODULE_ERR_MISC;
+       }
+       if(pid == 0)
+       {
+               Uint    * volatile stacksetup;  // Initialising Stack
+               Uint16  * volatile rmstack;     // Real Mode Stack
+                int    i;
+
+               Log_Debug("VM8086", "Initialising worker");     
+       
+               // Set Image Name
+               Threads_SetName("VM8086");
+
+               // Map ROM Area
+               for(i=0xA0;i<0x100;i++) {
+                       MM_Map( i * 0x1000, i * 0x1000 );
+               }
+               MM_Map( 0, 0 ); // IVT / BDA
+               // Map (but allow allocation) of 0x1000 - 0x9F000
+               // - So much hack, it isn't funny
+               for(i=1;i<0x9F;i++) {
+                       MM_Map( i * 0x1000, i * 0x1000 );
+                       MM_DerefPhys( i * 0x1000 );     // Above
+                       while(MM_GetRefCount(i*0x1000))
+                               MM_DerefPhys( i * 0x1000 );     // Phys setup
+               }
+               MM_Map( 0x9F000, 0x9F000 );     // Stack / EBDA
+               // System Stack / Stub
+               if( MM_Allocate( 0x100000 ) == 0 ) {
+                       Log_Error("VM8086", "Unable to allocate memory for stack/stub");
+                       gVM8086_WorkerPID = 0;
+                       Threads_Exit(0, 1);
+               }
+               
+               *(Uint8*)(0x100000) = VM8086_OP_IRET;
+               *(Uint8*)(0x100001) = 0x07;     // POP ES
+               *(Uint8*)(0x100002) = 0x1F;     // POP DS
+               *(Uint8*)(0x100003) = 0xCB;     // RET FAR
+               
+               rmstack = (Uint16*)(VM8086_STACK_SEG*16 + VM8086_STACK_OFS);
+               rmstack--;      *rmstack = 0xFFFF;      //CS
+               rmstack--;      *rmstack = 0x0010;      //IP
+               
+               // Setup Stack
+               stacksetup = (Uint*)0x101000;
+               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // GS
+               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // FS
+               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // DS
+               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // ES
+               stacksetup--;   *stacksetup = VM8086_STACK_SEG; // SS
+               stacksetup--;   *stacksetup = VM8086_STACK_OFS-2;       // SP
+               stacksetup--;   *stacksetup = 0x20202;  // FLAGS
+               stacksetup--;   *stacksetup = 0xFFFF;   // CS
+               stacksetup--;   *stacksetup = 0x10;     // IP
+               stacksetup--;   *stacksetup = 0xAAAA;   // AX
+               stacksetup--;   *stacksetup = 0xCCCC;   // CX
+               stacksetup--;   *stacksetup = 0xDDDD;   // DX
+               stacksetup--;   *stacksetup = 0xBBBB;   // BX
+               stacksetup--;   *stacksetup = 0x5454;   // SP
+               stacksetup--;   *stacksetup = 0xB4B4;   // BP
+               stacksetup--;   *stacksetup = 0x5151;   // SI
+               stacksetup--;   *stacksetup = 0xD1D1;   // DI
+               stacksetup--;   *stacksetup = 0x20|3;   // DS - Kernel
+               stacksetup--;   *stacksetup = 0x20|3;   // ES - Kernel
+               stacksetup--;   *stacksetup = 0x20|3;   // FS
+               stacksetup--;   *stacksetup = 0x20|3;   // GS
+               __asm__ __volatile__ (
+               "mov %%eax,%%esp;\n\t"  // Set stack pointer
+               "pop %%gs;\n\t"
+               "pop %%fs;\n\t"
+               "pop %%es;\n\t"
+               "pop %%ds;\n\t"
+               "popa;\n\t"
+               "iret;\n\t" : : "a" (stacksetup));
+               for(;;);        // Shouldn't be reached
+       }
+       
+       gVM8086_WorkerPID = pid;
+
+       // It's released when the GPF fires
+       Mutex_Acquire( &glVM8086_Process );
+       Mutex_Release( &glVM8086_Process );
+       
+       // Worker killed itself
+       if( gVM8086_WorkerPID != pid ) {
+               return MODULE_ERR_MISC;
+       }
+       
+       return MODULE_ERR_OK;
+}
+
+void VM8086_GPF(tRegs *Regs)
+{
+       Uint8   opcode;
+       
+//     Log_Log("VM8086", "GPF - %04x:%04x", Regs->cs, Regs->eip);
+       
+       if(Regs->eip == VM8086_MAGIC_IP && Regs->cs == VM8086_MAGIC_CS
+       && Threads_GetPID() == gVM8086_WorkerPID)
+       {
+               if( gpVM8086_State == (void*)-1 ) {
+                       Log_Log("VM8086", "Worker thread ready and waiting");
+                       gpVM8086_State = NULL;
+                       Mutex_Release( &glVM8086_Process );     // Release lock obtained in VM8086_Install
+               }
+//             Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i",
+//                     gpVM8086_State, gVM8086_CallingThread);
+               if( gpVM8086_State ) {
+                       gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx;
+                       gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx;
+                       gpVM8086_State->BP = Regs->ebp;
+                       gpVM8086_State->SI = Regs->esi; gpVM8086_State->DI = Regs->edi;
+                       gpVM8086_State->DS = Regs->ds;  gpVM8086_State->ES = Regs->es;
+                       gpVM8086_State = NULL;
+                       // Wake the caller
+                       Semaphore_Signal(&gVM8086_TaskComplete, 1);
+               }
+               
+               //Log_Log("VM8086", "Waiting for something to do");
+               __asm__ __volatile__ ("sti");
+               Semaphore_Wait(&gVM8086_TasksToDo, 1);
+               
+               //Log_Log("VM8086", "We have a task (%p)", gpVM8086_State);
+               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS;
+               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP;
+               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS;
+               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP;
+               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS;
+               Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES;
+               
+               // Set Registers
+               Regs->eip = 0x11;       Regs->cs = 0xFFFF;
+               Regs->eax = gpVM8086_State->AX; Regs->ecx = gpVM8086_State->CX;
+               Regs->edx = gpVM8086_State->DX; Regs->ebx = gpVM8086_State->BX;
+               Regs->esi = gpVM8086_State->SI; Regs->edi = gpVM8086_State->DI;
+               Regs->ebp = gpVM8086_State->BP;
+               Regs->ds = 0x23;        Regs->es = 0x23;
+               Regs->fs = 0x23;        Regs->gs = 0x23;
+               return ;
+       }
+       
+       opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip) );
+       Regs->eip ++;
+       switch(opcode)
+       {
+       case VM8086_OP_PUSHF:   //PUSHF
+               Regs->esp -= 2;
+               *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eflags & 0xFFFF;
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated PUSHF");
+               #endif
+               break;
+       case VM8086_OP_POPF:    //POPF
+               // Changing IF is not allowed
+               Regs->eflags &= 0xFFFF0202;
+               Regs->eflags |= *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) );
+               Regs->esp += 2;
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated POPF");
+               #endif
+               break;
+       
+       case VM8086_OP_INT_I:   //INT imm8
+               {
+                int    id;
+               id = *(Uint8*)( Regs->cs*16 +(Regs->eip&0xFFFF));
+               Regs->eip ++;
+               
+               Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs;
+               Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip;
+               
+               Regs->cs = *(Uint16*)(4*id + 2);
+               Regs->eip = *(Uint16*)(4*id);
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated INT 0x%x", id);
+               #endif
+               }
+               break;
+       
+       case VM8086_OP_IRET:    //IRET
+               Regs->eip = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) );     Regs->esp += 2;
+               Regs->cs  = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) );     Regs->esp += 2;
+               #if TRACE_EMU
+               Log_Debug("VM8086", "IRET to %04x:%04x", Regs->cs, Regs->eip);
+               #endif
+               break;
+       
+       
+       case VM8086_OP_IN_AD:   //IN AL, DX
+               Regs->eax &= 0xFFFFFF00;
+               Regs->eax |= inb(Regs->edx&0xFFFF);
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated IN AL, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
+               #endif
+               break;
+       case VM8086_OP_IN_ADX:  //IN AX, DX
+               Regs->eax &= 0xFFFF0000;
+               Regs->eax |= inw(Regs->edx&0xFFFF);
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated IN AX, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
+               #endif
+               break;
+               
+       case VM8086_OP_OUT_AD:  //OUT DX, AL
+               outb(Regs->edx&0xFFFF, Regs->eax&0xFF);
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated OUT DX, AL (*0x%04x = 0x%02x)\n", Regs->edx&0xFFFF, Regs->eax&0xFF);
+               #endif
+               break;
+       case VM8086_OP_OUT_ADX: //OUT DX, AX
+               outw(Regs->edx&0xFFFF, Regs->eax&0xFFFF);
+               #if TRACE_EMU
+               Log_Debug("VM8086", "Emulated OUT DX, AX (*0x%04x = 0x%04x)\n", Regs->edx&0xFFFF, Regs->eax&0xFFFF);
+               #endif
+               break;
+               
+       // TODO: Decide on allowing VM8086 Apps to enable/disable interrupts
+       case 0xFA:      //CLI
+               break;
+       case 0xFB:      //STI
+               break;
+       
+       case 0x66:
+               opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip&0xFFFF));
+               switch( opcode )
+               {
+               case VM8086_OP_IN_ADX:  //IN AX, DX
+                       Regs->eax = ind(Regs->edx&0xFFFF);
+                       #if TRACE_EMU
+                       Log_Debug("VM8086", "Emulated IN EAX, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
+                       #endif
+                       break;
+               case VM8086_OP_OUT_ADX: //OUT DX, AX
+                       outd(Regs->edx&0xFFFF, Regs->eax);
+                       #if TRACE_EMU
+                       Log_Debug("VM8086", "Emulated OUT DX, EAX (*0x%04x = 0x%08x)\n", Regs->edx&0xFFFF, Regs->eax);
+                       #endif
+                       break;
+               default:
+                       Log_Error("VM8086", "Error - Unknown opcode 66 %02x caused a GPF at %04x:%04x",
+                               Regs->cs, Regs->eip,
+                               opcode
+                               );
+                       // Force an end to the call
+                       Regs->cs = VM8086_MAGIC_CS;
+                       Regs->eip = VM8086_MAGIC_IP;
+                       break;
+               }
+               break;
+       
+       default:
+               Log_Error("VM8086", "Error - Unknown opcode %02x caused a GPF at %04x:%04x",
+                       opcode, Regs->cs, Regs->eip);
+               // Force an end to the call
+               Regs->cs = VM8086_MAGIC_CS;
+               Regs->eip = VM8086_MAGIC_IP;
+               break;
+       }
+}
+
+/**
+ * \brief Create an instance of the VM8086 Emulator
+ */
+tVM8086 *VM8086_Init(void)
+{
+       tVM8086 *ret;
+       ret = calloc( 1, sizeof(tVM8086) + sizeof(struct sVM8086_InternalData) );
+       ret->Internal = (void*)((tVAddr)ret + sizeof(tVM8086));
+       return ret;
+}
+
+void VM8086_Free(tVM8086 *State)
+{
+        int    i;
+       for( i = VM8086_PAGES_PER_INST; i --; )
+               MM_UnmapHWPages( State->Internal->AllocatedPages[i].VirtBase, 1);
+       free(State);
+}
+
+void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset)
+{
+        int    i, j, base = 0;
+        int    nBlocks, rem;
+       
+       Size = (Size + 127) & ~127;
+       nBlocks = Size / 128;
+       
+       if(Size > 4096) return NULL;
+       
+       for( i = 0; i < VM8086_PAGES_PER_INST; i++ )
+       {
+               if( State->Internal->AllocatedPages[i].VirtBase == 0 )  continue;
+               
+               
+               //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap);
+               
+               rem = nBlocks;
+               base = 0;
+               // Scan the bitmap for a free block
+               for( j = 0; j < 32; j++ ) {
+                       if( State->Internal->AllocatedPages[i].Bitmap & (1 << j) ) {
+                               base = j+1;
+                               rem = nBlocks;
+                       }
+                       
+                       rem --;
+                       if(rem == 0)    // Goodie, there's a gap
+                       {
+                               for( j = 0; j < nBlocks; j++ )
+                                       State->Internal->AllocatedPages[i].Bitmap |= 1 << (base + j);
+                               *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16 + base * 8;
+                               *Offset = 0;
+                               LOG("Allocated at #%i,%04x", i, base*128);
+                               LOG(" - %x:%x", *Segment, *Offset);
+                               return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 );
+                       }
+               }
+       }
+       
+       // No pages with free space?, allocate a new one
+       for( i = 0; i < VM8086_PAGES_PER_INST; i++ )
+       {
+               if( State->Internal->AllocatedPages[i].VirtBase == 0 )  break;
+       }
+       // Darn, we can't allocate any more
+       if( i == VM8086_PAGES_PER_INST ) {
+               Log_Warning("VM8086", "Out of pages in %p", State);
+               return NULL;
+       }
+       
+       State->Internal->AllocatedPages[i].VirtBase = MM_AllocDMA(
+               1, 20, &State->Internal->AllocatedPages[i].PhysAddr);
+       State->Internal->AllocatedPages[i].Bitmap = 0;
+               
+       for( j = 0; j < nBlocks; j++ )
+               State->Internal->AllocatedPages[i].Bitmap |= 1 << j;
+       LOG("AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap);
+       *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16;
+       *Offset = 0;
+       LOG(" - %x:%x", *Segment, *Offset);
+       return (void*) State->Internal->AllocatedPages[i].VirtBase;
+}
+
+void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset)
+{
+       return (void*)( KERNEL_BASE + Segment*16 + Offset );
+}
+
+void VM8086_Int(tVM8086 *State, Uint8 Interrupt)
+{
+       State->IP = *(Uint16*)(KERNEL_BASE+4*Interrupt);
+       State->CS = *(Uint16*)(KERNEL_BASE+4*Interrupt+2);
+
+//     Log_Debug("VM8086", "Software interrupt %i to %04x:%04x", Interrupt, State->CS, State->IP);
+       
+       Mutex_Acquire( &glVM8086_Process );
+       
+       gpVM8086_State = State;
+       gVM8086_CallingThread = Threads_GetTID();
+       Semaphore_Signal(&gVM8086_TasksToDo, 1);
+
+       Semaphore_Wait(&gVM8086_TaskComplete, 1);
+       
+       Mutex_Release( &glVM8086_Process );
+}
diff --git a/KernelLand/Kernel/arch/x86_64/Makefile b/KernelLand/Kernel/arch/x86_64/Makefile
new file mode 100644 (file)
index 0000000..a72216a
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Acess2 Kernel
+# i386 Architecture Makefile
+# arch/i386/Makefile
+
+MAX_CPUS := 4
+
+AS_SUFFIX = asm
+
+CPPFLAGS       := -DMAX_CPUS=$(MAX_CPUS) -D USE_MP=0
+CFLAGS         := $(KERNEL_CFLAGS) -mno-sse -mno-mmx
+ASFLAGS                := -f elf64 -D MAX_CPUS=$(MAX_CPUS) -D USE_MP=0
+LDFLAGS        := -nostdlib -nodefaultlibs
+
+ifeq ($(ARCH),amd64)
+       ASFLAGS += -D AMD64=1
+       CPPFLAGS += -DAMD64=1
+else
+       ifeq ($(ARCH),x86_64)
+               ASFLAGS += -D AMD64=0 -D X86_64=1
+               CPPFLAGS += -DAMD64=0 -DX86_64=1
+       endif
+endif
+       
+
+A_OBJ := start32.ao start64.ao desctab.ao proc.ao
+A_OBJ += main.o lib.o proc.o mm_virt.o mm_phys.o
+A_OBJ += kernelpanic.o errors.o time.o pci.o
+A_OBJ += vm8086.o
+# rme.o
+
+POSTBUILD = objcopy $(BIN) -F elf32-i386 $(BIN)
diff --git a/KernelLand/Kernel/arch/x86_64/desctab.asm b/KernelLand/Kernel/arch/x86_64/desctab.asm
new file mode 100644 (file)
index 0000000..6e8aa63
--- /dev/null
@@ -0,0 +1,438 @@
+;
+;
+;
+%include "arch/x86_64/include/common.inc.asm"
+[BITS 64]
+
+[extern Log]
+[extern gGDTPtr]
+[extern gGDT]
+
+%define NUM_IRQ_CALLBACKS      4
+
+MM_LOCALAPIC   equ     0xFFFFFD0000000000
+
+[section .text]
+[global Desctab_Init]
+Desctab_Init:  
+       ; Save to make following instructions smaller
+       mov rdi, gIDT
+       
+       ; Set an IDT entry to a callback
+       %macro SETIDT 2
+       mov rax, %2
+       mov WORD [rdi + %1*16], ax
+       shr rax, 16
+       mov WORD [rdi + %1*16 + 6], ax
+       shr rax, 16
+       mov DWORD [rdi + %1*16 + 8], eax
+       ; Enable
+       mov ax, WORD [rdi + %1*16 + 4]
+       or  ax, 0x8000
+       mov WORD [rdi + %1*16 + 4], ax
+       %endmacro
+       
+       ; Install error handlers
+       %macro SETISR 1
+       SETIDT %1, Isr%1
+       %endmacro
+       
+       %assign i 0
+       %rep 32
+       SETISR i
+       %assign i i+1
+       %endrep
+       
+       ; Install IRQs
+       SETIDT  0xF0, PIT_IRQ
+       SETIDT  0xF1, Irq1
+       SETIDT  0xF2, Irq2
+       SETIDT  0xF3, Irq3
+       SETIDT  0xF4, Irq4
+       SETIDT  0xF5, Irq5
+       SETIDT  0xF6, Irq6
+       SETIDT  0xF7, Irq7
+       SETIDT  0xF8, Irq8
+       SETIDT  0xF9, Irq9
+       SETIDT  0xFA, Irq10
+       SETIDT  0xFB, Irq11
+       SETIDT  0xFC, Irq12
+       SETIDT  0xFD, Irq13
+       SETIDT  0xFE, Irq14
+       SETIDT  0xFF, Irq15
+
+       ; Remap PIC
+       push rdx        ; Save RDX
+       mov dx, 0x20
+       mov al, 0x11
+       out dx, al      ;       Init Command
+       mov dx, 0x21
+       mov al, 0xF0
+       out dx, al      ;       Offset (Start of IDT Range)
+       mov al, 0x04
+       out dx, al      ;       IRQ connected to Slave (00000100b) = IRQ2
+       mov al, 0x01
+       out dx, al      ;       Set Mode
+       mov al, 0x00
+       out dx, al      ;       Set Mode
+       
+       mov dx, 0xA0
+       mov al, 0x11
+       out dx, al      ;       Init Command
+       mov dx, 0xA1
+       mov al, 0xF8
+       out dx, al      ;       Offset (Start of IDT Range)
+       mov al, 0x02
+       out dx, al      ;       IRQ Line connected to master
+       mov al, 0x01
+       out dx, al      ;       Set Mode
+       mov dl, 0x00
+       out dx, al      ;       Set Mode
+       pop rdx
+       
+       
+       ; Install IDT
+       mov rax, gIDTPtr
+       lidt [rax]
+       
+       ; Re-install GDT (in higher address space)
+       mov rax, gGDTPtr
+       mov rcx, gGDT
+       mov QWORD [rax+2], rcx
+       lgdt [rax]
+       
+       ; Start interrupts
+       sti
+
+       ; Set IA32_LSTAR (RIP of handler)
+       mov ecx, 0xC0000082     ; IA32_LSTAR
+       mov eax, SyscallStub - 0xFFFFFFFF00000000
+       mov edx, 0xFFFFFFFF
+       wrmsr
+       ; Set IA32_FMASK (flags mask)
+       mov ecx, 0xC0000084
+       rdmsr
+       mov eax, ~0x202
+       wrmsr
+       ; Set IA32_STAR (Kernel/User CS)
+       mov ecx, 0xC0000081
+       rdmsr
+       mov edx, 0x8 | (0x1B << 16)     ; Kernel CS (and Kernel DS/SS - 8), User CS
+       wrmsr
+       
+       ret
+
+; int IRQ_AddHandler(int IRQ, void (*Handler)(int IRQ), void *Ptr)
+; Return Values:
+;  0 on Success
+; -1 on an invalid IRQ Number
+; -2 when no slots are avaliable
+[global IRQ_AddHandler]
+IRQ_AddHandler:
+       ; RDI - IRQ Number
+       ; RSI - Callback
+       ; RDX - Ptr
+       
+       ; Check for RDI >= 16
+       cmp rdi, 16
+       jb .numOK
+       xor rax, rax
+       dec rax
+       jmp .ret
+.numOK:
+
+       ; Get handler base into RAX
+       lea rax, [rdi*4]
+       mov rcx, gaIRQ_Handlers
+       lea rax, [rcx+rax*8]
+       
+       ; Find a free callback slot
+       %rep NUM_IRQ_CALLBACKS
+       mov rcx, [rax]
+       test rcx, rcx
+       jz .assign
+       add rax, 8
+       %endrep
+       ; None found, return -2
+       xor rax, rax
+       dec rax
+       dec rax
+       jmp .ret
+       
+       ; Assign the IRQ Callback
+.assign:
+       ; A little bit of debug
+       push rdi
+       push rsi
+       push rax
+       push rdx
+       sub rsp, 8
+       mov rcx, rdi    ; IRQ Number
+       mov rdx, rsi    ; Callback
+       mov rsi, rax    ; Pointer
+       mov rdi, csIRQ_Assigned
+       call Log
+       add rsp, 8
+       pop rdx
+       pop rax
+       pop rsi
+       pop rdi
+
+       ; Assign and return
+       mov [rax], rsi
+       add rax, gaIRQ_DataPtrs - gaIRQ_Handlers
+       mov [rax], rdx
+       xor rax, rax
+
+.ret:
+       ret
+       
+[section .rodata]
+csIRQ_Assigned:
+       db      "IRQ %p := %p (IRQ %i)",0
+csIRQ_Fired:
+       db      "IRQ %i fired",0
+[section .text]
+
+%macro ISR_NOERRNO     1
+Isr%1:
+       push    QWORD 0
+       push    QWORD %1
+       jmp     ErrorCommon
+%endmacro
+%macro ISR_ERRNO       1
+Isr%1:
+       push    QWORD %1
+       jmp     ErrorCommon
+%endmacro
+
+ISR_NOERRNO    0;  0: Divide By Zero Exception
+ISR_NOERRNO    1;  1: Debug Exception
+ISR_NOERRNO    2;  2: Non Maskable Interrupt Exception
+ISR_NOERRNO    3;  3: Int 3 Exception
+ISR_NOERRNO    4;  4: INTO Exception
+ISR_NOERRNO    5;  5: Out of Bounds Exception
+ISR_NOERRNO    6;  6: Invalid Opcode Exception
+ISR_NOERRNO    7;  7: Coprocessor Not Available Exception
+ISR_ERRNO      8;  8: Double Fault Exception (With Error Code!)
+ISR_NOERRNO    9;  9: Coprocessor Segment Overrun Exception
+ISR_ERRNO      10; 10: Bad TSS Exception (With Error Code!)
+ISR_ERRNO      11; 11: Segment Not Present Exception (With Error Code!)
+ISR_ERRNO      12; 12: Stack Fault Exception (With Error Code!)
+ISR_ERRNO      13; 13: General Protection Fault Exception (With Error Code!)
+ISR_ERRNO      14; 14: Page Fault Exception (With Error Code!)
+ISR_NOERRNO    15; 15: Reserved Exception
+ISR_NOERRNO    16; 16: Floating Point Exception
+ISR_NOERRNO    17; 17: Alignment Check Exception
+ISR_NOERRNO    18; 18: Machine Check Exception
+ISR_NOERRNO    19; 19: Reserved
+ISR_NOERRNO    20; 20: Reserved
+ISR_NOERRNO    21; 21: Reserved
+ISR_NOERRNO    22; 22: Reserved
+ISR_NOERRNO    23; 23: Reserved
+ISR_NOERRNO    24; 24: Reserved
+ISR_NOERRNO    25; 25: Reserved
+ISR_NOERRNO    26; 26: Reserved
+ISR_NOERRNO    27; 27: Reserved
+ISR_NOERRNO    28; 28: Reserved
+ISR_NOERRNO    29; 29: Reserved
+ISR_NOERRNO    30; 30: Reserved
+ISR_NOERRNO    31; 31: Reserved
+
+[extern Error_Handler]
+[global ErrorCommon]
+ErrorCommon:
+       PUSH_GPR
+       push gs
+       push fs
+       ;PUSH_FPU
+       ;PUSH_XMM
+       
+       mov rdi, rsp
+;      xchg bx, bx
+       call Error_Handler
+       
+       ;POP_XMM
+       ;POP_FPU
+       pop fs
+       pop gs
+       POP_GPR
+       add rsp, 2*8
+       iretq
+
+%macro DEFIRQ  1
+Irq%1:
+       push    0
+       push    %1
+       jmp     IrqCommon
+%endmacro
+
+%assign i 0
+%rep 16
+DEFIRQ i
+%assign i i+1
+%endrep
+
+[global IrqCommon]
+IrqCommon:
+       PUSH_GPR
+       push gs
+       push fs
+
+;      mov rdi, csIRQ_Fired
+;      mov rsi, [rsp+(16+2)*8]
+;      call Log
+       
+       mov ebx, [rsp+(16+2)*8] ; Get interrupt number (16 GPRS + 2 SRs)
+       shl ebx, 2      ; *4
+       mov rax, gaIRQ_Handlers
+       lea rbx, [rax+rbx*8]
+       
+       ; Check all callbacks
+       sub rsp, 8      ; Shadow of argument
+       %assign i 0
+       %rep NUM_IRQ_CALLBACKS
+       ; Get callback address
+       mov rax, [rbx]
+       test rax, rax   ; Check if it exists
+       jz .skip.%[i]
+       ; Set RDI to IRQ number
+       mov rdi, [rsp+(16+2+1)*8]       ; Get IRQ number
+       mov rsi, [rbx-gaIRQ_Handlers+gaIRQ_DataPtrs]
+       call rax        ; Call
+.skip.%[i]:
+       add rbx, 8      ; Next!
+       %assign i i+1
+       %endrep
+       add rsp, 8
+       
+       ; ACK
+       mov al, 0x20
+       mov rdi, [rsp+(16+2)*8] ; Get IRQ number
+       cmp rdi, 8
+       jb .skipAckSecondary
+       out 0xA0, al
+.skipAckSecondary:
+       out 0x20, al
+       
+       pop fs
+       pop gs
+       POP_GPR
+       add rsp, 8*2
+       iretq
+
+[extern Time_UpdateTimestamp]
+
+%if USE_MP
+[global APIC_Timer_IRQ]
+APIC_Timer_IRQ:
+       PUSH_GPR
+       push gs
+       push fs
+
+       ; TODO: What to do?
+
+       mov eax, DWORD [gpMP_LocalAPIC]
+       mov DWORD [eax+0x0B0], 0
+
+       pop fs
+       pop gs
+       POP_GPR
+       iretq
+%endif
+
+[global PIT_IRQ]
+PIT_IRQ:
+       PUSH_GPR
+       ;PUSH_FPU
+       ;PUSH_XMM
+       
+       call Time_UpdateTimestamp
+
+       %if 0
+[section .rodata]
+csUserSS:      db      "User SS: 0x%x",0
+[section .text]
+       mov rdi, csUserSS
+       mov rsi, [rsp+0x80+0x20]
+       call Log
+       %endif
+
+       ; Send EOI
+       mov al, 0x20
+       out 0x20, al            ; ACK IRQ
+       
+       ;POP_XMM
+       ;POP_FPU
+       POP_GPR
+       iretq
+
+[extern ci_offsetof_tThread_KernelStack]
+[extern SyscallHandler]
+[global SyscallStub]
+SyscallStub:
+       mov rbp, dr0
+       mov ebx, [rel ci_offsetof_tThread_KernelStack]
+       mov rbp, [rbp+rbx]      ; Get kernel stack
+       xchg rbp, rsp   ; Swap stacks
+
+       push rbp        ; Save User RSP
+       push rcx        ; RIP
+       push r11        ; RFLAGS
+
+       ; RDI
+       ; RSI
+       ; RDX
+       ; R10 (RCX for non syscall)
+       ; R8
+       ; R9
+       sub rsp, (6+2)*8
+       mov [rsp+0x00], rax     ; Number
+;      mov [rsp+0x08], rax     ; Errno (output only)
+       mov [rsp+0x10], rdi     ; Arg1
+       mov [rsp+0x18], rsi     ; Arg2
+       mov [rsp+0x20], rdx     ; Arg3
+       mov [rsp+0x28], r10     ; Arg4
+       mov [rsp+0x30], r8      ; Arg5
+       mov [rsp+0x38], r9      ; Arg6
+       
+       mov rdi, rsp
+       sub rsp, 8
+       call SyscallHandler
+
+       %if 0
+[section .rodata]
+csSyscallReturn:       db      "Syscall Return: 0x%x",0
+[section .text]
+       mov rdi, csSyscallReturn
+       mov rsi, [rsp+0+8]
+       call Log
+       %endif
+
+       add rsp, 8
+       mov ebx, [rsp+8]        ; Get errno
+       mov rax, [rsp+0]        ; Get return
+       add rsp, (6+2)*8
+
+       pop r11
+       pop rcx
+       pop rsp         ; Change back to user stack
+       ; TODO: Determine if user is 64 or 32 bit
+
+       db 0x48 ; REX, nasm doesn't have a sysretq opcode
+       sysret
+
+[section .data]
+gIDT:
+       ; 64-bit Interrupt Gate, CS = 0x8, IST0 (Disabled)
+       times 256       dd      0x00080000, 0x00000E00, 0, 0
+gIDTPtr:
+       dw      256*16-1
+       dq      gIDT
+
+gaIRQ_Handlers:
+       times   16*NUM_IRQ_CALLBACKS    dq      0
+gaIRQ_DataPtrs:
+       times   16*NUM_IRQ_CALLBACKS    dq      0
+
+; vim: ft=nasm
diff --git a/KernelLand/Kernel/arch/x86_64/errors.c b/KernelLand/Kernel/arch/x86_64/errors.c
new file mode 100644 (file)
index 0000000..f7da7f9
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Acess2 x86_64 Project
+ * - Error Handling
+ */
+#include <acess.h>
+#include <proc.h>
+#include <mm_virt.h>
+#include <threads_int.h>       // Needed for SSE handling
+
+#define MAX_BACKTRACE  6
+
+// === IMPORTS ===
+extern int     MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
+extern void    Error_Backtrace(Uint IP, Uint BP);
+extern void    Proc_EnableSSE(void);
+extern void    Proc_RestoreSSE(Uint32 Data);
+
+// === PROTOTYPES ===
+void   Error_Handler(tRegs *Regs);
+
+// === GLOBALS ==
+const char * const csaERROR_NAMES[] = {
+       "Divide By Zero", "Debug", "NMI Exception", "INT3",
+       "INTO", "Out of Bounds", "Invalid Opcode", "Coprocessor not avaliable",
+       "Double Fault", "Coprocessor Segment Overrun", "Bad TSS", "Segment Not Present",
+       "Stack Fault Exception", "GPF", "#PF", "Reserved",
+       "Floating Point Exception", "Alignment Check Exception", "Machine Check Exception",     "Reserved",
+       "Reserved", "Reserved", "Reserved", "Reserved",
+       "Reserved", "Reserved", "Reserved", "Reserved",
+       "Reserved", "Reserved", "Reserved", "Reserved"
+       };
+
+// === CODE ===
+void Error_Handler(tRegs *Regs)
+{
+       Uint    cr;
+
+       if( Regs->IntNum == 7 )
+       {
+               tThread *thread = Proc_GetCurThread();
+               if(!thread->SavedState.bSSEModified)
+               {
+                       Proc_EnableSSE();
+                       if(!thread->SavedState.SSE)
+                               thread->SavedState.SSE = malloc(sizeof(tSSEState) + 0xF);
+                       else
+                               Proc_RestoreSSE( ((Uint)thread->SavedState.SSE + 0xF) & ~0xF );
+                       thread->SavedState.bSSEModified = 1;
+//                     __asm__ __volatile__ ("sti");
+                       return ;
+               }
+               // oops, SSE enabled but a #NM, bad news
+       }
+       
+       if( Regs->IntNum == 14 ) {
+               __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
+               if( MM_PageFault(cr, Regs->ErrorCode, Regs) == 0 )
+                       return ;
+       }
+       else {
+               Debug_KernelPanic();
+
+               Error_Backtrace(Regs->RIP, Regs->RBP);
+       }
+       
+       Log("CPU Error %x, Code: 0x%x", Regs->IntNum, Regs->ErrorCode);
+       Log(" - %s", csaERROR_NAMES[Regs->IntNum]);
+       Log(" CS:RIP = 0x%04x:%016llx", Regs->CS, Regs->RIP);
+       Log(" SS:RSP = 0x%04x:%016llx", Regs->SS, Regs->RSP);
+       Log(" RFLAGS = 0x%016llx", Regs->RFlags);
+       
+       Log(" RAX %016llx RCX %016llx RDX %016llx RBX %016llx",
+               Regs->RAX, Regs->RCX, Regs->RDX, Regs->RBX);
+       Log(" RSP %016llx RBP %016llx RSI %016llx RDI %016llx",
+               Regs->RSP, Regs->RBP, Regs->RSP, Regs->RDI);
+       Log(" R8  %016llx R9  %016llx R10 %016llx R11 %016llx",
+               Regs->R8, Regs->R9, Regs->R10, Regs->R11);
+       Log(" R12 %016llx R13 %016llx R14 %016llx R15 %016llx",
+               Regs->R12, Regs->R13, Regs->R14, Regs->R15);
+       Log(" FS %04x GS %04x", Regs->FS, Regs->GS);
+       
+       
+       // Control Registers
+       __asm__ __volatile__ ("mov %%cr0, %0":"=r"(cr));
+       Warning(" CR0 0x%08x", cr);
+       __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
+       Warning(" CR2 0x%016llx", cr);
+       __asm__ __volatile__ ("mov %%cr3, %0":"=r"(cr));
+       Warning(" CR3 0x%016llx", cr);
+       __asm__ __volatile__ ("mov %%cr4, %0":"=r"(cr));
+       Warning(" CR4 0x%08x", cr);
+       
+       switch( Regs->IntNum )
+       {
+       case 6: // #UD
+               Warning(" Offending bytes: %02x %02x %02x %02x",
+                       *(Uint8*)(Regs->RIP+0), *(Uint8*)(Regs->RIP+1),
+                       *(Uint8*)(Regs->RIP+2), *(Uint8*)(Regs->RIP+3)
+                       );
+               break;
+       }
+       
+       __asm__ __volatile__ ("cli");
+       for(;;)
+               __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Error_Backtrace(Uint eip, Uint ebp)
+ * \brief Unrolls the stack to trace execution
+ * \param eip  Current Instruction Pointer
+ * \param ebp  Current Base Pointer (Stack Frame)
+ */
+void Error_Backtrace(Uint IP, Uint BP)
+{
+        int    i = 0;
+       
+       //if(eip < 0xC0000000 && eip > 0x1000)
+       //{
+       //      LogF("Backtrace: User - 0x%x\n", eip);
+       //      return;
+       //}
+       
+       if( IP > USER_MAX && IP < MM_KERNEL_CODE
+        && (MM_MODULE_MIN > IP || IP > MM_MODULE_MAX)
+               )
+       {
+               LogF("Backtrace: Data Area - %p\n", IP);
+               return;
+       }
+       
+       //str = Debug_GetSymbol(eip, &delta);
+       //if(str == NULL)
+               LogF("Backtrace: %p", IP);
+       //else
+       //      LogF("Backtrace: %s+0x%x", str, delta);
+       if( !MM_GetPhysAddr(BP) )
+       {
+               LogF("\nBacktrace: Invalid BP, stopping\n");
+               return;
+       }
+       
+       
+       while( MM_GetPhysAddr(BP) && MM_GetPhysAddr(BP+8+7) && i < MAX_BACKTRACE )
+       {
+               //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
+               //if(str == NULL)
+                       LogF(" >> 0x%llx", ((Uint*)BP)[1]);
+               //else
+               //      LogF(" >> %s+0x%x", str, delta);
+               BP = ((Uint*)BP)[0];
+               i++;
+       }
+       LogF("\n");
+}
diff --git a/KernelLand/Kernel/arch/x86_64/include/arch.h b/KernelLand/Kernel/arch/x86_64/include/arch.h
new file mode 100644 (file)
index 0000000..bde7abd
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Acess2 x86-64 Architecure Module
+ * - By John Hodge (thePowersGang)
+ */
+#ifndef _ARCH_H_
+#define _ARCH_H_
+
+//#include <stdint.h>
+#define        USER_MAX        0x00007FFF##FFFFF000
+#define KERNEL_BASE    0xFFFFFFFF##80000000
+#define BITS   64
+#define PAGE_SIZE      0x1000
+
+#define STACKED_LOCKS  2       // 0: No, 1: Per-CPU, 2: Per-Thread
+#define LOCK_DISABLE_INTS      0
+
+#define INVLPTR        ((void*)0x0FFFFFFFFFFFFFFFULL)
+
+//#define INT_MAX      0x7FFFFFFF
+//#define UINT_MAX     0xFFFFFFFF
+
+// === Core Types ===
+typedef signed char    Sint8;
+typedef unsigned char  Uint8;
+typedef signed short   Sint16;
+typedef unsigned short Uint16;
+typedef signed int     Sint32;
+typedef unsigned int   Uint32;
+#if __WORDSIZE == 64
+typedef signed long int        Sint64;
+typedef unsigned long int      Uint64;
+#else
+typedef signed long long int   Sint64;
+typedef unsigned long long int Uint64;
+#endif
+
+typedef Sint64 Sint;
+typedef Uint64 Uint;
+typedef Uint64 tPAddr;
+typedef Uint64 tVAddr;
+
+typedef Uint64 size_t;
+typedef char   BOOL;
+
+#define __ASM__        __asm__ __volatile__
+
+// === MACROS ===
+/**
+ * \brief Halt the CPU
+ */
+#define        HALT()  __asm__ __volatile__ ("sti;\n\thlt")
+/**
+ * \brief Fire a magic breakpoint (bochs)
+ */
+#define        MAGIC_BREAK()   __asm__ __volatile__ ("xchg %bx, %bx")
+
+// Systemcall Registers
+// TODO: Fix this structure
+typedef struct sSyscallRegs
+{
+       union {
+               Uint    Num;
+               Uint    Return;
+       };      // RAX
+       Uint    Error;  // RBX
+       Uint    Arg1;   // RDI
+       Uint    Arg2;   // RSI
+       Uint    Arg3;   // RDX
+       Uint    Arg4;   // RCX
+       Uint    Arg5;   // R8
+       Uint    Arg6;   // R9
+       Uint    _Flags;
+       Uint    _IP;
+       Uint    StackPointer;   // RSP
+       
+}      tSyscallRegs;
+
+/**
+ * \brief Short Spinlock structure
+ */
+struct sShortSpinlock {
+       #if STACKED_LOCKS == 2
+       volatile void   *Lock;  //!< Lock value
+       #else
+       volatile int    Lock;   //!< Lock value
+       #endif
+       
+       #if LOCK_DISABLE_INTS
+        int    IF;     //!< Interrupt state on call to SHORTLOCK
+       #endif
+       #if STACKED_LOCKS
+        int    Depth;
+       #endif
+};
+
+// === FUNCTIONS ===
+extern int     IS_LOCKED(struct sShortSpinlock *Lock);
+extern int     CPU_HAS_LOCK(struct sShortSpinlock *Lock);
+extern void    SHORTLOCK(struct sShortSpinlock *Lock);
+extern void    SHORTREL(struct sShortSpinlock *Lock);
+
+extern void    Debug_PutCharDebug(char ch);
+extern void    Debug_PutStringDebug(const char *Str);
+
+// TODO: Move this to acess.h
+extern tPAddr  MM_AllocateZero(tVAddr VAddr);
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/x86_64/include/arch_config.h b/KernelLand/Kernel/arch/x86_64/include/arch_config.h
new file mode 100644 (file)
index 0000000..c9f47b0
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ */
+#ifndef _ARCH_CONFIG_H_
+#define _ARCH_CONFIG_H_
+
+
+#define PIT_TIMER_BASE_N       3579545
+#define PIT_TIMER_BASE_D       3
+// PIT Ticks at 1.1931816666666 MHz
+// Base is 1193182 HZ
+#define PIT_TIMER_DIVISOR      11931   //~100Hz
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86_64/include/common.inc.asm b/KernelLand/Kernel/arch/x86_64/include/common.inc.asm
new file mode 100644 (file)
index 0000000..d230177
--- /dev/null
@@ -0,0 +1,50 @@
+
+%define INITIAL_KSTACK_SIZE    8
+
+%macro SAVE_GPR 1
+       mov [%1-0x08], r15
+       mov [%1-0x10], r14
+       mov [%1-0x18], r13
+       mov [%1-0x20], r12
+       mov [%1-0x28], r11
+       mov [%1-0x30], r10
+       mov [%1-0x38], r9
+       mov [%1-0x40], r8
+       mov [%1-0x48], rdi
+       mov [%1-0x50], rsi
+       mov [%1-0x58], rbp
+       mov [%1-0x60], rsp
+       mov [%1-0x68], rbx
+       mov [%1-0x70], rdx
+       mov [%1-0x78], rcx
+       mov [%1-0x80], rax
+%endmacro
+
+%macro PUSH_GPR        0
+       SAVE_GPR rsp
+       sub rsp, 0x80
+%endmacro
+
+%macro RESTORE_GPR 1
+       mov r15, [%1-0x08]
+       mov r14, [%1-0x10]
+       mov r13, [%1-0x18]
+       mov r12, [%1-0x20]
+       mov r11, [%1-0x28]
+       mov r10, [%1-0x30]
+       mov r9,  [%1-0x38]
+       mov r8,  [%1-0x40]
+       mov rdi, [%1-0x48]
+       mov rsi, [%1-0x50]
+       mov rbp, [%1-0x58]
+       ;mov rsp, [%1-0x60]
+       mov rbx, [%1-0x68]
+       mov rdx, [%1-0x70]
+       mov rcx, [%1-0x78]
+       mov rax, [%1-0x80]
+%endmacro
+
+%macro POP_GPR 0
+       add rsp, 0x80
+       RESTORE_GPR rsp
+%endmacro
diff --git a/KernelLand/Kernel/arch/x86_64/include/desctab.h b/KernelLand/Kernel/arch/x86_64/include/desctab.h
new file mode 100644 (file)
index 0000000..de3996c
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ */
+#ifndef _DESCTAB_H_
+#define _DESCTAB_H_
+
+typedef struct {
+       union
+       {
+               struct
+               {
+                       Uint16  LimitLow;
+                       Uint16  BaseLow;
+                       Uint8   BaseMid;
+                       Uint8   Access;
+                       struct {
+                               unsigned LimitHi:       4;
+                               unsigned Flags:         4;
+                       } __attribute__ ((packed));
+                       Uint8   BaseHi;
+               };
+               Uint32  DWord[2];
+       };
+} __attribute__ ((packed)) tGDT;
+
+typedef struct {
+       Uint16  OffsetLo;
+       Uint16  CS;
+       Uint16  Flags;  // 0-2: IST, 3-7: 0, 8-11: Type, 12: 0, 13-14: DPL, 15: Present
+       Uint16  OffsetMid;
+       Uint32  OffsetHi;
+       Uint32  Reserved;
+} __attribute__ ((packed)) tIDT;
+
+typedef struct {
+       Uint32  Rsvd1;
+       
+       Uint64  RSP0;
+       Uint64  RSP1;
+       Uint64  RSP2;
+       
+       Uint32  Rsvd2[2];
+       
+       // Interrupt Stack Table Pointers
+       Uint64  IST1;
+       Uint64  IST2;
+       Uint64  IST3;
+       Uint64  IST4;
+       Uint64  IST5;
+       Uint64  IST6;
+       Uint64  IST7;
+       
+       Uint32  Rsvd3[2];
+       Uint16  Rsvd4;
+       Uint16  IOMapBase;
+} __attribute__ ((packed)) tTSS;
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86_64/include/mm_virt.h b/KernelLand/Kernel/arch/x86_64/include/mm_virt.h
new file mode 100644 (file)
index 0000000..6cf25f0
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Acess2 x86_64 Architecture Code
+ *
+ * This file is published under the terms of the Acess Licence.
+ * See the file COPYING for more details
+ *
+ * vmem.h - Virtual Memory Functions & Definitions
+ */
+#ifndef _VMEM_H_
+#define _VMEM_H_
+
+#include <arch.h>
+
+#define PAGE_SIZE      0x1000
+
+// === Memory Location Definitions ===
+/*
+ * Userland - Lower Half
+ * Kernel land - Upper Half
+ * 
+ *    START ADDRESS          END ADDRESS       BITS   SIZE      NAME
+ * 0x00000000 00000000 - 0x00007FFF FFFFFFFF   47      128 TiB User Space
+ * 0x00008000 00000000 - 0xFFFF7FFF FFFFFFFF   --- SIGN EXTENSION NULL ZONE
+ * 0xFFFF8000 00000000 - 0xFFFFFFFF FFFFFFFF   47      128     TiB     Kernel Range
+ *       8000 00000000 -       9000 00000000   42      16      TiB     Kernel Heap
+ *       9000 00000000 -       9800 00000000   43      8       TiB     Module Space
+ *       9800 00000000 -       9A00 00000000   41      2       TiB     Kernel VFS
+ *       ---- GAP ----                                 6       TiB
+ *       A000 00000000 -       B000 00000000   44      16      TiB     Kernel Stacks
+ *       C000 00000000 -       D000 00000000   44      16      TiB     Hardware Mappings
+ *       D000 00000000 -       D080 00000000   39      512     GiB     Per-Process Data
+ *       D080 00000000 -       D100 00000000   39      512     GiB     Kernel Supplied User Code
+ *       ---- GAP ----                                 15      TiB
+ *       E000 00000000 -       E800 00000000   43      8       TiB     Physical Page Nodes (2**40 pages * 8 bytes)
+ *       E800 00000000 -       EC00 00000000   42      4       TiB     Physical Page Reference Counts (2**40 pg * 4 bytes)
+ *       EC00 00000000 -       EC80 00000000   39      512     GiB     Physical Page Bitmap (1 page per bit)
+ *       EC80 00000000 -       ED00 00000000   39      512     GiB     Physical Page DblAlloc Bitmap (1 page per bit)
+ *       ED00 00000000 -       ED00 80000000   31      2       GiB     Physical Page Super Bitmap (64 pages per bit)
+ *       ---- GAP ----                                 9       TiB
+ *       FE00 00000000 -       FE80 00000000   39      512     GiB     Fractal Mapping (PML4 508)
+ *       FE80 00000000 -       FF00 00000000   39      512     GiB     Temp Fractal Mapping
+ *       FF00 00000000 -       FF80 00000000   39      512     GiB     Temporary page mappings
+ *       FF80 00000000 -       FF80 80000000   31      2       GiB     Local APIC
+ *       ---- GAP ----                                 506     GiB
+ *       FFFF 00000000 -       FFFF 80000000   31      2       GiB     User Code
+ *       FFFF 80000000 -       FFFF FFFFFFFF   31      2       GiB     Kernel code / data
+ */
+
+#define        MM_USER_MIN     0x00000000##00010000
+#define USER_LIB_MAX   0x00007000##00000000
+#define USER_STACK_PREALLOC    0x00000000##00002000    // 8 KiB
+#define USER_STACK_SZ  0x00000000##00020000    // 64 KiB
+#define USER_STACK_TOP 0x00008000##00000000
+#define        MM_KERNEL_RANGE 0xFFFF8000##00000000
+#define MM_KHEAP_BASE  (MM_KERNEL_RANGE|(0x8000##00000000))
+#define MM_KHEAP_MAX   (MM_KERNEL_RANGE|(0x9000##00000000))
+#define MM_MODULE_MIN  (MM_KERNEL_RANGE|(0x9000##00000000))
+#define MM_MODULE_MAX  (MM_KERNEL_RANGE|(0x9800##00000000))
+#define MM_KERNEL_VFS  (MM_KERNEL_RANGE|(0x9800##00000000))
+#define MM_KSTACK_BASE (MM_KERNEL_RANGE|(0xA000##00000000))
+#define MM_KSTACK_TOP  (MM_KERNEL_RANGE|(0xB000##00000000))
+
+#define MM_HWMAP_BASE  (MM_KERNEL_RANGE|(0xC000##00000000))
+#define MM_HWMAP_TOP   (MM_KERNEL_RANGE|(0xD000##00000000))
+#define MM_PPD_BASE    (MM_KERNEL_RANGE|(0xD000##00000000))
+#define MM_PPD_CFG     MM_PPD_BASE
+#define MM_PPD_HANDLES         (MM_KERNEL_RANGE|(0xD008##00000000))
+#define MM_USER_CODE   (MM_KERNEL_RANGE|(0xD080##00000000))
+
+#define MM_PAGE_NODES  (MM_KERNEL_RANGE|(0xE000##00000000))
+#define MM_PAGE_COUNTS (MM_KERNEL_RANGE|(0xE800##00000000))
+#define MM_PAGE_BITMAP (MM_KERNEL_RANGE|(0xEC00##00000000))
+#define MM_PAGE_DBLBMP (MM_KERNEL_RANGE|(0xEC00##00000000))
+#define MM_PAGE_SUPBMP (MM_KERNEL_RANGE|(0xED00##00000000))
+
+#define MM_FRACTAL_BASE        (MM_KERNEL_RANGE|(0xFE00##00000000))
+#define MM_TMPFRAC_BASE        (MM_KERNEL_RANGE|(0xFE80##00000000))
+#define MM_TMPMAP_BASE (MM_KERNEL_RANGE|(0xFF00##00000000))
+#define MM_TMPMAP_END  (MM_KERNEL_RANGE|(0xFF80##00000000))
+#define MM_LOCALAPIC   (MM_KERNEL_RANGE|(0xFF80##00000000))
+#define MM_KERNEL_CODE (MM_KERNEL_RANGE|(0xFFFF##80000000))
+
+
+// === FUNCTIONS ===
+void   MM_FinishVirtualInit(void);
+tVAddr MM_NewKStack(void);
+tVAddr MM_Clone(void);
+tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize);
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86_64/include/proc.h b/KernelLand/Kernel/arch/x86_64/include/proc.h
new file mode 100644 (file)
index 0000000..dad8f06
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Acess2 x86_64 Port
+ * 
+ * proc.h - Process/Thread management code
+ */
+#ifndef _PROC_H_
+#define _PROC_H_
+
+#include <arch.h>
+
+// Register Structure
+// TODO: Rebuild once IDT code is done
+typedef struct {
+       // MMX
+       // FPU
+       Uint    FS, GS;
+       
+       Uint    RAX, RCX, RDX, RBX;
+       Uint    KernelRSP, RBP, RSI, RDI;
+       Uint    R8,  R9,  R10, R11;
+       Uint    R12, R13, R14, R15;
+       
+       Uint    IntNum, ErrorCode;
+       Uint    RIP, CS;
+       Uint    RFlags, RSP, SS;
+} tRegs;
+
+/**
+ * \brief Memory State for thread handler
+ */
+typedef struct sMemoryState
+{
+       tPAddr  CR3;
+}      tMemoryState;
+
+// 512 bytes, 16 byte aligned
+typedef struct sSSEState
+{
+       char    data[512];
+} tSSEState;
+
+/**
+ * \brief Task state for thread handler
+ */
+typedef struct sTaskState
+{
+       Uint    RIP, RSP;
+       Uint64  UserRIP, UserCS;
+       tSSEState       *SSE;
+        int    bSSEModified;
+}      tTaskState;
+
+// === CONSTANTS ===
+#define KERNEL_STACK_SIZE      0x8000  // 32 KiB
+//#define KERNEL_STACK_SIZE    0x10000 // 64 KiB
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/x86_64/include/vm8086.h b/KernelLand/Kernel/arch/x86_64/include/vm8086.h
new file mode 100644 (file)
index 0000000..7c8dd47
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Acess2 VM8086 BIOS Interface
+ * - By John Hodge (thePowersGang)
+ *
+ * vm8086.h
+ * - Core Header
+ */
+#ifndef _VM80806_H_
+#define _VM80806_H_
+
+// === TYPES ===
+/**
+ * \note Semi-opaque - Past \a .IP, the implementation may add any data
+ *       it needs to the state.
+ */
+typedef struct sVM8086
+{
+       Uint16  AX, CX, DX, BX;
+       Uint16  BP, SP, SI, DI;
+       
+       Uint16  SS, DS, ES;
+       
+       Uint16  CS, IP;
+       
+       struct sVM8086_InternalData     *Internal;
+}      tVM8086;
+
+// === FUNCTIONS ===
+/**
+ * \brief Create an instance of the VM8086 Emulator
+ * \note Do not free this pointer with ::free, instead use ::VM8086_Free
+ * \return Pointer to a tVM8086 structure, this structure may be larger than
+ *         tVM8086 due to internal data.
+ */
+extern tVM8086 *VM8086_Init(void);
+/**
+ * \brief Free an allocated tVM8086 structure
+ * \param State        Emulator state to free
+ */
+extern void    VM8086_Free(tVM8086 *State);
+/**
+ * \brief Allocate a piece of memory in the emulated address space and
+ *        return a host and emulated pointer to it.
+ * \param State        Emulator state
+ * \param Size Size of memory block
+ * \param Segment      Pointer to location to store the allocated memory's segment
+ * \param Offset       Pointet to location to store the allocated memory's offset
+ * \return Host pointer to the allocated memory
+ */
+extern void    *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset);
+/**
+ * \brief Gets a pointer to a piece of emulated memory
+ * \todo Only 1 machine page is garenteed to be contiguous
+ * \param State        Emulator State
+ * \param Segment      Source Segment
+ * \param Offset       Source Offset
+ * \return Host pointer to the emulated memory
+ */
+extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset);
+/**
+ * \brief Calls a real-mode interrupt described by the current state of the IVT.
+ * \param State        Emulator State
+ * \param Interrupt    BIOS Interrupt to call
+ */
+extern void    VM8086_Int(tVM8086 *State, Uint8 Interrupt);
+
+#endif
diff --git a/KernelLand/Kernel/arch/x86_64/kernelpanic.c b/KernelLand/Kernel/arch/x86_64/kernelpanic.c
new file mode 100644 (file)
index 0000000..1ce8ae7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Acess2 x86_64 port
+ * - Kernel Panic output
+ */
+#include <acess.h>
+
+// === PROTOTYPES ===
+void   KernelPanic_SetMode(void);
+void   KernelPanic_PutChar(char ch);
+
+// === GLOBALS ===
+Uint16 *gpKernelPanic_Buffer = (void*)( KERNEL_BASE|0xB8000 );
+ int   giKernelPanic_CurPos = 0;
+
+// === CODE ===
+void KernelPanic_SetMode(void)
+{
+       giKernelPanic_CurPos = 0;
+}
+
+void KernelPanic_PutChar(char ch)
+{
+       switch(ch)
+       {
+       case '\n':
+               giKernelPanic_CurPos += 80;
+       case '\r':
+               giKernelPanic_CurPos /= 80;
+               giKernelPanic_CurPos *= 80;
+               break;
+       
+       default:
+               if(' ' <= ch && ch <= 0x7F)
+                       gpKernelPanic_Buffer[giKernelPanic_CurPos] = 0x4F00|ch;
+               giKernelPanic_CurPos ++;
+               break;
+       }
+}
diff --git a/KernelLand/Kernel/arch/x86_64/lib.c b/KernelLand/Kernel/arch/x86_64/lib.c
new file mode 100644 (file)
index 0000000..5b9609a
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ */
+#include <acess.h>
+#include <arch.h>
+
+#define DEBUG_TO_E9    1
+#define DEBUG_TO_SERIAL        1
+#define        SERIAL_PORT     0x3F8
+#define        GDB_SERIAL_PORT 0x2F8
+
+
+// === IMPORTS ===
+extern int     GetCPUNum(void);
+extern void    *Proc_GetCurThread(void);
+
+// === GLOBALS ===
+ int   gbDebug_SerialSetup = 0;
+ int   gbGDB_SerialSetup = 0;
+
+// === PROTOTYPEs ===
+ int   putDebugChar(char ch);
+
+// === CODE ===
+/**
+ * \brief Determine if a short spinlock is locked
+ * \param Lock Lock pointer
+ */
+int IS_LOCKED(struct sShortSpinlock *Lock)
+{
+       return !!Lock->Lock;
+}
+
+/**
+ * \brief Check if the current CPU has the lock
+ * \param Lock Lock pointer
+ */
+int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
+{
+       #if STACKED_LOCKS == 1
+       return Lock->Lock == GetCPUNum() + 1;
+       #elif STACKED_LOCKS == 2
+       return Lock->Lock == Proc_GetCurThread();
+       #else
+       return 0;
+       #endif
+}
+
+/**
+ * \brief Acquire a Short Spinlock
+ * \param Lock Lock pointer
+ * 
+ * This type of mutex should only be used for very short sections of code,
+ * or in places where a Mutex_* would be overkill, such as appending
+ * an element to linked list (usually two assignement lines in C)
+ * 
+ * \note This type of lock halts interrupts, so ensure that no timing
+ * functions are called while it is held. As a matter of fact, spend as
+ * little time as possible with this lock held
+ * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
+ */
+void SHORTLOCK(struct sShortSpinlock *Lock)
+{
+        int    v = 1;
+       #if LOCK_DISABLE_INTS
+        int    IF;
+       #endif
+       #if STACKED_LOCKS == 1
+        int    cpu = GetCPUNum() + 1;
+       #elif STACKED_LOCKS == 2
+       void    *thread = Proc_GetCurThread();
+       #endif
+       
+       #if LOCK_DISABLE_INTS
+       // Save interrupt state and clear interrupts
+       __ASM__ ("pushf;\n\tpop %0" : "=r"(IF));
+       IF &= 0x200;    // AND out all but the interrupt flag
+       #endif
+       
+       #if STACKED_LOCKS == 1
+       if( Lock->Lock == cpu ) {
+               Lock->Depth ++;
+               return ;
+       }
+       #elif STACKED_LOCKS == 2
+       if( Lock->Lock == thread ) {
+               Lock->Depth ++;
+               return ;
+       }
+       #endif
+       
+       // Wait for another CPU to release
+       while(v) {
+               // CMPXCHG:
+               //  If r/m32 == EAX, set ZF and set r/m32 = r32
+               //  Else, clear ZF and set EAX = r/m32
+               #if STACKED_LOCKS == 1
+               __ASM__("lock cmpxchgl %2, (%3)"
+                       : "=a"(v)
+                       : "a"(0), "r"(cpu), "r"(&Lock->Lock)
+                       );
+               #elif STACKED_LOCKS == 2
+               __ASM__("lock cmpxchgq %2, (%3)"
+                       : "=a"(v)
+                       : "a"(0), "r"(thread), "r"(&Lock->Lock)
+                       );
+               #else
+               __ASM__("xchgl %0, (%2)":"=a"(v):"a"(1),"D"(&Lock->Lock));
+               #endif
+               
+               #if LOCK_DISABLE_INTS
+               if( v ) __ASM__("sti"); // Re-enable interrupts
+               #endif
+       }
+       
+       #if LOCK_DISABLE_INTS
+       __ASM__("cli");
+       Lock->IF = IF;
+       #endif
+}
+/**
+ * \brief Release a short lock
+ * \param Lock Lock pointer
+ */
+void SHORTREL(struct sShortSpinlock *Lock)
+{
+       #if STACKED_LOCKS
+       if( Lock->Depth ) {
+               Lock->Depth --;
+               return ;
+       }
+       #endif
+       
+       #if LOCK_DISABLE_INTS
+       // Lock->IF can change anytime once Lock->Lock is zeroed
+       if(Lock->IF) {
+               Lock->Lock = 0;
+               __ASM__ ("sti");
+       }
+       else {
+               Lock->Lock = 0;
+       }
+       #else
+       Lock->Lock = 0;
+       #endif
+}
+
+// === DEBUG IO ===
+#if USE_GDB_STUB
+int putDebugChar(char ch)
+{
+       if(!gbGDB_SerialSetup) {
+               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
+               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
+               outb(GDB_SERIAL_PORT + 1, 0x00);    //  (base is         (hi byte)
+               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit (8N1)
+               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
+               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+               gbDebug_SerialSetup = 1;
+       }
+       while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
+       outb(GDB_SERIAL_PORT, ch);
+       return 0;
+}
+int getDebugChar(void)
+{
+       if(!gbGDB_SerialSetup) {
+               outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
+               outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+               outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
+               outb(GDB_SERIAL_PORT + 1, 0x00);    //                   (hi byte)
+               outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
+               outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
+               outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+               gbDebug_SerialSetup = 1;
+       }
+       while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0)     ;
+       return inb(GDB_SERIAL_PORT);
+}
+#endif
+
+void Debug_PutCharDebug(char ch)
+{
+       #if DEBUG_TO_E9
+       __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
+       #endif
+       
+       #if DEBUG_TO_SERIAL
+       if(!gbDebug_SerialSetup) {
+               outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
+               outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
+               outb(SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
+               outb(SERIAL_PORT + 1, 0x00);    //                   (hi byte)
+               outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
+               outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
+               outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
+               gbDebug_SerialSetup = 1;
+       }
+       while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
+       outb(SERIAL_PORT, ch);
+       #endif
+}
+
+void Debug_PutStringDebug(const char *String)
+{
+       while(*String)
+               Debug_PutCharDebug(*String++);
+}
+
+// === PORT IO ===
+void outb(Uint16 Port, Uint8 Data)
+{
+       __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
+}
+void outw(Uint16 Port, Uint16 Data)
+{
+       __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
+}
+void outd(Uint16 Port, Uint32 Data)
+{
+       __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
+}
+Uint8 inb(Uint16 Port)
+{
+       Uint8   ret;
+       __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
+       return ret;
+}
+Uint16 inw(Uint16 Port)
+{
+       Uint16  ret;
+       __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
+       return ret;
+}
+Uint32 ind(Uint16 Port)
+{
+       Uint32  ret;
+       __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
+       return ret;
+}
+
+// === Endianness ===
+/*
+Uint32 BigEndian32(Uint32 Value)
+{
+       Uint32  ret;
+       ret = (Value >> 24);
+       ret |= ((Value >> 16) & 0xFF) << 8;
+       ret |= ((Value >>  8) & 0xFF) << 16;
+       ret |= ((Value >>  0) & 0xFF) << 24;
+       return ret;
+}
+
+Uint16 BigEndian16(Uint16 Value)
+{
+       return  (Value>>8)|(Value<<8);
+}
+*/
+
+// === Memory Manipulation ===
+int memcmp(const void *__dest, const void *__src, size_t __count)
+{
+       if( ((tVAddr)__dest & 7) != ((tVAddr)__src & 7) ) {
+               const Uint8     *src = __src, *dst = __dest;
+               while(__count)
+               {
+                       if( *src != *dst )
+                               return *dst - *src;
+                       src ++; dst ++; __count --;
+               }
+               return 0;
+       }
+       else {
+               const Uint8     *src = __src;
+               const Uint8     *dst = __dest;
+               const Uint64    *src64, *dst64;
+               
+               while( (tVAddr)src & 7 && __count ) {
+                       if( *src != *dst )
+                               return *dst - *src;
+                       dst ++; src ++; __count --;
+               }
+
+               src64 = (void*)src;
+               dst64 = (void*)dst;
+
+               while( __count >= 8 )
+               {
+                       if( *src64 != *dst64 )
+                       {
+                               src = (void*)src64;
+                               dst = (void*)dst64;
+                               if(src[0] != dst[0])    return dst[0]-src[0];
+                               if(src[1] != dst[1])    return dst[1]-src[1];
+                               if(src[2] != dst[2])    return dst[2]-src[2];
+                               if(src[3] != dst[3])    return dst[3]-src[3];
+                               if(src[4] != dst[4])    return dst[4]-src[4];
+                               if(src[5] != dst[5])    return dst[5]-src[5];
+                               if(src[6] != dst[6])    return dst[6]-src[6];
+                               if(src[7] != dst[7])    return dst[7]-src[7];
+                               return -1;      // This should never happen
+                       }
+                       __count -= 8;
+                       src64 ++;
+                       dst64 ++;
+               }
+
+               src = (void*)src64;
+               dst = (void*)dst64;
+               while( __count-- )
+               {
+                       if(*dst != *src)        return *dst - *src;
+                       dst ++;
+                       src ++;
+               }
+       }
+       return 0;
+}
+
+void *memcpy(void *__dest, const void *__src, size_t __count)
+{
+       tVAddr  dst = (tVAddr)__dest, src = (tVAddr)__src;
+       if( (dst & 7) != (src & 7) )
+       {
+               __asm__ __volatile__ ("rep movsb" : : "D"(dst),"S"(src),"c"(__count));
+       }
+       else
+       {
+               while( (src & 7) && __count ) {
+                       *(char*)dst++ = *(char*)src++;
+                       __count --;
+               }
+
+               __asm__ __volatile__ ("rep movsq" : "=D"(dst),"=S"(src) : "0"(dst),"1"(src),"c"(__count/8));
+               __count = __count & 7;
+               while( __count-- )
+                       *(char*)dst++ = *(char*)src++;
+       }
+       return __dest;
+}
+
+void *memset(void *__dest, int __val, size_t __count)
+{
+       if( __val != 0 || ((tVAddr)__dest & 7) != 0 )
+               __asm__ __volatile__ ("rep stosb" : : "D"(__dest),"a"(__val),"c"(__count));
+       else {
+               Uint8   *dst = __dest;
+
+               __asm__ __volatile__ ("rep stosq" : : "D"(dst),"a"(0),"c"(__count/8));
+               dst += __count & ~7;
+               __count = __count & 7;
+               while( __count-- )
+                       *dst++ = 0;
+       }
+       return __dest;
+}
+
+void *memsetd(void *__dest, Uint32 __val, size_t __count)
+{
+       __asm__ __volatile__ ("rep stosl" : : "D"(__dest),"a"(__val),"c"(__count));
+       return __dest;
+}
+
+Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
+{
+       Uint64  ret, rem;
+       __asm__ __volatile__(
+               "div %4"
+               : "=a" (ret), "=d" (rem)
+               : "a" ( Num ), "d" (0), "r" (Den)
+               );
+       if(Rem) *Rem = rem;
+       return ret;
+}
+
diff --git a/KernelLand/Kernel/arch/x86_64/link.ld b/KernelLand/Kernel/arch/x86_64/link.ld
new file mode 100644 (file)
index 0000000..49fe7ae
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Acess2 x86_64 Kernel
+ * Linker Script
+ */
+
+/* _kernel_base = 0xFFFF800000000000; */
+/* -2 GiB */
+_kernel_base = 0xFFFFFFFF80000000;
+
+/*
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386:x86-64)
+*/
+OUTPUT_FORMAT(elf64-x86-64)
+ENTRY(start)
+
+SECTIONS {
+       . = 0x100000;
+       gKernelBase = .;
+       . += SIZEOF_HEADERS;
+       __load_addr = .;
+       .multiboot : AT(ADDR(.multiboot)) {
+               *(.multiboot)
+       }
+       
+       . += _kernel_base;
+       
+       .text ALIGN(0x1000): AT(ADDR(.text) - _kernel_base) {
+               *(.text)
+       }
+       
+       .usertext ALIGN(0x1000): AT(ADDR(.usertext) - _kernel_base) {
+               _UsertextBase = .;
+               *(.usertext)
+               _UsertextEnd = .;
+       }
+       
+       .rodata ALIGN(0x1000): AT(ADDR(.rodata) - _kernel_base) {
+               *(.initpd)
+               *(.rodata .rodata.*)
+               *(.rdata)
+               
+               . = ALIGN(0x10);
+               gKernelModules = .;
+               *(KMODULES)
+               gKernelModulesEnd = .;
+               . = ALIGN(0x10);
+               gKernelSymbols = .;
+               *(KEXPORT)
+               gKernelSymbolsEnd = .;
+       }
+       
+       .data ALIGN (0x1000) : AT(ADDR(.data) - _kernel_base) {
+               *(.padata)
+               *(.data)
+       }
+
+       __bss_start = .;
+       .bss : AT(ADDR(.bss) - _kernel_base) {
+               *(COMMON)
+               *(.bss)
+       }
+       gKernelEnd = (. + 0xFFF)&0xFFFFFFFFFFFFF000;
+}
diff --git a/KernelLand/Kernel/arch/x86_64/main.c b/KernelLand/Kernel/arch/x86_64/main.c
new file mode 100644 (file)
index 0000000..3532c80
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Acess2 x86_64 Project
+ */
+#include <acess.h>
+#include <mboot.h>
+#include <init.h>
+
+// === IMPORTS ===
+extern void    Desctab_Init(void);
+extern void    MM_InitVirt(void);
+extern void    Heap_Install(void);
+extern void    Threads_Init(void);
+extern int     Time_Setup(void);
+extern void    System_Init(char *Commandline);
+
+extern void    MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+
+// === PROTOTYPES ===
+void   kmain(Uint MbMagic, void *MbInfoPtr);
+
+// === GLOBALS ==
+char   *gsBootCmdLine = NULL;
+
+// === CODE ===
+void kmain(Uint MbMagic, void *MbInfoPtr)
+{
+       tMBoot_Info     *mbInfo;
+
+       LogF("Acess2 x86_64 v"EXPAND_STR(KERNEL_VERSION)"\n");
+       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+       
+       Desctab_Init();
+
+       MM_InitVirt();
+       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'C';
+       
+       switch(MbMagic)
+       {
+       // Multiboot 1
+       case MULTIBOOT_MAGIC:
+               // Adjust Multiboot structure address
+               mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
+               gsBootCmdLine = (char*)( (Uint)mbInfo->CommandLine + KERNEL_BASE);
+               MM_InitPhys_Multiboot( mbInfo );        // Set up physical memory manager
+               break;
+       default:
+               Panic("Multiboot magic invalid %08x, expected %08x\n",
+                       MbMagic, MULTIBOOT_MAGIC);
+               return ;
+       }
+       
+       Log("gsBootCmdLine = '%s'", gsBootCmdLine);
+       
+       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'D';
+       Heap_Install();
+       
+       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'E';
+       Threads_Init();
+       
+       Time_Setup();
+       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'F';
+       
+       // Load Virtual Filesystem
+       Log_Log("Arch", "Starting VFS...");
+       VFS_Init();
+       
+       *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'Z';
+       
+       // Pass on to Independent Loader
+       Log_Log("Arch", "Starting system");
+       System_Init(gsBootCmdLine);
+       
+       // Sleep forever (sleeping beauty)
+       for(;;)
+               Threads_Sleep();
+}
+
+void Arch_LoadBootModules(void)
+{
+       
+}
+
+void StartupPrint(const char *String)
+{
+       
+}
diff --git a/KernelLand/Kernel/arch/x86_64/mm_phys.c b/KernelLand/Kernel/arch/x86_64/mm_phys.c
new file mode 100644 (file)
index 0000000..c2c215b
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * Acess2 x86_64 Port
+ * 
+ * Physical Memory Manager
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <mboot.h>
+#include <mm_virt.h>
+
+#define TRACE_REF      0
+
+enum eMMPhys_Ranges
+{
+       MM_PHYS_16BIT,  // Does anything need this?
+       MM_PHYS_20BIT,  // Real-Mode
+       MM_PHYS_24BIT,  // ISA DMA
+       MM_PHYS_32BIT,  // x86 Hardware
+       MM_PHYS_MAX,    // Doesn't care
+       NUM_MM_PHYS_RANGES
+};
+
+// === IMPORTS ===
+extern char    gKernelBase[];
+extern char    gKernelEnd[];
+
+// === PROTOTYPES ===
+void   MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+//tPAddr       MM_AllocPhysRange(int Num, int Bits);
+//tPAddr       MM_AllocPhys(void);
+//void MM_RefPhys(tPAddr PAddr);
+//void MM_DerefPhys(tPAddr PAddr);
+ int   MM_int_GetRangeID( tPAddr Addr );
+
+// === MACROS ===
+#define PAGE_ALLOC_TEST(__page)        (gaMainBitmap[(__page)>>6] & (1ULL << ((__page)&63)))
+#define PAGE_ALLOC_SET(__page)         do{gaMainBitmap[(__page)>>6] |= (1ULL << ((__page)&63));}while(0)
+#define PAGE_ALLOC_CLEAR(__page)       do{gaMainBitmap[(__page)>>6] &= ~(1ULL << ((__page)&63));}while(0)
+//#define PAGE_MULTIREF_TEST(__page)   (gaMultiBitmap[(__page)>>6] & (1ULL << ((__page)&63)))
+//#define PAGE_MULTIREF_SET(__page)    do{gaMultiBitmap[(__page)>>6] |= 1ULL << ((__page)&63);}while(0)
+//#define PAGE_MULTIREF_CLEAR(__page)  do{gaMultiBitmap[(__page)>>6] &= ~(1ULL << ((__page)&63));}while(0)
+
+// === GLOBALS ===
+tMutex glPhysicalPages;
+Uint64 *gaSuperBitmap = (void*)MM_PAGE_SUPBMP; // 1 bit = 64 Pages, 16 MiB per Word
+Uint64 *gaMainBitmap = (void*)MM_PAGE_BITMAP;  // 1 bit = 1 Page, 256 KiB per Word
+Uint64 *gaMultiBitmap = (void*)MM_PAGE_DBLBMP; // Each bit means that the page is being used multiple times
+Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS;     // Reference Counts
+void   **gapPageNodes = (void*)MM_PAGE_NODES;  // Reference Counts
+tPAddr giFirstFreePage;        // First possibly free page
+Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES];    // Number of free pages in each range
+Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES];   // First free page in each range
+Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES];    // Last free page in each range
+Uint64 giMaxPhysPage = 0;      // Maximum Physical page
+// Only used in init, allows the init code to provide pages for use by
+// the allocator before the bitmaps exist.
+// 3 entries because the are three calls to MM_AllocPhys in MM_Map
+#define NUM_STATIC_ALLOC       3
+tPAddr gaiStaticAllocPages[NUM_STATIC_ALLOC] = {0};
+
+// === CODE ===
+/**
+ * \brief Initialise the physical memory map using a Multiboot 1 map
+ */
+void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
+{
+       tMBoot_MMapEnt  *mmapStart;
+       tMBoot_MMapEnt  *ent;
+       Uint64  maxAddr = 0;
+        int    numPages, superPages;
+        int    i;
+       Uint64  base, size;
+       tVAddr  vaddr;
+       tPAddr  paddr, firstFreePage;
+       
+       ENTER("pMBoot=%p", MBoot);
+       
+       // Scan the physical memory map
+       // Looking for the top of physical memory
+       mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
+       LOG("mmapStart = %p", mmapStart);
+       ent = mmapStart;
+       while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
+       {
+               // Adjust for the size of the entry
+               ent->Size += 4;
+               LOG("ent={Type:%i,Base:0x%x,Length:%x",
+                       ent->Type, ent->Base, ent->Length);
+               
+               // If entry is RAM and is above `maxAddr`, change `maxAddr`
+               if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
+                       maxAddr = ent->Base + ent->Length;
+               
+               // Go to next entry
+               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+       }
+       
+       // Did we find a valid end?
+       if(maxAddr == 0) {
+               // No, darn, let's just use the HighMem hack
+               giMaxPhysPage = (MBoot->HighMem >> 2) + 256;    // HighMem is a kByte value
+       }
+       else {
+               // Goodie, goodie gumdrops
+               giMaxPhysPage = maxAddr >> 12;
+       }
+       LOG("giMaxPhysPage = 0x%x", giMaxPhysPage);
+       
+       // Find a contigous section of memory to hold it in
+       // - Starting from the end of the kernel
+       // - We also need a region for the super bitmap
+       superPages = ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12;
+       numPages = (giMaxPhysPage + 7) / 8;
+       numPages = (numPages + 0xFFF) >> 12;
+       LOG("numPages = %i, superPages = %i", numPages, superPages);
+       if(maxAddr == 0)
+       {
+                int    todo = numPages*2 + superPages;
+               // Ok, naieve allocation, just put it after the kernel
+               // - Allocated Bitmap
+               vaddr = MM_PAGE_BITMAP;
+               paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
+               while(todo )
+               {
+                       // Allocate statics
+                       for( i = 0; i < NUM_STATIC_ALLOC; i++) {
+                               if(gaiStaticAllocPages[i] != 0) continue;
+                               gaiStaticAllocPages[i] = paddr;
+                               paddr += 0x1000;
+                       }
+                       
+                       MM_Map(vaddr, paddr);
+                       vaddr += 0x1000;
+                       paddr += 0x1000;
+                       
+                       todo --;
+                       
+                       if( todo == numPages + superPages )
+                               vaddr = MM_PAGE_DBLBMP;
+                       if( todo == superPages )
+                               vaddr = MM_PAGE_SUPBMP;
+               }
+       }
+       // Scan for a nice range
+       else
+       {
+                int    todo = numPages*2 + superPages;
+               paddr = 0;
+               vaddr = MM_PAGE_BITMAP;
+               // Scan!
+               for(
+                       ent = mmapStart;
+                       (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
+                       ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
+                       )
+               {
+                        int    avail;
+                       
+                       // RAM only please
+                       if( ent->Type != 1 )
+                               continue;
+                       
+                       // Let's not put it below the kernel, shall we?
+                       if( ent->Base + ent->Size < (tPAddr)&gKernelBase )
+                               continue;
+                       
+                       LOG("%x <= %x && %x > %x",
+                               ent->Base, (tPAddr)&gKernelBase,
+                               ent->Base + ent->Size, (tPAddr)&gKernelEnd - KERNEL_BASE
+                               );
+                       // Check if the kernel is in this range
+                       if( ent->Base <= (tPAddr)&gKernelBase
+                       && ent->Base + ent->Length > (tPAddr)&gKernelEnd - KERNEL_BASE )
+                       {
+                               avail = ent->Length >> 12;
+                               avail -= ((tPAddr)&gKernelEnd - KERNEL_BASE - ent->Base) >> 12;
+                               paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
+                       }
+                       // No? then we can use all of the block
+                       else
+                       {
+                               avail = ent->Length >> 12;
+                               paddr = ent->Base;
+                       }
+                       
+                       Log("MM_InitPhys_Multiboot: paddr=0x%x, avail=0x%x pg", paddr, avail);
+                       
+                       // Map
+                       while( todo && avail --)
+                       {
+                               // Static Allocations
+                               for( i = 0; i < NUM_STATIC_ALLOC && avail; i++) {
+                                       if(gaiStaticAllocPages[i] != 0) continue;
+                                       gaiStaticAllocPages[i] = paddr;
+                                       paddr += 0x1000;
+                                       avail --;
+                               }
+                               if(!avail)      break;
+                               
+                               // Map
+                               MM_Map(vaddr, paddr);
+                               todo --;
+                               vaddr += 0x1000;
+                               paddr += 0x1000;
+                               
+                               // Alter the destination address when needed
+                               if(todo == superPages+numPages)
+                                       vaddr = MM_PAGE_DBLBMP;
+                               if(todo == superPages)
+                                       vaddr = MM_PAGE_SUPBMP;
+                       }
+                       
+                       // Fast quit if there's nothing left to allocate
+                       if( !todo )             break;
+               }
+       }
+       // Save the current value of paddr to simplify the allocation later
+       firstFreePage = paddr;
+       
+       LOG("Clearing multi bitmap");
+       // Fill the bitmaps
+       memset(gaMultiBitmap, 0, (numPages<<12)/8);
+       // - initialise to one, then clear the avaliable areas
+       memset(gaMainBitmap, -1, (numPages<<12)/8);
+       memset(gaSuperBitmap, -1, (numPages<<12)/(8*64));
+       LOG("Setting main bitmap");
+       // - Clear all Type=1 areas
+       LOG("Clearing valid regions");
+       for(
+               ent = mmapStart;
+               (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
+               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
+               )
+       {
+               // Check if the type is RAM
+               if(ent->Type != 1)      continue;
+               
+               // Main bitmap
+               base = ent->Base >> 12;
+               size = ent->Size >> 12;
+               
+               if(base & 63) {
+                       Uint64  val = -1LL << (base & 63);
+                       gaMainBitmap[base / 64] &= ~val;
+                       size -= (base & 63);
+                       base += 64 - (base & 63);
+               }
+               memset( &gaMainBitmap[base / 64], 0, size/8 );
+               if( size & 7 ) {
+                       Uint64  val = -1LL << (size & 7);
+                       val <<= (size/8)&7;
+                       gaMainBitmap[base / 64] &= ~val;
+               }
+               
+               // Super Bitmap
+               base = ent->Base >> 12;
+               size = ent->Size >> 12;
+               size = (size + (base & 63) + 63) >> 6;
+               base = base >> 6;
+               if(base & 63) {
+                       Uint64  val = -1LL << (base & 63);
+                       gaSuperBitmap[base / 64] &= ~val;
+//                     size -= (base & 63);
+//                     base += 64 - (base & 63);
+               }
+       }
+       
+       // Reference the used pages
+       base = (tPAddr)&gKernelBase >> 12;
+       size = firstFreePage >> 12;
+       memset( &gaMainBitmap[base / 64], -1, size/8 );
+       if( size & 7 ) {
+               Uint64  val = -1LL << (size & 7);
+               val <<= (size/8)&7;
+               gaMainBitmap[base / 64] |= val;
+       }
+       
+       // Free the unused static allocs
+       for( i = 0; i < NUM_STATIC_ALLOC; i++) {
+               if(gaiStaticAllocPages[i] != 0)
+                       continue;
+               gaMainBitmap[ gaiStaticAllocPages[i] >> (12+6) ]
+                       &= ~(1LL << ((gaiStaticAllocPages[i]>>12)&63));
+       }
+       
+       // Fill the super bitmap
+       LOG("Filling super bitmap");
+       memset(gaSuperBitmap, 0, superPages<<12);
+       for( base = 0; base < (size+63)/64; base ++)
+       {
+               if( gaMainBitmap[ base ] + 1 == 0 )
+                       gaSuperBitmap[ base/64 ] |= 1LL << (base&63);
+       }
+       
+       // Set free page counts
+       for( base = 1; base < giMaxPhysPage; base ++ )
+       {
+                int    rangeID;
+               // Skip allocated
+               if( gaMainBitmap[ base >> 6 ] & (1LL << (base&63))  )   continue;
+               
+               // Get range ID
+               rangeID = MM_int_GetRangeID( base << 12 );
+               
+               // Increment free page count
+               giPhysRangeFree[ rangeID ] ++;
+               
+               // Check for first free page in range
+               if(giPhysRangeFirst[ rangeID ] == 0)
+                       giPhysRangeFirst[ rangeID ] = base;
+               // Set last (when the last free page is reached, this won't be
+               // updated anymore, hence will be correct)
+               giPhysRangeLast[ rangeID ] = base;
+       }
+       
+       LEAVE('-');
+}
+
+/**
+ * \brief Allocate a contiguous range of physical pages with a maximum
+ *        bit size of \a MaxBits
+ * \param Pages        Number of pages to allocate
+ * \param MaxBits      Maximum size of the physical address
+ * \note If \a MaxBits is <= 0, any sized address is used (with preference
+ *       to higher addresses)
+ */
+tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
+{
+       tPAddr  addr, ret;
+        int    rangeID;
+        int    nFree = 0, i;
+       
+       ENTER("iPages iBits", Pages, MaxBits);
+       
+       if( MaxBits <= 0 || MaxBits >= 64 )     // Speedup for the common case
+               rangeID = MM_PHYS_MAX;
+       else
+               rangeID = MM_int_GetRangeID( (1LL << MaxBits) - 1 );
+       
+       LOG("rangeID = %i", rangeID);
+       
+       Mutex_Acquire(&glPhysicalPages);
+       
+       // Check if the range actually has any free pages
+       while(giPhysRangeFree[rangeID] == 0 && rangeID)
+               rangeID --;
+       
+       LOG("rangeID = %i", rangeID);
+       
+       // What the? Oh, man. No free pages
+       if(giPhysRangeFree[rangeID] == 0) {
+               Mutex_Release(&glPhysicalPages);
+               // TODO: Page out
+               // ATM. Just Warning
+               Warning(" MM_AllocPhysRange: Out of free pages");
+               Log_Warning("Arch",
+                       "Out of memory (unable to fulfil request for %i pages), zero remaining",
+                       Pages
+                       );
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Check if there is enough in the range
+       if(giPhysRangeFree[rangeID] >= Pages)
+       {
+               LOG("{%i,0x%x -> 0x%x}",
+                       giPhysRangeFree[rangeID],
+                       giPhysRangeFirst[rangeID], giPhysRangeLast[rangeID]
+                       );
+               // Do a cheap scan, scanning upwards from the first free page in
+               // the range
+               nFree = 0;
+               addr = giPhysRangeFirst[ rangeID ];
+               while( addr <= giPhysRangeLast[ rangeID ] )
+               {
+                       //Log(" MM_AllocPhysRange: addr = 0x%x", addr);
+                       // Check the super bitmap
+                       if( gaSuperBitmap[addr >> (6+6)] + 1 == 0 ) {
+                               LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr += 1LL << (6+6);
+                               addr &= ~0xFFF; // (1LL << 6+6) - 1
+                               continue;
+                       }
+                       // Check page block (64 pages)
+                       if( gaMainBitmap[addr >> 6] + 1 == 0) {
+                               LOG("nFree = %i = 0 (main) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr += 1LL << (6);
+                               addr &= ~0x3F;
+                               continue;
+                       }
+                       // Check individual page
+                       if( gaMainBitmap[addr >> 6] & (1LL << (addr & 63)) ) {
+                               LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr ++;
+                               continue;
+                       }
+                       nFree ++;
+                       addr ++;
+                       LOG("nFree(%i) == %i (0x%x)", nFree, Pages, addr);
+                       if(nFree == Pages)
+                               break;
+               }
+               LOG("nFree = %i", nFree);
+               // If we don't find a contiguous block, nFree will not be equal
+               // to Num, so we set it to zero and do the expensive lookup.
+               if(nFree != Pages)      nFree = 0;
+       }
+       
+       if( !nFree )
+       {
+               // Oops. ok, let's do an expensive check (scan down the list
+               // until a free range is found)
+//             nFree = 1;
+//             addr = giPhysRangeLast[ rangeID ];
+               // TODO: Expensive Check
+               Mutex_Release(&glPhysicalPages);
+               // TODO: Page out
+               // ATM. Just Warning
+               Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
+               Log_Warning("Arch",
+                       "Out of memory (unable to fulfil request for %i pages)",
+                       Pages   
+                       );
+               LEAVE('i', 0);
+               return 0;
+       }
+       LOG("nFree = %i, addr = 0x%08x", nFree, addr);
+       
+       // Mark pages as allocated
+       addr -= Pages;
+       for( i = 0; i < Pages; i++, addr++ )
+       {
+               gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
+               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) )
+                       gaiPageReferences[addr] = 1;
+//             Log("page %P refcount = %i", MM_GetRefCount(addr<<12)); 
+               rangeID = MM_int_GetRangeID(addr << 12);
+               giPhysRangeFree[ rangeID ] --;
+               LOG("%x == %x", addr, giPhysRangeFirst[ rangeID ]);
+               if(addr == giPhysRangeFirst[ rangeID ])
+                       giPhysRangeFirst[ rangeID ] += 1;
+       }
+       addr -= Pages;
+       ret = addr;     // Save the return address
+       
+       // Update super bitmap
+       Pages += addr & (64-1);
+       addr &= ~(64-1);
+       Pages = (Pages + (64-1)) & ~(64-1);
+       for( i = 0; i < Pages/64; i++ )
+       {
+               if( gaMainBitmap[ addr >> 6 ] + 1 == 0 )
+                       gaSuperBitmap[addr>>12] |= 1LL << ((addr >> 6) & 63);
+       }
+       
+       Mutex_Release(&glPhysicalPages);
+       #if TRACE_REF
+       Log("MM_AllocPhysRange: ret = %P (Ref %i)", ret << 12, MM_GetRefCount(ret<<12));
+       #endif
+       LEAVE('x', ret << 12);
+       return ret << 12;
+}
+
+/**
+ * \brief Allocate a single physical page, with no preference as to address
+ *        size.
+ */
+tPAddr MM_AllocPhys(void)
+{
+        int    i;
+       
+       // Hack to allow allocation during setup
+       for(i = 0; i < NUM_STATIC_ALLOC; i++) {
+               if( gaiStaticAllocPages[i] ) {
+                       tPAddr  ret = gaiStaticAllocPages[i];
+                       gaiStaticAllocPages[i] = 0;
+                       Log("MM_AllocPhys: Return %P, static alloc %i", ret, i);
+                       return ret;
+               }
+       }
+       
+       return MM_AllocPhysRange(1, -1);
+}
+
+/**
+ * \brief Reference a physical page
+ */
+void MM_RefPhys(tPAddr PAddr)
+{
+       Uint64  page = PAddr >> 12;
+       
+       if( page > giMaxPhysPage )      return ;
+       
+       if( PAGE_ALLOC_TEST(page) )
+       {
+               tVAddr  ref_base = ((tVAddr)&gaiPageReferences[ page ]) & ~0xFFF;
+               // Allocate reference page
+               if( !MM_GetPhysAddr(ref_base) )
+               {
+                       const int       pages_per_refpage = PAGE_SIZE/sizeof(gaiPageReferences[0]);
+                        int    i;
+                        int    page_base = page / pages_per_refpage * pages_per_refpage;
+                       if( !MM_Allocate( ref_base ) ) {
+                               Log_Error("Arch", "Out of memory when allocating reference count page");
+                               return ;
+                       }
+                       // Fill block
+                       Log("Allocated references for %P-%P", page_base << 12, (page_base+pages_per_refpage)<<12);
+                       for( i = 0; i < pages_per_refpage; i ++ ) {
+                                int    pg = page_base + i;
+                               gaiPageReferences[pg] = !!PAGE_ALLOC_TEST(pg);
+                       }
+               }
+               gaiPageReferences[page] ++;
+       }
+       else
+       {
+               // Allocate
+               PAGE_ALLOC_SET(page);
+               if( gaMainBitmap[page >> 6] + 1 == 0 )
+                       gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
+               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+                       gaiPageReferences[page] = 1;
+       }
+
+       #if TRACE_REF
+       Log("MM_RefPhys: %P referenced (%i)", page << 12, MM_GetRefCount(page << 12));
+       #endif
+}
+
+/**
+ * \brief Dereference a physical page
+ */
+void MM_DerefPhys(tPAddr PAddr)
+{
+       Uint64  page = PAddr >> 12;
+       
+       if( PAddr >> 12 > giMaxPhysPage )       return ;
+       
+       if( MM_GetPhysAddr( (tVAddr) &gaiPageReferences[page] ) )
+       {
+               gaiPageReferences[ page ] --;
+               if( gaiPageReferences[ page ] == 0 )
+                       PAGE_ALLOC_CLEAR(page);
+       }
+       else
+               PAGE_ALLOC_CLEAR(page);
+       
+       // Update the free counts if the page was freed
+       if( !PAGE_ALLOC_TEST(page) )
+       {
+                int    rangeID;
+               rangeID = MM_int_GetRangeID( PAddr );
+               giPhysRangeFree[ rangeID ] ++;
+               if( giPhysRangeFirst[rangeID] > page )
+                       giPhysRangeFirst[rangeID] = page;
+               if( giPhysRangeLast[rangeID] < page )
+                       giPhysRangeLast[rangeID] = page;
+       }
+       
+       // If the bitmap entry is not -1, unset the bit in the super bitmap
+       if(gaMainBitmap[ page >> 6 ] + 1 != 0 ) {
+               gaSuperBitmap[page >> 12] &= ~(1LL << ((page >> 6) & 63));
+       }
+       
+       #if TRACE_REF
+       Log("Page %P dereferenced (%i)", page << 12, MM_GetRefCount(page << 12));
+       #endif
+}
+
+int MM_GetRefCount( tPAddr PAddr )
+{
+       PAddr >>= 12;
+       
+       if( PAddr > giMaxPhysPage )     return 0;
+
+       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+               return gaiPageReferences[PAddr];
+       }
+
+       if( PAGE_ALLOC_TEST(PAddr) )
+       {
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * \brief Takes a physical address and returns the ID of its range
+ * \param Addr Physical address of page
+ * \return Range ID from eMMPhys_Ranges
+ */
+int MM_int_GetRangeID( tPAddr Addr )
+{
+       if(Addr >> 32)
+               return MM_PHYS_MAX;
+       else if(Addr >> 24)
+               return MM_PHYS_32BIT;
+       else if(Addr >> 20)
+               return MM_PHYS_24BIT;
+       else if(Addr >> 16)
+               return MM_PHYS_20BIT;
+       else
+               return MM_PHYS_16BIT;
+}
+
+int MM_SetPageNode(tPAddr PAddr, void *Node)
+{
+       tPAddr  page = PAddr >> 12;
+       tVAddr  node_page = ((tVAddr)&gapPageNodes[page]) & ~(PAGE_SIZE-1);
+
+//     if( !MM_GetRefCount(PAddr) )    return 1;
+       
+       if( !MM_GetPhysAddr(node_page) ) {
+               if( !MM_Allocate(node_page) )
+                       return -1;
+               memset( (void*)node_page, 0, PAGE_SIZE );
+       }
+
+       gapPageNodes[page] = Node;
+       return 0;
+}
+
+int MM_GetPageNode(tPAddr PAddr, void **Node)
+{
+//     if( !MM_GetRefCount(PAddr) )    return 1;
+       PAddr >>= 12;
+       
+       if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+               *Node = NULL;
+               return 0;
+       }
+
+       *Node = gapPageNodes[PAddr];
+       return 0;
+}
+
diff --git a/KernelLand/Kernel/arch/x86_64/mm_virt.c b/KernelLand/Kernel/arch/x86_64/mm_virt.c
new file mode 100644 (file)
index 0000000..89aeaa1
--- /dev/null
@@ -0,0 +1,1110 @@
+/*
+ * Acess2 x86_64 Port
+ * 
+ * Virtual Memory Manager
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <mm_virt.h>
+#include <threads_int.h>
+#include <proc.h>
+#include <hal_proc.h>
+
+// === DEBUG OPTIONS ===
+#define TRACE_COW      0
+
+// === CONSTANTS ===
+#define PHYS_BITS      52      // TODO: Move out
+#define VIRT_BITS      48
+
+#define PML4_SHIFT     39
+#define PDP_SHIFT      30
+#define PDIR_SHIFT     21
+#define PTAB_SHIFT     12
+
+#define        PADDR_MASK      0x7FFFFFFF##FFFFF000
+#define PAGE_MASK      ((1LL << 36)-1)
+#define TABLE_MASK     ((1LL << 27)-1)
+#define PDP_MASK       ((1LL << 18)-1)
+#define PML4_MASK      ((1LL << 9)-1)
+
+#define        PF_PRESENT      0x001
+#define        PF_WRITE        0x002
+#define        PF_USER         0x004
+#define        PF_LARGE        0x080
+#define        PF_GLOBAL       0x100
+#define        PF_COW          0x200
+#define        PF_PAGED        0x400
+#define        PF_NX           0x80000000##00000000
+
+// === MACROS ===
+#define PAGETABLE(idx) (*((Uint64*)MM_FRACTAL_BASE+((idx)&PAGE_MASK)))
+#define PAGEDIR(idx)   PAGETABLE((MM_FRACTAL_BASE>>12)+((idx)&TABLE_MASK))
+#define PAGEDIRPTR(idx)        PAGEDIR((MM_FRACTAL_BASE>>21)+((idx)&PDP_MASK))
+#define PAGEMAPLVL4(idx)       PAGEDIRPTR((MM_FRACTAL_BASE>>30)+((idx)&PML4_MASK))
+
+#define TMPCR3()       PAGEMAPLVL4(MM_TMPFRAC_BASE>>39)
+#define TMPTABLE(idx)  (*((Uint64*)MM_TMPFRAC_BASE+((idx)&PAGE_MASK)))
+#define TMPDIR(idx)    PAGETABLE((MM_TMPFRAC_BASE>>12)+((idx)&TABLE_MASK))
+#define TMPDIRPTR(idx) PAGEDIR((MM_TMPFRAC_BASE>>21)+((idx)&PDP_MASK))
+#define TMPMAPLVL4(idx)        PAGEDIRPTR((MM_TMPFRAC_BASE>>30)+((idx)&PML4_MASK))
+
+#define INVLPG(__addr) __asm__ __volatile__ ("invlpg (%0)"::"r"(__addr))
+#define INVLPG_ALL()   __asm__ __volatile__ ("mov %cr3,%rax;\n\tmov %rax,%cr3;")
+#define INVLPG_GLOBAL()        __asm__ __volatile__ ("mov %cr4,%rax;\n\txorl $0x80, %eax;\n\tmov %rax,%cr4;\n\txorl $0x80, %eax;\n\tmov %rax,%cr4")
+
+// === CONSTS ===
+//tPAddr       * const gaPageTable = MM_FRACTAL_BASE;
+
+// === IMPORTS ===
+extern void    Error_Backtrace(Uint IP, Uint BP);
+extern tPAddr  gInitialPML4[512];
+extern void    Threads_SegFault(tVAddr Addr);
+extern char    _UsertextBase[];
+
+// === PROTOTYPES ===
+void   MM_InitVirt(void);
+//void MM_FinishVirtualInit(void);
+void   MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable );
+ int   MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
+void   MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected);
+//void MM_DumpTables(tVAddr Start, tVAddr End);
+ int   MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer);
+ int   MM_MapEx(tVAddr VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge);
+// int MM_Map(tVAddr VAddr, tPAddr PAddr);
+void   MM_Unmap(tVAddr VAddr);
+void   MM_int_ClearTableLevel(tVAddr VAddr, int LevelBits, int MaxEnts);
+//void MM_ClearUser(void);
+ int   MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags);
+
+// === GLOBALS ===
+tMutex glMM_TempFractalLock;
+tPAddr gMM_ZeroPage;
+
+// === CODE ===
+void MM_InitVirt(void)
+{
+//     Log_Debug("MMVirt", "&PAGEMAPLVL4(0) = %p", &PAGEMAPLVL4(0));
+//     MM_DumpTables(0, -1L);
+}
+
+void MM_FinishVirtualInit(void)
+{
+       PAGEMAPLVL4(0) = 0;
+}
+
+/**
+ * \brief Clone a page from an entry
+ * \param Ent  Pointer to the entry in the PML4/PDP/PD/PT
+ * \param NextLevel    Pointer to contents of the entry
+ * \param Addr Dest address
+ * \note Used in COW
+ */
+void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable )
+{
+       tPAddr  curpage = *Ent & PADDR_MASK; 
+        int    bCopied = 0;
+       
+       if( MM_GetRefCount( curpage ) <= 0 ) {
+               Log_KernelPanic("MMVirt", "Page %P still marked COW, but unreferenced", curpage);
+       }
+       if( MM_GetRefCount( curpage ) == 1 )
+       {
+               *Ent &= ~PF_COW;
+               *Ent |= PF_PRESENT|PF_WRITE;
+               #if TRACE_COW
+               Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
+               #endif
+       }
+       else
+       {
+               void    *tmp;
+               tPAddr  paddr;
+               
+               if( !(paddr = MM_AllocPhys()) ) {
+                       Threads_SegFault(Addr);
+                       return ;
+               }
+
+               ASSERT(paddr != curpage);
+                       
+               tmp = (void*)MM_MapTemp(paddr);
+               memcpy( tmp, NextLevel, 0x1000 );
+               MM_FreeTemp( (tVAddr)tmp );
+               
+               #if TRACE_COW
+               Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
+               #endif
+
+               MM_DerefPhys( curpage );
+               *Ent &= PF_USER;
+               *Ent |= paddr|PF_PRESENT|PF_WRITE;
+               
+               bCopied = 1;
+       }
+       INVLPG( (tVAddr)NextLevel );
+       
+       // Mark COW on contents if it's a PDPT, Dir or Table
+       if(bTable) 
+       {
+               Uint64  *dp = NextLevel;
+                int    i;
+               for( i = 0; i < 512; i ++ )
+               {
+                       if( !(dp[i] & PF_PRESENT) )
+                               continue;
+                       
+                       if( bCopied )
+                               MM_RefPhys( dp[i] & PADDR_MASK );
+                       if( dp[i] & PF_WRITE ) {
+                               dp[i] &= ~PF_WRITE;
+                               dp[i] |= PF_COW;
+                       }
+               }
+       }
+}
+
+/*
+ * \brief Called on a page fault
+ */
+int MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
+{
+//     Log_Debug("MMVirt", "Addr = %p, ErrorCode = %x", Addr, ErrorCode);
+
+       // Catch reserved bits first
+       if( ErrorCode & 0x8 )
+       {
+               Log_Warning("MMVirt", "Reserved bits trashed!");
+               Log_Warning("MMVirt", "PML4 Ent   = %P", PAGEMAPLVL4(Addr>>39));
+               if( !(PAGEMAPLVL4(Addr>>39) & PF_PRESENT) )     goto print_done;
+               Log_Warning("MMVirt", "PDP Ent    = %P", PAGEDIRPTR(Addr>>30));
+               if( !(PAGEDIRPTR(Addr>>30) & PF_PRESENT) )      goto print_done;
+               Log_Warning("MMVirt", "PDir Ent   = %P", PAGEDIR(Addr>>21));
+               if( !(PAGEDIR(Addr>>21) & PF_PRESENT) ) goto print_done;
+               Log_Warning("MMVirt", "PTable Ent = %P", PAGETABLE(Addr>>12));
+               if( !(PAGETABLE(Addr>>12) & PF_PRESENT) )       goto print_done;
+       print_done:
+               
+               for(;;);
+       }
+
+       // TODO: Implement Copy-on-Write
+       #if 1
+       if( PAGEMAPLVL4(Addr>>39) & PF_PRESENT
+        && PAGEDIRPTR (Addr>>30) & PF_PRESENT
+        && PAGEDIR    (Addr>>21) & PF_PRESENT
+        && PAGETABLE  (Addr>>12) & PF_PRESENT )
+       {
+               // PML4 Entry
+               if( PAGEMAPLVL4(Addr>>39) & PF_COW )
+               {
+                       tPAddr  *dp = &PAGEDIRPTR((Addr>>39)*512);
+                       MM_int_ClonePageEnt( &PAGEMAPLVL4(Addr>>39), dp, Addr, 1 );
+//                     MM_DumpTables(Addr>>39 << 39, (((Addr>>39) + 1) << 39) - 1);
+               }
+               // PDP Entry
+               if( PAGEDIRPTR(Addr>>30) & PF_COW )
+               {
+                       tPAddr  *dp = &PAGEDIR( (Addr>>30)*512 );
+                       MM_int_ClonePageEnt( &PAGEDIRPTR(Addr>>30), dp, Addr, 1 );
+//                     MM_DumpTables(Addr>>30 << 30, (((Addr>>30) + 1) << 30) - 1);
+               }
+               // PD Entry
+               if( PAGEDIR(Addr>>21) & PF_COW )
+               {
+                       tPAddr  *dp = &PAGETABLE( (Addr>>21)*512 );
+                       MM_int_ClonePageEnt( &PAGEDIR(Addr>>21), dp, Addr, 1 );
+//                     MM_DumpTables(Addr>>21 << 21, (((Addr>>21) + 1) << 21) - 1);
+               }
+               // PT Entry
+               if( PAGETABLE(Addr>>12) & PF_COW )
+               {
+                       MM_int_ClonePageEnt( &PAGETABLE(Addr>>12), (void*)(Addr & ~0xFFF), Addr, 0 );
+                       INVLPG( Addr & ~0xFFF );
+                       return 0;
+               }
+       }
+       #endif
+       
+       // If it was a user, tell the thread handler
+       if(ErrorCode & 4) {
+               Warning("User %s %s memory%s",
+                       (ErrorCode&2?"write to":"read from"),
+                       (ErrorCode&1?"bad/locked":"non-present"),
+                       (ErrorCode&16?" (Instruction Fetch)":"")
+                       );
+               Warning("User Pagefault: Instruction at %04x:%p accessed %p",
+                       Regs->CS, Regs->RIP, Addr);
+               __asm__ __volatile__ ("sti");   // Restart IRQs
+               Error_Backtrace(Regs->RIP, Regs->RBP);
+               Threads_SegFault(Addr);
+               return 0;
+       }
+       
+       // Kernel #PF
+       Debug_KernelPanic();
+       // -- Check Error Code --
+       if(ErrorCode & 8)
+               Warning("Reserved Bits Trashed!");
+       else
+       {
+               Warning("Kernel %s %s memory%s",
+                       (ErrorCode&2?"write to":"read from"),
+                       (ErrorCode&1?"bad/locked":"non-present"),
+                       (ErrorCode&16?" (Instruction Fetch)":"")
+                       );
+       }
+       
+       Log("Thread %i - Code at %p accessed %p", Threads_GetTID(), Regs->RIP, Addr);
+       // Print Stack Backtrace
+       Error_Backtrace(Regs->RIP, Regs->RBP);
+       
+       MM_DumpTables(0, -1);
+
+       return 1;       
+}
+
+void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected)
+{
+       #define CANOICAL(addr)  ((addr)&0x800000000000?(addr)|0xFFFF000000000000:(addr))
+       LogF("%016llx => ", CANOICAL(RangeStart));
+//     LogF("%6llx %6llx %6llx %016llx => ",
+//             MM_GetPhysAddr( (tVAddr)&PAGEDIRPTR(RangeStart>>30) ),
+//             MM_GetPhysAddr( (tVAddr)&PAGEDIR(RangeStart>>21) ),
+//             MM_GetPhysAddr( (tVAddr)&PAGETABLE(RangeStart>>12) ),
+//             CANOICAL(RangeStart)
+//             );
+       if( gMM_ZeroPage && (PAGETABLE(RangeStart>>12) & PADDR_MASK) == gMM_ZeroPage )
+               LogF("%13s", "zero" );
+       else
+               LogF("%13llx", PAGETABLE(RangeStart>>12) & PADDR_MASK );
+       LogF(" : 0x%6llx (%c%c%c%c%c%c)\r\n",
+               Length,
+               (Expected & PF_GLOBAL ? 'G' : '-'),
+               (Expected & PF_NX ? '-' : 'x'),
+               (Expected & PF_PAGED ? 'p' : '-'),
+               (Expected & PF_COW ? 'C' : '-'),
+               (Expected & PF_USER ? 'U' : '-'),
+               (Expected & PF_WRITE ? 'W' : '-')
+               );
+       #undef CANOICAL
+}
+
+/**
+ * \brief Dumps the layout of the page tables
+ */
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+       const tPAddr    FIXED_BITS = PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED|PF_NX|PF_GLOBAL;
+       const tPAddr    CHANGEABLE_BITS = ~FIXED_BITS & 0xFFF;
+       const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
+       tVAddr  rangeStart = 0;
+       tPAddr  expected = CHANGEABLE_BITS;     // CHANGEABLE_BITS is used because it's not a vaild value
+       tVAddr  curPos;
+       Uint    page;
+       tPAddr  expected_pml4 = PF_WRITE|PF_USER;       
+       tPAddr  expected_pdp = PF_WRITE|PF_USER;        
+       tPAddr  expected_pd = PF_WRITE|PF_USER; 
+
+       Log("Table Entries: (%p to %p)", Start, End);
+       
+       End &= (1L << 48) - 1;
+       
+       Start >>= 12;   End >>= 12;
+       
+       for(page = Start, curPos = Start<<12;
+               page < End;
+               curPos += 0x1000, page++)
+       {
+               //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27));
+               //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18));
+               //Debug("&PAGEDIR(%i page>>9) = %p", page>>9, &PAGEDIR(page>>9));
+               //Debug("&PAGETABLE(%i page) = %p", page, &PAGETABLE(page));
+               
+               // End of a range
+               if(!(PAGEMAPLVL4(page>>27) & PF_PRESENT)
+               ||  (PAGEMAPLVL4(page>>27) & FIXED_BITS) != expected_pml4
+               || !(PAGEDIRPTR(page>>18) & PF_PRESENT)
+               ||  (PAGEDIRPTR(page>>18) & FIXED_BITS) != expected_pdp
+               || !(PAGEDIR(page>>9) & PF_PRESENT)
+               ||  (PAGEDIR(page>>9) & FIXED_BITS) != expected_pd
+               || !(PAGETABLE(page) & PF_PRESENT)
+               ||  (PAGETABLE(page) & MASK) != expected)
+               {                       
+                       if(expected != CHANGEABLE_BITS)
+                       {
+                               // Merge
+                               expected &= expected_pml4 | ~(PF_WRITE|PF_USER);
+                               expected &= expected_pdp  | ~(PF_WRITE|PF_USER);
+                               expected &= expected_pd   | ~(PF_WRITE|PF_USER);
+                               expected |= expected_pml4 & PF_NX;
+                               expected |= expected_pdp  & PF_NX;
+                               expected |= expected_pd   & PF_NX;
+                               Log("expected (pml4 = %x, pdp = %x, pd = %x)",
+                                       expected_pml4, expected_pdp, expected_pd);
+                               // Dump
+                               MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
+                               expected = CHANGEABLE_BITS;
+                       }
+                       
+                       if( curPos == 0x800000000000L )
+                               curPos = 0xFFFF800000000000L;
+               
+                       if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) ) {
+                               page += (1 << 27) - 1;
+                               curPos += (1L << 39) - 0x1000;
+                               continue;
+                       }
+                       if( !(PAGEDIRPTR(page>>18) & PF_PRESENT) ) {
+                               page += (1 << 18) - 1;
+                               curPos += (1L << 30) - 0x1000;
+                               continue;
+                       }
+                       if( !(PAGEDIR(page>>9) & PF_PRESENT) ) {
+                               page += (1 << 9) - 1;
+                               curPos += (1L << 21) - 0x1000;
+                               continue;
+                       }
+                       if( !(PAGETABLE(page) & PF_PRESENT) )   continue;
+                       
+                       expected = (PAGETABLE(page) & MASK);
+                       expected_pml4 = (PAGEMAPLVL4(page>>27) & FIXED_BITS);
+                       expected_pdp  = (PAGEDIRPTR (page>>18) & FIXED_BITS);
+                       expected_pd   = (PAGEDIR    (page>> 9) & FIXED_BITS);
+                       rangeStart = curPos;
+               }
+               if(gMM_ZeroPage && (expected & PADDR_MASK) == gMM_ZeroPage )
+                       expected = expected;
+               else if(expected != CHANGEABLE_BITS)
+                       expected += 0x1000;
+       }
+       
+       if(expected != CHANGEABLE_BITS) {
+               // Merge
+               
+               // Dump
+               MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
+               expected = 0;
+       }
+}
+
+/**
+ * \brief Get a pointer to a page entry
+ * \param Addr Virtual Address
+ * \param bTemp        Use the Temporary fractal mapping
+ * \param bAllocate    Allocate entries
+ * \param bLargePage   Request a large page
+ * \param Pointer      Location to place the calculated pointer
+ * \return Page size, or -ve on error
+ */
+int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer)
+{
+       tPAddr  *pmlevels[4];
+       tPAddr  tmp;
+        int    i, size;
+       
+       #define BITMASK(bits)   ( (1LL << (bits))-1 )
+
+       if( bTemp )
+       {
+               pmlevels[3] = &TMPTABLE(0);     // Page Table
+               pmlevels[2] = &TMPDIR(0);       // PDIR
+               pmlevels[1] = &TMPDIRPTR(0);    // PDPT
+               pmlevels[0] = &TMPMAPLVL4(0);   // PML4
+       }
+       else
+       {
+               pmlevels[3] = (void*)MM_FRACTAL_BASE;   // Page Table
+               pmlevels[2] = &pmlevels[3][(MM_FRACTAL_BASE>>12)&BITMASK(VIRT_BITS-12)];        // PDIR
+               pmlevels[1] = &pmlevels[2][(MM_FRACTAL_BASE>>21)&BITMASK(VIRT_BITS-21)];        // PDPT
+               pmlevels[0] = &pmlevels[1][(MM_FRACTAL_BASE>>30)&BITMASK(VIRT_BITS-30)];        // PML4
+       }
+       
+       // Mask address
+       Addr &= (1ULL << 48)-1;
+       
+       for( size = 39, i = 0; size > 12; size -= 9, i ++ )
+       {
+               Uint64  *ent = &pmlevels[i][Addr >> size];
+//             INVLPG( &pmlevels[i][ (Addr >> ADDR_SIZES[i]) & 
+               
+               // Check for a free large page slot
+               // TODO: Better support with selectable levels
+               if( (Addr & ((1ULL << size)-1)) == 0 && bLargePage )
+               {
+                       if(Pointer)     *Pointer = ent;
+                       return size;
+               }
+               // Allocate an entry if required
+               if( !(*ent & PF_PRESENT) )
+               {
+                       if( !bAllocate )        return -4;      // If allocation is not requested, error
+                       if( !(tmp = MM_AllocPhys()) )   return -2;
+                       *ent = tmp | 3;
+                       if( Addr < 0x800000000000 )
+                               *ent |= PF_USER;
+                       INVLPG( &pmlevels[i+1][ (Addr>>size)*512 ] );
+                       memset( &pmlevels[i+1][ (Addr>>size)*512 ], 0, 0x1000 );
+                       LOG("Init PML%i ent 0x%x %p with %P (*ent = %P)", 4 - i,
+                               Addr>>size, (Addr>>size) << size, tmp, *ent);
+               }
+               // Catch large pages
+               else if( *ent & PF_LARGE )
+               {
+                       // Alignment
+                       if( (Addr & ((1ULL << size)-1)) != 0 )  return -3;
+                       if(Pointer)     *Pointer = ent;
+                       return size;    // Large page warning
+               }
+       }
+       
+       // And, set the page table entry
+       if(Pointer)     *Pointer = &pmlevels[i][Addr >> size];
+       return size;
+}
+
+/**
+ * \brief Map a physical page to a virtual one
+ * \param VAddr        Target virtual address
+ * \param PAddr        Physical address of page
+ * \param bTemp        Use tempoary mappings
+ * \param bLarge       Treat as a large page
+ */
+int MM_MapEx(tVAddr VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge)
+{
+       tPAddr  *ent;
+        int    rv;
+       
+       ENTER("pVAddr PPAddr", VAddr, PAddr);
+       
+       // Get page pointer (Allow allocating)
+       rv = MM_GetPageEntryPtr(VAddr, bTemp, 1, bLarge, &ent);
+       if(rv < 0)      LEAVE_RET('i', 0);
+       
+       if( *ent & 1 )  LEAVE_RET('i', 0);
+       
+       *ent = PAddr | 3;
+
+       if( VAddr < 0x800000000000 )
+               *ent |= PF_USER;
+
+       INVLPG( VAddr );
+
+       LEAVE('i', 1);  
+       return 1;
+}
+
+/**
+ * \brief Map a physical page to a virtual one
+ * \param VAddr        Target virtual address
+ * \param PAddr        Physical address of page
+ */
+int MM_Map(tVAddr VAddr, tPAddr PAddr)
+{
+       return MM_MapEx(VAddr, PAddr, 0, 0);
+}
+
+/**
+ * \brief Removed a mapped page
+ */
+void MM_Unmap(tVAddr VAddr)
+{
+       // Check PML4
+       if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )   return ;
+       // Check PDP
+       if( !(PAGEDIRPTR(VAddr >> 30) & 1) )    return ;
+       // Check Page Dir
+       if( !(PAGEDIR(VAddr >> 21) & 1) )       return ;
+
+       PAGETABLE(VAddr >> PTAB_SHIFT) = 0;
+       INVLPG( VAddr );
+}
+
+/**
+ * \brief Allocate a block of memory at the specified virtual address
+ */
+tPAddr MM_Allocate(tVAddr VAddr)
+{
+       tPAddr  ret;
+       
+       ENTER("xVAddr", VAddr);
+       
+       // Ensure the tables are allocated before the page (keeps things neat)
+       MM_GetPageEntryPtr(VAddr, 0, 1, 0, NULL);
+       
+       // Allocate the page
+       ret = MM_AllocPhys();
+       LOG("ret = %x", ret);
+       if(!ret)        LEAVE_RET('i', 0);
+       
+       if( !MM_Map(VAddr, ret) )
+       {
+               Warning("MM_Allocate: Unable to map. Strange, we should have errored earlier");
+               MM_DerefPhys(ret);
+               LEAVE('i');
+               return 0;
+       }
+       
+       LEAVE('X', ret);
+       return ret;
+}
+
+tPAddr MM_AllocateZero(tVAddr VAddr)
+{
+       tPAddr  ret = gMM_ZeroPage;
+       
+       MM_GetPageEntryPtr(VAddr, 0, 1, 0, NULL);
+
+       if(!gMM_ZeroPage) {
+               ret = gMM_ZeroPage = MM_AllocPhys();
+               MM_RefPhys(ret);        // Don't free this please
+               MM_Map(VAddr, ret);
+               memset((void*)VAddr, 0, 0x1000);
+       }
+       else {
+               MM_Map(VAddr, ret);
+       }
+       MM_RefPhys(ret);        // Refernce for this map
+       MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
+       return ret;
+}
+
+/**
+ * \brief Deallocate a page at a virtual address
+ */
+void MM_Deallocate(tVAddr VAddr)
+{
+       tPAddr  phys;
+       
+       phys = MM_GetPhysAddr(VAddr);
+       if(!phys)       return ;
+       
+       MM_Unmap(VAddr);
+       
+       MM_DerefPhys(phys);
+}
+
+/**
+ * \brief Get the page table entry of a virtual address
+ * \param Addr Virtual Address
+ * \param Phys Location to put the physical address
+ * \param Flags        Flags on the entry (set to zero if unmapped)
+ * \return Size of the entry (in address bits) - 12 = 4KiB page
+ */
+int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags)
+{
+       tPAddr  *ptr;
+        int    ret;
+       
+       if(!Phys || !Flags)     return 0;
+       
+       ret = MM_GetPageEntryPtr(Addr, 0, 0, 0, &ptr);
+       if( ret < 0 )   return 0;
+       
+       *Phys = *ptr & PADDR_MASK;
+       *Flags = *ptr & 0xFFF;
+       return ret;
+}
+
+/**
+ * \brief Get the physical address of a virtual location
+ */
+tPAddr MM_GetPhysAddr(tVAddr Addr)
+{
+       tPAddr  *ptr;
+        int    ret;
+       
+       ret = MM_GetPageEntryPtr(Addr, 0, 0, 0, &ptr);
+       if( ret < 0 )   return 0;
+       
+       if( !(*ptr & 1) )       return 0;
+       
+       return (*ptr & PADDR_MASK) | (Addr & 0xFFF);
+}
+
+/**
+ * \brief Sets the flags on a page
+ */
+void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
+{
+       tPAddr  *ent;
+        int    rv;
+       
+       // Get pointer
+       rv = MM_GetPageEntryPtr(VAddr, 0, 0, 0, &ent);
+       if(rv < 0)      return ;
+       
+       // Ensure the entry is valid
+       if( !(*ent & 1) )       return ;
+       
+       // Read-Only
+       if( Mask & MM_PFLAG_RO )
+       {
+               if( Flags & MM_PFLAG_RO ) {
+                       *ent &= ~PF_WRITE;
+               }
+               else {
+                       *ent |= PF_WRITE;
+               }
+       }
+       
+       // Kernel
+       if( Mask & MM_PFLAG_KERNEL )
+       {
+               if( Flags & MM_PFLAG_KERNEL ) {
+                       *ent &= ~PF_USER;
+               }
+               else {
+                       *ent |= PF_USER;
+               }
+       }
+       
+       // Copy-On-Write
+       if( Mask & MM_PFLAG_COW )
+       {
+               if( Flags & MM_PFLAG_COW ) {
+                       *ent &= ~PF_WRITE;
+                       *ent |= PF_COW;
+       INVLPG_ALL();
+               }
+               else {
+                       *ent &= ~PF_COW;
+                       *ent |= PF_WRITE;
+               }
+       }
+       
+       // Execute
+       if( Mask & MM_PFLAG_EXEC )
+       {
+               if( Flags & MM_PFLAG_EXEC ) {
+                       *ent &= ~PF_NX;
+               }
+               else {
+                       *ent |= PF_NX;
+               }
+       }
+}
+
+/**
+ * \brief Get the flags applied to a page
+ */
+Uint MM_GetFlags(tVAddr VAddr)
+{
+       tPAddr  *ent;
+        int    rv, ret = 0;
+       
+       rv = MM_GetPageEntryPtr(VAddr, 0, 0, 0, &ent);
+       if(rv < 0)      return 0;
+       
+       if( !(*ent & 1) )       return 0;
+       
+       // Read-Only
+       if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
+       // Kernel
+       if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
+       // Copy-On-Write
+       if( *ent & PF_COW )     ret |= MM_PFLAG_COW;    
+       // Execute
+       if( !(*ent & PF_NX) )   ret |= MM_PFLAG_EXEC;
+       
+       return ret;
+}
+
+/**
+ * \brief Check if the provided buffer is valid
+ * \return Boolean valid
+ */
+int MM_IsValidBuffer(tVAddr Addr, size_t Size)
+{
+        int    bIsUser;
+       Uint64  pml4, pdp, dir, tab;
+
+       Size += Addr & (PAGE_SIZE-1);
+       Addr &= ~(PAGE_SIZE-1);
+       Addr &= ((1UL << 48)-1);        // Clap to address space
+
+       pml4 = Addr >> 39;
+       pdp = Addr >> 30;
+       dir = Addr >> 21;
+       tab = Addr >> 12;
+
+       if( !(PAGEMAPLVL4(pml4) & 1) )  return 0;
+       if( !(PAGEDIRPTR(pdp) & 1) )    return 0;
+       if( !(PAGEDIR(dir) & 1) )       return 0;
+       if( !(PAGETABLE(tab) & 1) )     return 0;
+       
+       bIsUser = !!(PAGETABLE(tab) & PF_USER);
+
+       while( Size >= PAGE_SIZE )
+       {
+               if( (tab & 511) == 0 )
+               {
+                       dir ++;
+                       if( ((dir >> 9) & 511) == 0 )
+                       {
+                               pdp ++;
+                               if( ((pdp >> 18) & 511) == 0 )
+                               {
+                                       pml4 ++;
+                                       if( !(PAGEMAPLVL4(pml4) & 1) )  return 0;
+                               }
+                               if( !(PAGEDIRPTR(pdp) & 1) )    return 0;
+                       }
+                       if( !(PAGEDIR(dir) & 1) )       return 0;
+               }
+               
+               if( !(PAGETABLE(tab) & 1) )   return 0;
+               if( bIsUser && !(PAGETABLE(tab) & PF_USER) )    return 0;
+
+               tab ++;
+               Size -= PAGE_SIZE;
+       }
+       return 1;
+}
+
+// --- Hardware Mappings ---
+/**
+ * \brief Map a range of hardware pages
+ */
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
+{
+       tVAddr  ret;
+        int    num;
+       
+       //TODO: Add speedups (memory of first possible free)
+       for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_TOP; ret += 0x1000 )
+       {
+               for( num = Number; num -- && ret < MM_HWMAP_TOP; ret += 0x1000 )
+               {
+                       if( MM_GetPhysAddr(ret) != 0 )  break;
+               }
+               if( num >= 0 )  continue;
+               
+//             Log_Debug("MMVirt", "Mapping %i pages to %p (base %P)", Number, ret-Number*0x1000, PAddr);
+
+               PAddr += 0x1000 * Number;
+               
+               while( Number -- )
+               {
+                       ret -= 0x1000;
+                       PAddr -= 0x1000;
+                       MM_Map(ret, PAddr);
+                       MM_RefPhys(PAddr);
+               }
+               
+               return ret;
+       }
+       
+       Log_Error("MM", "MM_MapHWPages - No space for %i pages", Number);
+       return 0;
+}
+
+/**
+ * \brief Free a range of hardware pages
+ */
+void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
+{
+//     Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
+       while( Number -- )
+       {
+               MM_DerefPhys( MM_GetPhysAddr(VAddr) );
+               MM_Unmap(VAddr);
+               VAddr += 0x1000;
+       }
+}
+
+
+/**
+ * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
+ * \brief Allocates DMA physical memory
+ * \param Pages        Number of pages required
+ * \param MaxBits      Maximum number of bits the physical address can have
+ * \param PhysAddr     Pointer to the location to place the physical address allocated
+ * \return Virtual address allocate
+ */
+tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
+{
+       tPAddr  phys;
+       tVAddr  ret;
+       
+       // Sanity Check
+       if(MaxBits < 12 || !PhysAddr)   return 0;
+       
+       // Fast Allocate
+       if(Pages == 1 && MaxBits >= PHYS_BITS)
+       {
+               phys = MM_AllocPhys();
+               *PhysAddr = phys;
+               ret = MM_MapHWPages(phys, 1);
+               MM_DerefPhys(phys);
+               return ret;
+       }
+       
+       // Slow Allocate
+       phys = MM_AllocPhysRange(Pages, MaxBits);
+       // - Was it allocated?
+       if(phys == 0)   return 0;
+       
+       // Allocated successfully, now map
+       ret = MM_MapHWPages(phys, Pages);
+       // MapHWPages references the pages, so deref them back down to 1
+       for(;Pages--;phys+=0x1000)
+               MM_DerefPhys(phys);
+       if( ret == 0 ) {
+               // If it didn't map, free then return 0
+               return 0;
+       }
+       
+       *PhysAddr = phys;
+       return ret;
+}
+
+// --- Tempory Mappings ---
+tVAddr MM_MapTemp(tPAddr PAddr)
+{
+       const int max_slots = (MM_TMPMAP_END - MM_TMPMAP_BASE) / PAGE_SIZE;
+       tVAddr  ret = MM_TMPMAP_BASE;
+        int    i;
+       
+       for( i = 0; i < max_slots; i ++, ret += PAGE_SIZE )
+       {
+               tPAddr  *ent;
+               if( MM_GetPageEntryPtr( ret, 0, 1, 0, &ent) < 0 ) {
+                       continue ;
+               }
+
+               if( *ent & 1 )
+                       continue ;
+
+               *ent = PAddr | 3;
+               MM_RefPhys(PAddr);
+               INVLPG(ret);
+               return ret;
+       }
+       return 0;
+}
+
+void MM_FreeTemp(tVAddr VAddr)
+{
+       MM_Deallocate(VAddr);
+       return ;
+}
+
+
+// --- Address Space Clone --
+tPAddr MM_Clone(void)
+{
+       tPAddr  ret;
+        int    i;
+       tVAddr  kstackbase;
+
+       // #1 Create a copy of the PML4
+       ret = MM_AllocPhys();
+       if(!ret)        return 0;
+       
+       // #2 Alter the fractal pointer
+       Mutex_Acquire(&glMM_TempFractalLock);
+       TMPCR3() = ret | 3;
+       INVLPG_ALL();
+       
+       // #3 Set Copy-On-Write to all user pages
+       if( Threads_GetPID() != 0 )
+       {
+               for( i = 0; i < 256; i ++)
+               {
+                       if( PAGEMAPLVL4(i) & PF_WRITE ) {
+                               PAGEMAPLVL4(i) |= PF_COW;
+                               PAGEMAPLVL4(i) &= ~PF_WRITE;
+                       }
+       
+                       TMPMAPLVL4(i) = PAGEMAPLVL4(i);
+//                     Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i));
+                       if( !(TMPMAPLVL4(i) & PF_PRESENT) )     continue ;
+                       
+                       MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
+               }
+       }
+       else
+       {
+               for( i = 0; i < 256; i ++ )
+               {
+                       TMPMAPLVL4(i) = 0;
+               }
+       }
+       
+       // #4 Map in kernel pages
+       for( i = 256; i < 512; i ++ )
+       {
+               // Skip addresses:
+               // 320 0xFFFFA....      - Kernel Stacks
+               if( i == MM_KSTACK_BASE>>39 )   continue;
+               // 509 0xFFFFFE0..      - Fractal mapping
+               if( i == MM_FRACTAL_BASE>>39 )  continue;
+               // 510 0xFFFFFE8..      - Temp fractal mapping
+               if( i == MM_TMPFRAC_BASE>>39 )  continue;
+               
+               TMPMAPLVL4(i) = PAGEMAPLVL4(i);
+               if( TMPMAPLVL4(i) & 1 )
+                       MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
+       }
+
+       // Mark Per-Process data as COW
+       TMPMAPLVL4(MM_PPD_BASE>>39) |= PF_COW;
+       TMPMAPLVL4(MM_PPD_BASE>>39) &= ~PF_WRITE;
+       
+       // #5 Set fractal mapping
+       TMPMAPLVL4(MM_FRACTAL_BASE>>39) = ret | 3;      // Main
+       TMPMAPLVL4(MM_TMPFRAC_BASE>>39) = 0;    // Temp
+       
+       // #6 Create kernel stack
+       //  tThread->KernelStack is the top
+       //  There is 1 guard page below the stack
+       kstackbase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE;
+
+       // Clone stack
+       TMPMAPLVL4(MM_KSTACK_BASE >> PML4_SHIFT) = 0;
+       for( i = 1; i < KERNEL_STACK_SIZE/0x1000; i ++ )
+       {
+               tPAddr  phys = MM_AllocPhys();
+               tVAddr  tmpmapping;
+               MM_MapEx(kstackbase+i*0x1000, phys, 1, 0);
+               
+               tmpmapping = MM_MapTemp(phys);
+               if( MM_GetPhysAddr( kstackbase+i*0x1000 ) )
+                       memcpy((void*)tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
+               else
+                       memset((void*)tmpmapping, 0, 0x1000);
+//             if( i == 0xF )
+//                     Debug_HexDump("MM_Clone: *tmpmapping = ", (void*)tmpmapping, 0x1000);
+               MM_FreeTemp(tmpmapping);
+       }
+       
+//     MAGIC_BREAK();
+
+       // #7 Return
+       TMPCR3() = 0;
+       INVLPG_ALL();
+       Mutex_Release(&glMM_TempFractalLock);
+//     Log("MM_Clone: RETURN %P", ret);
+       return ret;
+}
+
+void MM_int_ClearTableLevel(tVAddr VAddr, int LevelBits, int MaxEnts)
+{
+       Uint64  * const table_bases[] = {&PAGETABLE(0), &PAGEDIR(0), &PAGEDIRPTR(0), &PAGEMAPLVL4(0)};
+       Uint64  *table = table_bases[(LevelBits-12)/9] + (VAddr >> LevelBits);
+        int    i;
+//     Log("MM_int_ClearTableLevel: (VAddr=%p, LevelBits=%i, MaxEnts=%i)", VAddr, LevelBits, MaxEnts);
+       for( i = 0; i < MaxEnts; i ++ )
+       {
+               // Skip non-present tables
+               if( !(table[i] & PF_PRESENT) ) {
+                       table[i] = 0;
+                       continue ;
+               }
+       
+               if( (table[i] & PF_COW) && MM_GetRefCount(table[i] & PADDR_MASK) > 1 ) {
+                       MM_DerefPhys(table[i] & PADDR_MASK);
+                       table[i] = 0;
+                       continue ;
+               }
+               // Clear table contents (if it is a table)
+               if( LevelBits > 12 )
+                       MM_int_ClearTableLevel(VAddr + ((tVAddr)i << LevelBits), LevelBits-9, 512);
+               MM_DerefPhys(table[i] & PADDR_MASK);
+               table[i] = 0;
+       }
+}
+
+void MM_ClearUser(void)
+{
+       MM_int_ClearTableLevel(0, 39, 256);     
+}
+
+tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize)
+{
+       tVAddr  ret;
+       tPAddr  phys;
+        int    i;
+       
+       // #1 Set temp fractal to PID0
+       Mutex_Acquire(&glMM_TempFractalLock);
+       TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3;
+       INVLPG_ALL();
+       
+       // #2 Scan for a free stack addresss < 2^47
+       for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE)
+       {
+               tPAddr  *ptr;
+               if( MM_GetPageEntryPtr(ret, 1, 0, 0, &ptr) <= 0 )       break;
+               if( !(*ptr & 1) )       break;
+       }
+       if( ret >= (1ULL << 47) ) {
+               Mutex_Release(&glMM_TempFractalLock);
+               return 0;
+       }
+       
+       // #3 Map all save the last page in the range
+       //  - This acts as as guard page
+       MM_GetPageEntryPtr(ret, 1, 1, 0, NULL); // Make sure tree is allocated
+       for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ )
+       {
+               phys = MM_AllocPhys();
+               if(!phys) {
+                       // TODO: Clean up
+                       Log_Error("MM", "MM_NewWorkerStack - Unable to allocate page");
+                       return 0;
+               }
+               MM_MapEx(ret + i*0x1000, phys, 1, 0);
+               MM_SetFlags(ret + i*0x1000, MM_PFLAG_KERNEL|MM_PFLAG_RO, MM_PFLAG_KERNEL);
+       }
+
+       // Copy data
+       if( StackSize > 0x1000 ) {
+               Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize);
+       }
+       else {
+               tVAddr  tmp_addr, dest;
+               tmp_addr = MM_MapTemp(phys);
+               dest = tmp_addr + (0x1000 - StackSize);
+               memcpy( (void*)dest, StackData, StackSize );
+               Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i);
+               Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret);
+               MM_FreeTemp(tmp_addr);
+       }
+
+       TMPCR3() = 0;
+       Mutex_Release(&glMM_TempFractalLock);
+       
+       return ret + i*0x1000;
+}
+
+/**
+ * \brief Allocate a new kernel stack
+ */
+tVAddr MM_NewKStack(void)
+{
+       tVAddr  base = MM_KSTACK_BASE;
+       Uint    i;
+       for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
+       {
+               if(MM_GetPhysAddr(base+KERNEL_STACK_SIZE-0x1000) != 0)
+                       continue;
+               
+               //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
+               for( i = 0x1000; i < KERNEL_STACK_SIZE; i += 0x1000)
+               {
+                       if( !MM_Allocate(base+i) )
+                       {
+                               Log_Warning("MM", "MM_NewKStack - Allocation failed");
+                               for( i -= 0x1000; i; i -= 0x1000)
+                                       MM_Deallocate(base+i);
+                               return 0;
+                       }
+               }
+               
+               return base + KERNEL_STACK_SIZE;
+       }
+       Log_Warning("MM", "MM_NewKStack - No address space left\n");
+       return 0;
+}
diff --git a/KernelLand/Kernel/arch/x86_64/pci.c b/KernelLand/Kernel/arch/x86_64/pci.c
new file mode 120000 (symlink)
index 0000000..cac29a8
--- /dev/null
@@ -0,0 +1 @@
+../x86/pci.c
\ No newline at end of file
diff --git a/KernelLand/Kernel/arch/x86_64/proc.asm b/KernelLand/Kernel/arch/x86_64/proc.asm
new file mode 100644 (file)
index 0000000..f540b3b
--- /dev/null
@@ -0,0 +1,148 @@
+;
+;
+;
+%include "arch/x86_64/include/common.inc.asm"
+[BITS 64]
+[section .text]
+
+[extern Threads_Exit]
+
+[global GetRIP]
+GetRIP:
+       mov rax, [rsp]
+       ret
+
+[global NewTaskHeader]
+NewTaskHeader:
+       ; [rsp+0x00]: Thread
+       ; [rsp+0x08]: Function
+       ; [rsp+0x10]: Argument
+
+       mov rdi, [rsp+0x10]
+       mov rax, [rsp+0x8]
+       add rsp, 0x10   ; Reclaim stack space (thread/fcn)
+       xchg bx, bx
+       call rax
+       
+       ; Quit thread with RAX as the return code
+       xor rdi, rdi
+       mov rsi, rax
+       call Threads_Exit
+
+.hlt:
+       jmp .hlt
+
+[extern MM_Clone]
+[extern MM_DumpTables]
+[global Proc_CloneInt]
+Proc_CloneInt:
+       PUSH_GPR
+       ; Save RSP
+       mov [rdi], rsp
+       call MM_Clone
+       ; Save CR3
+       mov rsi, [rsp+0x30]     ; Saved version of RSI
+       mov [rsi], rax
+       ; Undo the PUSH_GPR
+       add rsp, 0x80
+       mov rax, .newTask
+       ret
+.newTask:
+;      mov rdi, 0
+;      mov rsi, 0x800000000000
+;      call MM_DumpTables
+       POP_GPR
+       xor eax, eax
+       ret
+
+[global SaveState]
+SaveState:
+       ; Save regs to RSI
+       add rsi, 0x80
+       SAVE_GPR rsi
+       ; Save return addr
+       mov rax, [rsp]
+       mov [rsi], rax
+       ; Return RSI as the RSP value
+       sub rsi, 0x80
+       mov [rdi], rsi
+       ; Check for 
+       mov rax, .restore
+       ret
+.restore:
+       ; RSP = RSI now
+       POP_GPR
+       mov rax, [rsp]
+       mov rsp, [rsp-0x60]     ; Restore RSP from the saved value
+       mov [rsp], rax  ; Restore return address
+       xor eax, eax
+       ret
+
+[global SwitchTasks]
+; rdi = New RSP
+; rsi = Old RSP save loc
+; rdx = New RIP
+; rcx = Old RIP save loc
+; r8 = CR3
+SwitchTasks:
+       PUSH_GPR
+       
+       ; Save state RIP and RSP
+       lea rax, [rel .restore]
+       mov [rcx], rax
+       mov [rsi], rsp
+
+       ; Change CR3 if requested
+       test r8, r8
+       jz .setState
+       mov cr3, r8
+       
+       ; Make sure the stack is valid before jumping
+       invlpg [rdi-0x1000]
+       invlpg [rdi]
+       invlpg [rdi+0x1000]
+       
+       ; Go to new state
+.setState:
+       mov rsp, rdi
+       jmp rdx
+
+       ; Restore point for saved state
+.restore:
+       POP_GPR
+       xor eax, eax    ; Return zero
+       ret
+
+[global Proc_InitialiseSSE]
+Proc_InitialiseSSE:
+       mov rax, cr4
+       or ax, (1 << 9)|(1 << 10)       ; Set OSFXSR and OSXMMEXCPT
+       mov cr4, rax
+       mov rax, cr0
+       and ax, ~(1 << 2)       ; Clear EM
+       or rax, (1 << 1)        ; Set MP
+       mov rax, cr0
+       ret
+[global Proc_DisableSSE]
+Proc_DisableSSE:
+       mov rax, cr0
+       or ax, 1 << 3   ; Set TS
+       mov cr0, rax
+       ret
+[global Proc_EnableSSE]
+Proc_EnableSSE:
+       mov rax, cr0
+       and ax, ~(1 << 3)       ; Clear TS
+       mov cr0, rax
+       ret
+
+[global Proc_SaveSSE]
+Proc_SaveSSE:
+       fxsave [rdi]
+       ret
+[global Proc_RestoreSSE]
+Proc_RestoreSSE:
+       fxrstor [rdi]
+       ret
+
+; vim: ft=nasm
diff --git a/KernelLand/Kernel/arch/x86_64/proc.c b/KernelLand/Kernel/arch/x86_64/proc.c
new file mode 100644 (file)
index 0000000..5f71a45
--- /dev/null
@@ -0,0 +1,827 @@
+/*
+ * Acess2 x86_64 port
+ * proc.c
+ */
+#include <acess.h>
+#include <proc.h>
+#include <threads.h>
+#include <threads_int.h>
+#include <desctab.h>
+#include <mm_virt.h>
+#include <errno.h>
+#if USE_MP
+# include <mp.h>
+#endif
+#include <arch_config.h>
+#include <hal_proc.h>
+
+// === FLAGS ===
+#define DEBUG_TRACE_SWITCH     0
+#define BREAK_ON_SWITCH        0       // Break into bochs debugger on a task switch
+
+// === CONSTANTS ===
+
+// === TYPES ===
+typedef struct sCPU
+{
+       Uint8   APICID;
+       Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
+       Uint16  Resvd;
+       tThread *Current;
+       tThread *IdleThread;
+}      tCPU;
+
+// === IMPORTS ===
+extern tGDT    gGDT[];
+extern void    APStartup(void);        // 16-bit AP startup code
+
+extern Uint    GetRIP(void);   // start.asm
+extern Uint    SaveState(Uint *RSP, Uint *Regs);
+extern Uint    Proc_CloneInt(Uint *RSP, Uint *CR3);
+extern void    NewTaskHeader(void);    // Actually takes cdecl args
+extern void    Proc_InitialiseSSE(void);
+extern void    Proc_SaveSSE(Uint DestPtr);
+extern void    Proc_DisableSSE(void);
+
+extern Uint64  gInitialPML4[512];      // start.asm
+extern int     giNumCPUs;
+extern int     giNextTID;
+extern int     giTotalTickets;
+extern int     giNumActiveThreads;
+extern tThread gThreadZero;
+extern tProcess        gProcessZero;
+extern void    Threads_Dump(void);
+extern void    Proc_ReturnToUser(tVAddr Handler, tVAddr KStackTop, int Argument);
+extern void    Time_UpdateTimestamp(void);
+extern void    SwitchTasks(Uint NewSP, Uint *OldSP, Uint NewIP, Uint *OldIO, Uint CR3);
+
+// === PROTOTYPES ===
+//void ArchThreads_Init(void);
+#if USE_MP
+void   MP_StartAP(int CPU);
+void   MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
+#endif
+void   Proc_IdleTask(void *unused);
+//void Proc_Start(void);
+//tThread      *Proc_GetCurThread(void);
+// int Proc_NewKThread(void (*Fcn)(void*), void *Data);
+// int Proc_Clone(Uint *Err, Uint Flags);
+// int Proc_SpawnWorker(void);
+Uint   Proc_MakeUserStack(void);
+//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
+void   Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NORETURN;
+ int   Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
+//void Proc_CallFaultHandler(tThread *Thread);
+//void Proc_DumpThreadCPUState(tThread *Thread);
+//void Proc_Reschedule(void);
+void   Proc_Scheduler(int CPU, Uint RSP, Uint RIP);
+
+// === GLOBALS ===
+//!\brief Used by desctab.asm in SyscallStub
+const int ci_offsetof_tThread_KernelStack = offsetof(tThread, KernelStack);
+// --- Multiprocessing ---
+#if USE_MP
+volatile int   giNumInitingCPUs = 0;
+tMPInfo        *gMPFloatPtr = NULL;
+tAPIC  *gpMP_LocalAPIC = NULL;
+Uint8  gaAPIC_to_CPU[256] = {0};
+#endif
+tCPU   gaCPUs[MAX_CPUS];
+tTSS   *gTSSs = NULL;
+tTSS   gTSS0 = {0};
+// --- Error Recovery ---
+Uint32 gaDoubleFaultStack[1024];
+
+// === CODE ===
+/**
+ * \fn void ArchThreads_Init(void)
+ * \brief Starts the process scheduler
+ */
+void ArchThreads_Init(void)
+{
+       Uint    pos = 0;
+       
+       #if USE_MP
+       tMPTable        *mptable;
+       
+       // Mark BSP as active
+       gaCPUs[0].State = 2;
+       
+       // -- Initialise Multiprocessing
+       // Find MP Floating Table
+       // - EBDA/Last 1Kib (640KiB)
+       for(pos = KERNEL_BASE|0x9F000; pos < (KERNEL_BASE|0xA0000); pos += 16) {
+               if( *(Uint*)(pos) == MPPTR_IDENT ) {
+                       Log("Possible %p", pos);
+                       if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
+                       gMPFloatPtr = (void*)pos;
+                       break;
+               }
+       }
+       // - Last KiB (512KiB base mem)
+       if(!gMPFloatPtr) {
+               for(pos = KERNEL_BASE|0x7F000; pos < (KERNEL_BASE|0x80000); pos += 16) {
+                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
+                               Log("Possible %p", pos);
+                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
+                               gMPFloatPtr = (void*)pos;
+                               break;
+                       }
+               }
+       }
+       // - BIOS ROM
+       if(!gMPFloatPtr) {
+               for(pos = KERNEL_BASE|0xE0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
+                       if( *(Uint*)(pos) == MPPTR_IDENT ) {
+                               Log("Possible %p", pos);
+                               if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
+                               gMPFloatPtr = (void*)pos;
+                               break;
+                       }
+               }
+       }
+       
+       // If the MP Table Exists, parse it
+       if(gMPFloatPtr)
+       {
+                int    i;
+               tMPTable_Ent    *ents;
+               Log("gMPFloatPtr = %p", gMPFloatPtr);
+               Log("*gMPFloatPtr = {");
+               Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig);
+               Log("\t.MPConfig = 0x%08x", gMPFloatPtr->MPConfig);
+               Log("\t.Length = 0x%02x", gMPFloatPtr->Length);
+               Log("\t.Version = 0x%02x", gMPFloatPtr->Version);
+               Log("\t.Checksum = 0x%02x", gMPFloatPtr->Checksum);
+               Log("\t.Features = [0x%02x,0x%02x,0x%02x,0x%02x,0x%02x]",
+                       gMPFloatPtr->Features[0],       gMPFloatPtr->Features[1],
+                       gMPFloatPtr->Features[2],       gMPFloatPtr->Features[3],
+                       gMPFloatPtr->Features[4]
+                       );
+               Log("}");
+               
+               mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig );
+               Log("mptable = %p", mptable);
+               Log("*mptable = {");
+               Log("\t.Sig = 0x%08x", mptable->Sig);
+               Log("\t.BaseTableLength = 0x%04x", mptable->BaseTableLength);
+               Log("\t.SpecRev = 0x%02x", mptable->SpecRev);
+               Log("\t.Checksum = 0x%02x", mptable->Checksum);
+               Log("\t.OEMID = '%8c'", mptable->OemID);
+               Log("\t.ProductID = '%8c'", mptable->ProductID);
+               Log("\t.OEMTablePtr = %p'", mptable->OEMTablePtr);
+               Log("\t.OEMTableSize = 0x%04x", mptable->OEMTableSize);
+               Log("\t.EntryCount = 0x%04x", mptable->EntryCount);
+               Log("\t.LocalAPICMemMap = 0x%08x", mptable->LocalAPICMemMap);
+               Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen);
+               Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum);
+               Log("}");
+               
+               gpMP_LocalAPIC = (void*)MM_MapHWPage(mptable->LocalAPICMemMap, 1);
+               
+               ents = mptable->Entries;
+               giNumCPUs = 0;
+               
+               for( i = 0; i < mptable->EntryCount; i ++ )
+               {
+                        int    entSize = 0;
+                       switch( ents->Type )
+                       {
+                       case 0: // Processor
+                               entSize = 20;
+                               Log("%i: Processor", i);
+                               Log("\t.APICID = %i", ents->Proc.APICID);
+                               Log("\t.APICVer = 0x%02x", ents->Proc.APICVer);
+                               Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags);
+                               Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature);
+                               Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags);
+                               
+                               
+                               if( !(ents->Proc.CPUFlags & 1) ) {
+                                       Log("DISABLED");
+                                       break;
+                               }
+                               
+                               // Check if there is too many processors
+                               if(giNumCPUs >= MAX_CPUS) {
+                                       giNumCPUs ++;   // If `giNumCPUs` > MAX_CPUS later, it will be clipped
+                                       break;
+                               }
+                               
+                               // Initialise CPU Info
+                               gaAPIC_to_CPU[ents->Proc.APICID] = giNumCPUs;
+                               gaCPUs[giNumCPUs].APICID = ents->Proc.APICID;
+                               gaCPUs[giNumCPUs].State = 0;
+                               giNumCPUs ++;
+                               
+                               // Send IPI
+                               if( !(ents->Proc.CPUFlags & 2) )
+                               {
+                                       MP_StartAP( giNumCPUs-1 );
+                               }
+                               
+                               break;
+                       case 1: // Bus
+                               entSize = 8;
+                               Log("%i: Bus", i);
+                               Log("\t.ID = %i", ents->Bus.ID);
+                               Log("\t.TypeString = '%6c'", ents->Bus.TypeString);
+                               break;
+                       case 2: // I/O APIC
+                               entSize = 8;
+                               Log("%i: I/O APIC", i);
+                               Log("\t.ID = %i", ents->IOAPIC.ID);
+                               Log("\t.Version = 0x%02x", ents->IOAPIC.Version);
+                               Log("\t.Flags = 0x%02x", ents->IOAPIC.Flags);
+                               Log("\t.Addr = 0x%08x", ents->IOAPIC.Addr);
+                               break;
+                       case 3: // I/O Interrupt Assignment
+                               entSize = 8;
+                               Log("%i: I/O Interrupt Assignment", i);
+                               Log("\t.IntType = %i", ents->IOInt.IntType);
+                               Log("\t.Flags = 0x%04x", ents->IOInt.Flags);
+                               Log("\t.SourceBusID = 0x%02x", ents->IOInt.SourceBusID);
+                               Log("\t.SourceBusIRQ = 0x%02x", ents->IOInt.SourceBusIRQ);
+                               Log("\t.DestAPICID = 0x%02x", ents->IOInt.DestAPICID);
+                               Log("\t.DestAPICIRQ = 0x%02x", ents->IOInt.DestAPICIRQ);
+                               break;
+                       case 4: // Local Interrupt Assignment
+                               entSize = 8;
+                               Log("%i: Local Interrupt Assignment", i);
+                               Log("\t.IntType = %i", ents->LocalInt.IntType);
+                               Log("\t.Flags = 0x%04x", ents->LocalInt.Flags);
+                               Log("\t.SourceBusID = 0x%02x", ents->LocalInt.SourceBusID);
+                               Log("\t.SourceBusIRQ = 0x%02x", ents->LocalInt.SourceBusIRQ);
+                               Log("\t.DestLocalAPICID = 0x%02x", ents->LocalInt.DestLocalAPICID);
+                               Log("\t.DestLocalAPICIRQ = 0x%02x", ents->LocalInt.DestLocalAPICIRQ);
+                               break;
+                       default:
+                               Log("%i: Unknown (%i)", i, ents->Type);
+                               break;
+                       }
+                       ents = (void*)( (Uint)ents + entSize );
+               }
+               
+               if( giNumCPUs > MAX_CPUS ) {
+                       Warning("Too many CPUs detected (%i), only using %i of them", giNumCPUs, MAX_CPUS);
+                       giNumCPUs = MAX_CPUS;
+               }
+       
+               while( giNumInitingCPUs )
+                       MM_FinishVirtualInit();
+               
+               Panic("Uh oh... MP Table Parsing is unimplemented\n");
+       }
+       else {
+               Log("No MP Table was found, assuming uniprocessor\n");
+               giNumCPUs = 1;
+               gTSSs = &gTSS0;
+       }
+       #else
+       giNumCPUs = 1;
+       gTSSs = &gTSS0;
+       MM_FinishVirtualInit();
+       #endif
+       
+       #if USE_MP
+       // Initialise Normal TSS(s)
+       for(pos=0;pos<giNumCPUs;pos++)
+       {
+       #else
+       pos = 0;
+       #endif
+               gTSSs[pos].RSP0 = 0;    // Set properly by scheduler
+               gGDT[7+pos*2].LimitLow = sizeof(tTSS) & 0xFFFF;
+               gGDT[7+pos*2].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
+               gGDT[7+pos*2].BaseMid = ((Uint)(&gTSSs[pos])) >> 16;
+               gGDT[7+pos*2].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
+               gGDT[7+pos*2+1].DWord[0] = ((Uint)(&gTSSs[pos])) >> 32;
+       #if USE_MP
+       }
+       for(pos=0;pos<giNumCPUs;pos++) {
+               __asm__ __volatile__ ("ltr %%ax"::"a"(0x38+pos*16));
+       }
+       #else
+       __asm__ __volatile__ ("ltr %%ax"::"a"(0x38));
+       #endif
+       
+       // Set Debug registers
+       __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
+       __asm__ __volatile__ ("mov %%rax, %%db1" : : "a"(0));
+       
+       gaCPUs[0].Current = &gThreadZero;
+       
+       gProcessZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
+       gThreadZero.CurCPU = 0;
+       gThreadZero.KernelStack = 0xFFFFA00000000000 + KERNEL_STACK_SIZE;
+       
+       // Set timer frequency
+       outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
+       outb(0x40, PIT_TIMER_DIVISOR&0xFF);     // Low Byte of Divisor
+       outb(0x40, (PIT_TIMER_DIVISOR>>8)&0xFF);        // High Byte
+       
+       // Create Per-Process Data Block
+       if( !MM_Allocate(MM_PPD_CFG) )
+       {
+               Warning("Oh, hell, Unable to allocate PPD for Thread#0");
+       }
+
+       Proc_InitialiseSSE();
+
+       Log_Log("Proc", "Multithreading initialised");
+}
+
+#if USE_MP
+void MP_StartAP(int CPU)
+{
+       Log("Starting AP %i (APIC %i)", CPU, gaCPUs[CPU].APICID);
+       // Set location of AP startup code and mark for a warm restart
+       *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0);
+       *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
+       outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Warm Reset
+       MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);
+       giNumInitingCPUs ++;
+}
+
+void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
+{
+       Uint32  addr = (Uint)gpMP_LocalAPIC + 0x300;
+       Uint32  val;
+       
+       // High
+       val = (Uint)APICID << 24;
+       Log("*%p = 0x%08x", addr+0x10, val);
+       *(Uint32*)(addr+0x10) = val;
+       // Low (and send)
+       val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
+       Log("*%p = 0x%08x", addr, val);
+       *(Uint32*)addr = val;
+}
+#endif
+
+/**
+ * \brief Idle task
+ */
+void Proc_IdleTask(void *ptr)
+{
+       tCPU    *cpu = ptr;
+       cpu->IdleThread = Proc_GetCurThread();
+       cpu->IdleThread->ThreadName = (char*)"Idle Thread";
+       Threads_SetPriority( cpu->IdleThread, -1 );     // Never called randomly
+       cpu->IdleThread->Quantum = 1;   // 1 slice quantum
+       for(;;) {
+               HALT(); // Just yeilds
+               Threads_Yield();
+       }
+}
+
+/**
+ * \fn void Proc_Start(void)
+ * \brief Start process scheduler
+ */
+void Proc_Start(void)
+{
+       #if USE_MP
+        int    i;
+       #endif
+       
+       #if USE_MP
+       // Start APs
+       for( i = 0; i < giNumCPUs; i ++ )
+       {
+                int    tid;
+               if(i)   gaCPUs[i].Current = NULL;
+               
+               Proc_NewKThread(Proc_IdleTask, &gaCPUs[i]);             
+
+               // Create Idle Task
+               gaCPUs[i].IdleThread = Threads_GetThread(tid);
+               
+               
+               // Start the AP
+               if( i != giProc_BootProcessorID ) {
+                       MP_StartAP( i );
+               }
+       }
+       
+       // BSP still should run the current task
+       gaCPUs[0].Current = &gThreadZero;
+       __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
+       
+       // Start interrupts and wait for APs to come up
+       Log("Waiting for APs to come up\n");
+       __asm__ __volatile__ ("sti");
+       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
+       #else
+       Proc_NewKThread(Proc_IdleTask, &gaCPUs[0]);
+       
+       // Start Interrupts (and hence scheduler)
+       __asm__ __volatile__("sti");
+       #endif
+       MM_FinishVirtualInit();
+       Log_Log("Proc", "Multithreading started");
+}
+
+/**
+ * \fn tThread *Proc_GetCurThread(void)
+ * \brief Gets the current thread
+ */
+tThread *Proc_GetCurThread(void)
+{
+       #if USE_MP
+       tThread *ret;
+       __asm__ __volatile__ ("mov %%db0, %0" : "=r"(thread));
+       return ret;     // gaCPUs[ GetCPUNum() ].Current;
+       #else
+       return gaCPUs[ 0 ].Current;
+       #endif
+}
+
+void Proc_ClearProcess(tProcess *Process)
+{
+       Log_Warning("Proc", "TODO: Nuke address space etc");
+}
+
+/*
+ * 
+ */
+void Proc_ClearThread(tThread *Thread)
+{
+}
+
+/**
+ * \brief Create a new kernel thread
+ */
+tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
+{
+       Uint    rsp;
+       tThread *newThread, *cur;
+       
+       cur = Proc_GetCurThread();
+       newThread = Threads_CloneTCB(0);
+       if(!newThread)  return -1;
+       
+       // Create new KStack
+       newThread->KernelStack = MM_NewKStack();
+       // Check for errors
+       if(newThread->KernelStack == 0) {
+               free(newThread);
+               return -1;
+       }
+
+       rsp = newThread->KernelStack;
+       *(Uint*)(rsp-=8) = (Uint)Data;  // Data (shadowed)
+       *(Uint*)(rsp-=8) = (Uint)Fcn;   // Function to call
+       *(Uint*)(rsp-=8) = (Uint)newThread;     // Thread ID
+       
+       newThread->SavedState.RSP = rsp;
+       newThread->SavedState.RIP = (Uint)&NewTaskHeader;
+       newThread->SavedState.SSE = NULL;
+//     Log("New (KThread) %p, rsp = %p\n", newThread->SavedState.RIP, newThread->SavedState.RSP);
+       
+//     MAGIC_BREAK();  
+       Threads_AddActive(newThread);
+
+       return newThread->TID;
+}
+
+/**
+ * \fn int Proc_Clone(Uint Flags)
+ * \brief Clone the current process
+ */
+tTID Proc_Clone(Uint Flags)
+{
+       tThread *newThread, *cur = Proc_GetCurThread();
+       Uint    rip;
+
+       // Sanity check 
+       if( !(Flags & CLONE_VM) ) {
+               Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
+               return -1;
+       }
+
+       // Create new TCB
+       newThread = Threads_CloneTCB(Flags);
+       if(!newThread)  return -1;
+       
+       // Save core machine state
+       rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->Process->MemState.CR3);
+       if(rip == 0)    return 0;       // Child
+       newThread->KernelStack = cur->KernelStack;
+       newThread->SavedState.RIP = rip;
+       newThread->SavedState.SSE = NULL;
+
+       // DEBUG
+       #if 0
+       Log("New (Clone) %p, rsp = %p, cr3 = %p", rip, newThread->SavedState.RSP, newThread->MemState.CR3);
+       {
+               Uint cr3;
+               __asm__ __volatile__ ("mov %%cr3, %0" : "=r" (cr3));
+               Log("Current CR3 = 0x%x, PADDR(RSP) = 0x%x", cr3, MM_GetPhysAddr(newThread->SavedState.RSP));
+       }
+       #endif
+       // /DEBUG
+       
+       // Lock list and add to active
+       Threads_AddActive(newThread);
+       
+       return newThread->TID;
+}
+
+/**
+ * \fn int Proc_SpawnWorker(void)
+ * \brief Spawns a new worker thread
+ */
+int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+{
+       tThread *new, *cur;
+       Uint    stack_contents[3];
+
+       cur = Proc_GetCurThread();
+       
+       // Create new thread
+       new = Threads_CloneThreadZero();
+       if(!new) {
+               Warning("Proc_SpawnWorker - Out of heap space!\n");
+               return -1;
+       }
+
+       // Create the stack contents
+       stack_contents[2] = (Uint)Data;
+       stack_contents[1] = (Uint)Fcn;
+       stack_contents[0] = (Uint)new;
+       
+       // Create a new worker stack (in PID0's address space)
+       // - The stack is built by this code using stack_contents
+       new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
+
+       new->SavedState.RSP = new->KernelStack - sizeof(stack_contents);
+       new->SavedState.RIP = (Uint)&NewTaskHeader;
+       new->SavedState.SSE = NULL;
+       
+//     Log("New (Worker) %p, rsp = %p\n", new->SavedState.RIP, new->SavedState.RSP);
+       
+       // Mark as active
+       new->Status = THREAD_STAT_PREINIT;
+       Threads_AddActive( new );
+       
+       return new->TID;
+}
+
+/**
+ * \brief Creates a new user stack
+ */
+Uint Proc_MakeUserStack(void)
+{
+        int    i;
+       Uint    base = USER_STACK_TOP - USER_STACK_SZ;
+       
+       // Check Prospective Space
+       for( i = USER_STACK_SZ >> 12; i--; )
+       {
+               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+                       break;
+       }
+       
+       if(i != -1)     return 0;
+       
+       // Allocate Stack - Allocate incrementally to clean up MM_Dump output
+       // - Most of the user stack is the zero page
+       for( i = 0; i < (USER_STACK_SZ-USER_STACK_PREALLOC)/0x1000; i++ )
+       {
+               MM_AllocateZero( base + (i<<12) );
+       }
+       // - but the top USER_STACK_PREALLOC pages are actually allocated
+       for( ; i < USER_STACK_SZ/0x1000; i++ )
+       {
+               tPAddr  alloc = MM_Allocate( base + (i<<12) );
+               if( !alloc )
+               {
+                       // Error
+                       Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
+                       while( i -- )
+                               MM_Deallocate( base + (i<<12) );
+                       return 0;
+               }
+       }
+       
+       return base + USER_STACK_SZ;
+}
+
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
+{
+       Uint    *stack;
+        int    i;
+       const char      **envp = NULL;
+       Uint16  ss, cs;
+       
+       
+       // Copy Arguments
+       stack = (void*)Proc_MakeUserStack();
+       if(!stack) {
+               Log_Error("Proc", "Unable to create user stack!");
+               Threads_Exit(0, -1);
+       }
+       stack -= (DataSize+7)/8;
+       memcpy( stack, ArgV, DataSize );
+       free(ArgV);
+       
+       // Adjust Arguments and environment
+       if(DataSize)
+       {
+               Uint    delta = (Uint)stack - (Uint)ArgV;
+               ArgV = (const char**)stack;
+               for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
+               envp = &ArgV[i+1];
+               for( i = 0; envp[i]; i++ )      envp[i] += delta;
+       }
+       
+       // User Mode Segments
+       // 0x2B = 64-bit
+       ss = 0x23;      cs = 0x2B;
+       
+       // Arguments
+       *--stack = (Uint)envp;
+       *--stack = (Uint)ArgV;
+       *--stack = (Uint)ArgC;
+       *--stack = Base;
+       
+       Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
+}
+
+void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
+{
+       if( !(CS == 0x1B || CS == 0x2B) || SS != 0x23 ) {
+               Log_Error("Proc", "Proc_StartProcess: CS / SS are not valid (%x, %x)",
+                       CS, SS);
+               Threads_Exit(0, -1);
+       }
+//     Log("Proc_StartProcess: (SS=%x, Stack=%p, Flags=%x, CS=%x, IP=%p)", SS, Stack, Flags, CS, IP);
+//     MM_DumpTables(0, USER_MAX);
+       if(CS == 0x1B)
+       {
+               // 32-bit return
+               __asm__ __volatile__ (
+                       "mov %0, %%rsp;\n\t"    // Set stack pointer
+                       "mov %2, %%r11;\n\t"    // Set RFLAGS
+                       "sysret;\n\t"
+                       : : "r" (Stack), "c" (IP), "r" (Flags)
+                       );
+       }
+       else
+       {
+               // 64-bit return
+               __asm__ __volatile__ (
+                       "mov %0, %%rsp;\n\t"    // Set stack pointer
+                       "mov %2, %%r11;\n\t"    // Set RFLAGS
+                       "sysretq;\n\t"
+                       : : "r" (Stack), "c" (IP), "r" (Flags)
+                       );
+       }
+       for(;;);
+}
+
+/**
+ * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
+ * \brief Demotes a process to a lower permission level
+ * \param Err  Pointer to user's errno
+ * \param Dest New Permission Level
+ * \param Regs Pointer to user's register structure
+ */
+int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
+{
+        int    cpl = Regs->CS & 3;
+       // Sanity Check
+       if(Dest > 3 || Dest < 0) {
+               *Err = -EINVAL;
+               return -1;
+       }
+       
+       // Permission Check
+       if(cpl > Dest) {
+               *Err = -EACCES;
+               return -1;
+       }
+       
+       // Change the Segment Registers
+       Regs->CS = (((Dest+1)<<4) | Dest) - 8;
+       Regs->SS = ((Dest+1)<<4) | Dest;
+       
+       return 0;
+}
+
+/**
+ * \brief Calls a signal handler in user mode
+ * \note Used for signals
+ */
+void Proc_CallFaultHandler(tThread *Thread)
+{
+       // Never returns
+       Proc_ReturnToUser(Thread->FaultHandler, Thread->KernelStack, Thread->CurFaultNum);
+       for(;;);
+}
+
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       Log("  At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
+}
+
+void Proc_Reschedule(void)
+{
+       tThread *nextthread, *curthread;
+        int    cpu = GetCPUNum();
+
+       // TODO: Wait for it?
+       if(IS_LOCKED(&glThreadListLock))        return;
+       
+       curthread = gaCPUs[cpu].Current;
+
+       nextthread = Threads_GetNextToRun(cpu, curthread);
+
+       if(nextthread == curthread)     return ;
+       if(!nextthread)
+               nextthread = gaCPUs[cpu].IdleThread;
+       if(!nextthread)
+               return ;
+
+       #if DEBUG_TRACE_SWITCH
+       LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n",
+               nextthread->Process->MemState.CR3,
+               nextthread->SavedState.RIP,
+               nextthread->SavedState.RSP,
+               nextthread->TID,
+               nextthread->ThreadName
+               );
+       #endif
+
+       // Update CPU state
+       gaCPUs[cpu].Current = nextthread;
+       gTSSs[cpu].RSP0 = nextthread->KernelStack-4;
+       __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread));
+
+       if( curthread )
+       {
+               // Save FPU/MMX/XMM/SSE state
+               if( curthread->SavedState.SSE )
+               {
+                       Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
+                       curthread->SavedState.bSSEModified = 0;
+                       Proc_DisableSSE();
+               }
+               SwitchTasks(
+                       nextthread->SavedState.RSP, &curthread->SavedState.RSP,
+                       nextthread->SavedState.RIP, &curthread->SavedState.RIP,
+                       nextthread->Process->MemState.CR3
+                       );
+       }
+       else
+       {
+               Uint    tmp;
+               SwitchTasks(
+                       nextthread->SavedState.RSP, &tmp,
+                       nextthread->SavedState.RIP, &tmp,
+                       nextthread->Process->MemState.CR3
+                       );
+       }
+       return ;
+}
+
+/**
+ * \fn void Proc_Scheduler(int CPU)
+ * \brief Swap current thread and clears dead threads
+ */
+void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
+{
+#if 0
+       tThread *thread;
+
+       // If the spinlock is set, let it complete
+       if(IS_LOCKED(&glThreadListLock))        return;
+       
+       // Get current thread
+       thread = gaCPUs[CPU].Current;
+
+       if( thread )
+       {
+               tRegs   *regs;
+               // Reduce remaining quantum and continue timeslice if non-zero
+               if(thread->Remaining--) return;
+               // Reset quantum for next call
+               thread->Remaining = thread->Quantum;
+               
+               // TODO: Make this more stable somehow
+               {
+                       regs = (tRegs*)(RSP+(1)*8);     // CurThread
+                       thread->SavedState.UserCS = regs->CS;
+                       thread->SavedState.UserRIP = regs->RIP;
+               }
+       }
+
+       // ACK Timer here?
+
+       Proc_Reschedule();
+#endif
+}
+
+// === EXPORTS ===
+EXPORT(Proc_SpawnWorker);
diff --git a/KernelLand/Kernel/arch/x86_64/rme.c b/KernelLand/Kernel/arch/x86_64/rme.c
new file mode 120000 (symlink)
index 0000000..330f4f5
--- /dev/null
@@ -0,0 +1 @@
+/home/tpg/Projects/RealmodeEmulator/src/rme.c
\ No newline at end of file
diff --git a/KernelLand/Kernel/arch/x86_64/rme.h b/KernelLand/Kernel/arch/x86_64/rme.h
new file mode 120000 (symlink)
index 0000000..98b2739
--- /dev/null
@@ -0,0 +1 @@
+/home/tpg/Projects/RealmodeEmulator/src/rme.h
\ No newline at end of file
diff --git a/KernelLand/Kernel/arch/x86_64/start32.asm b/KernelLand/Kernel/arch/x86_64/start32.asm
new file mode 100644 (file)
index 0000000..52b133c
--- /dev/null
@@ -0,0 +1,188 @@
+;
+; Acess2 x86_64 port
+;
+
+%include "arch/x86_64/include/common.inc.asm"
+
+[BITS 32]
+
+;KERNEL_BASE   equ     0xFFFF800000000000
+KERNEL_BASE    equ     0xFFFFFFFF80000000
+
+[section .multiboot]
+mboot:
+       ; Multiboot macros to make a few lines later more readable
+       MULTIBOOT_PAGE_ALIGN    equ 1<<0
+       MULTIBOOT_MEMORY_INFO   equ 1<<1
+       MULTIBOOT_AOUT_KLUDGE   equ 1<<16
+       MULTIBOOT_HEADER_MAGIC  equ 0x1BADB002
+       MULTIBOOT_HEADER_FLAGS  equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO; | MULTIBOOT_AOUT_KLUDGE
+       MULTIBOOT_CHECKSUM      equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+       
+       ; This is the GRUB Multiboot header. A boot signature
+       dd MULTIBOOT_HEADER_MAGIC
+       dd MULTIBOOT_HEADER_FLAGS
+       dd MULTIBOOT_CHECKSUM
+       [extern __load_addr]
+       [extern __bss_start]
+       [extern gKernelEnd]
+       ; a.out kludge
+       dd mboot        ; Location of Multiboot Header
+       dd __load_addr  ; Load address
+       dd __bss_start - KERNEL_BASE    ; End of .data
+       dd gKernelEnd - KERNEL_BASE     ; End of .bss (and kernel)
+       dd start - KERNEL_BASE  ; Entrypoint
+
+[extern start64]
+
+[section .text]
+[global start]
+start:
+       mov [gMultibootMagic - KERNEL_BASE], eax
+       mov [gMultibootPtr - KERNEL_BASE], ebx
+
+       ; Check for Long Mode support
+       mov eax, 0x80000000
+       cpuid
+       cmp eax, 0x80000001     ; Compare the A-register with 0x80000001.
+       mov eax, 0x80000001
+       cpuid
+       jb .not64bitCapable
+       test edx, 1<<29
+       jz .not64bitCapable
+
+       ; Enable PGE (Page Global Enable)
+       ; + PAE (Physical Address Extension)
+       ; + PSE (Page Size Extensions)
+       mov eax, cr4
+       or eax, 0x80|0x20|0x10
+       mov cr4, eax
+
+       ; Load PDP4
+       mov eax, gInitialPML4 - KERNEL_BASE
+       mov cr3, eax
+
+       ; Enable IA-32e mode
+       ; (Also enables SYSCALL and NX)
+       mov ecx, 0xC0000080
+       rdmsr
+       or eax, (1 << 11)|(1 << 8)|(1 << 0)     ; NXE, LME, SCE
+       wrmsr
+
+       ; Enable paging
+       mov eax, cr0
+       or eax, 0x80010000      ; PG & WP
+       mov cr0, eax
+
+       ; Load GDT
+       lgdt [gGDTPtr - KERNEL_BASE]
+       jmp 0x08:start64 - KERNEL_BASE
+
+.not64bitCapable:
+       mov ah, 0x0F
+       mov edi, 0xB8000
+       mov esi, csNot64BitCapable - KERNEL_BASE
+
+.loop:
+       lodsb
+       test al, al
+       jz .hlt
+       stosw
+       jmp .loop
+       
+.hlt:
+       cli
+       hlt
+       jmp .hlt
+
+[section .data]
+[global gGDT]
+[global gGDTPtr]
+gGDT:
+       dd      0,0
+       dd      0x00000000, 0x00209A00  ; 0x08: 64-bit Code
+       dd      0x00000000, 0x00009200  ; 0x10: 64-bit Data
+       dd      0x00000000, 0x0040FA00  ; 0x18: 32-bit User Code
+       dd      0x00000000, 0x0040F200  ; 0x20: User Data
+       dd      0x00000000, 0x0020FA00  ; 0x28: 64-bit User Code
+       dd      0x00000000, 0x0000F200  ; 0x30: User Data (64 version)
+       times MAX_CPUS  dd      0, 0x00008900, 0, 0     ; 0x38+16*n: TSS 0
+gGDTPtr:
+       dw      $-gGDT-1
+       dd      gGDT-KERNEL_BASE
+       dd      0
+[global gMultibootPtr]
+[global gMultibootMagic]
+gMultibootMagic:
+       dd      0
+gMultibootPtr:
+       dd      0
+
+[section .padata]
+[global gInitialPML4]
+gInitialPML4:  ; Covers 256 TiB (Full 48-bit Virtual Address Space)
+       dd      gInitialPDP - KERNEL_BASE + 3, 0        ; Identity Map Low 4Mb
+       times 0xA0*2-1  dq      0
+       dd      gStackPDP - KERNEL_BASE + 3, 0
+       times 512-4-($-gInitialPML4)/8  dq      0
+       dd      gInitialPML4 - KERNEL_BASE + 3, 0       ; Fractal Mapping
+       dq      0
+       dq      0
+       dd      gHighPDP - KERNEL_BASE + 3, 0   ; Map Low 4Mb to kernel base
+
+gInitialPDP:   ; Covers 512 GiB
+       dd      gInitialPD - KERNEL_BASE + 3, 0
+       times 511       dq      0
+
+gStackPDP:
+       dd      gStackPD - KERNEL_BASE + 3, 0
+       times 511       dq      0
+
+gHighPDP:      ; Covers 512 GiB
+       times 510       dq      0
+       ;dq     0 + 0x143       ; 1 GiB Page from zero
+       dd      gInitialPD - KERNEL_BASE + 3, 0
+       dq      0
+
+gInitialPD:    ; Covers 1 GiB
+;      dq      0 + 0x143       ; 1 GiB Page from zero
+       dd      gInitialPT1 - KERNEL_BASE + 3, 0
+       dd      gInitialPT2 - KERNEL_BASE + 3, 0
+       times 510       dq      0
+
+gStackPD:
+       dd      gKStackPT - KERNEL_BASE + 3, 0
+       times 511       dq      0
+
+gKStackPT:     ; Covers 2 MiB
+       ; Initial stack - 64KiB
+       dq      0
+       %assign i 0
+       %rep INITIAL_KSTACK_SIZE-1
+       dd      gInitialKernelStack - KERNEL_BASE + i*0x1000 + 0x103, 0
+       %assign i i+1
+       %endrep
+       times 512-INITIAL_KSTACK_SIZE   dq 0
+gInitialPT1:   ; 2 MiB
+       %assign i 0
+       %rep 512
+       dq      i*4096+0x103
+       %assign i i+1
+       %endrep
+gInitialPT2:   ; 2 MiB
+       %assign i 512
+       %rep 512
+       dq      i*4096+0x103
+       %assign i i+1
+       %endrep
+
+[section .padata]
+[global gInitialKernelStack]
+gInitialKernelStack:
+       times 0x1000*(INITIAL_KSTACK_SIZE-1)    db 0    ; 8 Pages
+
+[section .rodata]
+csNot64BitCapable:
+       db "Not 64-bit Capable",0
+
+; vim: ft=nasm
diff --git a/KernelLand/Kernel/arch/x86_64/start64.asm b/KernelLand/Kernel/arch/x86_64/start64.asm
new file mode 100644 (file)
index 0000000..c8e7f9a
--- /dev/null
@@ -0,0 +1,143 @@
+;
+; Acess2 x86_64 Port
+;
+%include "arch/x86_64/include/common.inc.asm"
+[bits 64]
+;KERNEL_BASE   equ     0xFFFF800000000000
+KERNEL_BASE    equ     0xFFFFFFFF80000000
+
+[extern kmain]
+
+[extern gMultibootPtr]
+[extern gMultibootMagic]
+
+[section .text]
+[global start64]
+start64:
+       ; Load Registers
+       mov ax, 0x10
+       mov ds, ax
+       mov es, ax
+       mov fs, ax
+       mov gs, ax
+       
+       ; Go to high memory
+       mov rax, start64.himem
+       jmp rax
+.himem:
+       
+       xor rax, rax
+       mov dr0, rax    ; Set CPU0
+       
+       ; Clear the screen
+       mov rax, 0x1F201F201F201F20     ; Set the screen to White on blue, space (4 characters)
+       mov edi, 0xB8000
+       mov ecx, 80*25*2/8
+       rep stosq
+       
+       ; Set kernel stack
+       mov rsp, 0xFFFFA00000000000 + INITIAL_KSTACK_SIZE*0x1000
+       
+       ; Call main
+       mov edi, [gMultibootMagic - KERNEL_BASE]
+       mov esi, [gMultibootPtr - KERNEL_BASE]
+       call kmain
+       
+       cli
+.hlt:
+       hlt
+       jmp .hlt
+
+[global GetCPUNum]
+GetCPUNum:
+       mov rax, dr1
+       ret
+
+KSTACK_USERSTATE_SIZE  equ     (5+2+16+2)*8    ; IRET, ErrorNum, ErrorCode, GPRs, FS&GS
+[global Proc_ReturnToUser]
+Proc_ReturnToUser:
+       ; RDI - Handler
+       ; RSI - Kernel Stack
+       ; RDX - Signal num
+       
+       ;
+       ; NOTE: This can cause corruption if the signal happens while the user
+       ;       has called a kernel operation.
+       ; Good thing this can only be called on a user fault.
+       ;
+
+       xchg bx, bx     
+       ; Get and alter User SP
+       mov rcx, [rsi-0x20]     ; Get user SP
+       xor eax, eax
+       mov [rcx-16], rax
+       sub rcx, 16
+       
+       ; Drop down to user mode
+       cli
+       mov rsp, rcx    ; Set SP
+       mov rcx, rdi    ; SYSRET IP
+       
+       mov rdi, rdx    ; Argument for handler
+       mov r11, 0x202  ; RFlags
+       db 0x48
+       sysret
+
+; int CallWithArgArray(void *Ptr, int NArgs, Uint *Args)
+; Call a function passing the array as arguments
+[global CallWithArgArray]
+CallWithArgArray:
+       push rbp
+       mov rbp, rsp
+       push r10
+       push r11
+       
+       mov [rbp+2*8], rdi      ; Save Ptr to stack
+       
+       mov r11, rsi    ; NArgs
+       mov r10, rdx    ; Args
+
+       ; Arg 1: RDI
+       mov rdi, [r10]
+       add r10, 8
+       dec r11
+       jz .call
+       ; Arg 2: RSI
+       mov rsi, [r10]
+       add r10, 8
+       dec r11
+       jz .call
+       ; Arg 3: RDX
+       mov rdx, [r10]
+       add r10, 8
+       dec r11
+       jz .call
+       ; Arg 4: RCX
+       mov rcx, [r10]
+       add r10, 8
+       dec r11
+       jz .call
+       ; Arg 5: R8
+       mov r8, [r10]
+       add r10, 8
+       dec r11
+       jz .call
+       ; Arg 6: R9
+       mov r9, [r10]
+       add r10, 8
+       dec r11
+       jz .call
+       ; No support for more
+
+.call:
+       mov rax, [rbp+2*8]      ; Ptr
+       call rax
+       
+       pop r11
+       pop r10
+       
+       lea rsp, [rbp]
+       pop rbp
+       ret
+
+; vim: ft=nasm
diff --git a/KernelLand/Kernel/arch/x86_64/time.c b/KernelLand/Kernel/arch/x86_64/time.c
new file mode 100644 (file)
index 0000000..03c889f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Acess2 Kernel
+ * Timekeeping
+ * arch/x86_64/time.c
+ */
+#include <acess.h>
+#include <arch_config.h>
+
+// === MACROS ===
+#define        TIMER_QUANTUM   100
+#define TIMER_FREQ     PIT_TIMER_BASE_N/(PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR)
+#define MS_PER_TICK_WHOLE      (1000*(PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR)/PIT_TIMER_BASE_N)
+#define MS_PER_TICK_FRACT      ((0x80000000ULL*1000ULL*PIT_TIMER_BASE_D*PIT_TIMER_DIVISOR/PIT_TIMER_BASE_N)&0x7FFFFFFF)
+
+// === IMPORTS ===
+extern volatile Sint64 giTimestamp;
+extern volatile Uint64 giTicks;
+extern volatile Uint64 giPartMiliseconds;
+extern void    Timer_CallTimers(void);
+
+// === GLOBALS ===
+volatile Uint64        giTime_TSCAtLastTick = 0;
+volatile Uint64        giTime_TSCPerTick = 0;
+
+// === PROTOTYPES ===
+//Sint64       now(void);
+ int   Time_Setup(void);
+void   Time_UpdateTimestamp(void);
+Uint64 Time_ReadTSC(void);
+
+// === CODE ===
+/**
+ * \fn Sint64 now()
+ * \brief Return the current timestamp
+ */
+Sint64 now(void)
+{
+       Uint64  tsc = Time_ReadTSC();
+       tsc -= giTime_TSCAtLastTick;
+       tsc *= MS_PER_TICK_WHOLE;
+       if( giTime_TSCPerTick ) {
+               tsc /= giTime_TSCPerTick;
+       }
+       else
+               tsc = 0;
+       return giTimestamp + tsc;
+}
+
+/**
+ * \fn int Time_Setup(void)
+ * \brief Sets the system time from the Realtime-Clock
+ */
+int Time_Setup(void)
+{
+       Log_Log("Timer", "PIT Timer firing at %iHz, %i.0x%08x miliseconds per tick",
+               TIMER_FREQ, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
+
+       // TODO: Read time from RTC
+       
+       return 0;
+}
+
+/**
+ * \brief Called on the timekeeping IRQ
+ */
+void Time_UpdateTimestamp(void)
+{
+       Uint64  curTSC = Time_ReadTSC();
+       
+       if( giTime_TSCAtLastTick )
+       {
+               giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
+       }
+       giTime_TSCAtLastTick = curTSC;
+       
+       giTicks ++;
+       giTimestamp += MS_PER_TICK_WHOLE;
+       giPartMiliseconds += MS_PER_TICK_FRACT;
+       if(giPartMiliseconds > 0x80000000) {
+               giTimestamp ++;
+               giPartMiliseconds -= 0x80000000;
+       }
+       
+       Timer_CallTimers();
+}
+
+#if 0
+/**
+ * \fn void Time_TimerThread(void)
+ */
+void Time_TimerThread(void)
+{
+       Sint64  next;
+       Threads_SetName("TIMER");
+       
+       next = giTimestamp + TIMER_QUANTUM;
+       for(;;)
+       {
+               while(giTimestamp < next)       Threads_Yield();
+               next = giTimestamp + TIMER_QUANTUM;     
+               Timer_CallTimers();
+       }
+}
+#endif
+
+Uint64 Time_ReadTSC(void)
+{
+       Uint32  a, d;
+       __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
+       return ((Uint64)d << 32) | a;
+}
diff --git a/KernelLand/Kernel/arch/x86_64/vm8086.c b/KernelLand/Kernel/arch/x86_64/vm8086.c
new file mode 100644 (file)
index 0000000..4251570
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ */
+#include <acess.h>
+#include <vm8086.h>
+#include <modules.h>
+//#include "rme.h"
+
+// === CONSTANTS ===
+#define VM8086_STACK_SEG       0x9F00
+#define VM8086_STACK_OFS       0x0AFE
+#define VM8086_PAGES_PER_INST  4
+
+// === PROTOTYPES ===
+ int   VM8086_Install(char **Arguments);
+//tVM8086      *VM8086_Init(void);
+//void VM8086_Free(tVM8086 *State);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL);
+tMutex glVM8086_Process;
+//tRME_State   *gpVM8086_State;
+tPID   gVM8086_WorkerPID;
+tTID   gVM8086_CallingThread;
+tVM8086        volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions
+
+// === CODE ===
+int VM8086_Install(char **Arguments)
+{
+       //gpVM8086_State = RME_CreateState();
+       return MODULE_ERR_OK;
+}
+
+tVM8086 *VM8086_Init(void)
+{
+       return NULL;
+}
+
+void VM8086_Free(tVM8086 *State)
+{
+       
+}
+
+void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset)
+{
+       return NULL;
+}
+
+void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset)
+{
+       return NULL;
+}
+
+void VM8086_Int(tVM8086 *State, Uint8 Interrupt)
+{
+       
+}
diff --git a/KernelLand/Kernel/bin/README b/KernelLand/Kernel/bin/README
new file mode 100644 (file)
index 0000000..63d64bb
--- /dev/null
@@ -0,0 +1,24 @@
+Acess2 Binary File Loader Specifcation
+--------------------------------------
+
+Binary file loaders are defined by creating a \a tBinaryType variable that
+is registered with the kernel.
+
+\a tBinaryType contains seven fields.
+-#     \a Next
+       This field is used internally by the kernel and should be set to NULL
+       when the definition is initialise and not changed by the driver.
+-#     \a Ident
+       This field tells the kernel how to recognise this file format. If the
+       first 32-bits of the file (ANDed with the \a Mask field) match this
+       value, the file will be passed to this loader.
+-#     \a Mask
+       Determines what bits in the first 32-bits of the file matter for the
+       identifcation.
+-#     \a Name
+       This is a C string that uniquely identifies this binary format.
+-#     \a Load
+       This field is a pointer to a function that takes a VFS Handle of the
+       source exectuable file as an argument and returns a \a tBinary
+       pointer that defines the location and attributes of the exectable's
+       segments. (See \a tBinary for more information)
diff --git a/KernelLand/Kernel/bin/elf.c b/KernelLand/Kernel/bin/elf.c
new file mode 100644 (file)
index 0000000..8f51290
--- /dev/null
@@ -0,0 +1,643 @@
+/*\r
+ * Acess v0.1\r
+ * ELF Executable Loader Code\r
+ */\r
+#define DEBUG  0\r
+#include <acess.h>\r
+#include <binary.h>\r
+#include "elf.h"\r
+\r
+#define DEBUG_WARN     1\r
+\r
+// === PROTOTYPES ===\r
+tBinary        *Elf_Load(int fp);\r
+tBinary        *Elf_Load64(int fp, Elf64_Ehdr *hdr);\r
+tBinary        *Elf_Load32(int fp, Elf32_Ehdr *hdr);\r
+ int   Elf_Relocate(void *Base);\r
+ int   Elf_Relocate32(void *Base);\r
+ int   Elf_GetSymbol(void *Base, const char *Name, Uint *ret);\r
+ int   Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base);\r
+Uint   Elf_Int_HashString(const char *str);\r
+\r
+// === GLOBALS ===\r
+tBinaryType    gELF_Info = {\r
+       NULL,\r
+       0x464C457F, 0xFFFFFFFF, // '\x7FELF'\r
+       "ELF",\r
+       Elf_Load, Elf_Relocate, Elf_GetSymbol\r
+       };\r
+\r
+// === CODE ===\r
+tBinary *Elf_Load(int fp)\r
+{\r
+       Elf64_Ehdr      hdr;\r
+       \r
+       // Read ELF Header\r
+       VFS_Read(fp, sizeof(hdr), &hdr);\r
+       \r
+       // Check the file type\r
+       if(hdr.e_ident[0] != 0x7F || hdr.e_ident[1] != 'E' || hdr.e_ident[2] != 'L' || hdr.e_ident[3] != 'F') {\r
+               Log_Warning("ELF", "Non-ELF File was passed to the ELF loader");\r
+               return NULL;\r
+       }\r
+\r
+       switch(hdr.e_ident[4])  // EI_CLASS\r
+       {\r
+       case ELFCLASS32:\r
+               return Elf_Load32(fp, (Elf32_Ehdr*)&hdr);\r
+       case ELFCLASS64:\r
+               return Elf_Load64(fp, &hdr);\r
+       default:\r
+               Log_Warning("ELF", "Unknown EI_CLASS value %i", hdr.e_ident[4]);\r
+               return NULL;\r
+       }\r
+}\r
+\r
+tBinary *Elf_Load64(int FD, Elf64_Ehdr *Header)\r
+{\r
+       tBinary *ret;\r
+       Elf64_Phdr      phtab[Header->e_phnum];\r
+        int    nLoadSegments;\r
+        int    i, j;\r
+       \r
+       // Sanity check\r
+       if( Header->e_phoff == 0 )\r
+       {\r
+               Log_Warning("ELF", "No program header, panic!");\r
+               return NULL;\r
+       }\r
+       if( Header->e_shentsize != sizeof(Elf64_Shdr) ) {\r
+               Log_Warning("ELF", "Header gives shentsize as %i, my type is %i",\r
+                       Header->e_shentsize, sizeof(Elf64_Shdr) );\r
+       }\r
+       if( Header->e_phentsize != sizeof(Elf64_Phdr) ) {\r
+               Log_Warning("ELF", "Header gives phentsize as %i, my type is %i",\r
+                       Header->e_phentsize, sizeof(Elf64_Phdr) );\r
+       }\r
+\r
+       LOG("Header = {");\r
+       LOG("  e_ident = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",\r
+               Header->e_ident[0], Header->e_ident[1], Header->e_ident[2], Header->e_ident[3],\r
+               Header->e_ident[4], Header->e_ident[5], Header->e_ident[6], Header->e_ident[7],\r
+               Header->e_ident[8], Header->e_ident[9], Header->e_ident[10], Header->e_ident[11],\r
+               Header->e_ident[12], Header->e_ident[13], Header->e_ident[14], Header->e_ident[15]\r
+               );\r
+       LOG("  e_type = %i", Header->e_type);\r
+       LOG("  e_machine = %i", Header->e_machine);\r
+       LOG("  e_version = %i", Header->e_version);\r
+       LOG("  e_entry   = 0x%llx", Header->e_entry);\r
+       LOG("  e_phoff   = 0x%llx", Header->e_phoff);\r
+       LOG("  e_shoff   = 0x%llx", Header->e_shoff);\r
+       LOG("  e_flags   = 0x%x", Header->e_flags);\r
+       LOG("  e_ehsize  = %i", Header->e_ehsize);\r
+       LOG("  e_phentsize = %i", Header->e_phentsize);\r
+       LOG("  e_phnum   = %i", Header->e_phnum);\r
+       LOG("  e_shentsize = %i", Header->e_shentsize);\r
+       LOG("  e_shnum   = %i", Header->e_shnum);\r
+       LOG("  e_shstrndx = %i", Header->e_shstrndx);\r
+       LOG("}");\r
+\r
+       // Load Program Header table\r
+       VFS_Seek(FD, Header->e_phoff, SEEK_SET);\r
+       VFS_Read(FD, sizeof(Elf64_Phdr)*Header->e_phnum, phtab);\r
+\r
+       // Count load segments\r
+       nLoadSegments = 0;\r
+       for( i = 0; i < Header->e_phnum; i ++ )\r
+       {\r
+               if( phtab[i].p_type != PT_LOAD )        continue ;\r
+               nLoadSegments ++;\r
+       }\r
+       \r
+       // Allocate Information Structure\r
+       ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*nLoadSegments );\r
+       // Fill Info Struct\r
+       ret->Entry = Header->e_entry;\r
+       ret->Base = -1;         // Set Base to maximum value\r
+       ret->NumSections = nLoadSegments;\r
+       ret->Interpreter = NULL;\r
+\r
+       j = 0;  // LoadSections[] index\r
+       for( i = 0; i < Header->e_phnum; i ++ )\r
+       {\r
+               LOG("phtab[%i] = {", i);\r
+               LOG("  .p_type   = %i", phtab[i].p_type);\r
+               LOG("  .p_flags  = 0x%x", phtab[i].p_flags);\r
+               LOG("  .p_offset = 0x%llx", phtab[i].p_offset);\r
+               LOG("  .p_vaddr  = 0x%llx", phtab[i].p_vaddr);\r
+               LOG("  .p_paddr  = 0x%llx", phtab[i].p_paddr);\r
+               LOG("  .p_filesz = 0x%llx", phtab[i].p_filesz);\r
+               LOG("  .p_memsz  = 0x%llx", phtab[i].p_memsz);\r
+               LOG("  .p_align  = 0x%llx", phtab[i].p_align);\r
+               LOG("}");\r
+\r
+               // Get Interpreter Name\r
+               if( phtab[i].p_type == PT_INTERP )\r
+               {\r
+                       char *tmp;\r
+                       if(ret->Interpreter)    continue;\r
+                       tmp = malloc(phtab[i].p_filesz);\r
+                       VFS_Seek(FD, phtab[i].p_offset, 1);\r
+                       VFS_Read(FD, phtab[i].p_filesz, tmp);\r
+                       ret->Interpreter = Binary_RegInterp(tmp);\r
+                       LOG("Interpreter '%s'", tmp);\r
+                       free(tmp);\r
+                       continue;\r
+               }\r
+               \r
+               if( phtab[i].p_type != PT_LOAD )        continue ;\r
+               \r
+               // Find the executable base\r
+               if( phtab[i].p_vaddr < ret->Base )      ret->Base = phtab[i].p_vaddr;\r
+\r
+               ret->LoadSections[j].Offset = phtab[i].p_offset;\r
+               ret->LoadSections[j].Virtual = phtab[i].p_vaddr;\r
+               ret->LoadSections[j].FileSize = phtab[i].p_filesz;\r
+               ret->LoadSections[j].MemSize = phtab[i].p_memsz;\r
+               \r
+               ret->LoadSections[j].Flags = 0;\r
+               if( !(phtab[i].p_flags & PF_W) )\r
+                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
+               if( phtab[i].p_flags & PF_X )\r
+                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
+               j ++;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header)\r
+{\r
+       tBinary *ret;\r
+       Elf32_Phdr      *phtab;\r
+        int    i, j;\r
+        int    iLoadCount;\r
+\r
+       ENTER("xFD", FD);\r
+\r
+       // Check architecture with current CPU\r
+       // - TODO: Support kernel level emulation\r
+       #if ARCH_IS_x86\r
+       if( Header->machine != EM_386 )\r
+       {\r
+               Log_Warning("ELF", "Unknown architecure on ELF-32");\r
+               LEAVE_RET('n');\r
+               return NULL;\r
+       }\r
+       #endif\r
+\r
+       // Check for a program header\r
+       if(Header->phoff == 0) {\r
+               #if DEBUG_WARN\r
+               Log_Warning("ELF", "File does not contain a program header (phoff == 0)");\r
+               #endif\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Read Program Header Table\r
+       phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount );\r
+       if( !phtab ) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       LOG("hdr.phoff = 0x%08x", Header->phoff);\r
+       VFS_Seek(FD, Header->phoff, SEEK_SET);\r
+       VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab);\r
+       \r
+       // Count Pages\r
+       iLoadCount = 0;\r
+       LOG("Header->phentcount = %i", Header->phentcount);\r
+       for( i = 0; i < Header->phentcount; i++ )\r
+       {\r
+               // Ignore Non-LOAD types\r
+               if(phtab[i].Type != PT_LOAD)\r
+                       continue;\r
+               iLoadCount ++;\r
+               LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
+       }\r
+       \r
+       LOG("iLoadCount = %i", iLoadCount);\r
+       \r
+       // Allocate Information Structure\r
+       ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount );\r
+       // Fill Info Struct\r
+       ret->Entry = Header->entrypoint;\r
+       ret->Base = -1;         // Set Base to maximum value\r
+       ret->NumSections = iLoadCount;\r
+       ret->Interpreter = NULL;\r
+       \r
+       // Load Pages\r
+       j = 0;\r
+       for( i = 0; i < Header->phentcount; i++ )\r
+       {\r
+               //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
+               LOG("phtab[%i] = {", i);\r
+               LOG(" .Type = 0x%08x", phtab[i].Type);\r
+               LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
+               LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
+               LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
+               LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
+               LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
+               LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
+               LOG(" .Align = 0x%08x", phtab[i].Align);\r
+               LOG(" }");\r
+               // Get Interpreter Name\r
+               if( phtab[i].Type == PT_INTERP )\r
+               {\r
+                       char *tmp;\r
+                       if(ret->Interpreter)    continue;\r
+                       tmp = malloc(phtab[i].FileSize);\r
+                       VFS_Seek(FD, phtab[i].Offset, 1);\r
+                       VFS_Read(FD, phtab[i].FileSize, tmp);\r
+                       ret->Interpreter = Binary_RegInterp(tmp);\r
+                       LOG("Interpreter '%s'", tmp);\r
+                       free(tmp);\r
+                       continue;\r
+               }\r
+               // Ignore non-LOAD types\r
+               if(phtab[i].Type != PT_LOAD)    continue;\r
+               \r
+               // Find Base\r
+               if(phtab[i].VAddr < ret->Base)  ret->Base = phtab[i].VAddr;\r
+               \r
+               LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",\r
+                       i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);\r
+               \r
+               ret->LoadSections[j].Offset = phtab[i].Offset;\r
+               ret->LoadSections[j].FileSize = phtab[i].FileSize;\r
+               ret->LoadSections[j].Virtual = phtab[i].VAddr;\r
+               ret->LoadSections[j].MemSize = phtab[i].MemSize;\r
+               ret->LoadSections[j].Flags = 0;\r
+               if( !(phtab[i].Flags & PF_W) )\r
+                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
+               if( phtab[i].Flags & PF_X )\r
+                       ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
+               j ++;\r
+       }\r
+       \r
+       // Clean Up\r
+       free(phtab);\r
+       // Return\r
+       LEAVE('p', ret);\r
+       return ret;\r
+}\r
+\r
+// --- ELF RELOCATION ---\r
+int Elf_Relocate(void *Base)\r
+{\r
+       Elf64_Ehdr      *hdr = Base;\r
+       \r
+       switch( hdr->e_ident[EI_CLASS] )\r
+       {\r
+       case ELFCLASS32:\r
+               return Elf_Relocate32(Base);\r
+       case ELFCLASS64:\r
+               return 0;\r
+       default:\r
+               return 1;\r
+       }\r
+}\r
+\r
+\r
+/**\r
+ * \brief Relocates a loaded ELF Executable\r
+ */\r
+int Elf_Relocate32(void *Base)\r
+{\r
+       Elf32_Ehdr      *hdr = Base;\r
+       Elf32_Phdr      *phtab;\r
+        int    i, j;   // Counters\r
+       char    *libPath;\r
+       Uint    iRealBase = -1;\r
+       Uint    iBaseDiff;\r
+        int    iSegmentCount;\r
+        int    iSymCount = 0;\r
+       Elf32_Rel       *rel = NULL;\r
+       Elf32_Rela      *rela = NULL;\r
+       Uint32  *pltgot = NULL;\r
+       void    *plt = NULL;\r
+       Uint32  *ptr;\r
+        int    relSz=0, relEntSz=8;\r
+        int    relaSz=0, relaEntSz=8;\r
+        int    pltSz=0, pltType=0;\r
+       Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer\r
+       char    *dynstrtab = NULL;      // .dynamic String Table\r
+       Elf32_Sym       *dynsymtab = NULL;\r
+        int    bFailed = 0;\r
+       \r
+       ENTER("pBase", Base);\r
+       \r
+       // Parse Program Header to get Dynamic Table\r
+       phtab = (void *)( (tVAddr)Base + hdr->phoff );\r
+       iSegmentCount = hdr->phentcount;\r
+       for(i = 0; i < iSegmentCount; i ++ )\r
+       {\r
+               // Determine linked base address\r
+               if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)\r
+                       iRealBase = phtab[i].VAddr;\r
+               \r
+               // Find Dynamic Section\r
+               if(phtab[i].Type == PT_DYNAMIC) {\r
+                       if(dynamicTab) {\r
+                               Log_Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
+                               continue;\r
+                       }\r
+                       dynamicTab = (void *) (tVAddr) phtab[i].VAddr;\r
+                       j = i;  // Save Dynamic Table ID\r
+                       break;\r
+               }\r
+       }\r
+       \r
+       // Check if a PT_DYNAMIC segement was found\r
+       if(!dynamicTab) {\r
+               Log_Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
+               LEAVE('x', 0);\r
+               return 0;\r
+       }\r
+       \r
+       // Page Align real base\r
+       iRealBase &= ~0xFFF;\r
+       \r
+       // Adjust "Real" Base\r
+       iBaseDiff = (Uint)Base - iRealBase;\r
+       // Adjust Dynamic Table\r
+       dynamicTab = (void *) ((Uint)dynamicTab + iBaseDiff);\r
+       \r
+       // === Get Symbol table and String Table ===\r
+       for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
+       {\r
+               switch(dynamicTab[j].d_tag)\r
+               {\r
+               // --- Symbol Table ---\r
+               case DT_SYMTAB:\r
+                       dynamicTab[j].d_val += iBaseDiff;\r
+                       dynsymtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
+                       hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident\r
+                       break;\r
+               \r
+               // --- String Table ---\r
+               case DT_STRTAB:\r
+                       dynamicTab[j].d_val += iBaseDiff;\r
+                       dynstrtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
+                       break;\r
+               \r
+               // --- Hash Table --\r
+               case DT_HASH:\r
+                       dynamicTab[j].d_val += iBaseDiff;\r
+                       iSymCount = ((Uint*)((tVAddr)dynamicTab[j].d_val))[1];\r
+                       hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident\r
+                       break;\r
+               }\r
+       }\r
+\r
+       if( !dynsymtab && iSymCount > 0 ) {\r
+               Log_Warning("ELF", "Elf_Relocate: No Dynamic symbol table, but count >0");\r
+               return 0;\r
+       }\r
+\r
+       // Alter Symbols to true base\r
+       for(i = 0; i < iSymCount; i ++)\r
+       {\r
+               dynsymtab[i].value += iBaseDiff;\r
+               dynsymtab[i].nameOfs += (Uint)dynstrtab;\r
+               //LOG("Sym '%s' = 0x%x (relocated)\n", dynsymtab[i].name, dynsymtab[i].value);\r
+       }\r
+       \r
+       // === Add to loaded list (can be imported now) ===\r
+       //Binary_AddLoaded( (Uint)Base );\r
+\r
+       // === Parse Relocation Data ===\r
+       for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
+       {\r
+               switch(dynamicTab[j].d_tag)\r
+               {\r
+               // --- Shared Library Name ---\r
+               case DT_SONAME:\r
+                       LOG(".so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);\r
+                       break;\r
+               // --- Needed Library ---\r
+               case DT_NEEDED:\r
+                       libPath = dynstrtab + dynamicTab[j].d_val;\r
+                       Log_Notice("ELF", "%p - Required Library '%s' (Ignored in kernel mode)\n", Base, libPath);\r
+                       break;\r
+               // --- PLT/GOT ---\r
+               case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val);        break;\r
+               case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val);   break;\r
+               case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;\r
+               case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;\r
+               \r
+               // --- Relocation ---\r
+               case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
+               case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;\r
+               case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;\r
+               \r
+               case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;\r
+               case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;\r
+               case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;\r
+               }\r
+       }\r
+       \r
+       // Parse Relocation Entries\r
+       if(rel && relSz)\r
+       {\r
+               j = relSz / relEntSz;\r
+               for( i = 0; i < j; i++ )\r
+               {\r
+                       ptr = (void*)(iBaseDiff + rel[i].r_offset);\r
+                       if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {\r
+                               bFailed = 1;\r
+                       }\r
+               }\r
+       }\r
+       // Parse Relocation Entries\r
+       if(rela && relaSz)\r
+       {\r
+               j = relaSz / relaEntSz;\r
+               for( i = 0; i < j; i++ )\r
+               {\r
+                       ptr = (void*)(iBaseDiff + rela[i].r_offset);\r
+                       if( !Elf_Int_DoRelocate(rela[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
+                               bFailed = 1;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       // === Process PLT (Procedure Linkage Table) ===\r
+       if(plt && pltSz)\r
+       {\r
+               if(pltType == DT_REL)\r
+               {\r
+                       Elf32_Rel       *pltRel = plt;\r
+                       j = pltSz / sizeof(Elf32_Rel);\r
+                       LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
+                       for(i = 0; i < j; i++)\r
+                       {\r
+                               ptr = (void*)(iBaseDiff + pltRel[i].r_offset);\r
+                               if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {\r
+                                       bFailed = 1;\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       Elf32_Rela      *pltRela = plt;\r
+                       j = pltSz / sizeof(Elf32_Rela);\r
+                       LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
+                       for(i=0;i<j;i++)\r
+                       {\r
+                               ptr = (void*)(iBaseDiff + pltRela[i].r_offset);\r
+                               if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
+                                       bFailed = 1;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       if(bFailed) {\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       \r
+       LEAVE('x', 1);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn void Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)\r
+ * \brief Performs a relocation\r
+ * \param r_info       Field from relocation entry\r
+ * \param ptr  Pointer to location of relocation\r
+ * \param addend       Value to add to symbol\r
+ * \param symtab       Symbol Table\r
+ * \param base Base of loaded binary\r
+ */\r
+int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)\r
+{\r
+       Uint    val;\r
+        int    type = ELF32_R_TYPE(r_info);\r
+        int    sym = ELF32_R_SYM(r_info);\r
+       char    *sSymName = symtab[sym].name;\r
+       \r
+       //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",\r
+       //      r_info, ptr, addend, base);\r
+       \r
+       switch( type )\r
+       {\r
+       // Standard 32 Bit Relocation (S+A)\r
+       case R_386_32:\r
+               if( !Elf_GetSymbol((void*)base, sSymName, &val) )       // Search this binary first\r
+                       if( !Binary_GetSymbol( sSymName, &val ) )\r
+                               return 0;\r
+               LOG("%08x R_386_32 *0x%x += 0x%x('%s')", r_info, ptr, val, sSymName);\r
+               *ptr = val + addend;\r
+               break;\r
+               \r
+       // 32 Bit Relocation wrt. Offset (S+A-P)\r
+       case R_386_PC32:\r
+               if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
+                       if( !Binary_GetSymbol( sSymName, &val ) )\r
+                               return 0;\r
+               LOG("%08x R_386_PC32 *0x%x = 0x%x + 0x%x('%s') - 0x%x", r_info, ptr, *ptr, val, sSymName, (Uint)ptr );\r
+               // TODO: Check if it needs the true value of ptr or the compiled value\r
+               // NOTE: Testing using true value\r
+               *ptr = val + addend - (Uint)ptr;\r
+               break;\r
+\r
+       // Absolute Value of a symbol (S)\r
+       case R_386_GLOB_DAT:\r
+               if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
+                       if( !Binary_GetSymbol( sSymName, &val ) )\r
+                               return 0;\r
+               LOG("%08x R_386_GLOB_DAT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
+               *ptr = val;\r
+               break;\r
+       \r
+       // Absolute Value of a symbol (S)\r
+       case R_386_JMP_SLOT:\r
+               if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
+                       if( !Binary_GetSymbol( sSymName, &val ) )\r
+                               return 0;\r
+               LOG("%08x R_386_JMP_SLOT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
+               *ptr = val;\r
+               break;\r
+\r
+       // Base Address (B+A)\r
+       case R_386_RELATIVE:\r
+               LOG("%08x R_386_RELATIVE *0x%x = 0x%x + 0x%x", r_info, ptr, base, addend);\r
+               *ptr = base + addend;\r
+               break;\r
+               \r
+       default:\r
+               LOG("Rel 0x%x: 0x%x,%i", ptr, sym, type);\r
+               break;\r
+       }\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn int Elf_GetSymbol(void *Base, const char *name, Uint *ret)\r
+ * \brief Get a symbol from the loaded binary\r
+ */\r
+int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)\r
+{\r
+       Elf32_Ehdr      *hdr = (void*)Base;\r
+       Elf32_Sym       *symtab;\r
+        int    nbuckets = 0;\r
+        int    iSymCount = 0;\r
+        int    i;\r
+       Uint    *pBuckets;\r
+       Uint    *pChains;\r
+       Uint    iNameHash;\r
+\r
+       if(!Base)       return 0;\r
+\r
+       pBuckets = (void *) hdr->misc.HashTable;\r
+       symtab = (void *) hdr->misc.SymTable;\r
+       \r
+       nbuckets = pBuckets[0];\r
+       iSymCount = pBuckets[1];\r
+       pBuckets = &pBuckets[2];\r
+       pChains = &pBuckets[ nbuckets ];\r
+       \r
+       // Get hash\r
+       iNameHash = Elf_Int_HashString(Name);\r
+       iNameHash %= nbuckets;\r
+\r
+       // Check Bucket\r
+       i = pBuckets[ iNameHash ];\r
+       if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[i].name, Name) == 0) {\r
+               if(ret) *ret = symtab[ i ].value;\r
+               return 1;\r
+       }\r
+       \r
+       // Walk Chain\r
+       while(pChains[i] != STN_UNDEF)\r
+       {\r
+               i = pChains[i];\r
+               if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {\r
+                       if(ret) *ret = symtab[ i ].value;\r
+                       return 1;\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn Uint Elf_Int_HashString(char *str)\r
+ * \brief Hash a string in the ELF format\r
+ * \param str  String to hash\r
+ * \return Hash value\r
+ */\r
+Uint Elf_Int_HashString(const char *str)\r
+{\r
+       Uint    h = 0, g;\r
+       while(*str)\r
+       {\r
+               h = (h << 4) + *str++;\r
+               if( (g = h & 0xf0000000) )\r
+                       h ^= g >> 24;\r
+               h &= ~g;\r
+       }\r
+       return h;\r
+}\r
diff --git a/KernelLand/Kernel/bin/elf.h b/KernelLand/Kernel/bin/elf.h
new file mode 100644 (file)
index 0000000..13b5373
--- /dev/null
@@ -0,0 +1,287 @@
+/**\r
+ * \file elf.h\r
+ * \brief ELF Exeutable Loader\r
+ */\r
+#ifndef _BIN_ELF_H\r
+#define _BIN_ELF_H\r
+\r
+typedef Uint16 Elf64_Half;\r
+typedef Uint32 Elf64_Word;\r
+typedef Uint64 Elf64_Addr;\r
+typedef Uint64 Elf64_Off;\r
+typedef Uint64 Elf64_Xword;\r
+\r
+enum e_ident_values\r
+{\r
+       EI_MAG0,\r
+       EI_MAG1,\r
+       EI_MAG2,\r
+       EI_MAG3,\r
+       EI_CLASS,\r
+       EI_DATA,\r
+       EI_VERSION,\r
+       EI_OSABI,\r
+       EI_ABIVERSION,\r
+       EI_PAD,\r
+       EI_NIDENT = 16,\r
+};\r
+\r
+#define ELFCLASS32     1\r
+#define ELFCLASS64     2\r
+\r
+/**\r
+ * \brief ELF File Header\r
+ */\r
+struct sElf32_Ehdr\r
+{\r
+       union {\r
+               char    ident[16];      //!< Identifier Bytes\r
+               struct {\r
+                       Uint    Ident1;\r
+                       Uint    Ident2;\r
+                       Uint    HashTable;\r
+                       Uint    SymTable;\r
+               } misc;\r
+       };\r
+       Uint16  filetype;       //!< File Type\r
+       Uint16  machine;        //!< Machine / Arch\r
+       Uint32  version;        //!< Version (File?)\r
+       Uint32  entrypoint;     //!< Entry Point\r
+       Uint32  phoff;  //!< Program Header Offset\r
+       Uint32  shoff;  //!< Section Header Offset\r
+       Uint32  flags;  //!< Flags\r
+       Uint16  headersize;     //!< Header Size\r
+       Uint16  phentsize;      //!< Program Header Entry Size\r
+       Uint16  phentcount;     //!< Program Header Entry Count\r
+       Uint16  shentsize;      //!< Section Header Entry Size\r
+       Uint16  shentcount;     //!< Section Header Entry Count\r
+       Uint16  shstrindex;     //!< Section Header String Table Index\r
+} __attribute__ ((packed));\r
+\r
+typedef struct\r
+{\r
+       unsigned char   e_ident[16];\r
+       Elf64_Half      e_type;\r
+       Elf64_Half      e_machine;\r
+       Elf64_Word      e_version;\r
+       Elf64_Addr      e_entry;\r
+       Elf64_Off       e_phoff;\r
+       Elf64_Off       e_shoff;\r
+       Elf64_Word      e_flags;\r
+       Elf64_Half      e_ehsize;\r
+       Elf64_Half      e_phentsize;\r
+       Elf64_Half      e_phnum;\r
+       Elf64_Half      e_shentsize;\r
+       Elf64_Half      e_shnum;\r
+       Elf64_Half      e_shstrndx;\r
+} Elf64_Ehdr;\r
+\r
+/**\r
+ * \brief Executable Types\r
+ */\r
+enum eElf32_ExecTypes\r
+{\r
+       ET_NONE = 0,    //!< NULL Type\r
+       ET_REL  = 1,    //!< Relocatable (Object)\r
+       ET_EXEC = 2,    //!< Executable\r
+       ET_DYN  = 3,    //!< Dynamic Library\r
+       ET_CORE = 4,    //!< Core?\r
+       ET_LOPROC = 0xFF00,     //!< Low Impl Defined\r
+       ET_HIPROC = 0xFFFF      //!< High Impl Defined\r
+};\r
+\r
+/**\r
+ \name Section IDs\r
+ \{\r
+*/\r
+#define SHN_UNDEF              0       //!< Undefined Section\r
+#define SHN_LORESERVE  0xFF00  //!< Low Reserved\r
+#define SHN_LOPROC     0xFF00  //!< Low Impl Defined\r
+#define SHN_HIPROC     0xFF1F  //!< High Impl Defined\r
+#define SHN_ABS        0xFFF1  //!< Absolute Address (Base: 0, Size: -1)\r
+#define SHN_COMMON     0xFFF2  //!< Common\r
+#define SHN_HIRESERVE  0xFFFF  //!< High Reserved\r
+//! \}\r
+\r
+/**\r
+ \enum eElfSectionTypes\r
+ \brief ELF Section Types\r
+*/\r
+enum eElfSectionTypes {\r
+       SHT_NULL,       //0\r
+       SHT_PROGBITS,   //1\r
+       SHT_SYMTAB,     //2\r
+       SHT_STRTAB,     //3\r
+       SHT_RELA,       //4\r
+       SHT_HASH,       //5\r
+       SHT_DYNAMIC,    //6\r
+       SHT_NOTE,       //7\r
+       SHT_NOBITS,     //8\r
+       SHT_REL,        //9\r
+       SHT_SHLIB,      //A\r
+       SHT_DYNSYM,     //B\r
+       SHT_LAST,       //C\r
+       SHT_LOPROC = 0x70000000,\r
+       SHT_HIPROC = 0x7fffffff,\r
+       SHT_LOUSER = 0x80000000,\r
+       SHT_HIUSER = 0xffffffff\r
+};\r
+\r
+#define SHF_WRITE      0x1\r
+#define SHF_ALLOC      0x2\r
+#define SHF_EXECINSTR  0x4\r
+#define SHF_MASKPROC   0xf0000000\r
+\r
+struct sElf32_Shent {\r
+       Uint32  name;\r
+       Uint32  type;\r
+       Uint32  flags;\r
+       Uint32  address;\r
+       Uint32  offset;\r
+       Uint32  size;\r
+       Uint32  link;\r
+       Uint32  info;\r
+       Uint32  addralign;\r
+       Uint32  entsize;\r
+} __attribute__ ((packed));    //sizeof = 40\r
+\r
+typedef struct\r
+{\r
+       Elf64_Word      sh_name;\r
+       Elf64_Word      sh_type;\r
+       Elf64_Xword     sh_flags;\r
+       Elf64_Addr      sh_addr;\r
+       Elf64_Off       sh_offset;\r
+       Elf64_Xword     sh_size;\r
+       Elf64_Word      sh_link;\r
+       Elf64_Word      sh_info;\r
+       Elf64_Xword     sh_addralign;\r
+       Elf64_Xword     sh_entsize;\r
+} Elf64_Shdr;\r
+\r
+struct elf_sym_s {\r
+       union {\r
+               Uint32  nameOfs;\r
+               char    *name;\r
+       };\r
+       Uint32  value;  //Address\r
+       Uint32  size;\r
+       Uint8   info;\r
+       Uint8   other;\r
+       Uint16  shndx;\r
+} __attribute__ ((packed));\r
+#define        STN_UNDEF       0       // Undefined Symbol\r
+\r
+enum {\r
+       PT_NULL,        //0\r
+       PT_LOAD,        //1\r
+       PT_DYNAMIC,     //2\r
+       PT_INTERP,      //3\r
+       PT_NOTE,        //4\r
+       PT_SHLIB,       //5\r
+       PT_PHDR,        //6\r
+       PT_LOPROC = 0x70000000,\r
+       PT_HIPROC = 0x7fffffff\r
+};\r
+\r
+struct sElf32_Phdr {\r
+       Uint32  Type;\r
+       Uint32  Offset;\r
+       Uint32  VAddr;\r
+       Uint32  PAddr;\r
+       Uint32  FileSize;\r
+       Uint32  MemSize;\r
+       Uint32  Flags;\r
+       Uint32  Align;\r
+} __attribute__ ((packed));\r
+\r
+typedef struct\r
+{\r
+       Elf64_Word      p_type;\r
+       Elf64_Word      p_flags;\r
+       Elf64_Off       p_offset;\r
+       Elf64_Addr      p_vaddr;\r
+       Elf64_Addr      p_paddr;\r
+       Elf64_Xword     p_filesz;\r
+       Elf64_Xword     p_memsz;\r
+       Elf64_Xword     p_align;\r
+} Elf64_Phdr;\r
+\r
+#define PF_X   1\r
+#define PF_W   2\r
+#define PF_R   4\r
+\r
+struct elf32_rel_s {\r
+       Uint32  r_offset;\r
+       Uint32  r_info;\r
+} __attribute__ ((packed));\r
+\r
+struct elf32_rela_s {\r
+       Uint32  r_offset;\r
+       Uint32  r_info;\r
+       Sint32  r_addend;\r
+} __attribute__ ((packed));\r
+\r
+enum {\r
+       R_386_NONE = 0, // none\r
+       R_386_32,       // S+A\r
+       R_386_PC32,     // S+A-P\r
+       R_386_GOT32,    // G+A-P\r
+       R_386_PLT32,    // L+A-P\r
+       R_386_COPY,     // none\r
+       R_386_GLOB_DAT, // S\r
+       R_386_JMP_SLOT, // S\r
+       R_386_RELATIVE, // B+A\r
+       R_386_GOTOFF,   // S+A-GOT\r
+       R_386_GOTPC,    // GOT+A-P\r
+       R_386_LAST      // none\r
+};\r
+\r
+#define        ELF32_R_SYM(i)  ((i)>>8)        // Takes an info value and returns a symbol index\r
+#define        ELF32_R_TYPE(i) ((i)&0xFF)      // Takes an info value and returns a type\r
+#define        ELF32_R_INFO(s,t)       (((s)<<8)+((t)&0xFF))   // Takes a type and symbol index and returns an info value\r
+\r
+struct elf32_dyn_s {\r
+       Uint32  d_tag;\r
+       Uint32  d_val;  //Also d_ptr\r
+} __attribute__ ((packed));\r
+\r
+enum {\r
+       DT_NULL,        //!< Marks End of list\r
+       DT_NEEDED,      //!< Offset in strtab to needed library\r
+       DT_PLTRELSZ,    //!< Size in bytes of PLT\r
+       DT_PLTGOT,      //!< Address of PLT/GOT\r
+       DT_HASH,        //!< Address of symbol hash table\r
+       DT_STRTAB,      //!< String Table address\r
+       DT_SYMTAB,      //!< Symbol Table address\r
+       DT_RELA,        //!< Relocation table address\r
+       DT_RELASZ,      //!< Size of relocation table\r
+       DT_RELAENT,     //!< Size of entry in relocation table\r
+       DT_STRSZ,       //!< Size of string table\r
+       DT_SYMENT,      //!< Size of symbol table entry\r
+       DT_INIT,        //!< Address of initialisation function\r
+       DT_FINI,        //!< Address of termination function\r
+       DT_SONAME,      //!< String table offset of so name\r
+       DT_RPATH,       //!< String table offset of library path\r
+       DT_SYMBOLIC,//!< Reverse order of symbol searching for library, search libs first then executable\r
+       DT_REL,         //!< Relocation Entries (Elf32_Rel instead of Elf32_Rela)\r
+       DT_RELSZ,       //!< Size of above table (bytes)\r
+       DT_RELENT,      //!< Size of entry in above table\r
+       DT_PLTREL,      //!< Relocation entry of PLT\r
+       DT_DEBUG,       //!< Debugging Entry - Unknown contents\r
+       DT_TEXTREL,     //!< Indicates that modifcations to a non-writeable segment may occur\r
+       DT_JMPREL,      //!< Address of PLT only relocation entries\r
+       DT_LOPROC = 0x70000000, //!< Low Definable\r
+       DT_HIPROC = 0x7FFFFFFF  //!< High Definable\r
+};\r
+\r
+typedef struct sElf32_Ehdr     Elf32_Ehdr;\r
+typedef struct sElf32_Phdr     Elf32_Phdr;\r
+typedef struct sElf32_Shent    Elf32_Shent;\r
+typedef struct elf_sym_s       elf_symtab;\r
+typedef struct elf_sym_s       Elf32_Sym;\r
+typedef struct elf32_rel_s     Elf32_Rel;\r
+typedef struct elf32_rela_s    Elf32_Rela;\r
+typedef struct elf32_dyn_s     Elf32_Dyn;\r
+\r
+#endif // defined(_EXE_ELF_H)\r
diff --git a/KernelLand/Kernel/bin/pe.c b/KernelLand/Kernel/bin/pe.c
new file mode 100644 (file)
index 0000000..0e7d1ac
--- /dev/null
@@ -0,0 +1,221 @@
+/*\r
+ * Acess v1\r
+ * Portable Executable Loader\r
+ */\r
+#define DEBUG  1\r
+#include <acess.h>\r
+#include <binary.h>\r
+#include <modules.h>\r
+#include "pe.h"\r
+\r
+// === PROTOTYPES ===\r
+ int   PE_Install(char **Arguments);\r
+tBinary        *PE_Load(int fp);\r
+tBinary        *MZ_Open(int fp);\r
+ int   PE_Relocate(void *Base);\r
+ int   PE_GetSymbol(void *Base, const char *Name, Uint *Ret);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0032, BinPE, PE_Install, NULL, NULL);\r
+const char     *gsPE_DefaultInterpreter = "/Acess/Libs/ld-acess.so";\r
+tBinaryType    gPE_Loader = {\r
+       NULL,\r
+       ('M'|('Z'<<8)), 0xFFFF, // 'MZ'\r
+       "PE/DOS",\r
+       PE_Load, PE_Relocate, PE_GetSymbol\r
+       };\r
+\r
+// === CODE ===\r
+int PE_Install(char **Arguments)\r
+{\r
+       Binary_RegisterType(&gPE_Loader);\r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \brief Loads a PE Binary\r
+ */\r
+tBinary *PE_Load(int FP)\r
+{\r
+        int    count, i, j;\r
+        int    iSectCount;\r
+       tBinary *ret;\r
+       tPE_DOS_HEADER          dosHdr;\r
+       tPE_IMAGE_HEADERS       peHeaders;\r
+       tPE_SECTION_HEADER      *peSections;\r
+       char    namebuf[9] = {0};\r
+       Uint    iFlags, iVA;\r
+       \r
+       ENTER("xFP", FP);\r
+       \r
+       // Read DOS header and check\r
+       VFS_Read(FP, sizeof(tPE_DOS_HEADER), &dosHdr);\r
+       if( dosHdr.Ident != ('M'|('Z'<<8)) ) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // - Read PE Header\r
+       VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET);\r
+       if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) {\r
+               ret = MZ_Open(FP);\r
+               LEAVE('p', ret);\r
+               return ret;\r
+       }\r
+       VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders);\r
+       \r
+       // - Check PE Signature and pass on to the MZ Loader if invalid\r
+       if( peHeaders.Signature != (('P')|('E'<<8)) ) {\r
+               ret = MZ_Open(FP);\r
+               LEAVE('p', ret);\r
+               return ret;\r
+       }\r
+       \r
+       // Read Sections (Uses `count` as a temp variable)\r
+       count = sizeof(tPE_SECTION_HEADER) * peHeaders.FileHeader.SectionCount;\r
+       peSections = malloc( count );\r
+       if(!peSections)\r
+       {\r
+               Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       VFS_Read(FP, count, peSections);\r
+       \r
+       // Count Pages\r
+       iSectCount = 1; // 1st page is headers\r
+       for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
+       {\r
+               // Check if the section is loadable\r
+               // (VA is zero in non-loadable sections)\r
+               if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0)              continue;\r
+               \r
+               // Moar pages\r
+               iSectCount ++;\r
+       }\r
+       \r
+       LOG("%i Sections", iSectCount);\r
+       \r
+       // Initialise Executable Information\r
+       ret = malloc(sizeof(tBinary) + sizeof(tBinarySection)*iSectCount);\r
+       \r
+       ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase;\r
+       ret->Base = peHeaders.OptHeader.ImageBase;\r
+       ret->Interpreter = gsPE_DefaultInterpreter;\r
+       ret->NumSections = iSectCount;\r
+       \r
+       LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base);\r
+       \r
+       ret->LoadSections[0].Virtual = peHeaders.OptHeader.ImageBase;\r
+       ret->LoadSections[0].Offset = 0;\r
+       ret->LoadSections[0].FileSize = 4096;\r
+       ret->LoadSections[0].MemSize = 4096;\r
+       ret->LoadSections[0].Flags = 0;\r
+       \r
+       // Parse Sections\r
+       j = 1;  // Page Index\r
+       for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
+       {\r
+               tBinarySection  *sect = &ret->LoadSections[j];\r
+               iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase;\r
+               \r
+               // Skip non-loadable sections\r
+               if(iVA == 0)    continue;\r
+               \r
+               // Create Name Buffer\r
+               memcpy(namebuf, peSections[i].Name, 8);\r
+               LOG("Section %i '%s', iVA = %p", i, namebuf, iVA);\r
+               \r
+               // Create Flags\r
+               iFlags = 0;\r
+               if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE)\r
+                       iFlags |= BIN_SECTFLAG_EXEC;\r
+               if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) )\r
+                       iFlags |= BIN_SECTFLAG_RO;\r
+               \r
+               sect->Virtual = iVA;\r
+               sect->Offset = peSections[i].RawOffs;\r
+               sect->FileSize = peSections[i].RawSize;\r
+               sect->MemSize = peSections[i].VirtualSize;\r
+               sect->Flags = iFlags;\r
+               j ++;\r
+               \r
+               LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x",\r
+                       i, namebuf, \r
+                       iVA,\r
+                       peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs,\r
+                       peSections[i].Flags\r
+                       );\r
+               \r
+       }\r
+       // Free Executable Memory\r
+       free(peSections);\r
+       \r
+       LEAVE('p', ret);\r
+       return ret;\r
+}\r
+\r
+/**\r
+ */\r
+tBinary *MZ_Open(int FP)\r
+{\r
+       ENTER("xFP", FP);\r
+       UNIMPLEMENTED();\r
+       LEAVE('n');\r
+       return NULL;\r
+}\r
+\r
+int PE_Relocate(void *Base)\r
+{\r
+       tPE_DOS_HEADER          *dosHdr;\r
+       tPE_IMAGE_HEADERS       *peHeaders;\r
+       tPE_SECTION_HEADER      *peSections;\r
+       tPE_DATA_DIR    *directory;\r
+       tPE_IMPORT_DIR  *impDir;\r
+        int    i;\r
+       Uint    iBase = (Uint)Base;\r
+       #if 0\r
+       void    *hLibrary;\r
+       char    *libPath;\r
+       #endif\r
+       \r
+       ENTER("pBase", Base);\r
+       dosHdr = Base;\r
+       peHeaders = (void*)( iBase + dosHdr->PeHdrOffs );\r
+       LOG("Prefered Base %p", peHeaders->OptHeader.ImageBase);\r
+       peSections = (void*)( iBase + sizeof(tPE_IMAGE_HEADERS) );\r
+       \r
+       directory = (void*)(peSections[0].RVA + iBase);\r
+       \r
+       // === Load Import Tables\r
+       impDir = (void*)( directory[PE_DIR_IMPORT].RVA + iBase );\r
+       for( i = 0; impDir[i].DLLName != NULL; i++ )\r
+       {\r
+               impDir[i].DLLName += iBase;\r
+               impDir[i].ImportLookupTable += iBase/4;\r
+               impDir[i].ImportAddressTable += iBase/4;\r
+               LOG("DLL Required '%s'(0x%x)", impDir[i].DLLName, impDir[i].DLLName);\r
+               #if 0\r
+               libPath = FindLibrary(impDir[i].DLLName);\r
+               if(libPath == NULL)\r
+               {\r
+                       Warning("PE_Relocate - Unable to find library '%s'");\r
+                       LEAVE('i', -1);\r
+                       return -1;\r
+               }\r
+               LOG("DLL Path = '%s'", libPath);\r
+               hLibrary = DynLib_Load(libPath, 0);\r
+               #endif\r
+       }\r
+       \r
+       for(i=0;i<PE_DIR_LAST;i++)\r
+               LOG("directory[%i] = {RVA=0x%x,Size=0x%x}", i, directory[i].RVA, directory[i].Size);\r
+       \r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
+int PE_GetSymbol(void *Base, const char *Name, Uint *Ret)\r
+{\r
+       return 0;\r
+}\r
diff --git a/KernelLand/Kernel/bin/pe.h b/KernelLand/Kernel/bin/pe.h
new file mode 100644 (file)
index 0000000..4e85cf9
--- /dev/null
@@ -0,0 +1,136 @@
+/*\r
+AcessOS/AcessBasic v1\r
+PE Loader\r
+HEADER\r
+*/\r
+#ifndef _EXE_PE_H\r
+#define _EXE_PE_H\r
+\r
+enum ePE_MACHINES {\r
+       PE_MACHINE_I386 = 0x14c,        // Intel 386+\r
+       PE_MACHINE_IA64 = 0x200         // Intel-64\r
+};\r
+\r
+enum ePE_DIR_INDX {\r
+       PE_DIR_EXPORT,          // 0\r
+       PE_DIR_IMPORT,          // 1\r
+       PE_DIR_RESOURCE,        // 2\r
+       PE_DIR_EXCEPTION,       // 3\r
+       PE_DIR_SECRURITY,       // 4\r
+       PE_DIR_RELOC,           // 5\r
+       PE_DIR_DEBUG,           // 6\r
+       PE_DIR_COPYRIGHT,       // 7\r
+       PE_DIR_ARCHITECTURE,// 8\r
+       PE_DIR_GLOBALPTR,       // 9\r
+       PE_DIR_TLS,                     // 10\r
+       PE_DIR_LOAD_CFG,        // 11\r
+       PE_DIR_BOUND_IMPORT,// 12\r
+       PE_DIR_IAT,                     // 13\r
+       PE_DIR_DELAY_IMPORT,// 14\r
+       PE_DIR_COM_DESCRIPTOR,  //15\r
+       PE_DIR_LAST\r
+};\r
+\r
+typedef struct {\r
+       Uint32  RVA;\r
+       Uint32  Size;\r
+} tPE_DATA_DIR;\r
+\r
+typedef struct {\r
+       Uint32  *ImportLookupTable;     //0x80000000 is Ordninal Flag\r
+       Uint32  TimeStamp;\r
+       Uint32  FowarderChain;\r
+       char    *DLLName;\r
+       Uint32  *ImportAddressTable;    // Array of Addresses - To be edited by loader\r
+} tPE_IMPORT_DIR;\r
+\r
+typedef struct {\r
+       Uint16  Hint;\r
+       char    Name[]; // Zero Term String\r
+} tPE_HINT_NAME;\r
+\r
+typedef struct {\r
+       char    Name[8];\r
+       Uint32  VirtualSize;\r
+       Uint32  RVA;\r
+       Uint32  RawSize;\r
+       Uint32  RawOffs;\r
+       Uint32  RelocationsPtr; //Set to 0 in executables\r
+       Uint32  LineNumberPtr;  //Pointer to Line Numbers\r
+       Uint16  RelocationCount;        // Set to 0 in executables\r
+       Uint16  LineNumberCount;\r
+       Uint32  Flags;\r
+} tPE_SECTION_HEADER;\r
+\r
+#define PE_SECTION_FLAG_CODE   0x00000020      // Section contains executable code.\r
+#define PE_SECTION_FLAG_IDATA  0x00000040      // Section contains initialized data.\r
+#define PE_SECTION_FLAG_UDATA  0x00000080      // Section contains uninitialized data.\r
+#define PE_SECTION_FLAG_DISCARDABLE    0x02000000      // Section can be discarded as needed.\r
+#define PE_SECTION_FLAG_MEM_NOT_CACHED 0x04000000      // Section cannot be cached.\r
+#define PE_SECTION_FLAG_MEM_NOT_PAGED  0x08000000      // Section is not pageable.\r
+#define PE_SECTION_FLAG_MEM_SHARED     0x10000000      // Section can be shared in memory.\r
+#define PE_SECTION_FLAG_MEM_EXECUTE    0x20000000      // Section can be executed as code.\r
+#define PE_SECTION_FLAG_MEM_READ       0x40000000      // Section can be read.\r
+#define PE_SECTION_FLAG_MEM_WRITE      0x80000000      // Section can be written to.\r
+\r
+typedef struct {\r
+       Uint32  page;\r
+       Uint32  size;\r
+       Uint16  ents[];\r
+} tPE_FIXUP_BLOCK;\r
+\r
+//File Header\r
+typedef struct {\r
+       Uint16  Machine;\r
+       Uint16  SectionCount;\r
+       Uint32  CreationTimestamp;\r
+       Uint32  SymbolTableOffs;\r
+       Uint32  SymbolCount;\r
+       Uint16  OptHeaderSize;\r
+       Uint16  Flags;\r
+} tPE_FILE_HEADER;\r
+\r
+typedef struct {\r
+       Uint16  Magic;  //0x10b: 32Bit, 0x20b: 64Bit\r
+       Uint16  LinkerVersion;\r
+       Uint32  CodeSize;       //Sum of all Code Segment Sizes\r
+       Uint32  DataSize;       //Sum of all Intialised Data Segments\r
+       Uint32  BssSize;        //Sum of all Unintialised Data Segments\r
+       Uint32  EntryPoint;\r
+       Uint32  CodeRVA;\r
+       Uint32  DataRVA;\r
+       Uint32  ImageBase;      //Prefered Base Address\r
+       Uint32  SectionAlignment;\r
+       Uint32  FileAlignment;\r
+       Uint32  WindowsVersion; //Unused/Irrelevent\r
+       Uint32  ImageVersion;   //Unused/Irrelevent\r
+       Uint32  SubsystemVersion;       //Unused, Set to 4\r
+       Uint32  Win32Version;   //Unused\r
+       Uint32  ImageSize;\r
+       Uint32  HeaderSize;\r
+       Uint32  Checksum;       //Unknown Method, Can be set to 0\r
+       Uint16  Subsystem;      //Required Windows Subsystem (None, GUI, Console)\r
+       Uint16  DllFlags;\r
+       Uint32  MaxStackSize;           //Reserved Stack Size\r
+       Uint32  InitialStackSize;       //Commited Stack Size\r
+       Uint32  InitialReservedHeap;    // Reserved Heap Size\r
+       Uint32  InitialCommitedHeap;    // Commited Heap Size\r
+       Uint32  LoaderFlags;    // Obselete\r
+       Uint32  NumberOfDirEntries;\r
+       tPE_DATA_DIR    Directory[16];\r
+} tPE_OPT_HEADER;\r
+\r
+// Root Header\r
+typedef struct {\r
+       Uint32  Signature;\r
+       tPE_FILE_HEADER FileHeader;\r
+       tPE_OPT_HEADER  OptHeader;\r
+} tPE_IMAGE_HEADERS;\r
+\r
+typedef struct {\r
+       Uint16  Ident;\r
+       Uint16  Resvd[29];\r
+       Uint32  PeHdrOffs;              // File address of new exe header\r
+} tPE_DOS_HEADER;\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/binary.c b/KernelLand/Kernel/binary.c
new file mode 100644 (file)
index 0000000..5213bf2
--- /dev/null
@@ -0,0 +1,880 @@
+/*
+ * Acess2
+ * Common Binary Loader
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <binary.h>
+#include <mm_virt.h>
+#include <hal_proc.h>
+#include <vfs_threads.h>
+
+// === CONSTANTS ===
+#define BIN_LOWEST     MM_USER_MIN             // 1MiB
+#define BIN_GRANUALITY 0x10000         // 64KiB
+#define BIN_HIGHEST    (USER_LIB_MAX-BIN_GRANUALITY)           // Just below the kernel
+#define        KLIB_LOWEST     MM_MODULE_MIN
+#define KLIB_GRANUALITY        0x10000         // 32KiB
+#define        KLIB_HIGHEST    (MM_MODULE_MAX-KLIB_GRANUALITY)
+
+// === TYPES ===
+typedef struct sKernelBin {
+       struct sKernelBin       *Next;
+       void    *Base;
+       tBinary *Info;
+} tKernelBin;
+
+// === IMPORTS ===
+extern char    *Threads_GetName(int ID);
+extern tKernelSymbol   gKernelSymbols[];
+extern tKernelSymbol   gKernelSymbolsEnd[];
+extern tBinaryType     gELF_Info;
+
+// === PROTOTYPES ===
+ int   Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
+tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
+tBinary        *Binary_GetInfo(tMount MountID, tInode InodeID);
+tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
+tVAddr Binary_IsMapped(tBinary *Binary);
+tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path);
+void   Binary_Dereference(tBinary *Info);
+#if 0
+Uint   Binary_Relocate(void *Base);
+#endif
+Uint   Binary_GetSymbolEx(const char *Name, Uint *Value);
+#if 0
+Uint   Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
+#endif
+ int   Binary_int_CheckMemFree( tVAddr _start, size_t _len );
+
+// === GLOBALS ===
+tShortSpinlock glBinListLock;
+tBinary        *glLoadedBinaries = NULL;
+char   **gsaRegInterps = NULL;
+ int   giRegInterps = 0;
+tShortSpinlock glKBinListLock;
+tKernelBin     *glLoadedKernelLibs;
+tBinaryType    *gRegBinTypes = &gELF_Info;
+// === FUNCTIONS ===
+/**
+ * \brief Registers a binary type
+ */
+int Binary_RegisterType(tBinaryType *Type)
+{
+       Type->Next = gRegBinTypes;
+       gRegBinTypes = Type;
+       return 1;
+}
+
+/**
+ * \fn int Proc_Spawn(const char *Path)
+ */
+int Proc_Spawn(const char *Path)
+{
+       char    stackPath[strlen(Path)+1];
+       ENTER("sPath", Path);
+       
+       strcpy(stackPath, Path);
+       
+       LOG("stackPath = '%s'", stackPath);
+       
+       if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
+       {
+               // CHILD
+               const char      *args[2] = {stackPath, NULL};
+               LOG("stackPath = '%s'", stackPath);
+               Proc_Execve(stackPath, args, &args[1], 0);
+               for(;;);
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \todo Document
+ */
+int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
+{
+        int    size, argc=0, envc=0;
+        int    i;
+       char    *strbuf;
+       const char      **arrays;
+       
+       // Calculate size
+       size = 0;
+       if( ArgV && *ArgV )
+       {
+               const char      **argv = *ArgV;
+               for( argc = 0; argv[argc]; argc ++ )
+                       size += strlen( argv[argc] ) + 1;
+       }
+       if( EnvP && *EnvP )
+       {
+               const char      **envp = *EnvP;
+               for( envc = 0; envp[envc]; envc ++ )
+                       size += strlen( envp[envc] ) + 1;
+       }
+       size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1);   // Word align
+       size += (argc+1+envc+1)*sizeof(void*);  // Arrays
+       if( Path )
+       {
+               size += strlen( *Path ) + 1;
+       }
+
+       if( DestBuffer )        
+       {
+               arrays = DestBuffer;
+               strbuf = (void*)&arrays[argc+1+envc+1];
+       
+               // Fill ArgV
+               if( ArgV && *ArgV )
+               {
+                       const char      **argv = *ArgV;
+                       for( i = 0; argv[i]; i ++ )
+                       {
+                               arrays[i] = strbuf;
+                               strcpy(strbuf, argv[i]);
+                               strbuf += strlen( argv[i] ) + 1;
+                       }
+                       *ArgV = arrays;
+                       arrays += i;
+               }
+               *arrays++ = NULL;
+               // Fill EnvP
+               if( EnvP && *EnvP )
+               {
+                       const char      **envp = *EnvP;
+                       for( i = 0; envp[i]; i ++ )
+                       {
+                               arrays[i] = strbuf;
+                               strcpy(strbuf, envp[i]);
+                               strbuf += strlen( envp[i] ) + 1;
+                       }
+                       *EnvP = arrays;
+                       arrays += i;
+               }
+               *arrays++ = NULL;
+               // Fill path
+               if( Path )
+               {
+                       strcpy(strbuf, *Path);
+                       *Path = strbuf;
+               }
+       }
+       
+       return size;
+}
+
+/**
+ * \brief Create a new process with the specified set of file descriptors
+ */
+int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
+{
+       void    *handles;
+       void    *cachebuf;
+        int    size;
+       tPID    ret;
+       
+       // --- Save File, ArgV and EnvP
+       size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
+       cachebuf = malloc( size );
+       Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
+
+       // Cache the VFS handles        
+       handles = VFS_SaveHandles(nFD, FDs);
+
+       // Create new process   
+       ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
+       if( ret == 0 )
+       {
+               VFS_RestoreHandles(nFD, handles);
+               VFS_FreeSavedHandles(nFD, handles);
+               // Frees cachebuf
+               Proc_Execve(Binary, ArgV, EnvP, size);
+               for(;;);
+       }
+       if( ret < 0 )
+       {
+               VFS_FreeSavedHandles(nFD, handles);
+       }
+       
+       return ret;
+}
+
+/**
+ * \brief Replace the current user image with another
+ * \param File File to load as the next image
+ * \param ArgV Arguments to pass to user
+ * \param EnvP User's environment
+ * \note Called Proc_ for historical reasons
+ */
+int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
+{
+       void    *cachebuf;
+       tVAddr  entry;
+       Uint    base;   // Uint because Proc_StartUser wants it
+        int    argc;
+       
+       ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
+       
+       // --- Save File, ArgV and EnvP
+       if( DataSize == 0 )
+       {
+               DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
+               cachebuf = malloc( DataSize );
+               Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
+       }
+
+       // --- Get argc 
+       for( argc = 0; ArgV && ArgV[argc]; argc ++ );
+       
+       // --- Set Process Name
+       Threads_SetName(File);
+       
+       // --- Clear User Address space
+       // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
+       //       PPD area would be a better idea.
+       {
+                int    nfd = *Threads_GetMaxFD();
+               void    *handles;
+               handles = VFS_SaveHandles(nfd, NULL);
+               VFS_CloseAllUserHandles();
+               MM_ClearUser();
+               VFS_RestoreHandles(nfd, handles);
+               VFS_FreeSavedHandles(nfd, handles);
+       }
+       
+       // --- Load new binary
+       base = Binary_Load(File, &entry);
+       if(base == 0)
+       {
+               Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
+               LEAVE('-');
+               Threads_Exit(0, -10);
+               for(;;);
+       }
+       
+       LOG("entry = 0x%x, base = 0x%x", entry, base);
+       LEAVE('-');
+       // --- And... Jump to it
+       Proc_StartUser(entry, base, argc, ArgV, DataSize);
+       for(;;);        // Tell GCC that we never return
+}
+
+/**
+ * \brief Load a binary into the current address space
+ * \param Path Path to binary to load
+ * \param EntryPoint   Pointer for exectuable entry point
+ * \return Virtual address where the binary has been loaded
+ */
+tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint)
+{
+       tMount  mount_id;
+       tInode  inode;
+       tBinary *pBinary;
+       tVAddr  base = -1;
+
+       ENTER("sPath pEntryPoint", Path, EntryPoint);
+       
+       // Sanity Check Argument
+       if(Path == NULL) {
+               LEAVE('x', 0);
+               return 0;
+       }
+
+       // Check if this path has been loaded before.
+       #if 0
+       // TODO: Implement a list of string/tBinary pairs for loaded bins
+       #endif
+
+       // Get Inode
+       {
+               int fd;
+               tFInfo  info;
+               fd = VFS_Open(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_EXEC);
+               if( fd == -1 ) {
+                       LOG("%s does not exist", Path);
+                       LEAVE_RET('x', 0);
+               }
+               VFS_FInfo(fd, &info, 0);
+               VFS_Close(fd);
+               mount_id = info.mount;
+               inode = info.inode;
+               LOG("mount_id = %i, inode = %i", mount_id, inode);
+       }
+
+       // TODO: Also get modifcation time?
+
+       // Check if the binary has already been loaded
+       if( !(pBinary = Binary_GetInfo(mount_id, inode)) )
+               pBinary = Binary_DoLoad(mount_id, inode, Path); // Else load it
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       // Map into process space
+       base = Binary_MapIn(pBinary, Path, BIN_LOWEST, BIN_HIGHEST);
+       
+       // Check for errors
+       if(base == 0) {
+               LEAVE('x', 0);
+               return 0;
+       }
+       
+       // Interpret
+       if(pBinary->Interpreter) {
+               tVAddr  start;
+               if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {
+                       LEAVE('x', 0);
+                       return 0;
+               }
+               *EntryPoint = start;
+       }
+       else
+               *EntryPoint = pBinary->Entry - pBinary->Base + base;
+       
+       // Return
+       LOG("*EntryPoint = 0x%x", *EntryPoint);
+       LEAVE('x', base);
+       return base;    // Pass the base as an argument to the user if there is an interpreter
+}
+
+/**
+ * \brief Finds a matching binary entry
+ * \param MountID      Mountpoint ID of binary file
+ * \param InodeID      Inode ID of the file
+ * \return Pointer to the binary definition (if already loaded)
+ */
+tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
+{
+       tBinary *pBinary;
+       for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
+       {
+               if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
+                       return pBinary;
+       }
+       return NULL;
+}
+
+/**
+ * \brief Maps an already-loaded binary into an address space.
+ * \param Binary       Pointer to globally stored binary definition
+ * \param Path Path to the binary's file (for debug)
+ * \param LoadMin      Lowest location to map to
+ * \param LoadMax      Highest location to map to
+ * \return Base load address
+ */
+tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
+{
+       tVAddr  base;
+        int    i, fd;
+
+       ENTER("pBinary sPath pLoadMin pLoadMax", Binary, Path, LoadMin, LoadMax);
+
+       // Reference Executable (Makes sure that it isn't unloaded)
+       Binary->ReferenceCount ++;
+       
+       // Get Binary Base
+       base = Binary->Base;
+       
+       // Check if base is free
+       if(base != 0)
+       {
+               LOG("Checking base %p", base);
+               for( i = 0; i < Binary->NumSections; i ++ )
+               {
+                       if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
+                       {
+                               base = 0;
+                               LOG("Address 0x%x is taken\n", Binary->LoadSections[i].Virtual);
+                               break;
+                       }
+               }
+       }
+       
+       // Check if the executable has no base or it is not free
+       if(base == 0)
+       {
+               // If so, give it a base
+               base = LoadMax;
+               while(base >= LoadMin)
+               {
+                       for( i = 0; i < Binary->NumSections; i ++ )
+                       {
+                               tVAddr  addr = Binary->LoadSections[i].Virtual - Binary->Base + base;
+                               if( Binary_int_CheckMemFree( addr, Binary->LoadSections[i].MemSize ) )
+                                       break;
+                       }
+                       // If space was found, break
+                       if(i == Binary->NumSections)            break;
+                       // Else decrement pointer and try again
+                       base -= BIN_GRANUALITY;
+               }
+               LOG("Allocated base %p", base);
+       }
+       
+       // Error Check
+       if(base < LoadMin) {
+               Log_Warning("Binary", "Executable '%s' cannot be loaded, no space", Path);
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Map Executable In
+       fd = VFS_OpenInode(Binary->MountID, Binary->Inode, VFS_OPENFLAG_READ);
+       for( i = 0; i < Binary->NumSections; i ++ )
+       {
+               tBinarySection  *sect = &Binary->LoadSections[i];
+               Uint    protflags, mapflags;
+               tVAddr  addr = sect->Virtual - Binary->Base + base;
+               LOG("%i - %p to offset 0x%llx (%x)", i, addr, sect->Offset, sect->Flags);
+
+               protflags = MMAP_PROT_READ;
+               mapflags = MMAP_MAP_FIXED;
+
+               if( sect->Flags & BIN_SECTFLAG_EXEC )
+                       protflags |= MMAP_PROT_EXEC;
+               // Read only pages are COW
+               if( sect->Flags & BIN_SECTFLAG_RO  ) {
+                       VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
+               }
+               else {
+                       protflags |= MMAP_PROT_WRITE;
+                       VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
+               }
+               
+               // Apply anonymous memory for BSS
+               if( sect->FileSize < sect->MemSize ) {
+                       mapflags |= MMAP_MAP_ANONYMOUS;
+                       VFS_MMap(
+                               (void*)(addr + sect->FileSize), sect->MemSize - sect->FileSize,
+                               protflags, MMAP_MAP_PRIVATE|mapflags,
+                               0, 0
+                               );
+               }
+       }
+       
+       Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
+       VFS_Close(fd);
+       
+       LEAVE('p', base);
+       return base;
+}
+
+#if 0
+/**
+ * \fn Uint Binary_IsMapped(tBinary *binary)
+ * \brief Check if a binary is already mapped into the address space
+ * \param binary       Binary information to check
+ * \return Current Base or 0
+ */
+Uint Binary_IsMapped(tBinary *binary)
+{
+       Uint    iBase;
+       
+       // Check prefered base
+       iBase = binary->Base;
+       if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
+               return iBase;
+       
+       for(iBase = BIN_HIGHEST;
+               iBase >= BIN_LOWEST;
+               iBase -= BIN_GRANUALITY)
+       {
+               if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))
+                       return iBase;
+       }
+       
+       return 0;
+}
+#endif
+
+/**
+ * \fn tBinary *Binary_DoLoad(char *truePath)
+ * \brief Loads a binary file into memory
+ * \param truePath     Absolute filename of binary
+ */
+tBinary *Binary_DoLoad(tMount MountID, tInode Inode, const char *Path)
+{
+       tBinary *pBinary;
+        int    fp;
+       Uint32  ident;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       ENTER("iMountID XInode sPath", MountID, Inode, Path);
+       
+       // Open File
+       fp = VFS_OpenInode(MountID, Inode, VFS_OPENFLAG_READ);
+       if(fp == -1) {
+               LOG("Unable to load file, access denied");
+               LEAVE('n');
+               return NULL;
+       }
+
+       LOG("fp = 0x%x", fp);
+       
+       // Read File Type
+       VFS_Read(fp, 4, &ident);
+       VFS_Seek(fp, 0, SEEK_SET);
+
+       LOG("ident = 0x%x", ident);
+
+       // Determine the type   
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) != (Uint32)bt->Ident )
+                       continue;
+               LOG("bt = %p (%s)", bt, bt->Name);
+               pBinary = bt->Load(fp);
+               break;
+       }
+
+       // Close File
+       VFS_Close(fp);
+       
+       // Catch errors
+       if(!bt) {
+               Log_Warning("Binary", "'%s' is an unknown file type. (%02x %02x %02x %02x)",
+                       Path, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
+               LEAVE('n');
+               return NULL;
+       }
+       
+       LOG("pBinary = %p", pBinary);
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Initialise Structure
+       pBinary->ReferenceCount = 0;
+       pBinary->MountID = MountID;
+       pBinary->Inode = Inode;
+       
+       // Debug Information
+       LOG("Interpreter: '%s'", pBinary->Interpreter);
+       LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);
+       LOG("NumSections: %i", pBinary->NumSections);
+       
+       // Add to the list
+       SHORTLOCK(&glBinListLock);
+       pBinary->Next = glLoadedBinaries;
+       glLoadedBinaries = pBinary;
+       SHORTREL(&glBinListLock);
+
+       // TODO: Register the path with the binary      
+
+       // Return
+       LEAVE('p', pBinary);
+       return pBinary;
+}
+
+/**
+ * \fn void Binary_Unload(void *Base)
+ * \brief Unload / Unmap a binary
+ * \param Base Loaded Base
+ * \note Currently used only for kernel libaries
+ */
+void Binary_Unload(void *Base)
+{
+       tKernelBin      *pKBin;
+       tKernelBin      *prev = NULL;
+        int    i;
+       
+       if((Uint)Base < 0xC0000000)
+       {
+               // TODO: User Binaries
+               Log_Warning("BIN", "Unloading user binaries is currently unimplemented");
+               return;
+       }
+       
+       // Kernel Libraries
+       for(pKBin = glLoadedKernelLibs;
+               pKBin;
+               prev = pKBin, pKBin = pKBin->Next)
+       {
+               // Check the base
+               if(pKBin->Base != Base) continue;
+               // Deallocate Memory
+               for(i = 0; i < pKBin->Info->NumSections; i++)
+               {
+                       // TODO: VFS_MUnmap();
+               }
+               // Dereference Binary
+               Binary_Dereference( pKBin->Info );
+               // Remove from list
+               if(prev)        prev->Next = pKBin->Next;
+               else            glLoadedKernelLibs = pKBin->Next;
+               // Free Kernel Lib
+               free(pKBin);
+               return;
+       }
+}
+
+/**
+ * \fn void Binary_Dereference(tBinary *Info)
+ * \brief Dereferences and if nessasary, deletes a binary
+ * \param Info Binary information structure
+ */
+void Binary_Dereference(tBinary *Info)
+{
+       // Decrement reference count
+       Info->ReferenceCount --;
+       
+       // Check if it is still in use
+       if(Info->ReferenceCount)        return;
+       
+       /// \todo Implement binary freeing
+}
+
+/**
+ * \fn char *Binary_RegInterp(char *Path)
+ * \brief Registers an Interpreter
+ * \param Path Path to interpreter provided by executable
+ */
+char *Binary_RegInterp(char *Path)
+{
+        int    i;
+       // NULL Check Argument
+       if(Path == NULL)        return NULL;
+       // NULL Check the array
+       if(gsaRegInterps == NULL)
+       {
+               giRegInterps = 1;
+               gsaRegInterps = malloc( sizeof(char*) );
+               gsaRegInterps[0] = malloc( strlen(Path) );
+               strcpy(gsaRegInterps[0], Path);
+               return gsaRegInterps[0];
+       }
+       
+       // Scan Array
+       for( i = 0; i < giRegInterps; i++ )
+       {
+               if(strcmp(gsaRegInterps[i], Path) == 0)
+                       return gsaRegInterps[i];
+       }
+       
+       // Interpreter is not in list
+       giRegInterps ++;
+       gsaRegInterps = malloc( sizeof(char*)*giRegInterps );
+       gsaRegInterps[i] = malloc( strlen(Path) );
+       strcpy(gsaRegInterps[i], Path);
+       return gsaRegInterps[i];
+}
+
+// ============
+// Kernel Binary Handling
+// ============
+/**
+ * \fn void *Binary_LoadKernel(const char *File)
+ * \brief Load a binary into kernel space
+ * \note This function shares much with #Binary_Load, but does it's own mapping
+ * \param File File to load into the kernel
+ */
+void *Binary_LoadKernel(const char *File)
+{
+       tBinary *pBinary;
+       tKernelBin      *pKBinary;
+       tVAddr  base = -1;
+       tMount  mount_id;
+       tInode  inode;
+
+       ENTER("sFile", File);
+       
+       // Sanity Check Argument
+       if(File == NULL) {
+               LEAVE('n');
+               return 0;
+       }
+
+       {
+               int fd = VFS_Open(File, VFS_OPENFLAG_READ);
+               tFInfo  info;
+               if(fd == -1) {
+                       LEAVE('n');
+                       return NULL;
+               }
+               VFS_FInfo(fd, &info, 0);
+               mount_id = info.mount;
+               inode = info.inode;
+               VFS_Close(fd);
+       }
+       
+       // Check if the binary has already been loaded
+       if( (pBinary = Binary_GetInfo(mount_id, inode)) )
+       {
+               for(pKBinary = glLoadedKernelLibs;
+                       pKBinary;
+                       pKBinary = pKBinary->Next )
+               {
+                       if(pKBinary->Info == pBinary) {
+                               LEAVE('p', pKBinary->Base);
+                               return pKBinary->Base;
+                       }
+               }
+       }
+       else
+               pBinary = Binary_DoLoad(mount_id, inode, File); // Else load it
+       
+       // Error Check
+       if(pBinary == NULL) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // --------------
+       // Now pBinary is valid (either freshly loaded or only user mapped)
+       // So, map it into kernel space
+       // --------------
+       
+       // Reference Executable (Makes sure that it isn't unloaded)
+       pBinary->ReferenceCount ++;
+
+       Binary_MapIn(pBinary, File, KLIB_LOWEST, KLIB_HIGHEST);
+
+       // Relocate Library
+       if( !Binary_Relocate( (void*)base ) )
+       {
+               Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
+               Binary_Unload( (void*)base );
+               Binary_Dereference( pBinary );
+               LEAVE('n');
+               return 0;
+       }
+       
+       // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)
+       pKBinary = malloc(sizeof(*pKBinary));
+       pKBinary->Base = (void*)base;
+       pKBinary->Info = pBinary;
+       SHORTLOCK( &glKBinListLock );
+       pKBinary->Next = glLoadedKernelLibs;
+       glLoadedKernelLibs = pKBinary;
+       SHORTREL( &glKBinListLock );
+       
+       LEAVE('p', base);
+       return (void*)base;
+}
+
+/**
+ * \fn Uint Binary_Relocate(void *Base)
+ * \brief Relocates a loaded binary (used by kernel libraries)
+ * \param Base Loaded base address of binary
+ * \return Boolean Success
+ */
+Uint Binary_Relocate(void *Base)
+{
+       Uint32  ident = *(Uint32*) Base;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) == (Uint)bt->Ident )
+                       return bt->Relocate( (void*)Base);
+       }
+       
+       Log_Warning("BIN", "%p is an unknown file type. (%02x %02x %02x %02x)",
+               Base, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);
+       return 0;
+}
+
+/**
+ * \fn int Binary_GetSymbol(char *Name, Uint *Val)
+ * \brief Get a symbol value
+ * \return Value of symbol or -1 on error
+ * 
+ * Gets the value of a symbol from either the currently loaded
+ * libraries or the kernel's exports.
+ */
+int Binary_GetSymbol(const char *Name, Uint *Val)
+{
+       if( Binary_GetSymbolEx(Name, Val) )     return 1;
+       return 0;
+}
+
+/**
+ * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)
+ * \brief Get a symbol value
+ * 
+ * Gets the value of a symbol from either the currently loaded
+ * libraries or the kernel's exports.
+ */
+Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
+{
+        int    i;
+       tKernelBin      *pKBin;
+        int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
+       
+       // Scan Kernel
+       for( i = 0; i < numKSyms; i++ )
+       {
+               if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
+                       *Value = gKernelSymbols[i].Value;
+                       return 1;
+               }
+       }
+       
+       // Scan Loaded Libraries
+       for(pKBin = glLoadedKernelLibs;
+               pKBin;
+               pKBin = pKBin->Next )
+       {
+               if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {
+                       return 1;
+               }
+       }
+       
+       Log_Warning("BIN", "Unable to find symbol '%s'", Name);
+       return 0;
+}
+
+/**
+ * \fn Uint Binary_FindSymbol(void *Base, char *Name, Uint *Val)
+ * \brief Get a symbol from the specified library
+ * \param Base Base address
+ * \param Name Name of symbol to find
+ * \param Val  Pointer to place final value
+ */
+Uint Binary_FindSymbol(void *Base, const char *Name, Uint *Val)
+{
+       Uint32  ident = *(Uint32*) Base;
+       tBinaryType     *bt = gRegBinTypes;
+       
+       for(; bt; bt = bt->Next)
+       {
+               if( (ident & bt->Mask) == (Uint)bt->Ident )
+                       return bt->GetSymbol(Base, Name, Val);
+       }
+       
+       Log_Warning("BIN", "Binary_FindSymbol - %p is an unknown file type. (%02x %02x %02x %02x)",
+               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);
+       return 0;
+}
+
+/**
+ * \brief Check if a range of memory is fully free
+ * \return Inverse boolean free (0 if all pages are unmapped)
+ */
+int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
+{
+       _len += _start & (PAGE_SIZE-1);
+       _len = (_len + PAGE_SIZE - 1) & ~(PAGE_SIZE-1);
+       _start &= ~(PAGE_SIZE-1);
+       for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
+               if( MM_GetPhysAddr(_start) != 0 )
+                       return 1;
+       }
+       if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 )
+               return 1;
+       return 0;
+}
+
+
+// === EXPORTS ===
+EXPORT(Binary_FindSymbol);
+EXPORT(Binary_Unload);
diff --git a/KernelLand/Kernel/debug.c b/KernelLand/Kernel/debug.c
new file mode 100644 (file)
index 0000000..355624d
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * AcessOS Microkernel Version
+ * debug.c
+ * 
+ * TODO: Move the Debug_putchar methods out to the arch/ tree
+ */
+#include <acess.h>
+#include <stdarg.h>
+
+#define        DEBUG_MAX_LINE_LEN      256
+
+#define        LOCK_DEBUG_OUTPUT       1
+
+#define TRACE_TO_KTERM 0
+
+// === IMPORTS ===
+extern void    Threads_Dump(void);
+extern void    KernelPanic_SetMode(void);
+extern void    KernelPanic_PutChar(char Ch);
+
+// === PROTOTYPES ===
+static void    Debug_Putchar(char ch);
+static void    Debug_Puts(int bUseKTerm, const char *Str);
+void   Debug_DbgOnlyFmt(const char *format, va_list args);
+void   Debug_FmtS(int bUseKTerm, const char *format, ...);
+void   Debug_Fmt(int bUseKTerm, const char *format, va_list args);
+void   Debug_SetKTerminal(const char *File);
+
+// === GLOBALS ===
+ int   gDebug_Level = 0;
+ int   giDebug_KTerm = -1;
+ int   gbDebug_IsKPanic = 0;
+volatile int   gbInPutChar = 0;
+#if LOCK_DEBUG_OUTPUT
+tShortSpinlock glDebug_Lock;
+#endif
+
+// === CODE ===
+static void Debug_Putchar(char ch)
+{
+       Debug_PutCharDebug(ch);
+       if( !gbDebug_IsKPanic )
+       {
+               if(gbInPutChar) return ;
+               gbInPutChar = 1;
+               if(giDebug_KTerm != -1)
+                       VFS_Write(giDebug_KTerm, 1, &ch);
+               gbInPutChar = 0;
+       }
+       else
+               KernelPanic_PutChar(ch);
+}
+
+static void Debug_Puts(int UseKTerm, const char *Str)
+{
+        int    len = 0;
+       
+       Debug_PutStringDebug(Str);
+       
+       if( gbDebug_IsKPanic )
+       {               
+               for( len = 0; Str[len]; len ++ )
+                       KernelPanic_PutChar( Str[len] );
+       }
+       else
+               for( len = 0; Str[len]; len ++ );
+       
+       // Output to the kernel terminal
+       if( UseKTerm && !gbDebug_IsKPanic && giDebug_KTerm != -1)
+       {
+               if(gbInPutChar) return ;
+               gbInPutChar = 1;
+               VFS_Write(giDebug_KTerm, len, Str);
+               gbInPutChar = 0;
+       }
+}
+
+void Debug_DbgOnlyFmt(const char *format, va_list args)
+{
+       Debug_Fmt(0, format, args);
+}
+
+void Debug_Fmt(int bUseKTerm, const char *format, va_list args)
+{
+       char    buf[DEBUG_MAX_LINE_LEN];
+        int    len;
+       buf[DEBUG_MAX_LINE_LEN-1] = 0;
+       len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
+       //if( len < DEBUG_MAX_LINE )
+               // do something
+       Debug_Puts(bUseKTerm, buf);
+       return ;
+}
+
+void Debug_FmtS(int bUseKTerm, const char *format, ...)
+{
+       va_list args;   
+       va_start(args, format);
+       Debug_Fmt(bUseKTerm, format, args);
+       va_end(args);
+}
+
+void Debug_KernelPanic(void)
+{
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+       gbDebug_IsKPanic = 1;
+       KernelPanic_SetMode();
+}
+
+/**
+ * \fn void LogF(const char *Msg, ...)
+ * \brief Raw debug log (no new line, no prefix)
+ */
+void LogF(const char *Fmt, ...)
+{
+       va_list args;
+
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+       
+       va_start(args, Fmt);
+
+       Debug_Fmt(1, Fmt, args);
+
+       va_end(args);
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+/**
+ * \fn void Debug(const char *Msg, ...)
+ * \brief Print only to the debug channel (not KTerm)
+ */
+void Debug(const char *Fmt, ...)
+{
+       va_list args;
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+
+       Debug_Puts(0, "Debug: ");
+       va_start(args, Fmt);
+       Debug_DbgOnlyFmt(Fmt, args);
+       va_end(args);
+       Debug_PutCharDebug('\r');
+       Debug_PutCharDebug('\n');
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+/**
+ * \fn void Log(const char *Msg, ...)
+ */
+void Log(const char *Fmt, ...)
+{
+       va_list args;
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+
+       Debug_Puts(1, "Log: ");
+       va_start(args, Fmt);
+       Debug_Fmt(1, Fmt, args);
+       va_end(args);
+       Debug_Puts(1, "\r\n");
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+void Warning(const char *Fmt, ...)
+{
+       va_list args;
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+       
+       Debug_Puts(1, "Warning: ");
+       va_start(args, Fmt);
+       Debug_Fmt(1, Fmt, args);
+       va_end(args);
+       Debug_Putchar('\r');
+       Debug_Putchar('\n');
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+void Panic(const char *Fmt, ...)
+{
+       va_list args;
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+       // And never SHORTREL
+       
+       Debug_KernelPanic();
+       
+       Debug_Puts(1, "Panic: ");
+       va_start(args, Fmt);
+       Debug_Fmt(1, Fmt, args);
+       va_end(args);
+       Debug_Putchar('\r');
+       Debug_Putchar('\n');
+
+       Threads_Dump();
+
+       for(;;) ;
+}
+
+void Debug_SetKTerminal(const char *File)
+{
+        int    tmp;
+       if(giDebug_KTerm != -1) {
+               tmp = giDebug_KTerm;
+               giDebug_KTerm = -1;
+               VFS_Close(tmp);
+       }
+       tmp = VFS_Open(File, VFS_OPENFLAG_WRITE);
+//     Log_Log("Debug", "Opened '%s' as 0x%x", File, tmp);
+       giDebug_KTerm = tmp;
+//     Log_Log("Debug", "Returning to %p", __builtin_return_address(0));
+}
+
+void Debug_Enter(const char *FuncName, const char *ArgTypes, ...)
+{
+       va_list args;
+        int    i;
+        int    pos;
+       tTID    tid = Threads_GetTID();
+        
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+
+       i = gDebug_Level ++;
+
+       va_start(args, ArgTypes);
+
+       Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
+       while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
+
+       Debug_Puts(TRACE_TO_KTERM, FuncName);
+       Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
+       Debug_Puts(TRACE_TO_KTERM, ": (");
+
+       while(*ArgTypes)
+       {
+               pos = strpos(ArgTypes, ' ');
+               if(pos == -1 || pos > 1) {
+                       if(pos == -1)
+                               Debug_Puts(TRACE_TO_KTERM, ArgTypes+1);
+                       else {
+                               Debug_FmtS(TRACE_TO_KTERM, "%.*s", pos-1, ArgTypes+1);
+                       }
+                       Debug_Puts(TRACE_TO_KTERM, "=");
+               }
+               switch(*ArgTypes)
+               {
+               case 'p':       Debug_FmtS(TRACE_TO_KTERM, "%p", va_arg(args, void*));  break;
+               case 'P':       Debug_FmtS(TRACE_TO_KTERM, "%P", va_arg(args, tPAddr)); break;
+               case 's':       Debug_FmtS(TRACE_TO_KTERM, "'%s'", va_arg(args, char*));        break;
+               case 'i':       Debug_FmtS(TRACE_TO_KTERM, "%i", va_arg(args, int));    break;
+               case 'u':       Debug_FmtS(TRACE_TO_KTERM, "%u", va_arg(args, Uint));   break;
+               case 'x':       Debug_FmtS(TRACE_TO_KTERM, "0x%x", va_arg(args, Uint)); break;
+               case 'b':       Debug_FmtS(TRACE_TO_KTERM, "0b%b", va_arg(args, Uint)); break;
+               case 'X':       Debug_FmtS(TRACE_TO_KTERM, "0x%llx", va_arg(args, Uint64));     break;  // Extended (64-Bit)
+               case 'B':       Debug_FmtS(TRACE_TO_KTERM, "0b%llb", va_arg(args, Uint64));     break;  // Extended (64-Bit)
+               }
+               if(pos != -1) {
+                       Debug_Puts(TRACE_TO_KTERM, ", ");
+               }
+
+               if(pos == -1)   break;
+               ArgTypes = &ArgTypes[pos+1];
+       }
+
+       va_end(args);
+       Debug_Puts(TRACE_TO_KTERM, ")\r\n");
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+
+void Debug_Log(const char *FuncName, const char *Fmt, ...)
+{
+       va_list args;
+        int    i = gDebug_Level;
+       tTID    tid = Threads_GetTID();
+
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+
+       Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
+       while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
+
+       Debug_Puts(TRACE_TO_KTERM, FuncName);
+       Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
+       Debug_Puts(TRACE_TO_KTERM, ": ");
+
+       va_start(args, Fmt);
+       Debug_Fmt(TRACE_TO_KTERM, Fmt, args);
+       va_end(args);
+
+       Debug_Puts(TRACE_TO_KTERM, "\r\n");
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+
+void Debug_Leave(const char *FuncName, char RetType, ...)
+{
+       va_list args;
+        int    i;
+       tTID    tid = Threads_GetTID();
+
+       #if LOCK_DEBUG_OUTPUT
+       SHORTLOCK(&glDebug_Lock);
+       #endif
+       
+       i = --gDebug_Level;
+
+       va_start(args, RetType);
+
+       if( i == -1 ) {
+               gDebug_Level = 0;
+               i = 0;
+       }
+       Debug_FmtS(TRACE_TO_KTERM, "%014lli ", now());
+       // Indenting
+       while(i--)      Debug_Puts(TRACE_TO_KTERM, " ");
+
+       Debug_Puts(TRACE_TO_KTERM, FuncName);
+       Debug_FmtS(TRACE_TO_KTERM, "[%i]", tid);
+       Debug_Puts(TRACE_TO_KTERM, ": RETURN");
+
+       // No Return
+       if(RetType == '-') {
+               Debug_Puts(TRACE_TO_KTERM, "\r\n");
+               #if LOCK_DEBUG_OUTPUT
+               SHORTREL(&glDebug_Lock);
+               #endif
+               return;
+       }
+
+       switch(RetType)
+       {
+       case 'n':       Debug_Puts(TRACE_TO_KTERM, " NULL");    break;
+       case 'p':       Debug_Fmt(TRACE_TO_KTERM, " %p", args); break;
+       case 'P':       Debug_Fmt(TRACE_TO_KTERM, " %P", args); break;  // PAddr
+       case 's':       Debug_Fmt(TRACE_TO_KTERM, " '%s'", args);       break;
+       case 'i':       Debug_Fmt(TRACE_TO_KTERM, " %i", args); break;
+       case 'u':       Debug_Fmt(TRACE_TO_KTERM, " %u", args); break;
+       case 'x':       Debug_Fmt(TRACE_TO_KTERM, " 0x%x", args);       break;
+       // Extended (64-Bit)
+       case 'X':       Debug_Fmt(TRACE_TO_KTERM, " 0x%llx", args);     break;
+       }
+       Debug_Puts(TRACE_TO_KTERM, "\r\n");
+
+       va_end(args);
+       
+       #if LOCK_DEBUG_OUTPUT
+       SHORTREL(&glDebug_Lock);
+       #endif
+}
+
+void Debug_HexDump(const char *Header, const void *Data, Uint Length)
+{
+       const Uint8     *cdat = Data;
+       Uint    pos = 0;
+       LogF("%014lli ", now());
+       Debug_Puts(1, Header);
+       LogF(" (Hexdump of %p)\r\n", Data);
+
+       #define CH(n)   ((' '<=cdat[(n)]&&cdat[(n)]<0x7F) ? cdat[(n)] : '.')
+
+       while(Length >= 16)
+       {
+               LogF("%014lli Log: %04x:"
+                       " %02x %02x %02x %02x %02x %02x %02x %02x"
+                       " %02x %02x %02x %02x %02x %02x %02x %02x"
+                       "  %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c\r\n",
+                       now(),
+                       pos,
+                       cdat[ 0], cdat[ 1], cdat[ 2], cdat[ 3], cdat[ 4], cdat[ 5], cdat[ 6], cdat[ 7],
+                       cdat[ 8], cdat[ 9], cdat[10], cdat[11], cdat[12], cdat[13], cdat[14], cdat[15],
+                       CH(0),  CH(1),  CH(2),  CH(3),  CH(4),  CH(5),  CH(6),  CH(7),
+                       CH(8),  CH(9),  CH(10), CH(11), CH(12), CH(13), CH(14), CH(15)
+                       );
+               Length -= 16;
+               cdat += 16;
+               pos += 16;
+       }
+
+       {
+                int    i ;
+               LogF("%014lli Log: %04x: ", now(), pos);
+               for(i = 0; i < Length; i ++)
+               {
+                       LogF("%02x ", cdat[i]);
+               }
+               for( ; i < 16; i ++)    LogF("   ");
+               LogF(" ");
+               for(i = 0; i < Length; i ++)
+               {
+                       if( i == 8 )    LogF(" ");
+                       LogF("%c", CH(i));
+               }
+       
+               Debug_Putchar('\r');
+               Debug_Putchar('\n');
+       }
+}
+
+// --- EXPORTS ---
+EXPORT(Debug);
+EXPORT(Log);
+EXPORT(Warning);
+EXPORT(Debug_Enter);
+EXPORT(Debug_Log);
+EXPORT(Debug_Leave);
diff --git a/KernelLand/Kernel/drv/Makefile b/KernelLand/Kernel/drv/Makefile
new file mode 100644 (file)
index 0000000..44f17cd
--- /dev/null
@@ -0,0 +1,20 @@
+# Acess2 Module/Driver Templater Makefile
+# Makefile.tpl
+
+-include ../../Makefile.cfg
+
+CPPFLAGS = -I../include -I../arch/$(ARCHDIR)/include -DARCH=$(ARCH) -DBUILD_MODULE
+CFLAGS = -Wall -Werror $(CPPFLAGS)
+
+.PHONY: all clean
+
+all: bochsvbe.kmd
+
+%.kmd: %.o
+       $(CC) -shared -nostdlib -o $@ $<
+
+%.o: %.c
+       $(CC) $(CFLAGS) -o $@ -c $<
+
+#ata_x86.kmd: ata_x86.o
+#bochsvbe.kmd: bochsvbe.o
diff --git a/KernelLand/Kernel/drv/fifo.c b/KernelLand/Kernel/drv/fifo.c
new file mode 100644 (file)
index 0000000..0779a60
--- /dev/null
@@ -0,0 +1,436 @@
+/* AcessOS
+ * FIFO Pipe Driver
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <semaphore.h>
+
+// === CONSTANTS ===
+#define DEFAULT_RING_SIZE      2048
+#define PF_BLOCKING            1
+
+// === TYPES ===
+typedef struct sPipe {
+       struct sPipe    *Next;
+       char    *Name;
+       tVFS_Node       Node;
+       Uint    Flags;
+        int    ReadPos;
+        int    WritePos;
+        int    BufSize;
+       char    *Buffer;
+} tPipe;
+
+// === PROTOTYPES ===
+ int   FIFO_Install(char **Arguments);
+ int   FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
+char   *FIFO_ReadDir(tVFS_Node *Node, int Id);
+tVFS_Node      *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
+ int   FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+void   FIFO_Reference(tVFS_Node *Node);
+void   FIFO_Close(tVFS_Node *Node);
+ int   FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+tPipe  *FIFO_Int_NewPipe(int Size, const char *Name);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
+tVFS_NodeType  gFIFO_DirNodeType = {
+       .TypeName = "FIFO Dir Node",
+       .ReadDir = FIFO_ReadDir,
+       .FindDir = FIFO_FindDir,
+       .MkNod = FIFO_MkNod,
+       .Relink = FIFO_Relink,
+       .IOCtl = FIFO_IOCtl
+};
+tVFS_NodeType  gFIFO_PipeNodeType = {
+       .TypeName = "FIFO Pipe Node",
+       .Read = FIFO_Read,
+       .Write = FIFO_Write,
+       .Close = FIFO_Close,
+       .Reference = FIFO_Reference
+};
+tDevFS_Driver  gFIFO_DriverInfo = {
+       NULL, "fifo",
+       {
+       .Size = 1,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Type = &gFIFO_DirNodeType
+       }
+};
+tVFS_Node      gFIFO_AnonNode = {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       };
+tPipe  *gFIFO_NamedPipes = NULL;
+
+// === CODE ===
+/**
+ * \fn int FIFO_Install(char **Options)
+ * \brief Installs the FIFO Driver
+ */
+int FIFO_Install(char **Options)
+{
+       DevFS_AddDevice( &gFIFO_DriverInfo );
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ */
+int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       return 0;
+}
+
+/**
+ * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
+ * \brief Reads from the FIFO root
+ */
+char *FIFO_ReadDir(tVFS_Node *Node, int Id)
+{
+       tPipe   *tmp = gFIFO_NamedPipes;
+       
+       // Entry 0 is Anon Pipes
+       if(Id == 0)     return strdup("anon");
+       
+       // Find the id'th node
+       while(--Id && tmp)      tmp = tmp->Next;
+       // If node found, return it
+       if(tmp) return strdup(tmp->Name);
+       // else error return
+       return NULL;
+}
+
+/**
+ * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
+ * \brief Find a file in the FIFO root
+ * \note Creates an anon pipe if anon is requested
+ */
+tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
+{
+       tPipe   *tmp;
+       if(!Filename)   return NULL;
+       
+       // NULL String Check
+       if(Filename[0] == '\0') return NULL;
+       
+       // Anon Pipe
+       if(Filename[0] == 'a' && Filename[1] == 'n'
+       && Filename[2] == 'o' && Filename[3] == 'n'
+       && Filename[4] == '\0') {
+               tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
+               return &tmp->Node;
+       }
+       
+       // Check Named List
+       tmp = gFIFO_NamedPipes;
+       while(tmp)
+       {
+               if(strcmp(tmp->Name, Filename) == 0)
+                       return &tmp->Node;
+               tmp = tmp->Next;
+       }
+       return NULL;
+}
+
+/**
+ * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+ */
+int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+       return 0;
+}
+
+void FIFO_Reference(tVFS_Node *Node)
+{
+       if(!Node->ImplPtr)      return ;
+       
+       Node->ReferenceCount ++;
+}
+
+/**
+ * \fn void FIFO_Close(tVFS_Node *Node)
+ * \brief Close a FIFO end
+ */
+void FIFO_Close(tVFS_Node *Node)
+{
+       tPipe   *pipe;
+       if(!Node->ImplPtr)      return ;
+       
+       Node->ReferenceCount --;
+       if(Node->ReferenceCount)        return ;
+       
+       pipe = Node->ImplPtr;
+       
+       if(strcmp(pipe->Name, "anon") == 0) {
+               Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr);
+               free(Node->ImplPtr);
+               return ;
+       }
+       
+       return ;
+}
+
+/**
+ * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+ * \brief Relink a file (Deletes named pipes)
+ */
+int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+{
+       tPipe   *pipe, *tmp;
+       
+       if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
+       
+       // Can't relink anon
+       if(strcmp(OldName, "anon"))     return 0;
+       
+       // Find node
+       for(pipe = gFIFO_NamedPipes;
+               pipe;
+               pipe = pipe->Next)
+       {
+               if(strcmp(pipe->Name, OldName) == 0)
+                       break;
+       }
+       if(!pipe)       return 0;
+       
+       // Relink a named pipe
+       if(NewName) {
+               // Check new name
+               for(tmp = gFIFO_NamedPipes;
+                       tmp;
+                       tmp = tmp->Next)
+               {
+                       if(strcmp(tmp->Name, NewName) == 0)     return 0;
+               }
+               // Create new name
+               free(pipe->Name);
+               pipe->Name = malloc(strlen(NewName)+1);
+               strcpy(pipe->Name, NewName);
+               return 1;
+       }
+       
+       // Unlink the pipe
+       if(Node->ImplPtr) {
+               free(Node->ImplPtr);
+               return 1;
+       }
+       
+       return 0;
+}
+
+/**
+ * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a fifo pipe
+ */
+Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tPipe   *pipe = Node->ImplPtr;
+       Uint    len;
+       Uint    remaining = Length;
+
+       if(!pipe)       return 0;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       while(remaining)
+       {
+               // Wait for buffer to fill
+               if(pipe->Flags & PF_BLOCKING)
+               {
+                       if( pipe->ReadPos == pipe->WritePos )
+                               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
+                       
+               }
+               else
+               {
+                       if(pipe->ReadPos == pipe->WritePos)
+                       {
+                               VFS_MarkAvaliable(Node, 0);
+                               LEAVE('i', 0);
+                               return 0;
+                       }
+               }
+       
+               len = remaining;
+               if( pipe->ReadPos < pipe->WritePos )
+               {
+                        int    avail_bytes = pipe->WritePos - pipe->ReadPos;
+                       if( avail_bytes < remaining )   len = avail_bytes;
+               }
+               else
+               {
+                        int    avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
+                       if( avail_bytes < remaining )   len = avail_bytes;
+               }
+
+               LOG("len = %i, remaining = %i", len, remaining);                
+
+               // Check if read overflows buffer
+               if(len > pipe->BufSize - pipe->ReadPos)
+               {
+                       int ofs = pipe->BufSize - pipe->ReadPos;
+                       memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
+                       memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
+               }
+               else
+               {
+                       memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
+               }
+               
+               // Increment read position
+               pipe->ReadPos += len;
+               pipe->ReadPos %= pipe->BufSize;
+               
+               // Mark some flags
+               if( pipe->ReadPos == pipe->WritePos ) {
+                       VFS_MarkAvaliable(Node, 0);
+               }
+               VFS_MarkFull(Node, 0);  // Buffer can't still be full
+               
+               // Decrement Remaining Bytes
+               remaining -= len;
+               // Increment Buffer address
+               Buffer = (Uint8*)Buffer + len;
+               
+               // TODO: Option to read differently
+               LEAVE('i', len);
+               return len;
+       }
+
+       LEAVE('i', Length);
+       return Length;
+
+}
+
+/**
+ * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a fifo pipe
+ */
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tPipe   *pipe = Node->ImplPtr;
+       Uint    len;
+       Uint    remaining = Length;
+       
+       if(!pipe)       return 0;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       while(remaining)
+       {
+               // Wait for buffer to empty
+               if(pipe->Flags & PF_BLOCKING) {
+                       if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
+                               VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
+
+                       len = remaining;
+                       if( pipe->ReadPos > pipe->WritePos )
+                       {
+                                int    rem_space = pipe->ReadPos - pipe->WritePos;
+                               if(rem_space < remaining)       len = rem_space;
+                       }
+                       else
+                       {
+                                int    rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
+                               if(rem_space < remaining)       len = rem_space;
+                       }
+               }
+               else
+               {
+                       if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
+                       {
+                               LEAVE('i', 0);
+                               return 0;
+                       }
+                       // Write buffer
+                       if(pipe->ReadPos - pipe->WritePos < remaining)
+                               len = pipe->ReadPos - pipe->WritePos;
+                       else
+                               len = remaining;
+               }
+               
+               // Check if write overflows buffer
+               if(len > pipe->BufSize - pipe->WritePos)
+               {
+                       int ofs = pipe->BufSize - pipe->WritePos;
+                       memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
+                       memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
+               }
+               else
+               {
+                       memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
+               }
+               
+               // Increment read position
+               pipe->WritePos += len;
+               pipe->WritePos %= pipe->BufSize;
+               
+               // Mark some flags
+               if( pipe->ReadPos == pipe->WritePos ) {
+                       VFS_MarkFull(Node, 1);  // Buffer full
+               }
+               VFS_MarkAvaliable(Node, 1);
+               
+               // Decrement Remaining Bytes
+               remaining -= len;
+               // Increment Buffer address
+               Buffer = (Uint8*)Buffer + len;
+       }
+
+       LEAVE('i', Length);
+       return Length;
+}
+
+// --- HELPERS ---
+/**
+ * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
+ * \brief Create a new pipe
+ */
+tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
+{
+       tPipe   *ret;
+        int    namelen = strlen(Name) + 1;
+        int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
+       
+       ret = calloc(1, allocsize);
+       if(!ret)        return NULL;
+       
+       // Clear Return
+       ret->Flags = PF_BLOCKING;
+       
+       // Allocate Buffer
+       ret->BufSize = Size;
+       ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
+       
+       // Set name (and FIFO name)
+       ret->Name = ret->Buffer + Size;
+       strcpy(ret->Name, Name);
+       // - Start empty, max of `Size`
+       //Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
+       
+       // Set Node
+       ret->Node.ReferenceCount = 1;
+       ret->Node.Size = 0;
+       ret->Node.ImplPtr = ret;
+       ret->Node.UID = Threads_GetUID();
+       ret->Node.GID = Threads_GetGID();
+       ret->Node.NumACLs = 1;
+       ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
+               ret->Node.ACLs->Group = 0;
+               ret->Node.ACLs->ID = ret->Node.UID;
+               ret->Node.ACLs->Inv = 0;
+               ret->Node.ACLs->Perms = -1;
+       ret->Node.CTime
+               = ret->Node.MTime
+               = ret->Node.ATime = now();
+       ret->Node.Type = &gFIFO_PipeNodeType;
+       
+       return ret;
+}
diff --git a/KernelLand/Kernel/drv/iocache.c b/KernelLand/Kernel/drv/iocache.c
new file mode 100644 (file)
index 0000000..8f73541
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Acess2 Kernel
+ * - IO Cache
+ * 
+ * By thePowersGang (John Hodge)
+ * 
+ * TODO: Convert to use spare physical pages instead
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <iocache.h>
+
+// === TYPES ===
+typedef struct sIOCache_Ent    tIOCache_Ent;
+typedef struct sIOCache_PageInfo       tIOCache_PageInfo;
+
+// === STRUCTURES ===
+struct sIOCache_Ent
+{
+       tIOCache_Ent    *Next;
+       Uint64  Num;
+       Sint64  LastAccess;
+       Sint64  LastWrite;
+       Uint8   Data[];
+};
+
+struct sIOCache_PageInfo
+{
+       tIOCache_PageInfo       *GlobalNext;
+       tIOCache_PageInfo       *CacheNext;
+       tIOCache        *Owner;
+       tPAddr  BasePhys;
+       Uint64  BaseOffset;
+};
+
+struct sIOCache
+{
+       tIOCache        *Next;
+        int    SectorSize;
+       tMutex  Lock;
+        int    Mode;
+       Uint32  ID;
+       tIOCache_WriteCallback  Write;
+        int    CacheSize;
+        int    CacheUsed;
+       tIOCache_Ent    *Entries;
+};
+
+// === GLOBALS ===
+tShortSpinlock glIOCache_Caches;
+tIOCache       *gIOCache_Caches = NULL;
+ int   giIOCache_NumCaches = 0;
+tIOCache_PageInfo      *gIOCache_GlobalPages;
+
+// === CODE ===
+/**
+ * \fn tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
+ * \brief Creates a new IO Cache
+ */
+tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
+{
+       tIOCache        *ret = calloc( 1, sizeof(tIOCache) );
+       
+       // Sanity Check
+       if(!ret)        return NULL;
+       
+       // Fill Structure
+       ret->SectorSize = SectorSize;
+       ret->Mode = IOCACHE_WRITEBACK;
+       ret->ID = ID;
+       ret->Write = Write;
+       ret->CacheSize = CacheSize;
+       
+       // Append to list
+       SHORTLOCK( &glIOCache_Caches );
+       ret->Next = gIOCache_Caches;
+       gIOCache_Caches = ret;
+       SHORTREL( &glIOCache_Caches );
+       
+       // Return
+       return ret;
+}
+
+/**
+ * \fn int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
+ * \brief Read from a cached sector
+ */
+int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
+{
+       
+       ENTER("pCache XSector pBuffer", Cache, Sector, Buffer);
+       
+       // Sanity Check!
+       if(!Cache || !Buffer) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       // Lock
+       Mutex_Acquire( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               Mutex_Release( &Cache->Lock );
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       #if IOCACHE_USE_PAGES
+       tIOCache_PageInfo       *page;
+       size_t  offset = (Sector*Cache->SectorSize) % PAGE_SIZE;
+       Uint64  wanted_base = (Sector*Cache->SectorSize) & ~(PAGE_SIZE-1);
+       for( page = Cache->Pages; page; page = page->CacheNext )
+       {
+               void    *tmp;
+               if(page->BaseOffset < WantedBase)       continue;
+               if(page->BaseOffset > WantedBase)       break;
+               tmp = MM_MapTemp( page->BasePhys );
+               memcpy( Buffer, tmp + offset, Cache->SectorSize ); 
+               MM_FreeTemp( tmp );
+       }
+       #else   
+       tIOCache_Ent    *ent;
+       // Search the list
+       for( ent = Cache->Entries; ent; ent = ent->Next )
+       {
+               // Have we found what we are looking for?
+               if( ent->Num == Sector ) {
+                       memcpy(Buffer, ent->Data, Cache->SectorSize);
+                       ent->LastAccess = now();
+                       Mutex_Release( &Cache->Lock );
+                       LEAVE('i', 1);
+                       return 1;
+               }
+               // It's a sorted list, so as soon as we go past `Sector` we know
+               // it's not there
+               if(ent->Num > Sector)   break;
+       }
+       #endif
+       
+       Mutex_Release( &Cache->Lock );
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
+ * \brief Cache a sector
+ */
+int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
+{
+       tIOCache_Ent    *ent, *prev;
+       tIOCache_Ent    *new;
+       tIOCache_Ent    *oldest = NULL, *oldestPrev;
+       
+       // Sanity Check!
+       if(!Cache || !Buffer)
+               return -1;
+       
+       // Lock
+       Mutex_Acquire( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               Mutex_Release( &Cache->Lock );
+               return -1;
+       }
+       
+       // Search the list
+       prev = (tIOCache_Ent*)&Cache->Entries;
+       for( ent = Cache->Entries; ent; prev = ent, ent = ent->Next )
+       {
+               // Is it already here?
+               if( ent->Num == Sector ) {
+                       Mutex_Release( &Cache->Lock );
+                       return 0;
+               }
+               
+               // Check if we have found the oldest entry
+               if( !oldest || oldest->LastAccess > ent->LastAccess ) {
+                       oldest = ent;
+                       oldestPrev = prev;
+               }
+               
+               // Here we go!
+               if(ent->Num > Sector)
+                       break;
+       }
+       
+       // Create the new entry
+       new = malloc( sizeof(tIOCache_Ent) + Cache->SectorSize );
+       new->Next = ent;
+       new->Num = Sector;
+       new->LastAccess = now();
+       new->LastWrite = 0;     // Zero is special, it means unmodified
+       memcpy(new->Data, Buffer, Cache->SectorSize);
+       
+       // Have we reached the maximum cached entries?
+       if( Cache->CacheUsed == Cache->CacheSize )
+       {
+               tIOCache_Ent    *savedPrev = prev;
+               oldestPrev = (tIOCache_Ent*)&Cache->Entries;
+               // If so, search for the least recently accessed entry
+               for( ; ent; prev = ent, ent = ent->Next )
+               {       
+                       // Check if we have found the oldest entry
+                       if( !oldest || oldest->LastAccess > ent->LastAccess ) {
+                               oldest = ent;
+                               oldestPrev = prev;
+                       }
+               }
+               if( !oldest ) {
+                       Log_Error("IOCache", "Cache full, but also empty");
+                       return -1;
+               }
+               // Remove from list, write back and free
+               oldestPrev->Next = oldest->Next;
+               if(oldest->LastWrite && Cache->Mode != IOCACHE_VIRTUAL)
+                       Cache->Write(Cache->ID, oldest->Num, oldest->Data);
+               free(oldest);
+               
+               // Decrement the used count
+               Cache->CacheUsed --;
+               
+               // Restore `prev`
+               prev = savedPrev;
+       }
+       
+       // Append to list
+       prev->Next = new;
+       Cache->CacheUsed ++;
+       
+       // Release Spinlock
+       Mutex_Release( &Cache->Lock );
+       
+       // Return success
+       return 1;
+}
+
+/**
+ * \fn int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
+ * \brief Read from a cached sector
+ */
+int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
+{
+       tIOCache_Ent    *ent;
+       
+       // Sanity Check!
+       if(!Cache || !Buffer)
+               return -1;
+       // Lock
+       Mutex_Acquire( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               Mutex_Release( &Cache->Lock );
+               return -1;
+       }
+       
+       // Search the list
+       for( ent = Cache->Entries; ent; ent = ent->Next )
+       {
+               // Have we found what we are looking for?
+               if( ent->Num == Sector ) {
+                       memcpy(ent->Data, Buffer, Cache->SectorSize);
+                       ent->LastAccess = ent->LastWrite = now();
+                       
+                       if(Cache->Mode == IOCACHE_WRITEBACK) {
+                               Cache->Write(Cache->ID, Sector, Buffer);
+                               ent->LastWrite = 0;
+                       }
+                       
+                       Mutex_Release( &Cache->Lock );
+                       return 1;
+               }
+               // It's a sorted list, so as soon as we go past `Sector` we know
+               // it's not there
+               if(ent->Num > Sector)   break;
+       }
+       
+       Mutex_Release( &Cache->Lock );
+       return 0;
+}
+
+/**
+ * \fn void IOCache_Flush( tIOCache *Cache )
+ * \brief Flush a cache
+ */
+void IOCache_Flush( tIOCache *Cache )
+{
+       tIOCache_Ent    *ent;
+       
+       if( Cache->Mode == IOCACHE_VIRTUAL )    return;
+       
+       // Lock
+       Mutex_Acquire( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               Mutex_Release( &Cache->Lock );
+               return;
+       }
+       
+       // Write All
+       for( ent = Cache->Entries; ent; ent = ent->Next )
+       {
+               Cache->Write(Cache->ID, ent->Num, ent->Data);
+               ent->LastWrite = 0;
+       }
+       
+       Mutex_Release( &Cache->Lock );
+}
+
+/**
+ * \fn void IOCache_Destroy( tIOCache *Cache )
+ * \brief Destroy a cache
+ */
+void IOCache_Destroy( tIOCache *Cache )
+{
+       tIOCache_Ent    *ent, *prev = NULL;
+       
+       // Lock
+       Mutex_Acquire( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               Mutex_Release( &Cache->Lock );
+               return;
+       }
+       
+       // Free All
+       for(ent = Cache->Entries;
+               ent;
+               prev = ent, ent = ent->Next, free(prev) )
+       {
+               if( Cache->Mode != IOCACHE_VIRTUAL )
+               {
+                       Cache->Write(Cache->ID, ent->Num, ent->Data);
+                       ent->LastWrite = 0;
+               }
+       }
+       
+       Cache->CacheSize = 0;
+       
+       Mutex_Release( &Cache->Lock );
+       
+       // Remove from list
+       SHORTLOCK( &glIOCache_Caches );
+       {
+               tIOCache        *cache;
+               tIOCache        *prev_cache = (tIOCache*)&gIOCache_Caches;
+               for(cache = gIOCache_Caches;
+                       cache;
+                       prev_cache = cache, cache = cache->Next )
+               {
+                       if(cache == Cache) {
+                               prev_cache->Next = cache->Next;
+                               break;
+                       }
+               }
+       }
+       SHORTREL( &glIOCache_Caches );
+       
+       free(Cache);
+}
diff --git a/KernelLand/Kernel/drv/pci.c b/KernelLand/Kernel/drv/pci.c
new file mode 100644 (file)
index 0000000..8745080
--- /dev/null
@@ -0,0 +1,500 @@
+/*\r
+ * AcessOS/AcessBasic v0.1\r
+ * PCI Bus Driver\r
+ */\r
+#define DEBUG  0\r
+#include <acess.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <drv_pci_int.h>\r
+\r
+#define        LIST_DEVICES    1\r
+\r
+// === STRUCTURES ===\r
+typedef struct sPCIDevice\r
+{\r
+       Uint16  bus, slot, fcn;\r
+       Uint16  vendor, device;\r
+       Uint32  class;  // Class:Subclass:ProgIf\r
+       Uint8   revision;\r
+       Uint32  ConfigCache[256/4];\r
+       char    Name[8];\r
+       tVFS_Node       Node;\r
+} tPCIDevice;\r
+\r
+// === CONSTANTS ===\r
+#define SPACE_STEP     5\r
+#define MAX_RESERVED_PORT      0xD00\r
+\r
+// === PROTOTYPES ===\r
+ int   PCI_Install(char **Arguments);\r
+ int   PCI_ScanBus(int ID, int bFill);\r
\r
+char   *PCI_int_ReadDirRoot(tVFS_Node *node, int pos);\r
+tVFS_Node      *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename);\r
+Uint32 PCI_int_GetBusAddr(Uint16 Bus, Uint16 Slot, Uint16 Fcn, Uint8 Offset);\r
+Uint64 PCI_int_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);\r
+ int   PCI_int_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
+ int   giPCI_BusCount = 1;\r
+ int   giPCI_InodeHandle = -1;\r
+ int   giPCI_DeviceCount = 0;\r
+tPCIDevice     *gPCI_Devices = NULL;\r
+tVFS_NodeType  gPCI_RootNodeType = {\r
+       .TypeName = "PCI Root Node",\r
+       .ReadDir = PCI_int_ReadDirRoot,\r
+       .FindDir = PCI_int_FindDirRoot\r
+};\r
+tVFS_NodeType  gPCI_DevNodeType = {\r
+       .TypeName = "PCI Dev Node",\r
+       .Read = PCI_int_ReadDevice\r
+};\r
+tDevFS_Driver  gPCI_DriverStruct = {\r
+       NULL, "pci",\r
+       {\r
+       .Flags = VFS_FFLAG_DIRECTORY,\r
+       .Size = -1,\r
+       .NumACLs = 1,\r
+       .ACLs = &gVFS_ACL_EveryoneRX,\r
+       .Type = &gPCI_RootNodeType\r
+       }\r
+};\r
+Uint32 *gaPCI_PortBitmap = NULL;\r
+Uint32 gaPCI_BusBitmap[256/32];\r
\r
+// === CODE ===\r
+/**\r
+ * \brief Scan the PCI Bus for devices\r
+ * \param Arguments    Boot-time parameters\r
+ */\r
+int PCI_Install(char **Arguments)\r
+{\r
+        int    i;\r
+       void    *tmpPtr;\r
+       \r
+       // Build Portmap\r
+       gaPCI_PortBitmap = malloc( 1 << 13 );\r
+       if( !gaPCI_PortBitmap ) {\r
+               Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);\r
+               return MODULE_ERR_MALLOC;\r
+       }\r
+       memset( gaPCI_PortBitmap, 0, 1 << 13 );\r
+       for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )\r
+               gaPCI_PortBitmap[i] = -1;\r
+       for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
+               gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
+       \r
+       // Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
+       i = PCI_ScanBus(0, 0);\r
+       if(i != MODULE_ERR_OK)  return i;\r
+               \r
+       if(giPCI_DeviceCount == 0) {\r
+               Log_Notice("PCI", "No devices were found");\r
+               return MODULE_ERR_NOTNEEDED;\r
+       }\r
+       \r
+       // Allocate device buffer\r
+       tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));\r
+       if(tmpPtr == NULL) {\r
+               Log_Warning("PCI", "Malloc ERROR");\r
+               return MODULE_ERR_MALLOC;\r
+       }\r
+       gPCI_Devices = tmpPtr;\r
+       \r
+       Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);\r
+       \r
+       // Reset counts\r
+       giPCI_DeviceCount = 0;\r
+       giPCI_BusCount = 0;\r
+       memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));\r
+       // Rescan, filling the PCI device array\r
+       PCI_ScanBus(0, 1);\r
+       \r
+       // Complete Driver Structure\r
+       gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;\r
+       \r
+       // And add to DevFS\r
+       DevFS_AddDevice(&gPCI_DriverStruct);\r
+       \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \brief Scans a specific PCI Bus\r
+ * \param BusID        PCI Bus ID to scan\r
+ * \param bFill        Fill the \a gPCI_Devices array?\r
+ */\r
+int PCI_ScanBus(int BusID, int bFill)\r
+{\r
+        int    dev, fcn;\r
+       tPCIDevice      devInfo;\r
+       \r
+       if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )\r
+               return MODULE_ERR_OK;\r
+       \r
+       gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));\r
+       \r
+       for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus\r
+       {\r
+               for( fcn = 0; fcn < 8; fcn++ )  // Max 8 functions per device\r
+               {\r
+                       // Check if the device/function exists\r
+                       if(!PCI_int_EnumDevice(BusID, dev, fcn, &devInfo))\r
+                               continue;\r
+                       \r
+                       if(devInfo.class == PCI_OC_PCIBRIDGE)\r
+                       {\r
+                               #if LIST_DEVICES\r
+                               if( !bFill )\r
+                                       Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
+                                               BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
+                               #endif\r
+                               //TODO: Handle PCI-PCI Bridges\r
+                               //PCI_ScanBus(devInfo.???, bFill);\r
+                               giPCI_BusCount ++;\r
+                       }\r
+                       else\r
+                       {\r
+                               #if LIST_DEVICES\r
+                               if( !bFill )\r
+                                       Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x",\r
+                                               BusID, dev, fcn, devInfo.class, devInfo.vendor, devInfo.device);\r
+                               #endif\r
+                       }\r
+                       \r
+                       if( bFill ) {\r
+                               devInfo.Node.Inode = giPCI_DeviceCount;\r
+                               memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));\r
+                       }\r
+                       giPCI_DeviceCount ++;\r
+                       \r
+                       // If bit 23 of (soemthing) is set, there are sub-functions\r
+                       if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )\r
+                               break;\r
+               }\r
+       }\r
+       \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \brief Read from Root of PCI Driver\r
+*/\r
+char *PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos)\r
+{\r
+       ENTER("pNode iPos", Node, Pos);\r
+       if(Pos < 0 || Pos >= giPCI_DeviceCount) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       LEAVE('s', gPCI_Devices[Pos].Name);\r
+       return strdup( gPCI_Devices[Pos].Name );\r
+}\r
+/**\r
+ */\r
+tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename)\r
+{\r
+        int    bus,slot,fcn;\r
+        int    i;\r
+       // Validate Filename (Pointer and length)\r
+       if(!filename || strlen(filename) != 7)\r
+               return NULL;\r
+       // Check for spacers\r
+       if(filename[2] != '.' || filename[5] != ':')\r
+               return NULL;\r
+       \r
+       // Get Information\r
+       if(filename[0] < '0' || filename[0] > '9')      return NULL;\r
+       bus = (filename[0] - '0')*10;\r
+       if(filename[1] < '0' || filename[1] > '9')      return NULL;\r
+       bus += filename[1] - '0';\r
+       if(filename[3] < '0' || filename[3] > '9')      return NULL;\r
+       slot = (filename[3] - '0')*10;\r
+       if(filename[4] < '0' || filename[4] > '9')      return NULL;\r
+       slot += filename[4] - '0';\r
+       if(filename[6] < '0' || filename[6] > '9')      return NULL;\r
+       fcn = filename[6] - '0';\r
+       \r
+       // Find Match\r
+       for(i=0;i<giPCI_DeviceCount;i++)\r
+       {\r
+               if(gPCI_Devices[i].bus != bus)          continue;\r
+               if(gPCI_Devices[i].slot != slot)        continue;\r
+               if(gPCI_Devices[i].fcn != fcn)  continue;\r
+               \r
+               return &gPCI_Devices[i].Node;\r
+       }\r
+       \r
+       // Error Return\r
+       return NULL;\r
+}\r
+\r
+/**\r
+ */\r
+Uint64 PCI_int_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
+{      \r
+       if( pos + length > 256 )        return 0;\r
+       \r
+       memcpy(\r
+               buffer,\r
+               (char*)gPCI_Devices[node->Inode].ConfigCache + pos,\r
+               length);\r
+       \r
+       return length;\r
+}\r
+\r
+// --- Kernel Code Interface ---\r
+/**\r
+ * \brief Counts the devices with the specified codes\r
+ * \param vendor       Vendor ID\r
+ * \param device       Device ID\r
+ */\r
+int PCI_CountDevices(Uint16 vendor, Uint16 device)\r
+{\r
+       int i, ret=0;\r
+       for(i=0;i<giPCI_DeviceCount;i++)\r
+       {\r
+               if(gPCI_Devices[i].vendor != vendor)    continue;\r
+               if(gPCI_Devices[i].device != device)    continue;\r
+               ret ++;\r
+       }\r
+       return ret;\r
+}\r
+\r
+/**\r
+ * \brief Gets the ID of the specified PCI device\r
+ * \param vendor       Vendor ID\r
+ * \param device       Device ID\r
+ * \param idx  Number of matching entry wanted\r
+ */\r
+tPCIDev PCI_GetDevice(Uint16 vendor, Uint16 device, int idx)\r
+{\r
+        int    i, j=0;\r
+       for( i = 0; i < giPCI_DeviceCount; i ++ )\r
+       {\r
+               if(gPCI_Devices[i].vendor != vendor)    continue;\r
+               if(gPCI_Devices[i].device != device)    continue;\r
+               if(j == idx)    return i;\r
+               j ++;\r
+       }\r
+       return -1;\r
+}\r
+\r
+/**\r
+ * \brief Gets the ID of a device by it's class code\r
+ * \param class        Class Code\r
+ * \param mask Mask for class comparison\r
+ * \param prev ID of previous device (-1 for no previous)\r
+ */\r
+tPCIDev PCI_GetDeviceByClass(Uint32 class, Uint32 mask, tPCIDev prev)\r
+{\r
+        int    i;\r
+       // Check if prev is negative (meaning get first)\r
+       if(prev < 0)    i = 0;\r
+       else    i = prev+1;\r
+       \r
+       for( ; i < giPCI_DeviceCount; i++ )\r
+       {\r
+               if((gPCI_Devices[i].class & mask) == class)\r
+                       return i;\r
+       }\r
+       return -1;\r
+}\r
+\r
+int PCI_GetDeviceInfo(tPCIDev ID, Uint16 *Vendor, Uint16 *Device, Uint32 *Class)\r
+{\r
+       tPCIDevice      *dev = &gPCI_Devices[ID];\r
+       if(ID < 0 || ID >= giPCI_DeviceCount)   return 1;\r
+       \r
+       if(Vendor)      *Vendor = dev->vendor;\r
+       if(Device)      *Device = dev->device;\r
+       if(Class)       *Class = dev->class;\r
+       return 0;\r
+}\r
+\r
+int PCI_GetDeviceVersion(tPCIDev ID, Uint8 *Revision)\r
+{\r
+       tPCIDevice      *dev = &gPCI_Devices[ID];\r
+       if(ID < 0 || ID >= giPCI_DeviceCount)   return 1;\r
+       \r
+       if(Revision)    *Revision = dev->revision;\r
+       return 0;\r
+}\r
+\r
+int PCI_GetDeviceSubsys(tPCIDev ID, Uint16 *SubsystemVendor, Uint16 *SubsystemID)\r
+{\r
+       tPCIDevice      *dev = &gPCI_Devices[ID];\r
+       if(ID < 0 || ID >= giPCI_DeviceCount)   return 1;\r
+       \r
+       if(SubsystemVendor)     *SubsystemVendor = dev->ConfigCache[0x2c/4] & 0xFFFF;\r
+       if(SubsystemID) *SubsystemID = dev->ConfigCache[0x2c/4] >> 16;\r
+\r
+       return 0;\r
+}\r
+\r
+Uint32 PCI_int_GetBusAddr(Uint16 Bus, Uint16 Slot, Uint16 Fcn, Uint8 Offset)\r
+{\r
+       Bus &= 0xFF;\r
+       Slot &= 0x1F;\r
+       Fcn &= 7;\r
+       Offset &= 0xFC;\r
+       return ((Uint32)Bus << 16) | (Slot << 11) | (Fcn << 8) | (Offset & 0xFC);\r
+}\r
+\r
+Uint32 PCI_ConfigRead(tPCIDev ID, int Offset, int Size)\r
+{\r
+       tPCIDevice      *dev;\r
+       Uint32  dword, addr;\r
+       \r
+       if( ID < 0 || ID >= giPCI_DeviceCount ) return 0;\r
+       if( Offset < 0 || Offset > 256 )        return 0;\r
+\r
+       // TODO: Should I support non-aligned reads?\r
+       if( Offset & (Size - 1) )       return 0;\r
+\r
+       dev = &gPCI_Devices[ID];\r
+       addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
+\r
+       dword = PCI_CfgReadDWord(addr);\r
+       gPCI_Devices[ID].ConfigCache[Offset/4] = dword;\r
+       switch( Size )\r
+       {\r
+       case 1: return (dword >> (8 * (Offset&3))) & 0xFF;\r
+       case 2: return (dword >> (8 * (Offset&2))) & 0xFFFF;\r
+       case 4: return dword;\r
+       default:\r
+               return 0;\r
+       }\r
+}\r
+\r
+void PCI_ConfigWrite(tPCIDev ID, int Offset, int Size, Uint32 Value)\r
+{\r
+       tPCIDevice      *dev;\r
+       Uint32  dword, addr;\r
+        int    shift;\r
+       if( ID < 0 || ID >= giPCI_DeviceCount ) return ;\r
+       if( Offset < 0 || Offset > 256 )        return ;\r
+       \r
+       dev = &gPCI_Devices[ID];\r
+       addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
+\r
+       if(Size != 4)\r
+               dword = PCI_CfgReadDWord(addr);\r
+       switch(Size)\r
+       {\r
+       case 1:\r
+               shift = (Offset&3)*8;\r
+               dword &= ~(0xFF << shift);\r
+               dword |= Value << shift;\r
+               break;\r
+       case 2:\r
+               shift = (Offset&2)*8;\r
+               dword &= ~(0xFFFF << shift);\r
+               dword |= Value << shift;\r
+               break;\r
+       case 4:\r
+               dword = Value;\r
+               break;\r
+       default:\r
+               return;\r
+       }\r
+       PCI_CfgWriteDWord(addr, dword);\r
+}\r
+\r
+/**\r
+ * \brief Get the IRQ assigned to a device\r
+ */\r
+Uint8 PCI_GetIRQ(tPCIDev id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[15] & 0xFF;\r
+       //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);\r
+}\r
+\r
+/**\r
+ * \brief Read the a BAR (base address register) from the PCI config space\r
+ */\r
+Uint32 PCI_GetBAR(tPCIDev id, int BARNum)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       if(BARNum < 0 || BARNum >= 6)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[4+BARNum];\r
+}\r
+\r
+/**\r
+ * \brief Get device information for a slot/function\r
+ */\r
+int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
+{\r
+       Uint32  vendor_dev, tmp;\r
+        int    i;\r
+       Uint32  addr;\r
+       addr = PCI_int_GetBusAddr(bus, slot, fcn, 0);   \r
+\r
+       vendor_dev = PCI_CfgReadDWord( addr );\r
+       if((vendor_dev & 0xFFFF) == 0xFFFF)     // Invalid Device\r
+               return 0;\r
+\r
+       info->ConfigCache[0] = vendor_dev;\r
+       for( i = 1, addr += 4; i < 256/4; i ++, addr += 4 )\r
+       {\r
+               info->ConfigCache[i] = PCI_CfgReadDWord(addr);\r
+       }       \r
+\r
+       info->bus = bus;\r
+       info->slot = slot;\r
+       info->fcn = fcn;\r
+       info->vendor = vendor_dev & 0xFFFF;\r
+       info->device = vendor_dev >> 16;\r
+       tmp = info->ConfigCache[2];\r
+       info->revision = tmp & 0xFF;\r
+       info->class = tmp >> 8;\r
+       \r
+//     #if LIST_DEVICES\r
+//     Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);\r
+//     Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);\r
+//     Log("Class: 0x%06x", info->class);\r
+//     #endif\r
+       \r
+       // Make node name\r
+       info->Name[0] = '0' + bus/10;\r
+       info->Name[1] = '0' + bus%10;\r
+       info->Name[2] = '.';\r
+       info->Name[3] = '0' + slot/10;\r
+       info->Name[4] = '0' + slot%10;\r
+       info->Name[5] = ':';\r
+       info->Name[6] = '0' + fcn;\r
+       info->Name[7] = '\0';\r
+       \r
+       // Create VFS Node\r
+       memset( &info->Node, 0, sizeof(tVFS_Node) );\r
+       info->Node.Size = 256;\r
+       \r
+       info->Node.NumACLs = 1;\r
+       info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
+       \r
+       info->Node.Type = &gPCI_RootNodeType;\r
+       \r
+       return 1;\r
+}\r
+\r
+// === EXPORTS ===\r
+//*\r
+EXPORT(PCI_CountDevices);\r
+EXPORT(PCI_GetDevice);\r
+EXPORT(PCI_GetDeviceByClass);\r
+EXPORT(PCI_GetDeviceInfo);\r
+EXPORT(PCI_GetDeviceVersion);\r
+EXPORT(PCI_GetDeviceSubsys);\r
+//EXPORT(PCI_AssignPort);\r
+EXPORT(PCI_GetBAR);\r
+EXPORT(PCI_GetIRQ);\r
+//*/\r
diff --git a/KernelLand/Kernel/drv/proc.c b/KernelLand/Kernel/drv/proc.c
new file mode 100644 (file)
index 0000000..73f4535
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Acess2
+ * - Kernel Status Driver
+ */
+#define DEBUG  1
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <fs_sysfs.h>
+
+// === CONSTANTS ===
+#define        VERSION ((0 << 8) | (1))        // 0.01
+
+// === TYPES ===
+typedef struct sSysFS_Ent
+{
+       struct sSysFS_Ent       *Next;
+       struct sSysFS_Ent       *ListNext;
+       struct sSysFS_Ent       *Parent;
+       tVFS_Node       Node;
+       char    Name[];
+} tSysFS_Ent;
+
+// === PROTOTYPES ===
+ int   SysFS_Install(char **Arguments);
+ int   SysFS_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+#if 0
+ int   SysFS_RegisterFile(const char *Path, const char *Data, int Length);
+ int   SysFS_UpdateFile(int ID, const char *Data, int Length);
+ int   SysFS_RemoveFile(int ID);
+#endif
+
+char   *SysFS_Comm_ReadDir(tVFS_Node *Node, int Id);
+tVFS_Node      *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename);
+Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+void   SysFS_Comm_CloseFile(tVFS_Node *Node);
+
+// === GLOBALS ===
+extern tSysFS_Ent      gSysFS_Version; // Defined Later
+extern tSysFS_Ent      gSysFS_Root;    // Defined Later
+MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
+tVFS_NodeType  gSysFS_FileNodeType = {
+       .TypeName = "SysFS File",
+       .Read = SysFS_Comm_ReadFile
+       };
+tVFS_NodeType  gSysFS_DirNodeType = {
+       .TypeName = "SysFS Dir",
+       .ReadDir = SysFS_Comm_ReadDir,
+       .FindDir = SysFS_Comm_FindDir
+       };
+tSysFS_Ent     gSysFS_Version_Kernel = {
+       NULL, NULL,     // Nexts
+       &gSysFS_Version,        // Parent
+       {
+               .Inode = 1,     // File #1
+               .ImplPtr = NULL,
+               .ImplInt = (Uint)&gSysFS_Version_Kernel,        // Self-Link
+               .Size = 0,
+               .NumACLs = 1,
+               .ACLs = &gVFS_ACL_EveryoneRO,
+               .Type = &gSysFS_FileNodeType
+       },
+       "Kernel"
+};
+tSysFS_Ent     gSysFS_Version = {
+       NULL, NULL,
+       &gSysFS_Root,
+       {
+               .Size = 1,
+               .ImplPtr = &gSysFS_Version_Kernel,
+               .ImplInt = (Uint)&gSysFS_Version,       // Self-Link
+               .NumACLs = 1,
+               .ACLs = &gVFS_ACL_EveryoneRX,
+               .Flags = VFS_FFLAG_DIRECTORY,
+               .Type = &gSysFS_DirNodeType
+       },
+       "Version"
+};
+// Root of the SysFS tree (just used to keep the code clean)
+tSysFS_Ent     gSysFS_Root = {
+       NULL, NULL,
+       NULL,
+       {
+               .Size = 1,
+               .ImplPtr = &gSysFS_Version,
+               .ImplInt = (Uint)&gSysFS_Root   // Self-Link
+       },
+       "/"
+};
+tDevFS_Driver  gSysFS_DriverInfo = {
+       NULL, "system",
+       {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .ImplPtr = &gSysFS_Version,
+       .Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
+       .Type = &gSysFS_DirNodeType
+       }
+};
+ int   giSysFS_NextFileID = 2;
+tSysFS_Ent     *gSysFS_FileList;
+
+// === CODE ===
+/**
+ * \fn int SysFS_Install(char **Options)
+ * \brief Installs the SysFS Driver
+ */
+int SysFS_Install(char **Options)
+{
+       {
+               const char      *fmt = "Acess2 "EXPAND_STR(KERNEL_VERSION)" "EXPAND_STR(ARCHDIR)" build %i, hash %s";
+               gSysFS_Version_Kernel.Node.Size = sprintf(NULL, fmt, BUILD_NUM, gsGitHash);
+               gSysFS_Version_Kernel.Node.ImplPtr = malloc( gSysFS_Version_Kernel.Node.Size + 1 );
+               sprintf(gSysFS_Version_Kernel.Node.ImplPtr, fmt, BUILD_NUM, gsGitHash);
+       }
+
+       DevFS_AddDevice( &gSysFS_DriverInfo );
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \fn int SysFS_RegisterFile(char *Path, char *Data, int Length)
+ * \brief Registers a file (buffer) for the user to be able to read from
+ * \param Path Path for the file to be accessable from (relative to SysFS root)
+ * \param Data Pointer to the data buffer (must be non-volatile)
+ * \param Length       Length of the data buffer
+ * \return The file's identifier
+ */
+int SysFS_RegisterFile(const char *Path, const char *Data, int Length)
+{
+        int    start = 0;
+        int    tmp;
+       tSysFS_Ent      *ent = NULL;
+       tSysFS_Ent      *child, *prev;
+       
+       // Find parent directory
+       while( (tmp = strpos(&Path[start], '/')) != -1 )
+       {
+               prev = NULL;
+               
+               if(ent)
+                       child = ent->Node.ImplPtr;
+               else
+                       child = gSysFS_DriverInfo.RootNode.ImplPtr;
+               for( ; child; prev = child, child = child->Next )
+               {
+                       if( strncmp( &Path[start], child->Name, tmp+1 ) == '/' )
+                               break;
+               }
+               
+               // Need a new directory?
+               if( !child )
+               {
+                       child = calloc( 1, sizeof(tSysFS_Ent)+tmp+1 );
+                       child->Next = NULL;
+                       memcpy(child->Name, &Path[start], tmp);
+                       child->Name[tmp] = '\0';
+                       child->Parent = ent;
+                       child->Node.Inode = 0;
+                       child->Node.ImplPtr = NULL;
+                       child->Node.ImplInt = (Uint)child;      // Uplink
+                       child->Node.NumACLs = 1;
+                       child->Node.ACLs = &gVFS_ACL_EveryoneRX;
+                       child->Node.Flags = VFS_FFLAG_DIRECTORY;
+                       child->Node.Type = &gSysFS_DirNodeType;
+                       if( !prev ) {
+                               if(ent)
+                                       ent->Node.ImplPtr = child;
+                               else
+                                       gSysFS_DriverInfo.RootNode.ImplPtr = child;
+                               // ^^^ Impossible (There is already /Version)
+                       }
+                       else
+                               prev->Next = child;
+                       if(ent)
+                               ent->Node.Size ++;
+                       else
+                               gSysFS_DriverInfo.RootNode.Size ++;
+                       Log_Log("SysFS", "Added directory '%s'", child->Name);
+               }
+               
+               ent = child;
+               
+               start = tmp+1;
+       }
+       
+       // ent: Parent tSysFS_Ent or NULL
+       // start: beginning of last path element
+       
+       // Check if the name is taken
+       prev = NULL;
+       if(ent)
+               child = ent->Node.ImplPtr;
+       else
+               child = gSysFS_DriverInfo.RootNode.ImplPtr;
+       for( ; child; child = child->Next )
+       {
+               if( strcmp( &Path[start], child->Name ) == 0 )
+                       break;
+       }
+       if( child ) {
+               Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
+               return 0;
+       }
+       
+       // Create new node
+       child = calloc( 1, sizeof(tSysFS_Ent)+strlen(&Path[start])+1 );
+       child->Next = NULL;
+       strcpy(child->Name, &Path[start]);
+       child->Parent = ent;
+       
+       child->Node.Inode = giSysFS_NextFileID++;
+       child->Node.ImplPtr = (void*)Data;
+       child->Node.ImplInt = (Uint)child;      // Uplink
+       child->Node.Size = Length;
+       child->Node.NumACLs = 1;
+       child->Node.ACLs = &gVFS_ACL_EveryoneRO;
+       child->Node.Type = &gSysFS_FileNodeType;
+       
+       // Add to parent's child list
+       if(ent) {
+               ent->Node.Size ++;
+               child->Next = ent->Node.ImplPtr;
+               ent->Node.ImplPtr = child;
+       }
+       else {
+               gSysFS_DriverInfo.RootNode.Size ++;
+               child->Next = gSysFS_DriverInfo.RootNode.ImplPtr;
+               gSysFS_DriverInfo.RootNode.ImplPtr = child;
+       }
+       // Add to global file list
+       child->ListNext = gSysFS_FileList;
+       gSysFS_FileList = child;
+       
+       Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
+       
+       return child->Node.Inode;
+}
+
+/**
+ * \fn int SysFS_UpdateFile(int ID, char *Data, int Length)
+ * \brief Updates a file
+ * \param ID   Identifier returned by ::SysFS_RegisterFile
+ * \param Data Pointer to the data buffer
+ * \param Length       Length of the data buffer
+ * \return Boolean Success
+ */
+int SysFS_UpdateFile(int ID, const char *Data, int Length)
+{
+       tSysFS_Ent      *ent;
+       
+       for( ent = gSysFS_FileList; ent; ent = ent->Next )
+       {
+               // It's a reverse sorted list
+               if(ent->Node.Inode < ID)        return 0;
+               if(ent->Node.Inode == ID)
+               {
+                       ent->Node.ImplPtr = (void*)Data;
+                       ent->Node.Size = Length;
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
+
+/**
+ * \fn int SysFS_RemoveFile(int ID)
+ * \brief Removes a file from user access
+ * \param ID   Identifier returned by ::SysFS_RegisterFile
+ * \return Boolean Success
+ * \note If a handle is still open to the file, it will be invalidated
+ */
+int SysFS_RemoveFile(int ID)
+{
+       tSysFS_Ent      *file;
+       tSysFS_Ent      *ent, *parent, *prev;
+       
+       prev = NULL;
+       for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
+       {
+               // It's a reverse sorted list
+               if(ent->Node.Inode < ID)        return 0;
+               if(ent->Node.Inode == ID)       break;
+       }
+       
+       if(!ent)        return 0;
+       
+       // Set up for next part
+       file = ent;
+       parent = file->Parent;
+       
+       // Remove from file list
+       if(prev)
+               prev->ListNext = file->ListNext;
+       else
+               gSysFS_FileList = file->ListNext;
+       file->Node.Size = 0;
+       file->Node.ImplPtr = NULL;
+       
+       // Search parent directory
+       for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
+       {
+               if( ent == file )       break;
+       }
+       if(!ent) {
+               Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
+               return 0;
+       }
+       
+       // Remove from parent directory
+       if(prev)
+               prev->Next = ent->Next;
+       else
+               parent->Node.ImplPtr = ent->Next;
+       
+       // Free if not in use
+       if(file->Node.ReferenceCount == 0)
+               free(file);
+       
+       return 1;
+}
+
+/**
+ * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
+ * \brief Reads from a SysFS directory
+ */
+char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
+       if(Pos < 0 || Pos >= Node->Size)        return NULL;
+       
+       for( ; child; child = child->Next, Pos-- )
+       {
+               if( Pos == 0 )  return strdup(child->Name);
+       }
+       return NULL;
+}
+
+/**
+ * \fn tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
+ * \brief Find a file in a SysFS directory
+ */
+tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename)
+{
+       tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
+       
+       for( ; child; child = child->Next )
+       {
+               if( strcmp(child->Name, Filename) == 0 )
+                       return &child->Node;
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from an exposed buffer
+ */
+Uint64 SysFS_Comm_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       if( Offset > Node->Size )       return -1;
+       if( Length > Node->Size )       Length = Node->Size;
+       if( Offset + Length > Node->Size)       Length = Node->Size - Offset;
+       
+       if( Node->ImplPtr )
+               memcpy(Buffer, (void*)((Uint)Node->ImplPtr+(Uint)Offset), Length);
+       else
+               return -1;
+       
+       return Length;
+}
+
+/**
+ * \fn void SysFS_Comm_CloseFile(tVFS_Node *Node)
+ * \brief Closes an open file
+ * \param Node Node to close
+ */
+void SysFS_Comm_CloseFile(tVFS_Node *Node)
+{
+       // Dereference
+       Node->ReferenceCount --;
+       if( Node->ReferenceCount > 0 )  return;
+       
+       // Check if it is still valid
+       if( Node->ImplPtr )     return;
+       
+       // Delete
+       free( (void*)Node->ImplInt );
+}
diff --git a/KernelLand/Kernel/drv/vterm.c b/KernelLand/Kernel/drv/vterm.c
new file mode 100644 (file)
index 0000000..2ae38ee
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * Acess2 Virtual Terminal Driver
+ */
+#define DEBUG  0
+#include "vterm.h"
+#include <fs_devfs.h>
+#include <modules.h>
+#include <api_drv_keyboard.h>
+#include <api_drv_video.h>
+#include <errno.h>
+#include <semaphore.h>
+
+// === CONSTANTS ===
+#define VERSION        ((0<<8)|(50))
+
+#define        NUM_VTS 8
+//#define DEFAULT_OUTPUT       "BochsGA"
+#define DEFAULT_OUTPUT "Vesa"
+#define FALLBACK_OUTPUT        "x86_VGAText"
+#define DEFAULT_INPUT  "PS2Keyboard"
+#define        DEFAULT_WIDTH   640
+#define        DEFAULT_HEIGHT  480
+#define DEFAULT_SCROLLBACK     2       // 2 Screens of text + current screen
+//#define DEFAULT_SCROLLBACK   0
+
+// === TYPES ===
+
+// === IMPORTS ===
+extern void    Debug_SetKTerminal(const char *File);
+
+// === PROTOTYPES ===
+ int   VT_Install(char **Arguments);
+char   *VT_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *VT_FindDir(tVFS_Node *Node, const char *Name);
+ int   VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
+Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+ int   VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === CONSTANTS ===
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_INPUT, NULL);
+tVFS_NodeType  gVT_RootNodeType = {
+       .TypeName = "VTerm Root",
+       .ReadDir = VT_ReadDir,
+       .FindDir = VT_FindDir,
+       .IOCtl = VT_Root_IOCtl
+       };
+tVFS_NodeType  gVT_TermNodeType = {
+       .TypeName = "VTerm",
+       .Read = VT_Read,
+       .Write = VT_Write,
+       .IOCtl = VT_Terminal_IOCtl
+       };
+tDevFS_Driver  gVT_DrvInfo = {
+       NULL, "VTerm",
+       {
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Size = NUM_VTS,
+       .Inode = -1,
+       .NumACLs = 0,
+       .Type = &gVT_RootNodeType
+       }
+};
+// --- Terminals ---
+tVTerm gVT_Terminals[NUM_VTS];
+ int   giVT_CurrentTerminal = 0;
+tVTerm *gpVT_CurTerm = &gVT_Terminals[0];
+// --- Video State ---
+short  giVT_RealWidth  = DEFAULT_WIDTH;        //!< Screen Width
+short  giVT_RealHeight = DEFAULT_HEIGHT;       //!< Screen Height
+ int   giVT_Scrollback = DEFAULT_SCROLLBACK;
+// --- Driver Handles ---
+char   *gsVT_OutputDevice = NULL;
+char   *gsVT_InputDevice = NULL;
+ int   giVT_OutputDevHandle = -2;
+ int   giVT_InputDevHandle = -2;
+
+// === CODE ===
+/**
+ * \fn int VT_Install(char **Arguments)
+ * \brief Installs the Virtual Terminal Driver
+ */
+int VT_Install(char **Arguments)
+{
+        int    i;
+       
+       // Scan Arguments
+       if(Arguments)
+       {
+               char    **args;
+               const char      *arg;
+               for(args = Arguments; (arg = *args); args++ )
+               {
+                       char    data[strlen(arg)+1];
+                       char    *opt = data;
+                       char    *val;
+                       
+                       val = strchr(arg, '=');
+                       strcpy(data, arg);
+                       if( val ) {
+                               data[ val - arg ] = '\0';
+                               val ++;
+                       }
+                       Log_Debug("VTerm", "Argument '%s'", arg);
+                       
+                       if( strcmp(opt, "Video") == 0 ) {
+                               if( !gsVT_OutputDevice )
+                                       gsVT_OutputDevice = strdup(val);
+                       }
+                       else if( strcmp(opt, "Input") == 0 ) {
+                               if( !gsVT_InputDevice )
+                                       gsVT_InputDevice = strdup(val);
+                       }
+                       else if( strcmp(opt, "Width") == 0 ) {
+                               giVT_RealWidth = atoi( val );
+                       }
+                       else if( strcmp(opt, "Height") == 0 ) {
+                               giVT_RealHeight = atoi( val );
+                       }
+                       else if( strcmp(opt, "Scrollback") == 0 ) {
+                               giVT_Scrollback = atoi( val );
+                       }
+               }
+       }
+       
+       // Apply Defaults
+       if(!gsVT_OutputDevice)  gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
+       else if( Module_EnsureLoaded( gsVT_OutputDevice ) )     gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
+       if( Module_EnsureLoaded( gsVT_OutputDevice ) )  gsVT_OutputDevice = (char*)FALLBACK_OUTPUT;
+       if( Module_EnsureLoaded( gsVT_OutputDevice ) ) {
+               Log_Error("VTerm", "Fallback video '%s' is not avaliable, giving up", FALLBACK_OUTPUT);
+               return MODULE_ERR_MISC;
+       }
+       
+       if(!gsVT_InputDevice)   gsVT_InputDevice = (char*)DEFAULT_INPUT;
+       else if( Module_EnsureLoaded( gsVT_InputDevice ) )      gsVT_InputDevice = (char*)DEFAULT_INPUT;
+       
+       // Create device paths
+       {
+               char    *tmp;
+               tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 );
+               strcpy(tmp, "/Devices/");
+               strcpy(&tmp[9], gsVT_OutputDevice);
+               gsVT_OutputDevice = tmp;
+
+               tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 );
+               strcpy(tmp, "/Devices/");
+               strcpy(&tmp[9], gsVT_InputDevice);
+               gsVT_InputDevice = tmp;
+       }
+       
+       Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice);
+       Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice);
+       
+       VT_InitOutput();
+       VT_InitInput();
+       
+       // Create Nodes
+       for( i = 0; i < NUM_VTS; i++ )
+       {
+               gVT_Terminals[i].Mode = TERM_MODE_TEXT;
+               gVT_Terminals[i].Flags = 0;
+//             gVT_Terminals[i].Flags = VT_FLAG_HIDECSR;       //HACK - Stop all those memcpy calls
+               gVT_Terminals[i].CurColour = DEFAULT_COLOUR;
+               gVT_Terminals[i].WritePos = 0;
+               gVT_Terminals[i].AltWritePos = 0;
+               gVT_Terminals[i].ViewPos = 0;
+               gVT_Terminals[i].ReadingThread = -1;
+               gVT_Terminals[i].ScrollHeight = 0;
+               
+               // Initialise
+               VT_int_ChangeMode( &gVT_Terminals[i],
+                       TERM_MODE_TEXT, giVT_RealWidth, giVT_RealHeight );
+               
+               gVT_Terminals[i].Name[0] = '0'+i;
+               gVT_Terminals[i].Name[1] = '\0';
+               gVT_Terminals[i].Node.Inode = i;
+               gVT_Terminals[i].Node.ImplPtr = &gVT_Terminals[i];
+               gVT_Terminals[i].Node.NumACLs = 0;      // Only root can open virtual terminals
+       
+               gVT_Terminals[i].Node.Type = &gVT_TermNodeType; 
+//             Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
+       }
+       
+       // Add to DevFS
+       DevFS_AddDevice( &gVT_DrvInfo );
+       
+       // Set kernel output to VT0
+       Debug_SetKTerminal("/Devices/VTerm/0");
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Set the video resolution
+ * \param Width        New screen width
+ * \param Height       New screen height
+ */
+void VT_SetResolution(int Width, int Height)
+{
+       tVideo_IOCtl_Mode       mode = {0};
+        int    tmp;
+        int    i;
+       
+       // Create the video mode
+       mode.width = Width;
+       mode.height = Height;
+       mode.bpp = 32;
+       mode.flags = 0;
+       
+       // Set video mode
+       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode );
+       tmp = mode.id;
+       if( Width != mode.width || Height != mode.height )
+       {
+               Log_Warning("VTerm",
+                       "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)",
+                       giVT_RealWidth, giVT_RealHeight,
+                       mode.width, mode.height
+                       );
+               giVT_RealWidth = mode.width;
+               giVT_RealHeight = mode.height;
+       }
+       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp );
+       
+       // Resize text terminals if needed
+       if( gVT_Terminals[0].Text && (giVT_RealWidth != mode.width || giVT_RealHeight != mode.height) )
+       {
+                int    newBufSize = (giVT_RealWidth/giVT_CharWidth)
+                                       *(giVT_RealHeight/giVT_CharHeight)
+                                       *(giVT_Scrollback+1);
+               //tVT_Char      *tmp;
+               // Resize the text terminals
+               Log_Debug("VTerm", "Resizing terminals to %ix%i",
+                       giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight);
+               for( i = 0; i < NUM_VTS; i ++ )
+               {
+                       if( gVT_Terminals[i].Mode != TERM_MODE_TEXT )   continue;
+                       
+                       gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth;
+                       gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight;
+                       gVT_Terminals[i].ScrollHeight = gVT_Terminals[i].TextHeight;
+                       
+                       gVT_Terminals[i].Text = realloc(
+                               gVT_Terminals[i].Text,
+                               newBufSize*sizeof(tVT_Char)
+                               );
+               }
+       }
+}
+
+/**
+ * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
+ * \brief Read from the VTerm Directory
+ */
+char *VT_ReadDir(tVFS_Node *Node, int Pos)
+{
+       if(Pos < 0)     return NULL;
+       if(Pos >= NUM_VTS)      return NULL;
+       return strdup( gVT_Terminals[Pos].Name );
+}
+
+/**
+ * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name)
+ * \brief Find an item in the VTerm directory
+ * \param Node Root node
+ * \param Name Name (number) of the terminal
+ */
+tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name)
+{
+        int    num;
+       
+       ENTER("pNode sName", Node, Name);
+       
+       // Open the input and output files if needed
+       if(giVT_OutputDevHandle == -2)  VT_InitOutput();
+       if(giVT_InputDevHandle == -2)   VT_InitInput();
+       
+       // Sanity check name
+       if(Name[0] < '0' || Name[0] > '9' || Name[1] != '\0') {
+               LEAVE('n');
+               return NULL;
+       }
+       // Get index
+       num = Name[0] - '0';
+       if(num >= NUM_VTS) {
+               LEAVE('n');
+               return NULL;
+       }
+       // Return node
+       LEAVE('p', &gVT_Terminals[num].Node);
+       return &gVT_Terminals[num].Node;
+}
+
+/**
+ * \fn int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Control the VTerm Driver
+ */
+int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+        int    len;
+       switch(Id)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_MISC;
+       case DRV_IOCTL_IDENT:   memcpy(Data, "VT\0\0", 4);      return 0;
+       case DRV_IOCTL_VERSION: return VERSION;
+       case DRV_IOCTL_LOOKUP:  return 0;
+       
+       case 4: // Get Video Driver
+               if(Data)        strcpy(Data, gsVT_OutputDevice);
+               return strlen(gsVT_OutputDevice);
+       
+       case 5: // Set Video Driver
+               if(!Data)       return -EINVAL;
+               if(Threads_GetUID() != 0)       return -EACCES;
+               
+               len = strlen(Data);
+               
+               // TODO: Check if the string used is a heap string
+               
+               free(gsVT_OutputDevice);
+               
+               gsVT_OutputDevice = malloc(len+1);
+               strcpy(gsVT_OutputDevice, Data);
+               
+               VFS_Close(giVT_OutputDevHandle);
+               giVT_OutputDevHandle = -1;
+               
+               VT_InitOutput();
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * \brief Read from a virtual terminal
+ */
+Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    pos = 0;
+        int    avail;
+       tVTerm  *term = &gVT_Terminals[ Node->Inode ];
+       Uint32  *codepoint_buf = Buffer;
+       Uint32  *codepoint_in;
+       
+       Mutex_Acquire( &term->ReadingLock );
+       
+       // Check current mode
+       switch(term->Mode)
+       {
+       // Text Mode (UTF-8)
+       case TERM_MODE_TEXT:
+               VT_int_UpdateCursor(term, 1);
+       
+               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UTF-8)");
+               
+               avail = term->InputWrite - term->InputRead;
+               if(avail < 0)
+                       avail += MAX_INPUT_CHARS8;
+               if(avail > Length - pos)
+                       avail = Length - pos;
+               
+               while( avail -- )
+               {
+                       ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead];
+                       pos ++;
+                       term->InputRead ++;
+                       while(term->InputRead >= MAX_INPUT_CHARS8)
+                               term->InputRead -= MAX_INPUT_CHARS8;
+               }
+               break;
+       
+       //case TERM_MODE_FB:
+       // Other - UCS-4
+       default:
+               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)");
+               
+               avail = term->InputWrite - term->InputRead;
+               if(avail < 0)
+                       avail += MAX_INPUT_CHARS32;
+               Length /= 4;
+               if(avail > Length - pos)
+                       avail = Length - pos;
+               
+               codepoint_in = (void*)term->InputBuffer;
+               codepoint_buf = Buffer;
+               
+               while( avail -- )
+               {
+                       codepoint_buf[pos] = codepoint_in[term->InputRead];
+                       pos ++;
+                       term->InputRead ++;
+                       while(term->InputRead >= MAX_INPUT_CHARS32)
+                               term->InputRead -= MAX_INPUT_CHARS32;
+               }
+               pos *= 4;
+               break;
+       }
+       
+       // Mark none avaliable if buffer empty
+       if( term->InputRead == term->InputWrite )
+               VFS_MarkAvaliable(&term->Node, 0);
+       
+       term->ReadingThread = -1;
+
+//     VT_int_UpdateCursor(term, term->Mode == TERM_MODE_TEXT);
+
+       Mutex_Release( &term->ReadingLock );
+       
+       return pos;
+}
+
+/**
+ * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+ * \brief Write to a virtual terminal
+ */
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tVTerm  *term = &gVT_Terminals[ Node->Inode ];
+        int    size;
+       
+       // Write
+       switch( term->Mode )
+       {
+       // Print Text
+       case TERM_MODE_TEXT:
+               VT_int_PutString(term, Buffer, Length);
+               break;
+       
+       // Framebuffer :)
+       case TERM_MODE_FB:
+               // - Sanity Checking
+               size = term->Width*term->Height*4;
+               if( Offset > size ) {
+                       Log_Notice("VTerm", "VT_Write: Offset (0x%llx) > FBSize (0x%x)",
+                               Offset, size);
+                       return 0;
+               }
+               if( Offset + Length > size ) {
+                       Log_Notice("VTerm", "VT_Write: Offset+Length (0x%llx) > FBSize (0x%x)",
+                               Offset+Length, size);
+                       Length = size - Offset;
+               }
+               
+               // Update screen if needed
+               if( Node->Inode == giVT_CurrentTerminal )
+               {
+                       if( giVT_RealHeight > term->Height )
+                               Offset += (giVT_RealHeight - term->Height) / 2 * term->Width * 4;
+                       // Handle undersized virtual terminals
+                       if( giVT_RealWidth > term->Width )
+                       {
+                               // No? :( Well, just center it
+                                int    x, y, w, h;
+                               Uint    dst_ofs;
+                               // TODO: Fix to handle the final line correctly?
+                               x = Offset/4;   y = x / term->Width;    x %= term->Width;
+                               w = Length/4+x; h = w / term->Width;    w %= term->Width;
+                               
+                               // Center
+                               x += (giVT_RealWidth - term->Width) / 2;
+                               dst_ofs = (x + y * giVT_RealWidth) * 4;
+                               while(h--)
+                               {
+                                       VFS_WriteAt( giVT_OutputDevHandle,
+                                               dst_ofs,
+                                               term->Width * 4,
+                                               Buffer
+                                               );
+                                       Buffer = (void*)( (Uint)Buffer + term->Width*4 );
+                                       dst_ofs += giVT_RealWidth * 4;
+                               }
+                               return 0;
+                       }
+                       else
+                       {
+                               return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer );
+                       }
+               }
+               else
+               {
+                       if( !term->Buffer )
+                               term->Buffer = malloc( term->Width * term->Height * 4 );
+                       // Copy to the local cache
+                       memcpy( (char*)term->Buffer + (Uint)Offset, Buffer, Length );
+               }
+               break;
+       // Just pass on (for now)
+       // TODO: Handle locally too to ensure no information is lost on
+       //       VT Switch (and to isolate terminals from each other)
+       case TERM_MODE_2DACCEL:
+       //case TERM_MODE_3DACCEL:
+               if( Node->Inode == giVT_CurrentTerminal )
+               {
+                       VFS_Write( giVT_OutputDevHandle, Length, Buffer );
+               }
+               break;
+       }
+       
+       return 0;
+}
+
+/**
+ * \fn int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Call an IO Control on a virtual terminal
+ */
+int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+        int    *iData = Data;
+        int    ret;
+       tVTerm  *term = Node->ImplPtr;
+       ENTER("pNode iId pData", Node, Id, Data);
+       
+       if(Id >= DRV_IOCTL_LOOKUP) {
+               // Only root can fiddle with graphics modes
+               // TODO: Remove this and replace with user ownership
+               if( Threads_GetUID() != 0 )     return -1;
+       }
+       
+       switch(Id)
+       {
+       // --- Core Defined
+       case DRV_IOCTL_TYPE:
+               LEAVE('i', DRV_TYPE_TERMINAL);
+               return DRV_TYPE_TERMINAL;
+       case DRV_IOCTL_IDENT:
+               memcpy(Data, "VT\0\0", 4);
+               LEAVE('i', 0);
+               return 0;
+       case DRV_IOCTL_VERSION:
+               LEAVE('x', VERSION);
+               return VERSION;
+       case DRV_IOCTL_LOOKUP:
+               LEAVE('i', 0);
+               return 0;
+       
+       // Get/Set the mode (and apply any changes)
+       case TERM_IOCTL_MODETYPE:
+               if(Data != NULL)
+               {
+                       if( CheckMem(Data, sizeof(int)) == 0 ) {
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData);
+                       
+                       // Update mode if needed
+                       if( term->Mode != *iData || term->NewWidth || term->NewHeight)
+                       {
+                               // Adjust for text mode
+                               if( *iData == TERM_MODE_TEXT ) {
+                                       term->NewHeight *= giVT_CharHeight;
+                                       term->NewWidth *= giVT_CharWidth;
+                               }
+                               // Fill unchanged dimensions
+                               if(term->NewHeight == 0)        term->NewHeight = term->Height;
+                               if(term->NewWidth == 0) term->NewWidth = term->Width;
+                               // Set new mode
+                               VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight);
+                               // Clear unapplied dimensions
+                               term->NewWidth = 0;
+                               term->NewHeight = 0;
+                       }
+                       
+                       // Update the screen dimensions
+                       if(Node->Inode == giVT_CurrentTerminal)
+                               VT_SetTerminal( giVT_CurrentTerminal );
+               }
+               LEAVE('i', term->Mode);
+               return term->Mode;
+       
+       // Get/set the terminal width
+       case TERM_IOCTL_WIDTH:
+               if(Data != NULL) {
+                       if( CheckMem(Data, sizeof(int)) == 0 ) {
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       term->NewWidth = *iData;
+               }
+               if( term->NewWidth )
+                       ret = term->NewWidth;
+               else if( term->Mode == TERM_MODE_TEXT )
+                       ret = term->TextWidth;
+               else
+                       ret = term->Width;
+               LEAVE('i', ret);
+               return ret;
+       
+       // Get/set the terminal height
+       case TERM_IOCTL_HEIGHT:
+               if(Data != NULL) {
+                       if( CheckMem(Data, sizeof(int)) == 0 ) {
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       term->NewHeight = *iData;
+               }
+               if( term->NewHeight )
+                       ret = term->NewHeight;
+               else if( term->Mode == TERM_MODE_TEXT )
+                       ret = term->TextHeight;
+               else
+                       ret = term->Height;
+               LEAVE('i', ret);
+               return ret;
+       
+       case TERM_IOCTL_FORCESHOW:
+               Log_Log("VTerm", "Thread %i forced VTerm %i to be shown",
+                       Threads_GetTID(), (int)Node->Inode);
+               VT_SetTerminal( Node->Inode );
+               LEAVE('i', 1);
+               return 1;
+       
+       case TERM_IOCTL_GETSETCURSOR:
+               if(Data != NULL)
+               {
+                       tVideo_IOCtl_Pos        *pos = Data;
+                       if( !CheckMem(Data, sizeof(*pos)) ) {
+                               errno = -EINVAL;
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+               
+                       if( term->Mode == TERM_MODE_TEXT )
+                       {
+                               if(term->Flags & VT_FLAG_ALTBUF)
+                                       term->AltWritePos = pos->x + pos->y * term->TextWidth;
+                               else
+                                       term->WritePos = pos->x + pos->y * term->TextWidth + term->ViewPos;
+                               VT_int_UpdateCursor(term, 0);
+                       }
+                       else
+                       {
+                               term->VideoCursorX = pos->x;
+                               term->VideoCursorY = pos->y;
+                               VT_int_UpdateCursor(term, 1);
+                       }
+               }
+               ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos;
+               LEAVE('i', ret);
+               return ret;
+
+       case TERM_IOCTL_SETCURSORBITMAP: {
+               tVideo_IOCtl_Bitmap     *bmp = Data;
+               if( Data == NULL )
+               {
+                       free( term->VideoCursor );
+                       term->VideoCursor = NULL;
+                       LEAVE('i', 0);
+                       return 0;
+               }
+
+               // Sanity check bitmap
+               if( !CheckMem(bmp, sizeof(tVideo_IOCtl_Bitmap)) ) {
+                       Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
+                       errno = -EINVAL;
+                       LEAVE_RET('i', -1);
+               }
+               if( !CheckMem(bmp->Data, bmp->W*bmp->H*sizeof(Uint32)) ) {
+                       Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
+                       errno = -EINVAL;
+                       LEAVE_RET('i', -1);
+               }
+
+               // Reallocate if needed
+               if(term->VideoCursor)
+               {
+                       if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) {
+                               free(term->VideoCursor);
+                               term->VideoCursor = NULL;
+                       }
+               }
+               if(!term->VideoCursor) {
+                       term->VideoCursor = malloc(sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
+                       if(!term->VideoCursor) {
+                               Log_Error("VTerm", "Unable to allocate memory for cursor");
+                               errno = -ENOMEM;
+                               LEAVE_RET('i', -1);
+                       }
+               }
+               
+               memcpy(term->VideoCursor, bmp, sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
+       
+               Log_Debug("VTerm", "Set VT%i's cursor to %p %ix%i",
+                       (int)term->Node.Inode, bmp, bmp->W, bmp->H);
+
+               if(gpVT_CurTerm == term)
+                       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, term->VideoCursor);
+       
+               LEAVE('i', 0);
+               return 0; }
+       }
+       LEAVE('i', -1);
+       return -1;
+}
+
+/**
+ * \fn void VT_SetTerminal(int ID)
+ * \brief Set the current terminal
+ */
+void VT_SetTerminal(int ID)
+{
+       // Copy the screen state
+       if( ID != giVT_CurrentTerminal && gpVT_CurTerm->Mode != TERM_MODE_TEXT )
+       {
+               if( !gpVT_CurTerm->Buffer )
+                       gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 );
+               if( gpVT_CurTerm->Width < giVT_RealWidth )
+               {
+                        int    line;
+                       Uint    ofs = 0;
+                       Uint32  *dest = gpVT_CurTerm->Buffer;
+                       // Slower scanline copy
+                       for( line = 0; line < gpVT_CurTerm->Height; line ++ )
+                       {
+                               VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest);
+                               ofs += giVT_RealWidth * 4;
+                               dest += gpVT_CurTerm->Width;
+                       }
+               }
+               else
+               {
+                       VFS_ReadAt(giVT_OutputDevHandle,
+                               0, gpVT_CurTerm->Height*giVT_RealWidth*4,
+                               gpVT_CurTerm->Buffer
+                               );
+               }
+       }
+
+       // Update current terminal ID
+       Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID);
+       giVT_CurrentTerminal = ID;
+       gpVT_CurTerm = &gVT_Terminals[ID];
+       
+       if( gpVT_CurTerm->Mode == TERM_MODE_TEXT )
+       {
+               VT_SetMode( VIDEO_BUFFMT_TEXT );
+       }
+       else
+       {
+               // Update the cursor image
+               if(gpVT_CurTerm->VideoCursor)
+                       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor);
+               VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER );
+       }
+       
+       if(gpVT_CurTerm->Buffer)
+       {
+               // TODO: Handle non equal sized
+               VFS_WriteAt(
+                       giVT_OutputDevHandle,
+                       0,
+                       gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32),
+                       gpVT_CurTerm->Buffer
+                       );
+       }
+       
+       VT_int_UpdateCursor(gpVT_CurTerm, 1);
+       // Update the screen
+       VT_int_UpdateScreen(gpVT_CurTerm, 1);
+}
diff --git a/KernelLand/Kernel/drv/vterm.h b/KernelLand/Kernel/drv/vterm.h
new file mode 100644 (file)
index 0000000..cd37ebd
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm.h
+ * - Virtual Terminal - Common
+ */
+#ifndef _VTERM_H_
+#define _VTERM_H_
+
+#include <acess.h>
+#include <api_drv_video.h>     // tVT_Char
+#include <api_drv_terminal.h>
+#include <vfs.h>
+
+// === CONSTANTS ===
+#define MAX_INPUT_CHARS32      64
+#define MAX_INPUT_CHARS8       (MAX_INPUT_CHARS32*4)
+#define        DEFAULT_COLOUR  (VT_COL_BLACK|(0xAAA<<16))
+
+/**
+ * \{
+ */
+#define        VT_FLAG_HIDECSR 0x01    //!< Hide the cursor
+#define        VT_FLAG_ALTBUF  0x02    //!< Alternate screen buffer
+#define VT_FLAG_RAWIN  0x04    //!< Don't handle ^Z/^C/^V
+#define        VT_FLAG_HASFB   0x10    //!< Set if the VTerm has requested the Framebuffer
+#define VT_FLAG_SHOWCSR        0x20    //!< Always show the text cursor
+/**
+ * \}
+ */
+
+enum eVT_InModes {
+       VT_INMODE_TEXT8,        // UTF-8 Text Mode (VT100/xterm Emulation)
+       VT_INMODE_TEXT32,       // UTF-32 Text Mode (Acess Native)
+       NUM_VT_INMODES
+};
+
+
+// === TYPES ==
+typedef struct sVTerm  tVTerm;
+
+// === STRUCTURES ===
+struct sVTerm
+{
+        int    Mode;   //!< Current Mode (see ::eTplTerminal_Modes)
+        int    Flags;  //!< Flags (see VT_FLAG_*)
+       
+       short   NewWidth;       //!< Un-applied dimensions (Width)
+       short   NewHeight;      //!< Un-applied dimensions (Height)
+       short   Width;  //!< Virtual Width
+       short   Height; //!< Virtual Height
+       short   TextWidth;      //!< Text Virtual Width
+       short   TextHeight;     //!< Text Virtual Height
+       
+       Uint32  CurColour;      //!< Current Text Colour
+       
+        int    ViewPos;        //!< View Buffer Offset (Text Only)
+        int    WritePos;       //!< Write Buffer Offset (Text Only)
+       tVT_Char        *Text;
+       
+       tVT_Char        *AltBuf;        //!< Alternate Screen Buffer
+        int    AltWritePos;    //!< Alternate write position
+       short   ScrollTop;      //!< Top of scrolling region (smallest)
+       short   ScrollHeight;   //!< Length of scrolling region
+
+        int    VideoCursorX;
+        int    VideoCursorY;
+       
+       tMutex  ReadingLock;    //!< Lock the VTerm when a process is reading from it
+       tTID    ReadingThread;  //!< Owner of the lock
+        int    InputRead;      //!< Input buffer read position
+        int    InputWrite;     //!< Input buffer write position
+       char    InputBuffer[MAX_INPUT_CHARS8];
+//     tSemaphore      InputSemaphore;
+       
+       Uint32          *Buffer;
+
+       // TODO: Do I need to keep this about?
+       // When should it be deallocated? on move to text mode, or some other time
+       // Call set again, it's freed, and if NULL it doesn't get reallocated.
+       tVideo_IOCtl_Bitmap     *VideoCursor;
+       
+       char    Name[2];        //!< Name of the terminal
+       tVFS_Node       Node;
+};
+
+// === GOBALS ===
+extern tVTerm  *gpVT_CurTerm;
+extern int     giVT_Scrollback;
+extern short   giVT_RealWidth; //!< Screen Width
+extern short   giVT_RealHeight;        //!< Screen Width
+extern char    *gsVT_OutputDevice;
+extern char    *gsVT_InputDevice;
+extern int     giVT_OutputDevHandle;
+extern int     giVT_InputDevHandle;
+
+// === FUNCTIONS ===
+extern void    VT_SetResolution(int Width, int Height);
+extern void    VT_SetTerminal(int ID);
+// --- Output ---
+extern void    VT_InitOutput(void);
+extern void    VT_SetMode(int Mode);
+extern void    VT_int_ScrollFramebuffer( tVTerm *Term, int Count );
+extern void    VT_int_UpdateCursor( tVTerm *Term, int bShow );
+extern void    VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
+// --- Input ---
+extern void    VT_InitInput(void);
+extern void    VT_KBCallBack(Uint32 Codepoint);
+// --- VT100 Emulation ---
+extern void    VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args);
+extern int     VT_int_ParseEscape(tVTerm *Term, const char *Buffer);
+// --- Terminal Buffer ---
+extern void    VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count);
+extern void    VT_int_PutChar(tVTerm *Term, Uint32 Ch);
+extern void    VT_int_ScrollText(tVTerm *Term, int Count);
+extern void    VT_int_ClearLine(tVTerm *Term, int Num);
+extern void    VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight);
+extern void    VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
+
+#endif
+
diff --git a/KernelLand/Kernel/drv/vterm_font.c b/KernelLand/Kernel/drv/vterm_font.c
new file mode 100644 (file)
index 0000000..841ea50
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_font.c
+ * - Virtual Terminal - Font rendering code
+ */
+#include "vterm.h"
+#include <api_drv_terminal.h>
+
+// ---
+// Font Render
+// ---
+#define MONOSPACE_FONT 10816
+
+#if MONOSPACE_FONT == 10808    // 8x8
+# include "vterm_font_8x8.h"
+#elif MONOSPACE_FONT == 10816  // 8x16
+# include "vterm_font_8x16.h"
+#endif
+
+// === PROTOTYPES ===
+Uint8  *VT_Font_GetChar(Uint32 Codepoint);
+
+// === GLOBALS ===
+int    giVT_CharWidth = FONT_WIDTH;
+int    giVT_CharHeight = FONT_HEIGHT;
+
+// === CODE ===
+/**
+ * \brief Render a font character
+ */
+void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC)
+{
+       Uint8   *font;
+        int    x, y;
+       
+       // 8-bpp and below
+       if( Depth <= 8 )
+       {
+               Uint8   *buf = Buffer;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               if(*font & (1 << (FONT_WIDTH-x-1)))
+                                       buf[x] = FGC;
+                               else
+                                       buf[x] = BGC;
+                       }
+                       buf = (void*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+       // 16-bpp and below
+       else if( Depth <= 16 )
+       {
+               Uint16  *buf = Buffer;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               if(*font & (1 << (FONT_WIDTH-x-1)))
+                                       buf[x] = FGC;
+                               else
+                                       buf[x] = BGC;
+                       }
+                       buf = (void*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+       // 24-bpp colour
+       // - Special handling to not overwrite the next pixel
+       //TODO: Endian issues here
+       else if( Depth == 24 )
+       {
+               Uint8   *buf = Buffer;
+               Uint8   bg_r = (BGC >> 16) & 0xFF;
+               Uint8   bg_g = (BGC >>  8) & 0xFF;
+               Uint8   bg_b = (BGC >>  0) & 0xFF;
+               Uint8   fg_r = (FGC >> 16) & 0xFF;
+               Uint8   fg_g = (FGC >>  8) & 0xFF;
+               Uint8   fg_b = (FGC >>  0) & 0xFF;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               Uint8   r, g, b;
+                               
+                               if(*font & (1 << (FONT_WIDTH-x-1))) {
+                                       r = fg_r;       g = fg_g;       b = fg_b;
+                               }
+                               else {
+                                       r = bg_r;       g = bg_g;       b = bg_b;
+                               }
+                               buf[x*3+0] = b;
+                               buf[x*3+1] = g;
+                               buf[x*3+2] = r;
+                       }
+                       buf = (void*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+       // 32-bpp colour (nice and easy)
+       else if( Depth == 32 )
+       {
+               Uint32  *buf = Buffer;
+               
+               font = VT_Font_GetChar(Codepoint);
+               
+               for(y = 0; y < FONT_HEIGHT; y ++)
+               {
+                       for(x = 0; x < FONT_WIDTH; x ++)
+                       {
+                               if(*font & (1 << (FONT_WIDTH-x-1)))
+                                       buf[x] = FGC;
+                               else
+                                       buf[x] = BGC;
+                       }
+                       buf = (Uint32*)( (tVAddr)buf + Pitch );
+                       font ++;
+               }
+       }
+}
+
+/**
+ * \fn Uint32 VT_Colour12to24(Uint16 Col12)
+ * \brief Converts a 12-bit colour into 24 bits
+ */
+Uint32 VT_Colour12to24(Uint16 Col12)
+{
+       Uint32  ret;
+        int    tmp;
+       tmp = Col12 & 0xF;
+       ret  = (tmp << 0) | (tmp << 4);
+       tmp = (Col12 & 0xF0) >> 4;
+       ret |= (tmp << 8) | (tmp << 12);
+       tmp = (Col12 & 0xF00) >> 8;
+       ret |= (tmp << 16) | (tmp << 20);
+       return ret;
+}
+/**
+ * \brief Converts a 12-bit colour into 15 bits
+ */
+Uint16 VT_Colour12to15(Uint16 Col12)
+{
+       Uint32  ret;
+        int    tmp;
+       tmp = Col12 & 0xF;
+       ret  = (tmp << 1) | (tmp & 1);
+       tmp = (Col12 & 0xF0) >> 4;
+       ret |= ( (tmp << 1) | (tmp & 1) ) << 5;
+       tmp = (Col12 & 0xF00) >> 8;
+       ret |= ( (tmp << 1) | (tmp & 1) ) << 10;
+       return ret;
+}
+
+/**
+ * \brief Converts a 12-bit colour into any other depth
+ * \param Col12        12-bit source colour
+ * \param Depth        Desired bit deptj
+ * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5)
+ */
+Uint32 VT_Colour12toN(Uint16 Col12, int Depth)
+{
+       Uint32  ret;
+       Uint32  r, g, b;
+        int    rSize, gSize, bSize;
+       
+       // Fast returns
+       if( Depth == 24 )       return VT_Colour12to24(Col12);
+       if( Depth == 15 )       return VT_Colour12to15(Col12);
+       // - 32 is a special case, it's usually 24-bit colour with an unused byte
+       if( Depth == 32 )       return VT_Colour12to24(Col12);
+       
+       // Bounds checks
+       if( Depth < 8 ) return 0;
+       if( Depth > 32 )        return 0;
+       
+       r = Col12 & 0xF;
+       g = (Col12 & 0xF0) >> 4;
+       b = (Col12 & 0xF00) >> 8;
+       
+       rSize = gSize = bSize = Depth / 3;
+       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 1
+               gSize ++;
+       if( rSize + gSize + bSize < Depth )     // Depth % 3 == 2
+               bSize ++;
+       
+       // Expand
+       r <<= rSize - 4;        g <<= gSize - 4;        b <<= bSize - 4;
+       // Fill with the lowest bit
+       if( Col12 & 0x001 )     r |= (1 << (rSize - 4)) - 1;
+       if( Col12 & 0x010 )     r |= (1 << (gSize - 4)) - 1;
+       if( Col12 & 0x100 )     r |= (1 << (bSize - 4)) - 1;
+       
+       // Create output
+       ret  = r;
+       ret |= g << rSize;
+       ret |= b << (rSize + gSize);
+       
+       return ret;
+}
+
+/**
+ * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)
+ * \brief Gets an index into the font array given a Unicode Codepoint
+ * \note See http://en.wikipedia.org/wiki/CP437
+ */
+Uint8 *VT_Font_GetChar(Uint32 Codepoint)
+{
+        int    index = 0;
+       if(Codepoint < 128)
+               return &VTermFont[Codepoint*FONT_HEIGHT];
+       switch(Codepoint)
+       {
+       case 0xC7:      index = 128;    break;  // Ã‡
+       case 0xFC:      index = 129;    break;  // Ã¼
+       case 0xE9:      index = 130;    break;  // Ã©
+       case 0xE2:      index = 131;    break;  // Ã¢
+       case 0xE4:      index = 132;    break;  // Ã¤
+       case 0xE0:      index = 133;    break;  // Ã 
+       case 0xE5:      index = 134;    break;  // Ã¥
+       case 0xE7:      index = 135;    break;  // Ã§
+       case 0xEA:      index = 136;    break;  // Ãª
+       case 0xEB:      index = 137;    break;  // Ã«
+       case 0xE8:      index = 138;    break;  // Ã¨
+       case 0xEF:      index = 139;    break;  // Ã¯
+       case 0xEE:      index = 140;    break;  // Ã®
+       case 0xEC:      index = 141;    break;  // Ã¬
+       case 0xC4:      index = 142;    break;  // Ã„
+       case 0xC5:      index = 143;    break;  // Ã…
+       }
+       
+       return &VTermFont[index*FONT_HEIGHT];
+}
+
+EXPORTAS(&giVT_CharWidth, giVT_CharWidth);
+EXPORTAS(&giVT_CharHeight, giVT_CharHeight);
+EXPORT(VT_Font_Render);
+EXPORT(VT_Colour12to24);
diff --git a/KernelLand/Kernel/drv/vterm_font_8x16.h b/KernelLand/Kernel/drv/vterm_font_8x16.h
new file mode 100644 (file)
index 0000000..7c61332
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
+ * Altered for Acess2
+ */
+#define FONT_WIDTH     8
+#define FONT_HEIGHT    16
+static Uint8 VTermFont[256*16]=
+{
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+       0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+       0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+       0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+       0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+       0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+       0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+       0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+       0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+       0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+       0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+       0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+       0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/KernelLand/Kernel/drv/vterm_font_8x8.h b/KernelLand/Kernel/drv/vterm_font_8x8.h
new file mode 100644 (file)
index 0000000..2a5311d
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
+ * Altered for Acess2
+ */
+#define FONT_WIDTH     8
+#define FONT_HEIGHT    8
+static Uint8 VTermFont[256*8]=
+{
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+       0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+       0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+       0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+       0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+       0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+       0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+       0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+       0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+       0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+       0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+       0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+       0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+       0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+       0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+       0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+       0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+       0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+       0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+       0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+       0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+       0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+       0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+       0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+       0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+       0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+       0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+       0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+       0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+       0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+       0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+       0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+       0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+       0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+       0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+       0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+       0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+       0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+       0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+       0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+       0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+       0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+       0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+       0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+       0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+       0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+       0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+       0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+       0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+       0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+       0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+       0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+       0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+       0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+       0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+       0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+       0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+       0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+       0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+       0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+       0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+       0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+       0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+       0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+       0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+       0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+       0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+       0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+       0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+       0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+       0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+       0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+       0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+       0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+       0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+       0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+       0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+       0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+       0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+       0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+       0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+       0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+       0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+       0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+       0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+       0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+       0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+       0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+       0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+       0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+       0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+       0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+       0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+       0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+       0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+       0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+       0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+       0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+       0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+       0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+       0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+       0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+       0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+       0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+       0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+       0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+       0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+       0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+       0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+       0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+       0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+       0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+       0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+       0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+       0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+       0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+       0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+       0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+       0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+       0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+       0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+       0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+       0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+       0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+       0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+       0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+       0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+       0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+       0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+       0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+       0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+       0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+       0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+       0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+       0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+       0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+       0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+       0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+       0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+       0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+       0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+       0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+       0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+       0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+       0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+       0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+       0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+       0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+       0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+       0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+       0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+       0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+       0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+       0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+       0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+       0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+       0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+       0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+       0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+       0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+       0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+       0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+       0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+       0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+       0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+       0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+       0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+       0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+       0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+       0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+       0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+       0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+       0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+       0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+       0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+       0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+       0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+       0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+       0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+       0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+       0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+       0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+       0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+       0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+       0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+       0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+       0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+       0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+       0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+       0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+       0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+       0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+       0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+       0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+       0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+       0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+       0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+       0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/KernelLand/Kernel/drv/vterm_input.c b/KernelLand/Kernel/drv/vterm_input.c
new file mode 100644 (file)
index 0000000..d83cede
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_input.c
+ * - Virtual Terminal - Input code
+ */
+#include "vterm.h"
+#include <api_drv_keyboard.h>
+
+// === GLOBALS ===
+// --- Key States --- (Used for VT Switching/Magic Combos)
+ int   gbVT_CtrlDown = 0;
+ int   gbVT_AltDown = 0;
+ int   gbVT_SysrqDown = 0;
+
+// === CODE ===
+/**
+ * \fn void VT_InitInput()
+ * \brief Initialises the input
+ */
+void VT_InitInput()
+{
+       giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
+       if(giVT_InputDevHandle == -1) {
+               Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice);
+               return ;
+       }
+       VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
+}
+
+/**
+ * \fn void VT_KBCallBack(Uint32 Codepoint)
+ * \brief Called on keyboard interrupt
+ * \param Codepoint    Pseudo-UTF32 character
+ * 
+ * Handles a key press and sends the key code to the user's buffer.
+ * If the code creates a kernel-magic sequence, it is not passed to the
+ * user and is handled in-kernel.
+ */
+void VT_KBCallBack(Uint32 Codepoint)
+{
+       tVTerm  *term = gpVT_CurTerm;
+
+       // Catch VT binds
+       switch( Codepoint & KEY_ACTION_MASK )
+       {
+       case KEY_ACTION_RELEASE:
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               case KEY_LALT:  gbVT_AltDown &= ~1;     break;
+               case KEY_RALT:  gbVT_AltDown &= ~2;     break;
+               case KEY_LCTRL: gbVT_CtrlDown &= ~1;    break;
+               case KEY_RCTRL: gbVT_CtrlDown &= ~2;    break;
+               }
+               break;
+       
+       case KEY_ACTION_PRESS:
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               case KEY_LALT:  gbVT_AltDown |= 1;      break;
+               case KEY_RALT:  gbVT_AltDown |= 2;      break;
+               case KEY_LCTRL: gbVT_CtrlDown |= 1;     break;
+               case KEY_RCTRL: gbVT_CtrlDown |= 2;     break;
+               }
+               
+               if(!gbVT_AltDown || !gbVT_CtrlDown)
+                       break;
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               case KEY_F1:    VT_SetTerminal(0);      return;
+               case KEY_F2:    VT_SetTerminal(1);      return;
+               case KEY_F3:    VT_SetTerminal(2);      return;
+               case KEY_F4:    VT_SetTerminal(3);      return;
+               case KEY_F5:    VT_SetTerminal(4);      return;
+               case KEY_F6:    VT_SetTerminal(5);      return;
+               case KEY_F7:    VT_SetTerminal(6);      return;
+               case KEY_F8:    VT_SetTerminal(7);      return;
+               case KEY_F9:    VT_SetTerminal(8);      return;
+               case KEY_F10:   VT_SetTerminal(9);      return;
+               case KEY_F11:   VT_SetTerminal(10);     return;
+               case KEY_F12:   VT_SetTerminal(11);     return;
+               }
+               
+               // Scrolling is only valid in text mode
+               if(gpVT_CurTerm->Mode != TERM_MODE_TEXT)
+                       break;
+               
+               switch(Codepoint & KEY_CODEPOINT_MASK)
+               {
+               // Scrolling
+               case KEY_PGUP:
+                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
+                               return ;
+                       gpVT_CurTerm->ViewPos = MAX(
+                               0,
+                               gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width
+                               );
+                       return;
+               case KEY_PGDOWN:
+                       if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
+                               return ;
+                       gpVT_CurTerm->ViewPos = MIN(
+                               gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width,
+                               gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback
+                               );
+                       return;
+               }
+               break;
+       }
+       
+       // Encode key
+       if(term->Mode == TERM_MODE_TEXT)
+       {
+               Uint8   buf[6] = {0};
+                int    len = 0;
+       
+               // Ignore anything that isn't a press or refire
+               if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
+                && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
+                   )
+               {
+                       return ;
+               }
+       
+               Codepoint &= KEY_CODEPOINT_MASK;
+
+               // Ignore Modifer Keys
+               if(Codepoint > KEY_MODIFIERS)   return;
+               
+               // Get UTF-8/ANSI Encoding
+               switch(Codepoint)
+               {
+               // 0: No translation, don't send to user
+               case 0: break;
+               case KEY_LEFT:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
+                       len = 3;
+                       break;
+               case KEY_RIGHT:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
+                       len = 3;
+                       break;
+               case KEY_UP:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
+                       len = 3;
+                       break;
+               case KEY_DOWN:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
+                       len = 3;
+                       break;
+               
+               case KEY_PGUP:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
+                       len = 4;
+                       break;
+               case KEY_PGDOWN:
+                       buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
+                       len = 4;
+                       break;
+               
+               // Attempt to encode in UTF-8
+               default:
+                       len = WriteUTF8( buf, Codepoint );
+                       if(len == 0) {
+                               Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
+                       }
+                       break;
+               }
+               
+               if(len == 0) {
+                       // Unprintable / Don't Pass
+                       return;
+               }
+
+#if 0
+               // Handle meta characters
+               if( !(term->Flags & VT_FLAG_RAWIN) )
+               {
+                       switch(buf[0])
+                       {
+                       case '\3':      // ^C
+                               
+                               break;
+                       }
+               }
+#endif
+               
+               // Write
+               if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
+                       memcpy( &term->InputBuffer[term->InputWrite], buf, len );
+               else {
+                       memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
+                       memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
+               }
+               // Roll the buffer over
+               term->InputWrite += len;
+               term->InputWrite %= MAX_INPUT_CHARS8;
+               if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
+                       term->InputRead = term->InputWrite + 1;
+                       term->InputRead %= MAX_INPUT_CHARS8;
+               }
+       }
+       else
+       {
+               // Encode the raw key event
+               Uint32  *raw_in = (void*)term->InputBuffer;
+       
+               #if 0
+               // Drop new keys
+               if( term->InputWrite == term->InputRead )
+                       return ;                
+               #endif
+
+               raw_in[ term->InputWrite ] = Codepoint;
+               term->InputWrite ++;
+               if(term->InputWrite >= MAX_INPUT_CHARS32)
+                       term->InputWrite -= MAX_INPUT_CHARS32;
+               
+               #if 1
+               // TODO: Should old or new be dropped?
+               if(term->InputRead == term->InputWrite) {
+                       term->InputRead ++;
+                       if( term->InputRead >= MAX_INPUT_CHARS32 )
+                               term->InputRead -= MAX_INPUT_CHARS32;
+               }
+               #endif
+       }
+       
+       VFS_MarkAvaliable(&term->Node, 1);
+}
+
diff --git a/KernelLand/Kernel/drv/vterm_output.c b/KernelLand/Kernel/drv/vterm_output.c
new file mode 100644 (file)
index 0000000..95a2bce
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_input.c
+ * - Virtual Terminal - Input code
+ */
+#include "vterm.h"
+#include <api_drv_video.h>
+
+// === CODE ===
+/**
+ * \fn void VT_InitOutput()
+ * \brief Initialise Video Output
+ */
+void VT_InitOutput()
+{
+       giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
+       if(giVT_OutputDevHandle == -1) {
+               Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
+               return ;
+       }
+       VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
+       VT_SetTerminal( 0 );
+       VT_SetMode( VIDEO_BUFFMT_TEXT );
+}
+
+/**
+ * \brief Set video output buffer mode
+ */
+void VT_SetMode(int Mode)
+{
+       VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode );
+}
+
+/**
+ * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
+ * \note Scrolls the framebuffer down by \a Count text lines
+ */
+void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
+{
+        int    tmp;
+       struct {
+               Uint8   Op;
+               Uint16  DstX, DstY;
+               Uint16  SrcX, SrcY;
+               Uint16  W, H;
+       } PACKED        buf;
+       
+       // Only update if this is the current terminal
+       if( Term != gpVT_CurTerm )      return;
+       
+       if( Count > Term->ScrollHeight )        Count = Term->ScrollHeight;
+       if( Count < -Term->ScrollHeight )       Count = -Term->ScrollHeight;
+       
+       // Switch to 2D Command Stream
+       tmp = VIDEO_BUFFMT_2DSTREAM;
+       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
+       
+       // BLIT to 0,0 from 0,giVT_CharHeight
+       buf.Op = VIDEO_2DOP_BLIT;
+       buf.SrcX = 0;   buf.DstX = 0;
+       // TODO: Don't assume character dimensions
+       buf.W = Term->TextWidth * giVT_CharWidth;
+       if( Count > 0 )
+       {
+               buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
+               buf.DstY = Term->ScrollTop * giVT_CharHeight;
+       }
+       else    // Scroll up, move text down
+       {
+               Count = -Count;
+               buf.SrcY = Term->ScrollTop * giVT_CharHeight;
+               buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
+       }
+       buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
+       VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
+       
+       // Restore old mode (this function is only called during text mode)
+       tmp = VIDEO_BUFFMT_TEXT;
+       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
+}
+
+void VT_int_UpdateCursor( tVTerm *Term, int bShow )
+{
+       tVideo_IOCtl_Pos        csr_pos;
+
+       if( Term != gpVT_CurTerm )      return ;
+
+       if( !bShow )
+       {
+               csr_pos.x = -1; 
+               csr_pos.y = -1; 
+       }
+       else if( Term->Mode == TERM_MODE_TEXT )
+       {
+                int    offset;
+               
+//             if( !(Term->Flags & VT_FLAG_SHOWCSR)
+//              && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads)
+//               )
+               if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR )
+               {
+                       csr_pos.x = -1;
+                       csr_pos.y = -1;
+               }
+               else
+               {
+                       if(Term->Flags & VT_FLAG_ALTBUF)
+                               offset = Term->AltWritePos;
+                       else
+                               offset = Term->WritePos - Term->ViewPos;
+                                       
+                       csr_pos.x = offset % Term->TextWidth;
+                       csr_pos.y = offset / Term->TextWidth;
+                       if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight )
+                               csr_pos.y = -1, csr_pos.x = -1;
+               }
+       }
+       else
+       {
+               csr_pos.x = Term->VideoCursorX;
+               csr_pos.y = Term->VideoCursorY;
+       }
+       VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
+}      
+
+/**
+ * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+ * \brief Updates the video framebuffer
+ */
+void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+{
+       tVT_Char        *buffer;
+        int    view_pos, write_pos;
+       // Only update if this is the current terminal
+       if( Term != gpVT_CurTerm )      return;
+       
+       switch( Term->Mode )
+       {
+       case TERM_MODE_TEXT:
+               view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos;
+               write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
+               buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
+               // Re copy the entire screen?
+               if(UpdateAll) {
+                       VFS_WriteAt(
+                               giVT_OutputDevHandle,
+                               0,
+                               Term->TextWidth*Term->TextHeight*sizeof(tVT_Char),
+                               &buffer[view_pos]
+                               );
+               }
+               // Only copy the current line
+               else {
+                        int    ofs = write_pos - write_pos % Term->TextWidth;
+                       VFS_WriteAt(
+                               giVT_OutputDevHandle,
+                               (ofs - view_pos)*sizeof(tVT_Char),
+                               Term->TextWidth*sizeof(tVT_Char),
+                               &buffer[ofs]
+                               );
+               }
+               break;
+       case TERM_MODE_FB:
+               break;
+       }
+       
+       VT_int_UpdateCursor(Term, 1);
+}
+
diff --git a/KernelLand/Kernel/drv/vterm_termbuf.c b/KernelLand/Kernel/drv/vterm_termbuf.c
new file mode 100644 (file)
index 0000000..2511048
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_termbuf.c
+ * - Virtual Terminal - Terminal buffer manipulation
+ */
+#include "vterm.h"
+
+// === CODE ===
+
+/**
+ * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
+ * \brief Print a string to the Virtual Terminal
+ */
+void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
+{
+       Uint32  val;
+        int    i;
+       
+       // Iterate
+       for( i = 0; i < Count; i++ )
+       {
+               // Handle escape sequences
+               if( Buffer[i] == 0x1B )
+               {
+                       i ++;
+                       i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
+                       continue;
+               }
+               
+               // Fast check for non UTF-8
+               if( Buffer[i] < 128 )   // Plain ASCII
+                       VT_int_PutChar(Term, Buffer[i]);
+               else {  // UTF-8
+                       i += ReadUTF8(&Buffer[i], &val) - 1;
+                       VT_int_PutChar(Term, val);
+               }
+       }
+       // Update Screen
+       VT_int_UpdateScreen( Term, 0 );
+}
+
+/**
+ * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
+ * \brief Write a single character to a VTerm
+ */
+void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
+{
+        int    i;
+       tVT_Char        *buffer;
+        int    write_pos;
+       
+       if(Term->Flags & VT_FLAG_ALTBUF) {
+               buffer = Term->AltBuf;
+               write_pos = Term->AltWritePos;
+       }
+       else {
+               buffer = Term->Text;
+               write_pos = Term->WritePos;
+       }
+       
+       switch(Ch)
+       {
+       case '\0':      return; // Ignore NULL byte
+       case '\n':
+               VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
+               write_pos += Term->TextWidth;
+       case '\r':
+               write_pos -= write_pos % Term->TextWidth;
+               break;
+       
+       case '\t': { int tmp = write_pos / Term->TextWidth;
+               write_pos %= Term->TextWidth;
+               do {
+                       buffer[ write_pos ].Ch = '\0';
+                       buffer[ write_pos ].Colour = Term->CurColour;
+                       write_pos ++;
+               } while(write_pos & 7);
+               write_pos += tmp * Term->TextWidth;
+               break; }
+       
+       case '\b':
+               // Backspace is invalid at Offset 0
+               if(write_pos == 0)      break;
+               
+               write_pos --;
+               // Singe Character
+               if(buffer[ write_pos ].Ch != '\0') {
+                       buffer[ write_pos ].Ch = 0;
+                       buffer[ write_pos ].Colour = Term->CurColour;
+                       break;
+               }
+               // Tab
+               i = 7;  // Limit it to 8
+               do {
+                       buffer[ write_pos ].Ch = 0;
+                       buffer[ write_pos ].Colour = Term->CurColour;
+                       write_pos --;
+               } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
+               if(buffer[ write_pos ].Ch != '\0')
+                       write_pos ++;
+               break;
+       
+       default:
+               buffer[ write_pos ].Ch = Ch;
+               buffer[ write_pos ].Colour = Term->CurColour;
+               // Update the line before wrapping
+               if( (write_pos + 1) % Term->TextWidth == 0 )
+                       VT_int_UpdateScreen( Term, 0 );
+               write_pos ++;
+               break;
+       }
+       
+       if(Term->Flags & VT_FLAG_ALTBUF)
+       {
+               Term->AltBuf = buffer;
+               Term->AltWritePos = write_pos;
+               
+               if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
+               {
+                       Term->AltWritePos -= Term->TextWidth;
+                       VT_int_ScrollText(Term, 1);
+               }
+               
+       }
+       else
+       {
+               Term->Text = buffer;
+               Term->WritePos = write_pos;
+               // Move Screen
+               // - Check if we need to scroll the entire scrollback buffer
+               if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
+               {
+                        int    base;
+                       
+                       // Update previous line
+                       Term->WritePos -= Term->TextWidth;
+                       VT_int_UpdateScreen( Term, 0 );
+                       
+                       // Update view position
+                       base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
+                       if(Term->ViewPos < base)
+                               Term->ViewPos += Term->Width;
+                       if(Term->ViewPos > base)
+                               Term->ViewPos = base;
+                       
+                       VT_int_ScrollText(Term, 1);
+               }
+               // Ok, so we only need to scroll the screen
+               else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
+               {
+                       // Update the last line
+                       Term->WritePos -= Term->TextWidth;
+                       VT_int_UpdateScreen( Term, 0 );
+                       Term->WritePos += Term->TextWidth;
+                       
+                       VT_int_ScrollText(Term, 1);
+                       
+                       Term->ViewPos += Term->TextWidth;
+               }
+       }
+       
+       //LEAVE('-');
+}
+
+void VT_int_ScrollText(tVTerm *Term, int Count)
+{
+       tVT_Char        *buf;
+        int    height, init_write_pos;
+        int    len, i;
+        int    scroll_top, scroll_height;
+
+       // Get buffer pointer and attributes    
+       if( Term->Flags & VT_FLAG_ALTBUF )
+       {
+               buf = Term->AltBuf;
+               height = Term->TextHeight;
+               init_write_pos = Term->AltWritePos;
+               scroll_top = Term->ScrollTop;
+               scroll_height = Term->ScrollHeight;
+       }
+       else
+       {
+               buf = Term->Text;
+               height = Term->TextHeight*(giVT_Scrollback+1);
+               init_write_pos = Term->WritePos;
+               scroll_top = 0;
+               scroll_height = height;
+       }
+
+       // Scroll text downwards        
+       if( Count > 0 )
+       {
+                int    base;
+       
+               // Set up
+               if(Count > scroll_height)       Count = scroll_height;
+               base = Term->TextWidth*(scroll_top + scroll_height - Count);
+               len = Term->TextWidth*(scroll_height - Count);
+               
+               // Scroll terminal cache
+               memmove(
+                       &buf[Term->TextWidth*scroll_top],
+                       &buf[Term->TextWidth*(scroll_top+Count)],
+                       len*sizeof(tVT_Char)
+                       );
+               // Clear last rows
+               for( i = 0; i < Term->TextWidth*Count; i ++ )
+               {
+                       buf[ base + i ].Ch = 0;
+                       buf[ base + i ].Colour = Term->CurColour;
+               }
+               
+               // Update Screen
+               VT_int_ScrollFramebuffer( Term, Count );
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       Term->AltWritePos = base;
+               else
+                       Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
+               for( i = 0; i < Count; i ++ )
+               {
+                       VT_int_UpdateScreen( Term, 0 );
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                               Term->AltWritePos += Term->TextWidth;
+                       else
+                               Term->WritePos += Term->TextWidth;
+               }
+       }
+       else
+       {
+               Count = -Count;
+               if(Count > scroll_height)       Count = scroll_height;
+               
+               len = Term->TextWidth*(scroll_height - Count);
+               
+               // Scroll terminal cache
+               memmove(
+                       &buf[Term->TextWidth*(scroll_top+Count)],
+                       &buf[Term->TextWidth*scroll_top],
+                       len*sizeof(tVT_Char)
+                       );
+               // Clear preceding rows
+               for( i = 0; i < Term->TextWidth*Count; i ++ )
+               {
+                       buf[ i ].Ch = 0;
+                       buf[ i ].Colour = Term->CurColour;
+               }
+               
+               VT_int_ScrollFramebuffer( Term, -Count );
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       Term->AltWritePos = Term->TextWidth*scroll_top;
+               else
+                       Term->WritePos = Term->ViewPos;
+               for( i = 0; i < Count; i ++ )
+               {
+                       VT_int_UpdateScreen( Term, 0 );
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                               Term->AltWritePos += Term->TextWidth;
+                       else
+                               Term->WritePos += Term->TextWidth;
+               }
+       }
+       
+       if( Term->Flags & VT_FLAG_ALTBUF )
+               Term->AltWritePos = init_write_pos;
+       else
+               Term->WritePos = init_write_pos;
+}
+
+/**
+ * \brief Clears a line in a virtual terminal
+ * \param Term Terminal to modify
+ * \param Num  Line number to clear
+ */
+void VT_int_ClearLine(tVTerm *Term, int Num)
+{
+        int    i;
+       tVT_Char        *cell;
+       
+       if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
+       
+       cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
+       cell = &cell[ Num*Term->TextWidth ];
+       
+       for( i = Term->TextWidth; i--; )
+       {
+               cell[ i ].Ch = 0;
+               cell[ i ].Colour = Term->CurColour;
+       }
+}
+
+/**
+ * \brief Update the screen mode
+ * \param Term Terminal to update
+ * \param NewMode      New mode to set
+ * \param NewWidth     New framebuffer width
+ * \param NewHeight    New framebuffer height
+ */
+void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
+{
+        int    oldW = Term->Width;
+        int    oldTW = Term->TextWidth;
+        int    oldH = Term->Height;
+        int    oldTH = Term->TextHeight;
+       tVT_Char        *oldTBuf = Term->Text;
+       Uint32  *oldFB = Term->Buffer;
+        int    w, h, i;
+       
+       // TODO: Increase RealWidth/RealHeight when this happens
+       if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
+       if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
+       
+       Term->Mode = NewMode;
+
+       // Fast exit if no resolution change
+       if(NewWidth == Term->Width && NewHeight == Term->Height)
+               return ;
+       
+       // Calculate new dimensions
+       Term->Width = NewWidth;
+       Term->Height = NewHeight;
+       Term->TextWidth = NewWidth / giVT_CharWidth;
+       Term->TextHeight = NewHeight / giVT_CharHeight;
+       Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
+       
+       // Allocate new buffers
+       // - Text
+       Term->Text = calloc(
+               Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
+               sizeof(tVT_Char)
+               );
+       if(oldTBuf) {
+               // Copy old buffer
+               w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
+               h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
+               h *= giVT_Scrollback + 1;
+               for( i = 0; i < h; i ++ )
+               {
+                       memcpy(
+                               &Term->Text[i*Term->TextWidth],
+                               &oldTBuf[i*oldTW],
+                               w*sizeof(tVT_Char)
+                               );      
+               }
+               free(oldTBuf);
+       }
+       
+       // - Alternate Text
+       Term->AltBuf = realloc(
+               Term->AltBuf,
+               Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
+               );
+       
+       // - Framebuffer
+       if(oldFB) {
+               Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
+               // Copy old buffer
+               w = (oldW > Term->Width) ? Term->Width : oldW;
+               h = (oldH > Term->Height) ? Term->Height : oldH;
+               for( i = 0; i < h; i ++ )
+               {
+                       memcpy(
+                               &Term->Buffer[i*Term->Width],
+                               &oldFB[i*oldW],
+                               w*sizeof(Uint32)
+                               );
+               }
+               free(oldFB);
+       }
+       
+       // Debug
+       switch(NewMode)
+       {
+       case TERM_MODE_TEXT:
+               Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
+                       Term, Term->TextWidth, Term->TextHeight);
+               break;
+       case TERM_MODE_FB:
+               Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
+                       Term, Term->Width, Term->Height);
+               break;
+       //case TERM_MODE_2DACCEL:
+       //case TERM_MODE_3DACCEL:
+       //      return;
+       }
+}
+
+
+void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
+{      
+       if(Enabled)
+               Term->Flags |= VT_FLAG_ALTBUF;
+       else
+               Term->Flags &= ~VT_FLAG_ALTBUF;
+       VT_int_UpdateScreen(Term, 1);
+}
+
diff --git a/KernelLand/Kernel/drv/vterm_vt100.c b/KernelLand/Kernel/drv/vterm_vt100.c
new file mode 100644 (file)
index 0000000..fb152a3
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_vt100.c
+ * - Virtual Terminal - VT100 (Kinda) Emulation
+ */
+#include "vterm.h"
+
+// === CONSTANTS ===
+const Uint16   caVT100Colours[] = {
+               // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
+               // Same again, but bright
+               VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
+               VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
+       };
+
+// === CODE ===
+/**
+ * \brief Handle a standard large escape code
+ * 
+ * Handles any escape code of the form \x1B[n,...A where n is an integer
+ * and A is any letter.
+ */
+void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
+{
+        int    tmp = 1;
+       switch(CmdChar)
+       {
+       // Left
+       case 'D':
+               tmp = -1;
+       // Right
+       case 'C':
+               if(argc == 1)   tmp *= args[0];
+               if( Term->Flags & VT_FLAG_ALTBUF )
+               {
+                       if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
+                               Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
+                               Term->AltWritePos += Term->TextWidth - 1;
+                       }
+                       else
+                               Term->AltWritePos += tmp;
+               }
+               else
+               {
+                       if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
+                               Term->WritePos -= Term->WritePos % Term->TextWidth;
+                               Term->WritePos += Term->TextWidth - 1;
+                       }
+                       else
+                               Term->WritePos += tmp;
+               }
+               break;
+       
+       // Erase
+       case 'J':
+               switch(args[0])
+               {
+               case 0: // Erase below
+                       break;
+               case 1: // Erase above
+                       break;
+               case 2: // Erase all
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                                int    i = Term->TextHeight;
+                               while( i-- )    VT_int_ClearLine(Term, i);
+                               Term->AltWritePos = 0;
+                               VT_int_UpdateScreen(Term, 1);
+                       }
+                       else
+                       {
+                                int    i = Term->TextHeight * (giVT_Scrollback + 1);
+                               while( i-- )    VT_int_ClearLine(Term, i);
+                               Term->WritePos = 0;
+                               Term->ViewPos = 0;
+                               VT_int_UpdateScreen(Term, 1);
+                       }
+                       break;
+               }
+               break;
+       
+       // Erase in line
+       case 'K':
+               switch(args[0])
+               {
+               case 0: // Erase to right
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                                int    i, max;
+                               max = Term->Width - Term->AltWritePos % Term->Width;
+                               for( i = 0; i < max; i ++ )
+                                       Term->AltBuf[Term->AltWritePos+i].Ch = 0;
+                       }
+                       else
+                       {
+                                int    i, max;
+                               max = Term->Width - Term->WritePos % Term->Width;
+                               for( i = 0; i < max; i ++ )
+                                       Term->Text[Term->WritePos+i].Ch = 0;
+                       }
+                       VT_int_UpdateScreen(Term, 0);
+                       break;
+               case 1: // Erase to left
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                                int    i = Term->AltWritePos % Term->Width;
+                               while( i -- )
+                                       Term->AltBuf[Term->AltWritePos++].Ch = 0;
+                       }
+                       else
+                       {
+                                int    i = Term->WritePos % Term->Width;
+                               while( i -- )
+                                       Term->Text[Term->WritePos++].Ch = 0;
+                       }
+                       VT_int_UpdateScreen(Term, 0);
+                       break;
+               case 2: // Erase all
+                       if( Term->Flags & VT_FLAG_ALTBUF )
+                       {
+                               VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
+                       }
+                       else
+                       {
+                               VT_int_ClearLine(Term, Term->WritePos / Term->Width);
+                       }
+                       VT_int_UpdateScreen(Term, 0);
+                       break;
+               }
+               break;
+       
+       // Set cursor position
+       case 'H':
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
+               else
+                       Term->WritePos = args[0] + args[1]*Term->TextWidth;
+               //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
+               break;
+       
+       // Scroll up `n` lines
+       case 'S':
+               tmp = -1;
+       // Scroll down `n` lines
+       case 'T':
+               if(argc == 1)   tmp *= args[0];
+               if( Term->Flags & VT_FLAG_ALTBUF )
+                       VT_int_ScrollText(Term, tmp);
+               else
+               {
+                       if(Term->ViewPos/Term->TextWidth + tmp < 0)
+                               break;
+                       if(Term->ViewPos/Term->TextWidth + tmp  > Term->TextHeight * (giVT_Scrollback + 1))
+                               break;
+                       
+                       Term->ViewPos += Term->TextWidth*tmp;
+               }
+               break;
+       
+       // Set Font flags
+       case 'm':
+               for( ; argc--; )
+               {
+                        int    colour_idx;
+                       // Flags
+                       if( 0 <= args[argc] && args[argc] <= 8)
+                       {
+                               switch(args[argc])
+                               {
+                               case 0: Term->CurColour = DEFAULT_COLOUR;       break;  // Reset
+                               case 1: Term->CurColour |= 0x80000000;  break;  // Bright
+                               case 2: Term->CurColour &= ~0x80000000; break;  // Dim
+                               }
+                       }
+                       // Foreground Colour
+                       else if(30 <= args[argc] && args[argc] <= 37) {
+                               // Get colour index, accounting for bright bit
+                               colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
+                               Term->CurColour &= 0x8000FFFF;
+                               Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
+                       }
+                       // Background Colour
+                       else if(40 <= args[argc] && args[argc] <= 47) {
+                               // Get colour index, accounting for bright bit
+                               colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
+                               Term->CurColour &= 0xFFFF8000;
+                               Term->CurColour |= caVT100Colours[ colour_idx ];
+                       }
+                       else {
+                               Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
+                       }
+               }
+               break;
+       
+       // Set scrolling region
+       case 'r':
+               if( argc != 2 ) break;
+               Term->ScrollTop = args[0];
+               Term->ScrollHeight = args[1] - args[0];
+               break;
+       
+       default:
+               Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
+               break;
+       }
+}
+
+/**
+ * \fn int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
+ * \brief Parses a VT100 Escape code
+ */
+int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
+{
+       char    c;
+        int    argc = 0, j = 1;
+        int    args[6] = {0,0,0,0};
+        int    bQuestionMark = 0;
+       
+       switch(Buffer[0])
+       {
+       //Large Code
+       case '[':
+               // Get Arguments
+               c = Buffer[j++];
+               if(c == '?') {
+                       bQuestionMark = 1;
+                       c = Buffer[j++];
+               }
+               if( '0' <= c && c <= '9' )
+               {
+                       do {
+                               if(c == ';')    c = Buffer[j++];
+                               while('0' <= c && c <= '9') {
+                                       args[argc] *= 10;
+                                       args[argc] += c-'0';
+                                       c = Buffer[j++];
+                               }
+                               argc ++;
+                       } while(c == ';');
+               }
+               
+               // Get Command
+               if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+               {
+                       if( bQuestionMark )
+                       {
+                               switch(c)
+                               {
+                               // DEC Private Mode Set
+                               case 'h':
+                                       if(argc != 1)   break;
+                                       switch(args[0])
+                                       {
+                                       case 25:
+                                               Term->Flags &= ~VT_FLAG_HIDECSR;
+                                               break;
+                                       case 1047:
+                                               VT_int_ToggleAltBuffer(Term, 1);
+                                               break;
+                                       }
+                                       break;
+                               case 'l':
+                                       if(argc != 1)   break;
+                                       switch(args[0])
+                                       {
+                                       case 25:
+                                               Term->Flags |= VT_FLAG_HIDECSR;
+                                               break;
+                                       case 1047:
+                                               VT_int_ToggleAltBuffer(Term, 0);
+                                               break;
+                                       }
+                                       break;
+                               default:
+                                       Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
+                       }
+               }
+               break;
+               
+       default:
+               Log_Notice("VTerm", "TODO: Handle short escape codes");
+               break;
+       }
+       
+       //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
+       return j;
+}
diff --git a/KernelLand/Kernel/drvutil.c b/KernelLand/Kernel/drvutil.c
new file mode 100644 (file)
index 0000000..d19a050
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil.c
+ * - Common Driver/Filesystem Helper Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <api_drv_disk.h>
+#include <api_drv_video.h>
+
+// === TYPES ===
+
+// === PROTOTYPES ===
+//int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
+//size_t       DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
+//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
+//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
+void   DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
+//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
+void   DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
+void   DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
+
+// === GLOBALS ===
+tDrvUtil_Video_2DHandlers      gDrvUtil_Stub_2DFunctions = {
+       NULL,
+       DrvUtil_Video_2D_Fill,
+       DrvUtil_Video_2D_Blit
+};
+tVideo_IOCtl_Bitmap    gDrvUtil_TextModeCursor = {
+       8, 16,
+       0, 0,
+       {
+               0, 0, 0         , 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0, 0, 0         , 0, 0, 0, 0, 0,
+               0, 0, 0         , 0, 0, 0, 0, 0
+       }
+};
+
+// === CODE ===
+// --- Video Driver Helpers ---
+int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
+       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
+{
+       const Uint8     *stream = Buffer;
+        int    rem = Length;
+        int    op;
+       while( rem )
+       {
+               rem --;
+               op = *stream;
+               stream ++;
+               
+               if(op > NUM_VIDEO_2DOPS) {
+                       Log_Warning("DrvUtil",
+                               "DrvUtil_Video_2DStream: Unknown operation %i",
+                               op);
+                       return Length-rem;
+               }
+               
+               if(op*sizeof(void*) > SizeofHandlers) {
+                       Log_Warning("DrvUtil",
+                               "DrvUtil_Video_2DStream: Driver does not support op %i",
+                               op);
+                       return Length-rem;
+               }
+               
+               switch(op)
+               {
+               case VIDEO_2DOP_NOP:    break;
+               
+               case VIDEO_2DOP_FILL:
+                       if(rem < 10)    return Length-rem;
+                       
+                       if(!Handlers->Fill) {
+                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+                                       " does not support VIDEO_2DOP_FILL");
+                               return Length-rem;
+                       }
+                       
+                       Handlers->Fill(
+                               Ent,
+                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
+                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
+                               ((const Uint32*)stream)[4]
+                               );
+                       
+                       rem -= 10;
+                       stream += 10;
+                       break;
+               
+               case VIDEO_2DOP_BLIT:
+                       if(rem < 12)    return Length-rem;
+                       
+                       if(!Handlers->Blit) {
+                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+                                       " does not support VIDEO_2DOP_BLIT");
+                               return Length-rem;
+                       }
+                       
+                       Handlers->Blit(
+                               Ent,
+                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
+                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
+                               ((const Uint16*)stream)[4], ((const Uint16*)stream)[5]
+                               );
+                       
+                       rem -= 12;
+                       stream += 12;
+                       break;
+               
+               }
+       }
+       return 0;
+}
+
+int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
+{
+       Uint8   *dest;
+       const Uint32    *src = Buffer;
+        int    csr_x, csr_y;
+        int    x, y;
+        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
+       ENTER("pFBInfo xOffset xLength pBuffer",
+               Mode, FBInfo, Offset, Length, Buffer);
+
+       csr_x = FBInfo->CursorX;
+       csr_y = FBInfo->CursorY;
+
+       DrvUtil_Video_RemoveCursor(FBInfo);
+
+       switch( FBInfo->BufferFormat )
+       {
+       case VIDEO_BUFFMT_TEXT:
+               {
+               const tVT_Char  *chars = Buffer;
+                int    widthInChars = FBInfo->Width/giVT_CharWidth;
+                int    heightInChars = FBInfo->Height/giVT_CharHeight;
+                int    i;
+       
+               LOG("bytes_per_px = %i", bytes_per_px);
+               LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
+       
+               Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
+               
+               x = Offset % widthInChars;      y = Offset / widthInChars;
+               LOG("x = %i, y = %i", x, y);    
+       
+               // Sanity Check
+               if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
+               if(y >= heightInChars)  LEAVE_RET('i', 0);
+               
+               if( Offset + Length > heightInChars*widthInChars )
+               {
+                       Length = heightInChars*widthInChars - Offset;
+               }
+               
+               dest = FBInfo->Framebuffer;
+               LOG("dest = %p", dest);
+               dest += y * giVT_CharHeight * FBInfo->Pitch;
+               LOG("dest = %p", dest);
+               
+               for( i = 0; i < Length; i++ )
+               {
+                       if( y >= heightInChars )
+                       {
+                               Log_Notice("DrvUtil", "Stopped at %i", i);
+                               break;
+                       }
+
+                       VT_Font_Render(
+                               chars->Ch,
+                               dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
+                               VT_Colour12toN(chars->BGCol, FBInfo->Depth),
+                               VT_Colour12toN(chars->FGCol, FBInfo->Depth)
+                               );
+                       
+                       chars ++;
+                       x ++;
+                       if( x >= widthInChars )
+                       {
+                               x = 0;
+                               y ++;
+                               dest += FBInfo->Pitch*giVT_CharHeight;
+                               LOG("dest = %p", dest);
+                       }
+               }
+               Length = i * sizeof(tVT_Char);
+               }
+               break;
+       
+       case VIDEO_BUFFMT_FRAMEBUFFER:
+               if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
+               {
+                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
+                       return 0;
+               }
+               
+               switch(FBInfo->Depth)
+               {
+               case 15:
+               case 16:
+                       Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
+                       break;
+               case 24:
+                       x = Offset % FBInfo->Width;
+                       y = Offset / FBInfo->Width;
+                       dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
+                       for( ; Length >= 4; Length -= 4 )
+                       {
+                               dest[x*3+0] = *src & 0xFF;
+                               dest[x*3+1] = (*src >> 8) & 0xFF;
+                               dest[x*3+2] = (*src >> 16) & 0xFF;
+                               x ++;
+                               if(x == FBInfo->Width) {
+                                       dest += FBInfo->Pitch;
+                                       x = 0;
+                               }
+                       }
+                       break;
+               case 32:
+                       // Copy to Frambuffer
+                       if( FBInfo->Pitch != FBInfo->Width*4 )
+                       {
+                               Uint32  *px;
+                               // Pitch isn't 4*Width
+                               x = Offset % FBInfo->Width;
+                               y = Offset / FBInfo->Height;
+                               
+                               px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
+
+                               for( ; Length >= 4; Length -= 4, x )
+                               {
+                                       px[x++] = *src ++;
+                                       if( x == FBInfo->Width ) {
+                                               x = 0;
+                                               px += FBInfo->Pitch;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               dest = (Uint8 *)FBInfo->Framebuffer + Offset;
+                               memcpy(dest, Buffer, Length);
+                       }
+                       break;
+               default:
+                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
+                       break;
+               }
+               break;
+       
+       case VIDEO_BUFFMT_2DSTREAM:
+               Length = DrvUtil_Video_2DStream(
+                       FBInfo, Buffer, Length,
+                       &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
+                       );
+               break;
+       
+       default:
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
+
+       LEAVE('x', Length);
+       return Length;
+}
+
+int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
+{
+        int    csrX = Buf->CursorX, csrY = Buf->CursorY;
+       size_t  size;
+
+       // Clear old bitmap
+       if( Buf->CursorBitmap )
+       {
+               DrvUtil_Video_RemoveCursor(Buf);
+               if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
+               {
+                       free( Buf->CursorSaveBuf );
+                       Buf->CursorSaveBuf = NULL;
+               }
+               if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
+                       free(Buf->CursorBitmap);
+               Buf->CursorBitmap = NULL;
+       }
+       
+       // If the new bitmap is null, disable drawing
+       if( !Bitmap )
+       {
+               Buf->CursorX = -1;
+               Buf->CursorY = -1;
+               return 0;
+       }
+
+       // Sanity check the bitmap
+       if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
+       {
+               Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
+               errno = -EINVAL;
+               return -1;
+       }
+
+       // Don't take a copy of the DrvUtil provided cursor
+       if( Bitmap == &gDrvUtil_TextModeCursor )
+       {
+               Buf->CursorBitmap = Bitmap;
+       }
+       else
+       {
+               size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
+               
+               // Take a copy
+               Buf->CursorBitmap = malloc( size );
+               memcpy(Buf->CursorBitmap, Bitmap, size);
+       }
+       
+       // Restore cursor position
+       DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
+       return 0;
+}
+
+void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
+{
+        int    render_ox=0, render_oy=0, render_w, render_h;
+
+       DrvUtil_Video_RemoveCursor(Buf);
+
+       // X < 0 disables the cursor
+       if( X < 0 ) {
+               Buf->CursorX = -1;
+               return ;
+       }
+
+       // Sanity checking
+       if( X < 0 || Y < 0 )    return;
+       if( X >= Buf->Width || Y >= Buf->Height )       return;
+
+       // Ensure the cursor is enabled
+       if( !Buf->CursorBitmap )        return ;
+       
+       // Save cursor position (for changing the bitmap)
+       Buf->CursorX = X;       Buf->CursorY = Y;
+
+       // Apply cursor's center offset
+       X -= Buf->CursorBitmap->XOfs;
+       Y -= Buf->CursorBitmap->YOfs;
+       
+       // Get the width of the cursor on screen (clipping to right/bottom edges)
+       render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
+       render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
+
+       // Clipp to left/top edges
+       if(X < 0) {     render_ox = -X; X = 0;  }
+       if(Y < 0) {     render_oy = -Y; Y = 0;  }
+
+       // Save values
+       Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
+       Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
+       Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
+
+       // Call render routine
+       DrvUtil_Video_RenderCursor(Buf);
+}
+
+void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+        int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
+        int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
+        int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
+        int    bytes_per_px = (Buf->Depth + 7) / 8;
+        int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       void    *dest;
+       Uint32  *src;
+        int    x, y;
+
+       dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
+       src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
+       
+       // Allocate save buffer if not already
+       if( !Buf->CursorSaveBuf )
+               Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
+
+       // Save behind the cursor
+       for( y = 0; y < render_h; y ++ )
+               memcpy(
+                       (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
+                       (Uint8*)dest + y*Buf->Pitch,
+                       render_w*bytes_per_px
+                       );
+
+       // Draw the cursor
+       switch(Buf->Depth)
+       {
+       case 15:
+       case 16:
+               Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
+               break;
+       case 24:
+               for( y = 0; y < render_h; y ++ )
+               {
+                       Uint8   *px;
+                       px = dest;
+                       for(x = 0; x < render_w; x ++, px += 3)
+                       {
+                               Uint32  value = src[x];
+                               // TODO: Should I implement alpha blending?
+                               if(value & 0xFF000000)
+                               {
+                                       px[0] = value & 0xFF;
+                                       px[1] = (value >> 8) & 0xFF;
+                                       px[2] = (value >> 16) & 0xFF;
+                               }
+                               else
+                                       ;
+                       }
+                       src += Buf->CursorBitmap->W;
+                       dest = (Uint8*)dest + Buf->Pitch;
+               }
+               break;
+       case 32:
+               for( y = 0; y < render_h; y ++ )
+               {
+                       Uint32  *px;
+                       px = dest;
+                       for(x = 0; x < render_w; x ++, px ++)
+                       {
+                               Uint32  value = src[x];
+                               // TODO: Should I implement alpha blending?
+                               if(value & 0xFF000000)
+                                       *px = value;
+                               else
+                                       ;       // NOP, completely transparent
+                       }
+                       src += Buf->CursorBitmap->W;
+                       dest = (Uint8*)dest + Buf->Pitch;
+               }
+               break;
+       default:
+               Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
+               Buf->CursorX = -1;
+               break;
+       }
+}
+
+void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+        int    bytes_per_px = (Buf->Depth + 7) / 8;
+        int    y, save_pitch;
+       Uint8   *dest, *src;
+
+       // Just a little sanity
+       if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
+       if( !Buf->CursorSaveBuf )       return ;
+
+//     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
+
+       // Set up
+       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
+       src = Buf->CursorSaveBuf;
+       
+       // Copy each line back
+       for( y = 0; y < Buf->CursorRenderH; y ++ )
+       {
+               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
+               src += save_pitch;
+               dest += Buf->Pitch;
+       }
+       
+       // Set the cursor as removed
+       Buf->CursorX = -1;
+}
+
+void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
+{
+       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
+
+       // TODO: Handle non-32bit modes
+       if( FBInfo->Depth != 32 )       return;
+
+       // TODO: Be less hacky
+        int    pitch = FBInfo->Pitch/4;
+       Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
+       while( H -- ) {
+               Uint32 *tmp;
+                int    i;
+               tmp = buf;
+               for(i=W;i--;tmp++)      *tmp = Colour;
+               buf += pitch;
+       }
+}
+
+void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
+{
+       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
+        int    scrnpitch = FBInfo->Pitch;
+        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
+        int    dst = DstY*scrnpitch + DstX;
+        int    src = SrcY*scrnpitch + SrcX;
+        int    tmp;
+       
+       //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
+       //      Ent, DstX, DstY, SrcX, SrcY, W, H);
+       
+       if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
+       if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
+       if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
+       if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
+       
+       //Debug("W = %i, H = %i", W, H);
+       
+       if( dst > src ) {
+               // Reverse copy
+               dst += H*scrnpitch;
+               src += H*scrnpitch;
+               while( H -- ) {
+                       dst -= scrnpitch;
+                       src -= scrnpitch;
+                       tmp = W*bytes_per_px;
+                       for( tmp = W; tmp --; ) {
+                               *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
+                       }
+               }
+       }
+       else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
+               memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
+       }
+       else {
+               // Normal copy is OK
+               while( H -- ) {
+                       memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
+                       dst += scrnpitch;
+                       src += scrnpitch;
+               }
+       }
+       //Log("Vesa_2D_Blit: RETURN");
+}
+       
+
+// --- Disk Driver Helpers ---
+Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
+{
+       Uint8   tmp[BlockSize]; // C99
+       Uint64  block = Start / BlockSize;
+        int    offset = Start - block * BlockSize;
+        int    leading = BlockSize - offset;
+       Uint64  num;
+        int    tailings;
+       Uint64  ret;
+       
+       ENTER("XStart XLength pBuffer pReadBlocks XBlockSize xArgument",
+               Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
+       
+       // Non aligned start, let's fix that!
+       if(offset != 0)
+       {
+               if(leading > Length)    leading = Length;
+               LOG("Reading %i bytes from Block1+%i", leading, offset);
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               memcpy( Buffer, &tmp[offset], leading );
+               
+               if(leading == Length) {
+                       LEAVE('i', leading);
+                       return leading;
+               }
+               
+               Buffer = (Uint8*)Buffer + leading;
+               block ++;
+               num = ( Length - leading ) / BlockSize;
+               tailings = Length - num * BlockSize - leading;
+       }
+       else {
+               num = Length / BlockSize;
+               tailings = Length % BlockSize;
+       }
+       
+       // Read central blocks
+       if(num)
+       {
+               LOG("Reading %i blocks", num);
+               ret = ReadBlocks(block, num, Buffer, Argument);
+               if(ret != num ) {
+                       LEAVE('X', leading + ret * BlockSize);
+                       return leading + ret * BlockSize;
+               }
+       }
+       
+       // Read last tailing block
+       if(tailings != 0)
+       {
+               LOG("Reading %i bytes from last block", tailings);
+               block += num;
+               Buffer = (Uint8*)Buffer + num * BlockSize;
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               memcpy( Buffer, tmp, tailings );
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
+
+Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
+       Uint64 BlockSize, Uint Argument)
+{
+       Uint8   tmp[BlockSize]; // C99
+       Uint64  block = Start / BlockSize;
+        int    offset = Start - block * BlockSize;
+        int    leading = BlockSize - offset;
+       Uint64  num;
+        int    tailings;
+       Uint64  ret;
+       
+       ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize xArgument",
+               Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
+       
+       // Non aligned start, let's fix that!
+       if(offset != 0)
+       {
+               if(leading > Length)    leading = Length;
+               LOG("Writing %i bytes to Block1+%i", leading, offset);
+               // Read a copy of the block
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               // Modify
+               memcpy( &tmp[offset], Buffer, leading );
+               // Write Back
+               ret = WriteBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               
+               if(leading == Length) {
+                       LEAVE('i', leading);
+                       return leading;
+               }
+               
+               Buffer = (Uint8*)Buffer + leading;
+               block ++;
+               num = ( Length - leading ) / BlockSize;
+               tailings = Length - num * BlockSize - leading;
+       }
+       else {
+               num = Length / BlockSize;
+               tailings = Length % BlockSize;
+       }
+       
+       // Read central blocks
+       if(num)
+       {
+               LOG("Writing %i blocks", num);
+               ret = WriteBlocks(block, num, Buffer, Argument);
+               if(ret != num ) {
+                       LEAVE('X', leading + ret * BlockSize);
+                       return leading + ret * BlockSize;
+               }
+       }
+       
+       // Read last tailing block
+       if(tailings != 0)
+       {
+               LOG("Writing %i bytes to last block", tailings);
+               block += num;
+               Buffer = (Uint8*)Buffer + num * BlockSize;
+               // Read
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               // Modify
+               memcpy( tmp, Buffer, tailings );
+               // Write
+               ret = WriteBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
diff --git a/KernelLand/Kernel/events.c b/KernelLand/Kernel/events.c
new file mode 100644 (file)
index 0000000..a9eab78
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * events.c
+ * - Thread level event handling
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <threads_int.h>
+#include <events.h>
+
+// === CODE ===
+void Threads_PostEvent(tThread *Thread, Uint32 EventMask)
+{
+       // Sanity checking
+       if( !Thread )   return ;
+       if( EventMask == 0 )    return ;
+       // TODO: Check that only one bit is set?
+       
+       ENTER("pThread xEventMask", Thread, EventMask);
+
+       SHORTLOCK( &Thread->IsLocked );
+
+       Thread->EventState |= EventMask;
+       LOG("Thread->EventState = 0x%x", Thread->EventState);
+       
+       // Currently sleeping on an event?
+       if( Thread->Status == THREAD_STAT_EVENTSLEEP )
+       {
+               // Waiting on this event?
+               if( (Uint32)Thread->RetStatus & EventMask )
+               {
+                       // Wake up
+                       LOG("Waking thread %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
+                       Threads_AddActive(Thread);
+               }
+       }
+       
+       SHORTREL( &Thread->IsLocked );
+       LEAVE('-');
+}
+
+/**
+ * \brief Wait for an event to occur
+ */
+Uint32 Threads_WaitEvents(Uint32 EventMask)
+{
+       Uint32  rv;
+       tThread *us = Proc_GetCurThread();
+
+       ENTER("xEventMask", EventMask);
+
+       // Early return check
+       if( EventMask == 0 )
+       {
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       LOG("us = %p(%i %s)", us, us->TID, us->ThreadName);
+
+       // Check if a wait is needed
+       SHORTLOCK( &us->IsLocked );
+       while( !(us->EventState & EventMask) )
+       {
+               LOG("Locked and preparing for wait");
+               // Wait
+               us->RetStatus = EventMask;      // HACK: Store EventMask in RetStatus
+               SHORTLOCK( &glThreadListLock );
+               us = Threads_RemActive();
+               us->Status = THREAD_STAT_EVENTSLEEP;
+               // Note stored anywhere because we're woken using other means
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &us->IsLocked );
+               while(us->Status == THREAD_STAT_EVENTSLEEP)     Threads_Yield();
+               // Woken when lock is acquired
+               SHORTLOCK( &us->IsLocked );
+       }
+       
+       // Get return value and clear changed event bits
+       rv = us->EventState & EventMask;
+       us->EventState &= ~EventMask;
+       
+       SHORTREL( &us->IsLocked );
+       
+       LEAVE('x', rv);
+       return rv;
+}
+
diff --git a/KernelLand/Kernel/heap.c b/KernelLand/Kernel/heap.c
new file mode 100644 (file)
index 0000000..eefd13c
--- /dev/null
@@ -0,0 +1,753 @@
+/*
+ * AcessOS Microkernel Version
+ * heap.c
+ */
+#include <acess.h>
+#include <mm_virt.h>
+#include <heap_int.h>
+
+#define WARNINGS       1
+#define        DEBUG_TRACE     0
+#define        VERBOSE_DUMP    0
+
+// === CONSTANTS ===
+#define        HEAP_INIT_SIZE  0x8000  // 32 KiB
+#define        MIN_SIZE        (sizeof(void*))*8       // 8 Machine Words
+#define        POW2_SIZES      0
+#define        COMPACT_HEAP    0       // Use 4 byte header?
+#define        FIRST_FIT       0
+
+//#define      MAGIC_FOOT      0x2ACE5505
+//#define      MAGIC_FREE      0xACE55000
+//#define      MAGIC_USED      0x862B0505      // MAGIC_FOOT ^ MAGIC_FREE
+#define        MAGIC_FOOT      0x544F4F46      // 'FOOT'
+#define        MAGIC_FREE      0x45455246      // 'FREE'
+#define        MAGIC_USED      0x44455355      // 'USED'
+
+// === PROTOTYPES ===
+void   Heap_Install(void);
+void   *Heap_Extend(int Bytes);
+void   *Heap_Merge(tHeapHead *Head);
+//void *Heap_Allocate(const char *File, int Line, size_t Bytes);
+//void *Heap_AllocateZero(const char *File, int Line, size_t Bytes);
+//void *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes);
+//void Heap_Deallocate(void *Ptr);
+void   Heap_Dump(void);
+void   Heap_Stats(void);
+
+// === GLOBALS ===
+tMutex glHeap;
+void   *gHeapStart;
+void   *gHeapEnd;
+
+// === CODE ===
+void Heap_Install(void)
+{
+       gHeapStart      = (void*)MM_KHEAP_BASE;
+       gHeapEnd        = (void*)MM_KHEAP_BASE;
+       Heap_Extend(HEAP_INIT_SIZE);
+}
+
+/**
+ * \brief Extend the size of the heap
+ */
+void *Heap_Extend(int Bytes)
+{
+       Uint    i;
+       tHeapHead       *head = gHeapEnd;
+       tHeapFoot       *foot;
+       
+       // Bounds Check
+       if( (tVAddr)gHeapEnd == MM_KHEAP_MAX )
+               return NULL;
+       
+       if( Bytes == 0 ) {
+               Log_Warning("Heap", "Heap_Extend called with Bytes=%i", Bytes);
+               return NULL;
+       }
+       
+       // Bounds Check
+       if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
+//             Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
+               return NULL;
+       }
+       
+       // Heap expands in pages
+       for( i = 0; i < (Bytes+0xFFF) >> 12; i ++ )
+       {
+               if( !MM_Allocate( (tVAddr)gHeapEnd+(i<<12) ) )
+               {
+                       Warning("OOM - Heap_Extend");
+                       return NULL;
+               }
+       }
+       
+       // Increas heap end
+       gHeapEnd = (Uint8*)gHeapEnd + (i << 12);
+       
+       // Create Block
+       head->Size = (Bytes+0xFFF)&~0xFFF;
+       head->Magic = MAGIC_FREE;
+       foot = (void*)( (Uint)gHeapEnd - sizeof(tHeapFoot) );
+       foot->Head = head;
+       foot->Magic = MAGIC_FOOT;
+       
+       return Heap_Merge(head);        // Merge with previous block
+}
+
+/**
+ * \brief Merges two ajacent heap blocks
+ */
+void *Heap_Merge(tHeapHead *Head)
+{
+       tHeapFoot       *foot;
+       tHeapFoot       *thisFoot;
+       tHeapHead       *head;
+       
+       //Log("Heap_Merge: (Head=%p)", Head);
+       
+       thisFoot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
+       if((Uint)thisFoot > (Uint)gHeapEnd)     return NULL;
+       
+       // Merge Left (Down)
+       foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
+       if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
+       && foot->Head->Magic == MAGIC_FREE) {
+               foot->Head->Size += Head->Size; // Increase size
+               thisFoot->Head = foot->Head;    // Change backlink
+               Head->Magic = 0;        // Clear old head
+               Head->Size = 0;
+               Head = foot->Head;      // Save new head address
+               foot->Head = NULL;      // Clear central footer
+               foot->Magic = 0;
+       }
+       
+       // Merge Right (Upwards)
+       head = (void*)( (Uint)Head + Head->Size );
+       if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
+       {
+               Head->Size += head->Size;
+               foot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
+               foot->Head = Head;      // Update Backlink
+               thisFoot->Head = NULL;  // Clear old footer
+               thisFoot->Magic = 0;
+               head->Size = 0;         // Clear old header
+               head->Magic = 0;
+       }
+       
+       // Return new address
+       return Head;
+}
+
+/**
+ * \param File Allocating source file
+ * \param Line Source line
+ * \param __Bytes      Size of region to allocate
+ */
+void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
+{
+       tHeapHead       *head, *newhead;
+       tHeapFoot       *foot, *newfoot;
+       tHeapHead       *best = NULL;
+       Uint    bestSize = 0;   // Speed hack
+       size_t  Bytes;
+
+       if( __Bytes == 0 ) {
+               //return NULL;  // TODO: Return a known un-mapped range.
+               return INVLPTR;
+       }
+       
+       // Get required size
+       #if POW2_SIZES
+       Bytes = __Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot);
+       Bytes = 1UUL << LOG2(__Bytes);
+       #else
+       Bytes = (__Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + MIN_SIZE-1) & ~(MIN_SIZE-1);
+       #endif
+       
+       // Lock Heap
+       Mutex_Acquire(&glHeap);
+       
+       // Traverse Heap
+       for( head = gHeapStart;
+               (Uint)head < (Uint)gHeapEnd;
+               head = (void*)((Uint)head + head->Size)
+               )
+       {
+               // Alignment Check
+               #if POW2_SIZES
+               if( head->Size != 1UUL << LOG2(head->Size) ) {
+               #else
+               if( head->Size & (MIN_SIZE-1) ) {
+               #endif
+                       Mutex_Release(&glHeap); // Release spinlock
+                       #if WARNINGS
+                       Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
+                       Heap_Dump();
+                       #endif
+                       return NULL;
+               }
+               
+               // Check if allocated
+               if(head->Magic == MAGIC_USED)   continue;
+               // Error check
+               if(head->Magic != MAGIC_FREE)   {
+                       Mutex_Release(&glHeap); // Release spinlock
+                       #if WARNINGS
+                       Log_Warning("Heap", "Magic of heap address %p is invalid (%p = 0x%x)",
+                               head, &head->Magic, head->Magic);
+                       Heap_Dump();
+                       #endif
+                       return NULL;
+               }
+               
+               // Size check
+               if(head->Size < Bytes)  continue;
+               
+               // Perfect fit
+               if(head->Size == Bytes) {
+                       head->Magic = MAGIC_USED;
+                       head->File = File;
+                       head->Line = Line;
+                       head->ValidSize = __Bytes;
+                       head->AllocateTime = now();
+                       Mutex_Release(&glHeap); // Release spinlock
+                       #if DEBUG_TRACE
+                       Debug("[Heap   ] Malloc'd %p (%i bytes), returning to %p",
+                               head->Data, head->Size,  __builtin_return_address(0));
+                       #endif
+                       return head->Data;
+               }
+               
+               // Break out of loop
+               #if FIRST_FIT
+               best = head;
+               bestSize = head->Size;
+               break;
+               #else
+               // or check if the block is the best size
+               if(bestSize > head->Size) {
+                       best = head;
+                       bestSize = head->Size;
+               }
+               #endif
+       }
+       
+       // If no block large enough is found, create one
+       if(!best)
+       {
+               best = Heap_Extend( Bytes );
+               // Check for errors
+               if(!best) {
+                       Mutex_Release(&glHeap); // Release spinlock
+                       return NULL;
+               }
+               // Check size
+               if(best->Size == Bytes) {
+                       best->Magic = MAGIC_USED;       // Mark block as used
+                       best->File = File;
+                       best->Line = Line;
+                       best->ValidSize = __Bytes;
+                       best->AllocateTime = now();
+                       Mutex_Release(&glHeap); // Release spinlock
+                       #if DEBUG_TRACE
+                       Debug("[Heap   ] Malloc'd %p (%i bytes), returning to %s:%i", best->Data, best->Size, File, Line);
+                       #endif
+                       return best->Data;
+               }
+       }
+       
+       // Split Block
+       newhead = (void*)( (Uint)best + Bytes );
+       newfoot = (void*)( (Uint)best + Bytes - sizeof(tHeapFoot) );
+       foot = (void*)( (Uint)best + best->Size - sizeof(tHeapFoot) );
+       
+       newfoot->Head = best;   // Create new footer
+       newfoot->Magic = MAGIC_FOOT;
+       newhead->Size = best->Size - Bytes;     // Create new header
+       newhead->Magic = MAGIC_FREE;
+       foot->Head = newhead;   // Update backlink in old footer
+       best->Size = Bytes;             // Update size in old header
+       best->ValidSize = __Bytes;
+       best->Magic = MAGIC_USED;       // Mark block as used
+       best->File = File;
+       best->Line = Line;
+       best->AllocateTime = now();
+       
+       Mutex_Release(&glHeap); // Release spinlock
+       #if DEBUG_TRACE
+       Debug("[Heap   ] Malloc'd %p (0x%x bytes), returning to %s:%i",
+               best->Data, best->Size, File, Line);
+       #endif
+       return best->Data;
+}
+
+/**
+ * \brief Free an allocated memory block
+ */
+void Heap_Deallocate(void *Ptr)
+{
+       tHeapHead       *head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
+       tHeapFoot       *foot;
+       
+       // INVLPTR is returned from Heap_Allocate when the allocation
+       // size is zero.
+       if( Ptr == INVLPTR )    return;
+       
+       #if DEBUG_TRACE
+       Debug("[Heap   ] free: %p freed by %p (%i old)", Ptr, __builtin_return_address(0), now()-head->AllocateTime);
+       #endif
+       
+       // Alignment Check
+       if( (Uint)Ptr & (sizeof(Uint)-1) ) {
+               Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
+               return;
+       }
+       
+       // Sanity check
+       if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
+       {
+               Log_Warning("Heap", "free - Passed a non-heap address by %p (%p < %p < %p)\n",
+                       __builtin_return_address(0), gHeapStart, Ptr, gHeapEnd);
+               return;
+       }
+       
+       // Check memory block - Header
+       head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
+       if(head->Magic == MAGIC_FREE) {
+               Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
+               return;
+       }
+       if(head->Magic != MAGIC_USED) {
+               Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)", head, head->Magic);
+               Log_Notice("Heap", "Allocated by %s:%i", head->File, head->Line);
+               return;
+       }
+       
+       // Check memory block - Footer
+       foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
+       if(foot->Head != head) {
+               Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)", head, foot->Head);
+               Log_Notice("Heap", "Allocated by %s:%i", head->File, head->Line);
+               return;
+       }
+       if(foot->Magic != MAGIC_FOOT) {
+               Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)", head, &foot->Magic, foot->Magic);
+               Log_Notice("Heap", "Allocated by %s:%i", head->File, head->Line);
+               return;
+       }
+       
+       // Lock
+       Mutex_Acquire( &glHeap );
+       
+       // Mark as free
+       head->Magic = MAGIC_FREE;
+       //head->File = NULL;
+       //head->Line = 0;
+       head->ValidSize = 0;
+       // Merge blocks
+       Heap_Merge( head );
+       
+       // Release
+       Mutex_Release( &glHeap );
+}
+
+/**
+ * \brief Increase/Decrease the size of an allocation
+ * \param File Calling File
+ * \param Line Calling Line
+ * \param __ptr        Old memory
+ * \param __size       New Size
+ */
+void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
+{
+       tHeapHead       *head = (void*)( (Uint)__ptr-sizeof(tHeapHead) );
+       tHeapHead       *nextHead;
+       tHeapFoot       *foot;
+       Uint    newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+MIN_SIZE-1)&~(MIN_SIZE-1);
+       
+       // Check for reallocating NULL
+       if(__ptr == NULL)       return Heap_Allocate(File, Line, __size);
+       
+       // Check if resize is needed
+       if(newSize <= head->Size)       return __ptr;
+       
+       // Check if next block is free
+       nextHead = (void*)( (Uint)head + head->Size );
+       
+       // Extend into next block
+       if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
+       {
+               Uint    size = nextHead->Size + head->Size;
+               foot = (void*)( (Uint)nextHead + nextHead->Size - sizeof(tHeapFoot) );
+               // Exact Fit
+               if(size == newSize) {
+                       head->Size = newSize;
+                       head->ValidSize = __size;
+                       head->File = File;
+                       head->Line = Line;
+                       foot->Head = head;
+                       nextHead->Magic = 0;
+                       nextHead->Size = 0;
+                       return __ptr;
+               }
+               // Create a new heap block
+               nextHead = (void*)( (Uint)head + newSize );
+               nextHead->Size = size - newSize;
+               nextHead->Magic = MAGIC_FREE;
+               foot->Head = nextHead;  // Edit 2nd footer
+               head->Size = newSize;   // Edit first header
+               head->File = File;
+               head->Line = Line;
+               head->ValidSize = __size;
+               // Create new footer
+               foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) );
+               foot->Head = head;
+               foot->Magic = MAGIC_FOOT;
+               return __ptr;
+       }
+       
+       // Extend downwards?
+       foot = (void*)( (Uint)head - sizeof(tHeapFoot) );
+       nextHead = foot->Head;
+       if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
+       {
+               Uint    size = nextHead->Size + head->Size;
+               // Inexact fit, split things up
+               if(size > newSize)
+               {
+                       // TODO
+                       Warning("[Heap   ] TODO: Space efficient realloc when new size is smaller");
+               }
+               
+               // Exact fit
+               if(size >= newSize)
+               {
+                       Uint    oldDataSize;
+                       // Set 1st (new/lower) header
+                       nextHead->Magic = MAGIC_USED;
+                       nextHead->Size = newSize;
+                       nextHead->File = File;
+                       nextHead->Line = Line;
+                       nextHead->ValidSize = __size;
+                       // Get 2nd (old) footer
+                       foot = (void*)( (Uint)nextHead + newSize );
+                       foot->Head = nextHead;
+                       // Save old data size
+                       oldDataSize = head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead);
+                       // Clear old header
+                       head->Size = 0;
+                       head->Magic = 0;
+                       // Copy data
+                       memcpy(nextHead->Data, __ptr, oldDataSize);
+                       // Return
+                       return nextHead->Data;
+               }
+               // On to the expensive then
+       }
+       
+       // Well, darn
+       nextHead = Heap_Allocate( File, Line, __size );
+       nextHead -= 1;
+       nextHead->File = File;
+       nextHead->Line = Line;
+       nextHead->ValidSize = __size;
+       
+       memcpy(
+               nextHead->Data,
+               __ptr,
+               head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead)
+               );
+       
+       free(__ptr);
+       
+       return nextHead->Data;
+}
+
+/**
+ * \fn void *Heap_AllocateZero(const char *File, int Line, size_t Bytes)
+ * \brief Allocate and Zero a buffer in memory
+ * \param File Allocating file
+ * \param Line Line of allocation
+ * \param Bytes        Size of the allocation
+ */
+void *Heap_AllocateZero(const char *File, int Line, size_t Bytes)
+{
+       void    *ret = Heap_Allocate(File, Line, Bytes);
+       if(ret == NULL) return NULL;
+       
+       memset( ret, 0, Bytes );
+       
+       return ret;
+}
+
+/**
+ * \fn int Heap_IsHeapAddr(void *Ptr)
+ * \brief Checks if an address is a heap pointer
+ */
+int Heap_IsHeapAddr(void *Ptr)
+{
+       tHeapHead       *head;
+       if((Uint)Ptr < (Uint)gHeapStart)        return 0;
+       if((Uint)Ptr > (Uint)gHeapEnd)  return 0;
+       if((Uint)Ptr & (sizeof(Uint)-1))        return 0;
+       
+       head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
+       if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
+               return 0;
+       
+       return 1;
+}
+
+/**
+ */
+void Heap_Validate(void)
+{
+       Heap_Dump();
+}
+
+#if WARNINGS
+void Heap_Dump(void)
+{
+       tHeapHead       *head, *badHead;
+       tHeapFoot       *foot = NULL;
+       
+       head = gHeapStart;
+       while( (Uint)head < (Uint)gHeapEnd )
+       {               
+               foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
+               #if VERBOSE_DUMP
+               Log_Log("Heap", "%p (0x%P): 0x%08x (%i) %4C",
+                       head, MM_GetPhysAddr((tVAddr)head), head->Size, head->ValidSize, &head->Magic);
+               Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
+               if(head->File) {
+                       Log_Log("Heap", "%sowned by %s:%i",
+                               (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line);
+               }
+               #endif
+               
+               // Sanity Check Header
+               if(head->Size == 0) {
+                       Log_Warning("Heap", "HALTED - Size is zero");
+                       break;
+               }
+               if(head->Size & (MIN_SIZE-1)) {
+                       Log_Warning("Heap", "HALTED - Size is malaligned");
+                       break;
+               }
+               if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
+                       Log_Warning("Heap", "HALTED - Head Magic is Bad");
+                       break;
+               }
+               
+               // Check footer
+               if(foot->Magic != MAGIC_FOOT) {
+                       Log_Warning("Heap", "HALTED - Foot Magic is Bad");
+                       break;
+               }
+               if(head != foot->Head) {
+                       Log_Warning("Heap", "HALTED - Footer backlink is invalid");
+                       break;
+               }
+               
+               #if VERBOSE_DUMP
+               Log_Log("Heap", "");
+               #endif
+               
+               // All OK? Go to next
+               head = foot->NextHead;
+       }
+       
+       // If the heap is valid, ok!
+       if( (tVAddr)head == (tVAddr)gHeapEnd )
+               return ;
+       
+       // Check for a bad return
+       if( (tVAddr)head >= (tVAddr)gHeapEnd )
+               return ;
+
+       #if !VERBOSE_DUMP
+       Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
+               head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
+       if(foot)
+               Log_Log("Heap", "Foot %p = {Head:%p,Magic:%4C}", foot, foot->Head, &foot->Magic);
+       if(head->File) {
+               Log_Log("Heap", "%sowned by %s:%i",
+                       (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line);
+       }
+       Log_Log("Heap", "");
+       #endif
+       
+       
+       badHead = head;
+       
+       // Work backwards
+       foot = (void*)( (tVAddr)gHeapEnd - sizeof(tHeapFoot) );
+       Log_Log("Heap", "==== Going Backwards ==== (from %p)", foot);
+       head = foot->Head;
+       while( (tVAddr)head >= (tVAddr)badHead )
+       {
+               Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
+                       head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
+               Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
+               if(head->File)
+                       Log_Log("Heap", "%sowned by %s:%i",
+                               (head->Magic!=MAGIC_USED?"was ":""),
+                               head->File, head->Line);
+               Log_Log("Heap", "");
+               
+               // Sanity Check Header
+               if(head->Size == 0) {
+                       Log_Warning("Heap", "HALTED - Size is zero");
+                       break;
+               }
+               if(head->Size & (MIN_SIZE-1)) {
+                       Log_Warning("Heap", " - Size is malaligned (&0x%x)", ~(MIN_SIZE-1));
+                       break ;
+               }
+               if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
+                       Log_Warning("Heap", "HALTED - Head Magic is Bad");
+                       break;
+               }
+               
+               // Check footer
+               if(foot->Magic != MAGIC_FOOT) {
+                       Log_Warning("Heap", "HALTED - Foot Magic is Bad");
+                       break;
+               }
+               if(head != foot->Head) {
+                       Log_Warning("Heap", "HALTED - Footer backlink is invalid");
+                       break;
+               }
+               
+               if(head == badHead)     break;
+               
+               foot = (void*)( (tVAddr)head - sizeof(tHeapFoot) );
+               head = foot->Head;
+               Log_Debug("Heap", "head=%p", head);
+       }
+       
+       Panic("Heap_Dump - Heap is corrupted, kernel panic!");
+}
+#endif
+
+#if 1
+void Heap_Stats(void)
+{
+       tHeapHead       *head;
+        int    nBlocks = 0;
+        int    nFree = 0;
+        int    totalBytes = 0;
+        int    freeBytes = 0;
+        int    maxAlloc=0, minAlloc=-1;
+        int    avgAlloc, frag, overhead;
+       
+       for(head = gHeapStart;
+               (Uint)head < (Uint)gHeapEnd;
+               head = (void*)( (Uint)head + head->Size )
+               )
+       {       
+               nBlocks ++;
+               totalBytes += head->Size;
+               if( head->Magic == MAGIC_FREE )
+               {
+                       nFree ++;
+                       freeBytes += head->Size;
+               }
+               else if( head->Magic == MAGIC_USED) {
+                       if(maxAlloc < head->Size)       maxAlloc = head->Size;
+                       if(minAlloc == -1 || minAlloc > head->Size)
+                               minAlloc = head->Size;
+               }
+               else {
+                       Log_Warning("Heap", "Magic on %p invalid, skipping remainder of heap", head);
+                       break;
+               }
+               
+               // Print the block info?
+               #if 1
+               if( head->Magic == MAGIC_FREE )
+                       Log_Debug("Heap", "%p (%P) - 0x%x free",
+                               head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size);
+               else
+                       Log_Debug("Heap", "%p (%P) - 0x%x (%i) Owned by %s:%i (%lli ms old)",
+                               head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size, head->ValidSize, head->File, head->Line,
+                               now() - head->AllocateTime
+                               );
+               #endif
+       }
+
+       Log_Log("Heap", "%i blocks (0x%x bytes)", nBlocks, totalBytes);
+       Log_Log("Heap", "%i free blocks (0x%x bytes)", nFree, freeBytes);
+       if(nBlocks != 0)
+               frag = (nFree-1)*10000/nBlocks;
+       else
+               frag = 0;
+       Log_Log("Heap", "%i.%02i%% Heap Fragmentation", frag/100, frag%100);
+       if(nBlocks <= nFree)
+               avgAlloc = 0;
+       else
+               avgAlloc = (totalBytes-freeBytes)/(nBlocks-nFree);
+       if(avgAlloc != 0)
+               overhead = (sizeof(tHeapFoot)+sizeof(tHeapHead))*10000/avgAlloc;
+       else
+               overhead = 0;
+       Log_Log("Heap", "Average allocation: %i bytes, Average Overhead: %i.%02i%%",
+               avgAlloc, overhead/100, overhead%100
+               );
+       Log_Log("Heap", "Smallest Block: %i bytes, Largest: %i bytes", 
+               minAlloc, maxAlloc);
+       
+       // Scan and get distribution
+       #if 1
+       if(nBlocks > 0)
+       {
+               struct {
+                       Uint    Size;
+                       Uint    Count;
+               }       sizeCounts[nBlocks];
+                int    i;
+               
+               memset(sizeCounts, 0, nBlocks*sizeof(sizeCounts[0]));
+               
+               for(head = gHeapStart;
+                       (Uint)head < (Uint)gHeapEnd;
+                       head = (void*)( (Uint)head + head->Size )
+                       )
+               {
+                       for( i = 0; i < nBlocks; i ++ ) {
+                               if( sizeCounts[i].Size == 0 )
+                                       break;
+                               if( sizeCounts[i].Size == head->Size )
+                                       break;
+                       }
+                       // Should never reach this part (in a non-concurrent case)
+                       if( i == nBlocks )      continue;
+                       sizeCounts[i].Size = head->Size;
+                       sizeCounts[i].Count ++;
+                       #if 1
+                       //Log("Heap_Stats: %i %p - 0x%x bytes (%s) (%i)", nBlocks, head,
+                       //      head->Size, (head->Magic==MAGIC_FREE?"FREE":"used"), i
+                       //      );
+                       //Log("Heap_Stats: sizeCounts[%i] = {Size:0x%x, Count: %i}", i,
+                       //      sizeCounts[i].Size, sizeCounts[i].Count);
+                       #endif
+               }
+               
+               for( i = 0; i < nBlocks && sizeCounts[i].Count; i ++ )
+               {
+                       Log("Heap_Stats: 0x%x - %i blocks",
+                               sizeCounts[i].Size, sizeCounts[i].Count
+                               );
+               }
+       }
+       #endif
+}
+#endif
+
+// === EXPORTS ===
+EXPORT(Heap_Allocate);
+EXPORT(Heap_AllocateZero);
+EXPORT(Heap_Reallocate);
+EXPORT(Heap_Deallocate);
+EXPORT(Heap_IsHeapAddr);
diff --git a/KernelLand/Kernel/include/acess.h b/KernelLand/Kernel/include/acess.h
new file mode 100644 (file)
index 0000000..2cd2cff
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * AcessOS Microkernel Version
+ * acess.h
+ */
+#ifndef _ACESS_H
+#define _ACESS_H
+/**
+ * \file acess.h
+ * \brief Acess2 Kernel API Core
+ */
+
+//! NULL Pointer
+#define NULL   ((void*)0)
+//! Pack a structure
+#define PACKED __attribute__((packed))
+//! Mark a function as not returning
+#define NORETURN       __attribute__((noreturn))
+//! Mark a parameter as unused
+#define UNUSED(x)      UNUSED_##x __attribute__((unused))
+//! Get the offset of a member in a structure
+#define offsetof(st, m) ((Uint)((char *)&((st *)(0))->m - (char *)0 ))
+
+/**
+ * \name Boolean constants
+ * \{
+ */
+#define TRUE   1
+#define FALSE  0
+/**
+ * \}
+ */
+
+#include <arch.h>
+#include <stdarg.h>
+#include "errno.h"
+
+// --- Types ---
+typedef Uint32 tPID;   //!< Process ID type
+typedef Uint32 tTID;   //!< Thread ID Type
+typedef Uint32 tUID;   //!< User ID Type
+typedef Uint32 tGID;   //!< Group ID Type
+typedef Sint64 tTimestamp;     //!< Timestamp (miliseconds since 00:00 1 Jan 1970)
+typedef Sint64 tTime;  //!< Same again
+typedef struct sShortSpinlock  tShortSpinlock; //!< Opaque (kinda) spinlock
+typedef int    bool;   //!< Boolean type
+
+// --- Helper Macros ---
+/**
+ * \name Helper Macros
+ * \{
+ */
+#define        CONCAT(x,y) x ## y
+#define EXPAND_CONCAT(x,y) CONCAT(x,y)
+#define STR(x) #x
+#define EXPAND_STR(x) STR(x)
+
+extern char    __buildnum[];
+#define BUILD_NUM      ((int)(Uint)&__buildnum)
+extern const char gsGitHash[];
+
+#define VER2(major,minor)      ((((major)&0xFF)<<8)|((minor)&0xFF))
+/**
+ * \}
+ */
+
+//! \brief Error number
+#define errno  (*Threads_GetErrno())
+
+// === CONSTANTS ===
+// --- Memory Flags --
+/**
+ * \name Memory Flags
+ * \{
+ * \todo Move to mm_virt.h
+ */
+#define        MM_PFLAG_RO             0x01    // Writes disallowed
+#define        MM_PFLAG_EXEC   0x02    // Allow execution
+#define        MM_PFLAG_NOPAGE 0x04    // Prevent from being paged out
+#define        MM_PFLAG_COW    0x08    // Copy-On-Write
+#define        MM_PFLAG_KERNEL 0x10    // Kernel-Only (Ring0)
+/**
+ * \}
+ */
+// --- Interface Flags & Macros
+/**
+ * \name Flags for Proc_Clone
+ * \{
+ */
+//! Clone the entire process
+#define CLONE_VM       0x10
+//! Don't copy user pages
+#define CLONE_NOUSER   0x20
+/**
+ * \}
+ */
+
+// === Types ===
+/**
+ * \brief Thread root function
+ * 
+ * Function pointer prototype of a thread entrypoint. When it
+ * returns, Threads_Exit is called
+ */
+typedef void (*tThreadFunction)(void*);
+
+// === Kernel Export Macros ===
+/**
+ * \name Kernel exports
+ * \{
+ */
+//! Kernel symbol definition
+typedef struct sKernelSymbol {
+       const char      *Name;  //!< Symbolic name
+       tVAddr  Value;  //!< Value of the symbol
+} tKernelSymbol;
+//! Export a pointer symbol (function/array)
+#define        EXPORT(_name)   tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (tVAddr)_name}
+//! Export a variable
+#define        EXPORTV(_name)  tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (tVAddr)&_name}
+//! Export a symbol under another name
+#define        EXPORTAS(_sym,_name)    tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (tVAddr)_sym}
+/**
+ * \}
+ */
+
+// === FUNCTIONS ===
+// --- IRQs ---
+/**
+ * \name IRQ hander registration
+ * \{
+ */
+extern int     IRQ_AddHandler(int Num, void (*Callback)(int, void*), void *Ptr);
+extern void    IRQ_RemHandler(int Handle);
+/**
+ * \}
+ */
+
+// --- Logging ---
+/**
+ * \name Logging to kernel ring buffer
+ * \{
+ */
+extern void    Log_KernelPanic(const char *Ident, const char *Message, ...);
+extern void    Log_Panic(const char *Ident, const char *Message, ...);
+extern void    Log_Error(const char *Ident, const char *Message, ...);
+extern void    Log_Warning(const char *Ident, const char *Message, ...);
+extern void    Log_Notice(const char *Ident, const char *Message, ...);
+extern void    Log_Log(const char *Ident, const char *Message, ...);
+extern void    Log_Debug(const char *Ident, const char *Message, ...);
+/**
+ * \}
+ */
+
+// --- Debug ---
+/**
+ * \name Debugging and Errors
+ * \{
+ */
+extern void    Debug_KernelPanic(void);        //!< Initiate a kernel panic
+extern void    Panic(const char *Msg, ...);    //!< Print a panic message (initiates a kernel panic)
+extern void    Warning(const char *Msg, ...);  //!< Print a warning message
+extern void    LogF(const char *Fmt, ...);     //!< Print a log message without a trailing newline
+extern void    Log(const char *Fmt, ...);      //!< Print a log message
+extern void    Debug(const char *Fmt, ...);    //!< Print a debug message (doesn't go to KTerm)
+extern void    LogV(const char *Fmt, va_list Args);    //!< va_list Log message
+extern void    Debug_Enter(const char *FuncName, const char *ArgTypes, ...);
+extern void    Debug_Log(const char *FuncName, const char *Fmt, ...);
+extern void    Debug_Leave(const char *FuncName, char RetType, ...);
+extern void    Debug_HexDump(const char *Header, const void *Data, Uint Length);
+#define UNIMPLEMENTED()        Warning("'%s' unimplemented", __func__)
+#if DEBUG
+# define ENTER(_types...)      Debug_Enter((char*)__func__, _types)
+# define LOG(_fmt...)  Debug_Log((char*)__func__, _fmt)
+# define LEAVE(_t...)  Debug_Leave((char*)__func__, _t)
+# define LEAVE_RET(_t,_v...)   do{LEAVE(_t,_v);return _v;}while(0)
+# define LEAVE_RET0()  do{LEAVE('-');return;}while(0)
+#else
+# define ENTER(...)
+# define LOG(...)
+# define LEAVE(...)
+# define LEAVE_RET(_t,_v...)   return (_v)
+# define LEAVE_RET0()  return
+#endif
+#if SANITY
+# define ASSERT(expr) do{if(!(expr))Panic("%s: Assertion '"#expr"' failed",(char*)__func__);}while(0)
+#else
+# define ASSERT(expr)
+#endif
+/**
+ * \}
+ */
+
+// --- IO ---
+#if NO_IO_BUS
+#define inb(a) (Log_Panic("Arch", STR(ARCHDIR)" does not support in*/out* (%s:%i)", __FILE__, __LINE__),0)
+#define inw(a) inb(a)
+#define ind(a) inb(a)
+#define inq(a) inb(a)
+#define outb(a,b)      inb(a)
+#define outw(a,b)      inb(a)
+#define outd(a,b)      inb(a)
+#define outq(a,b)      inb(a)
+#else
+/**
+ * \name I/O Memory Access
+ * \{
+ */
+extern void    outb(Uint16 Port, Uint8 Data);
+extern void    outw(Uint16 Port, Uint16 Data);
+extern void    outd(Uint16 Port, Uint32 Data);
+extern void    outq(Uint16 Port, Uint64 Data);
+extern Uint8   inb(Uint16 Port);
+extern Uint16  inw(Uint16 Port);
+extern Uint32  ind(Uint16 Port);
+extern Uint64  inq(Uint16 Port);
+/**
+ * \}
+ */
+#endif
+// --- Memory Management ---
+/**
+ * \name Memory Management
+ * \{
+ * \todo Move to mm_virt.h
+ */
+/**
+ * \brief Allocate a physical page at \a VAddr
+ * \param VAddr        Virtual Address to allocate at
+ * \return Physical address allocated
+ */
+extern tPAddr  MM_Allocate(tVAddr VAddr) __attribute__ ((warn_unused_result));
+/**
+ * \brief Deallocate a page
+ * \param VAddr        Virtual address to unmap
+ */
+extern void    MM_Deallocate(tVAddr VAddr);
+/**
+ * \brief Map a physical page at \a PAddr to \a VAddr
+ * \param VAddr        Target virtual address
+ * \param PAddr        Physical address to map
+ * \return Boolean Success
+ */
+extern int     MM_Map(tVAddr VAddr, tPAddr PAddr);
+/**
+ * \brief Get the physical address of \a Addr
+ * \param Addr Address of the page to get the physical address of
+ * \return Physical page mapped at \a Addr
+ */
+extern tPAddr  MM_GetPhysAddr(tVAddr Addr);
+/**
+ * \brief Set the access flags on a page
+ * \param VAddr        Virtual address of the page
+ * \param Flags New flags value
+ * \param Mask Flags to set
+ */
+extern void    MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask);
+/**
+ * \brief Get the flags on a flag
+ * \param VAddr        Virtual address of page
+ * \return Flags value of the page
+ */
+extern Uint    MM_GetFlags(tVAddr VAddr);
+/**
+ * \brief Checks is a memory range is user accessable
+ * \param VAddr        Base address to check
+ * \return 1 if the memory is all user-accessable, 0 otherwise
+ */
+#define MM_IsUser(VAddr)       (!(MM_GetFlags((VAddr))&MM_PFLAG_KERNEL))
+/**
+ * \brief Temporarily map a page into the address space
+ * \param PAddr        Physical addres to map
+ * \return Virtual address of page in memory
+ * \note There is only a limited ammount of slots avaliable
+ */
+extern tVAddr  MM_MapTemp(tPAddr PAddr);
+/**
+ * \brief Free a temporarily mapped page
+ * \param VAddr        Allocate virtual addres of page
+ */
+extern void    MM_FreeTemp(tVAddr VAddr);
+/**
+ * \brief Map a physcal address range into the virtual address space
+ * \param PAddr        Physical address to map in
+ * \param Number       Number of pages to map
+ */
+extern tVAddr  MM_MapHWPages(tPAddr PAddr, Uint Number);
+/**
+ * \brief Allocates DMA physical memory
+ * \param Pages        Number of pages required
+ * \param MaxBits      Maximum number of bits the physical address can have
+ * \param PhysAddr     Pointer to the location to place the physical address allocated
+ * \return Virtual address allocate
+ */
+extern tVAddr  MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr);
+/**
+ * \brief Unmaps an allocated hardware range
+ * \param VAddr        Virtual address allocate by ::MM_MapHWPages or ::MM_AllocDMA
+ * \param Number       Number of pages to free
+ */
+extern void    MM_UnmapHWPages(tVAddr VAddr, Uint Number);
+/**
+ * \brief Allocate a single physical page
+ * \return Physical address allocated
+ */
+extern tPAddr  MM_AllocPhys(void);
+/**
+ * \brief Allocate a contiguous range of physical pages
+ * \param Pages        Number of pages to allocate
+ * \param MaxBits      Maximum number of address bits allowed
+ * \return First physical address allocated
+ */
+extern tPAddr  MM_AllocPhysRange(int Pages, int MaxBits);
+/**
+ * \brief Reference a physical page
+ * \param PAddr        Page to mark as referenced
+ */
+extern void    MM_RefPhys(tPAddr PAddr);
+/**
+ * \brief Dereference a physical page
+ * \param PAddr        Page to dereference
+ */
+extern void    MM_DerefPhys(tPAddr PAddr);
+/**
+ * \brief Get the number of times a page has been referenced
+ * \param PAddr        Address to check
+ * \return Reference count for the page
+ */
+extern int     MM_GetRefCount(tPAddr PAddr);
+/**
+ * \brief Set the node associated with a page
+ * \param PAddr        Physical address of page
+ * \param Node Node pointer (tVFS_Node)
+ * \return Boolean failure
+ * \retval 0   Success
+ * \retval 1   Page not allocated
+ */
+extern int     MM_SetPageNode(tPAddr PAddr, void *Node);
+/**
+ * \brief Get the node associated with a page
+ * \param PAddr        Physical address of page
+ * \param Node Node pointer (tVFS_Node) destination
+ * \return Boolean failure
+ * \retval 0   Success
+ * \retval 1   Page not allocated
+ */
+extern int     MM_GetPageNode(tPAddr PAddr, void **Node);
+/**
+ * \}
+ */
+
+// --- Memory Manipulation ---
+/**
+ * \name Memory Manipulation
+ * \{
+ */
+extern int     memcmp(const void *m1, const void *m2, size_t count);
+extern void    *memcpy(void *dest, const void *src, size_t count);
+extern void    *memcpyd(void *dest, const void *src, size_t count);
+extern void    *memmove(void *dest, const void *src, size_t len);
+extern void    *memset(void *dest, int val, size_t count);
+extern void    *memsetd(void *dest, Uint32 val, size_t count);
+/**
+ * \}
+ */
+/**
+ * \name Memory Validation
+ * \{
+ */
+extern int     CheckString(const char *String);
+extern int     CheckMem(const void *Mem, int Num);
+/**
+ * \}
+ */
+
+// --- Endianness ---
+/**
+ * \name Endianness Swapping
+ * \{
+ */
+#ifdef __BIG_ENDIAN__
+#define        LittleEndian16(_val)    SwapEndian16(_val)
+#define        LittleEndian32(_val)    SwapEndian32(_val)
+#define        BigEndian16(_val)       (_val)
+#define        BigEndian32(_val)       (_val)
+#else
+#define        LittleEndian16(_val)    (_val)
+#define        LittleEndian32(_val)    (_val)
+#define        BigEndian16(_val)       SwapEndian16(_val)
+#define        BigEndian32(_val)       SwapEndian32(_val)
+#endif
+extern Uint16  SwapEndian16(Uint16 Val);
+extern Uint32  SwapEndian32(Uint32 Val);
+/**
+ * \}
+ */
+
+// --- Strings ---
+/**
+ * \name Strings
+ * \{
+ */
+extern int     vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
+extern int     sprintf(char *__s, const char *__format, ...);
+extern size_t  strlen(const char *Str);
+extern char    *strcpy(char *__dest, const char *__src);
+extern char    *strncpy(char *__dest, const char *__src, size_t max);
+extern char    *strcat(char *__dest, const char *__src);
+extern char    *strncat(char *__dest, const char *__src, size_t n);
+extern int     strcmp(const char *__str1, const char *__str2);
+extern int     strncmp(const char *Str1, const char *Str2, size_t num);
+extern int     strucmp(const char *Str1, const char *Str2);
+// strdup macro is defined in heap.h
+extern char    *_strdup(const char *File, int Line, const char *Str);
+extern char    **str_split(const char *__str, char __ch);
+extern char    *strchr(const char *__s, int __c);
+extern int     strpos(const char *Str, char Ch);
+extern int     strpos8(const char *str, Uint32 search);
+extern void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
+extern int     atoi(const char *string);
+extern int     ParseInt(const char *string, int *Val);
+extern int     ReadUTF8(const Uint8 *str, Uint32 *Val);
+extern int     WriteUTF8(Uint8 *str, Uint32 Val);
+extern int     ModUtil_SetIdent(char *Dest, const char *Value);
+extern int     ModUtil_LookupString(const char **Array, const char *Needle);
+
+extern Uint8   ByteSum(const void *Ptr, int Size);
+extern int     Hex(char *Dest, size_t Size, const Uint8 *SourceData);
+extern int     UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
+/**
+ * \}
+ */
+
+/**
+ * \brief Get a random number
+ * \return Random number
+ * \note Current implementation is a linear congruency
+ */
+extern int     rand(void);
+/**
+ * \brief Call a function with a variable number of arguments
+ * \param Function     Function address
+ * \param NArgs        Number of entries in \a Args
+ * \param Args Array of arguments
+ * \return Integer from called Function
+ */
+extern int     CallWithArgArray(void *Function, int NArgs, Uint *Args);
+
+// --- Heap ---
+#include <heap.h>
+/**
+ * \brief Magic heap allocation function
+ */
+extern void    *alloca(size_t Size);
+
+// --- Modules ---
+/**
+ * \name Modules
+ * \{
+ */
+extern int     Module_LoadMem(void *Buffer, Uint Length, const char *ArgStr);
+extern int     Module_LoadFile(const char *Path, const char *ArgStr);
+/**
+ * \}
+ */
+
+// --- Timing ---
+/**
+ * \name Time and Timing
+ * \{
+ */
+/**
+ * \brief Create a timestamp from a time
+ */
+extern tTime   timestamp(int sec, int mins, int hrs, int day, int month, int year);
+/**
+ * \brief Extract the date/time from a timestamp
+ */
+extern void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+/**
+ * \brief Gets the current timestamp (miliseconds since Midnight 1st January 1970)
+ */
+extern Sint64  now(void);
+/**
+ * \}
+ */
+
+// --- Threads ---
+/**
+ * \name Threads and Processes
+ * \{
+ */
+extern int     Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
+extern int     Proc_Spawn(const char *Path);
+extern int     Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
+extern int     Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
+extern void    Threads_Exit(int TID, int Status);
+extern void    Threads_Yield(void);
+extern void    Threads_Sleep(void);
+extern int     Threads_WakeTID(tTID Thread);
+extern tPID    Threads_GetPID(void);
+extern tTID    Threads_GetTID(void);
+extern tUID    Threads_GetUID(void);
+extern tGID    Threads_GetGID(void);
+extern int     SpawnTask(tThreadFunction Function, void *Arg);
+extern int     *Threads_GetErrno(void);
+extern int     Threads_SetName(const char *NewName);
+/**
+ * \}
+ */
+
+// --- Simple Math ---
+//! Divide and round up
+extern int     DivUp(int num, int dem);
+//! Divide and Modulo 64-bit unsigned integer
+extern Uint64  DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem);
+
+static inline int MIN(int a, int b) { return a < b ? a : b; }
+static inline int MAX(int a, int b) { return a > b ? a : b; }
+
+#include <binary_ext.h>
+#include <vfs_ext.h>
+#include <mutex.h>
+
+#endif
diff --git a/KernelLand/Kernel/include/adt.h b/KernelLand/Kernel/include/adt.h
new file mode 100644 (file)
index 0000000..67e1266
--- /dev/null
@@ -0,0 +1,48 @@
+/* 
+ * Acess2
+ * - Abstract Data Types
+ */
+#ifndef _ADT_H_
+#define _ADT_H_
+
+/**
+ * \name Ring Buffers
+ * \{
+ */
+typedef struct sRingBuffer
+{
+       size_t  Start;  //!< Start of data in ring buffer
+       size_t  Length; //!< Number of data bytes in buffer
+       size_t  Space;  //!< Allocated space in buffer
+       tShortSpinlock  Lock;   //!< Lock to prevent collisions
+       char    Data[]; //!< Buffer
+}      tRingBuffer;
+
+/**
+ * \brief Create a ring buffer \a Space bytes large
+ * \param Space        Ammount of space to allocate within the buffer
+ * \return Pointer to the buffer structure
+ */
+extern tRingBuffer     *RingBuffer_Create(size_t Space);
+/**
+ * \brief Read at most \a Length bytes from the buffer
+ * \param Dest Destinaton buffer
+ * \param Buffer       Source ring buffer
+ * \param Length       Requested number of bytes
+ * \return Number of bytes read
+ */
+extern size_t  RingBuffer_Read(void *Dest, tRingBuffer *Buffer, size_t Length);
+/**
+ * \brief Write at most \a Length bytes to the buffer
+ * \param Buffer       Destination ring buffer
+ * \param Source       Source buffer
+ * \param Length       Provided number of bytes
+ * \return Number of bytes written
+ */
+extern size_t  RingBuffer_Write(tRingBuffer *Buffer, const void *Source, size_t Length);
+/**
+ * \}
+ */
+
+
+#endif
diff --git a/KernelLand/Kernel/include/api_drv_common.h b/KernelLand/Kernel/include/api_drv_common.h
new file mode 100644 (file)
index 0000000..59bef5f
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * \file api_drv_common.h
+ * \brief Common Driver Interface Definitions
+ * \author John Hodge (thePowersGang)
+ * 
+ * \section Introduction
+ * There are two ways Acess drivers can communicate with userspace
+ * applications, both are through the VFS. The first is by exposing a
+ * device as a file buffer, the second is by sending commands via the
+ * ioctl() system call.
+ * All drivers in Acess must at least conform to the specifcation in this
+ * file (even if it is just implementing eTplDrv_IOCtl.DRV_IOCTL_TYPE and
+ * returning eTplDrv_Type.DRV_TYPE_NULL, however, doing so is discouraged)
+ * 
+ * \section ioctls Core IOCtl calls
+ * As said, the core Acess driver specifcation defines specific IOCtl calls
+ * that all drivers should implement. The four core IOCtls (defined in
+ * ::eTplDrv_IOCtl) allow another binary (wether it be a user-mode application
+ * or another driver) to tell what type of device a driver provides, the
+ * basic identifcation of the driver (4 character ID and BCD version number)
+ * and be able to use externally standardised calls that may not have
+ * standardised call numbers.
+ * NOTE: All ioctl calls WILL return -1 if the driver ran into an error
+ * of its own fault while executing the call. If the user was at fault
+ * (e.g. by passing a bad buffer) the call will return -2.
+ * 
+ * \section types Driver Types
+ * When the eTplDrv_IOCtl.DRV_IOCTL_TYPE call is made, the driver should
+ * return the relevant entry in the ::eTplDrv_Type enumeration that describes
+ * what sub-specifcation (and hence, what device type) it implements.
+ * These device types are described in their own files, which are liked
+ * from their entries in ::eTplDrv_Type.
+ */
+#ifndef _API_DRV_COMMON_H
+#define _API_DRV_COMMON_H
+
+/**
+ * \enum eTplDrv_IOCtl
+ * \brief Common IOCtl Calls
+ */
+enum eTplDrv_IOCtl {
+       /**
+        * ioctl(...)
+        * \brief Get driver type
+        * \return The relevant entry from ::eTplDrv_Type
+        */
+       DRV_IOCTL_TYPE,
+       
+       /**
+        * ioctl(..., char *dest[32])
+        * \brief Get driver identifier string
+        * \return 0 on no error
+        * 
+        * This call sets the 32-byte array \a dest to the drivers 31 charater
+        * identifier. This identifier must be unique to the driver series.
+        */
+       DRV_IOCTL_IDENT,
+       
+       /**
+        * ioctl(...)
+        * \brief Get driver version number
+        * \return 24-bit BCD version number (2.2.2)
+        * 
+        * This call returns the 6-digit (2 major, 2 minor, 2 patch) version
+        * number of the driver.
+        */
+       DRV_IOCTL_VERSION,
+       
+       /**
+        * ioctl(..., char *name)
+        * \brief Get a IOCtl call ID from a symbolic name
+        * \return ID number of the call, or 0 if not found
+        * 
+        * This call allows user applications to not need to know the ID numbers
+        * of this driver's IOCtl calls by taking a string and returning the
+        * IOCtl call number associated with that method name.
+        */
+       DRV_IOCTL_LOOKUP,
+
+       /**
+        * \brief First non-reserved IOCtl number for driver extension
+        */
+       DRV_IOCTL_USERMIN = 0x1000,
+};
+
+/**
+ * \brief eTplDrv_IOCtl.DRV_IOCTL_LOOKUP names for the core IOCtls
+ * These are the official lookup names of the core calls
+ */
+#define        DRV_IOCTLNAMES  "type", "ident", "version", "lookup"
+
+/**
+ * \brief Helper macro for the base IOCtl calls
+ * \param _type        Type number from eTplDrv_Type to return
+ * \param _ident       String of max 32-characters that identifies this driver
+ * \param _version     Driver's 8.8.8 BCD version number
+ * \param _ioctls      Pointer to the IOCtls string array
+ * \warning If you have DEBUG enabled in the calling file, this function
+ *          will do LEAVE()s before returning, so make sure that the
+ *          IOCtl function is ENTER()ed when using debug with this macro
+ * 
+ * Usage: (Id is the IOCtl call ID)
+ * \code
+ * switch(Id)
+ * {
+ * BASE_IOCTLS(DRV_TYPE_MISC, "Ident", 0x100, csaIOCtls)
+ * // Your IOCtls go here, starting at index 4
+ * }
+ * \endcode
+ */
+#define BASE_IOCTLS(_type, _ident, _version, _ioctls)  \
+       case DRV_IOCTL_TYPE:    LEAVE('i', (_type));    return (_type);\
+       case DRV_IOCTL_IDENT: {\
+               int tmp = ModUtil_SetIdent(Data, (_ident));\
+               LEAVE('i', tmp);        return tmp;\
+               }\
+       case DRV_IOCTL_VERSION: LEAVE('x', (_version)); return (_version);\
+       case DRV_IOCTL_LOOKUP:{\
+               int tmp = ModUtil_LookupString( _ioctls, (const char*)Data );\
+               LEAVE('i', tmp);\
+               return tmp;\
+               }
+
+/**
+ * \enum eTplDrv_Type
+ * \brief Driver Types returned by DRV_IOCTL_TYPE
+ */
+enum eTplDrv_Type {
+       DRV_TYPE_NULL,          //!< NULL Type - Custom Interface
+       DRV_TYPE_MISC,          //!< Miscelanious Compilant - Supports the core calls
+       DRV_TYPE_TERMINAL,      //!< Terminal - see api_drv_terminal.h
+       DRV_TYPE_VIDEO,         //!< Video - see api_drv_video.h
+       DRV_TYPE_SOUND,         //!< Audio
+       DRV_TYPE_DISK,          //!< Disk - see api_drv_disk.h
+       DRV_TYPE_KEYBOARD,      //!< Keyboard - see api_drv_keyboard.h
+       DRV_TYPE_MOUSE,         //!< Mouse
+       DRV_TYPE_JOYSTICK,      //!< Joystick / Gamepad
+       DRV_TYPE_NETWORK        //!< Network Device - see api_drv_network.h
+};
+
+#endif
diff --git a/KernelLand/Kernel/include/api_drv_disk.h b/KernelLand/Kernel/include/api_drv_disk.h
new file mode 100644 (file)
index 0000000..94ea2c9
--- /dev/null
@@ -0,0 +1,185 @@
+/**\r
+ * \file api_drv_disk.h\r
+ * \brief Disk Driver Interface Definitions\r
+ * \author John Hodge (thePowersGang)\r
+ * \r
+ * \section Nomeclature\r
+ * All addreses are 64-bit counts of bytes from the logical beginning of\r
+ * the disk unless explicitly stated.\r
+ * \r
+ * \section dirs VFS Layout\r
+ * Disk drivers have a flexible directory layout. The root directory can\r
+ * contain subdirectories, with the only conditions being that all nodes\r
+ * must support ::eTplDrv_IOCtl with DRV_IOCTL_TYPE returning DRV_TYPE_DISK.\r
+ * And all file nodes representing disk devices (or partitions) and implemeting\r
+ * ::eTplDisk_IOCtl fully\r
+ * \r
+ * \section files Files\r
+ * When a read or write occurs on a normal file in the disk driver it will\r
+ * read/write the represented device. The accesses need not be aligned to\r
+ * the block size, however aligned reads/writes should be handled specially\r
+ * to improve speed (this can be aided by using ::DrvUtil_ReadBlock and\r
+ * ::DrvUtil_WriteBlock)\r
+ */\r
+#ifndef _API_DRV_DISK_H\r
+#define _API_DRV_DISK_H\r
+\r
+#include <api_drv_common.h>\r
+\r
+/**\r
+ * \enum eTplDisk_IOCtl\r
+ * \brief Common Disk IOCtl Calls\r
+ * \extends eTplDrv_IOCtl\r
+ */\r
+enum eTplDisk_IOCtl {\r
+       /**\r
+        * ioctl(..., void)\r
+        * \brief Get the block size\r
+        * \return Size of a hardware block for this device\r
+        */\r
+       DISK_IOCTL_GETBLOCKSIZE = 4,\r
+       \r
+       /**\r
+        * ioctl(..., tTplDisk_CacheRegion *RegionInfo)\r
+        * \brief Sets the cache importantce and protocol for a section of\r
+        *        memory.\r
+        * \param RegionInfo    Pointer to a region information structure\r
+        * \return Boolean failure\r
+        */\r
+       DISK_IOCTL_SETCACHEREGION,\r
+       \r
+       /**\r
+        * ioctl(..., Uint64 *Info[2])\r
+        * \brief Asks the driver to precache a region of disk.\r
+        * \param Region        64-bit Address and Size pair describing the area to cache\r
+        * \return Number of blocks cached\r
+        */\r
+       DISK_IOCTL_PRECACHE,\r
+       \r
+       /**\r
+        * ioclt(..., Uint64 *Region[2])\r
+        * \brief Asks to driver to flush the region back to disk\r
+        * \param Region        64-bit Address and Size pair describing the area to flush\r
+        * \note If Region[0] == -1 then the entire disk's cache is flushed\r
+        * \return Number of blocks flushed (or 0 for entire disk)\r
+        */\r
+       DISK_IOCTL_FLUSH\r
+};\r
+\r
+/**\r
+ * \brief Describes the cache parameters of a region on the disk\r
+ */\r
+typedef struct sTplDisk_CacheRegion\r
+{\r
+       Uint64  Base;   //!< Base of cache region\r
+       Uint64  Length; //!< Size of cache region\r
+       /**\r
+        * \brief Cache Protocol & Flags\r
+        * \r
+        * The low 4 bits denot the cache protocol to be used by the\r
+        * region (see ::eTplDisk_CacheProtocols for a list).\r
+        * The high 4 bits denote flags to apply to the cache (see\r
+        * ::eTplDisk_CacheFlags)\r
+        */\r
+       Uint8   Flags;\r
+       Uint8   Priority;       //!< Lower is a higher proritory\r
+       /**\r
+        * \brief Maximum size of cache, in blocks\r
+        * \note If CacheSize is zero, the implemenation defined limit is used\r
+        */\r
+       Uint16  CacheSize;\r
+}      tTplDisk_CacheRegion;\r
+\r
+/**\r
+ * \brief Cache protocols to use\r
+ */\r
+enum eTplDisk_CacheProtocols\r
+{\r
+       /**\r
+        * \brief Don't cache the region\r
+        */\r
+       \r
+       DISK_CACHEPROTO_DONTCACHE,\r
+       /**\r
+        * \brief Most recently used blocks cached\r
+        * \note This is the default action for undefined regions\r
+        */\r
+       DISK_CACHEPROTO_RECENTLYUSED,\r
+       /**\r
+        * \brief Cache the entire region in memory\r
+        * \r
+        * This is a faster version of setting Length to CacheSize*BlockSize\r
+        */\r
+       DISK_CACHEPROTO_FULLCACHE,\r
+       \r
+       /**\r
+        * \brief Cache only on demand\r
+        * \r
+        * Only cache when the ::DISK_IOCTL_PRECACHE IOCtl is used\r
+        */\r
+       DISK_CACHEPROTO_EXPLICIT\r
+};\r
+\r
+/**\r
+ * \brief Flags for the cache\r
+ */\r
+enum eTplDisk_CacheFlags\r
+{\r
+       /**\r
+        * \brief Write all changes to the region straight back to media\r
+        */\r
+       DISK_CACHEFLAG_WRITETHROUGH = 0x10\r
+};\r
+\r
+/**\r
+ * \brief IOCtl name strings\r
+ */\r
+#define        DRV_DISK_IOCTLNAMES     "get_block_size","set_cache_region","set_precache"\r
+\r
+/**\r
+ * \name Disk Driver Utilities\r
+ * \{\r
+ */\r
+\r
+/**\r
+ * \brief Callback function type used by DrvUtil_ReadBlock and DrvUtil_WriteBlock\r
+ * \param Address      Zero based block number to read\r
+ * \param Count        Number of blocks to read\r
+ * \param Buffer       Destination for read blocks\r
+ * \param Argument     Argument provided in ::DrvUtil_ReadBlock and ::DrvUtil_WriteBlock\r
+ */\r
+typedef Uint   (*tDrvUtil_Read_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
+typedef Uint   (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *Buffer, Uint Argument);\r
+\r
+/**\r
+ * \brief Reads a range from a block device using aligned reads\r
+ * \param Start        Base byte offset\r
+ * \param Length       Number of bytes to read\r
+ * \param Buffer       Destination for read data\r
+ * \param ReadBlocks   Callback function to read a sequence of blocks\r
+ * \param BlockSize    Size of an individual block\r
+ * \param Argument     An argument to pass to \a ReadBlocks\r
+ * \return Number of bytes read\r
+ */\r
+extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
+       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
+/**\r
+ * \brief Writes a range to a block device using aligned writes\r
+ * \param Start        Base byte offset\r
+ * \param Length       Number of bytes to write\r
+ * \param Buffer       Destination for read data\r
+ * \param ReadBlocks   Callback function to read a sequence of blocks\r
+ * \param WriteBlocks  Callback function to write a sequence of blocks\r
+ * \param BlockSize    Size of an individual block\r
+ * \param Argument     An argument to pass to \a ReadBlocks and \a WriteBlocks\r
+ * \return Number of bytes written\r
+ */\r
+extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
+       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
+       Uint64 BlockSize, Uint Argument);\r
+\r
+/**\r
+ * \}\r
+ */\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/include/api_drv_joystick.h b/KernelLand/Kernel/include/api_drv_joystick.h
new file mode 100644 (file)
index 0000000..3ec8597
--- /dev/null
@@ -0,0 +1,150 @@
+/**\r
+ * \file api_drv_joystick.h\r
+ * \brief Joystick Driver Interface Definitions\r
+ * \author John Hodge (thePowersGang)\r
+ * \r
+ * \section dirs VFS Layout\r
+ * Joystick drivers define a single VFS node, that acts as a fixed size file.\r
+ * Reads from this file return the current state, writes are ignored.\r
+ *\r
+ * \section File Structure\r
+ * The device file must begin with a valid sJoystick_FileHeader structure.\r
+ * The file header is followed by \a NAxies instances of sJoystick_Axis, one\r
+ * for each axis.\r
+ * This is followed by \a NButtons boolean values (represented using \a Uint8),\r
+ * each representing the state of a single button (where 0 is unpressed,\r
+ * 0xFF is fully depressed - intermediate values are valid in the case of\r
+ * variable-pressure buttons)\r
+ */\r
+#ifndef _API_DRV_JOYSTICK_H\r
+#define _API_DRV_JOYSTICK_H\r
+\r
+#include <api_drv_common.h>\r
+\r
+/**\r
+ * \enum eTplJoystick_IOCtl\r
+ * \brief Common Joystick IOCtl Calls\r
+ * \extends eTplDrv_IOCtl\r
+ */\r
+enum eTplJoystick_IOCtl {\r
+       /**\r
+        * ioctl(..., tJoystick_Callback *Callback)\r
+        * \brief Sets the callback\r
+        * \note Can be called from kernel mode only\r
+        *\r
+        * Sets the callback that is called when a event occurs (button or axis\r
+        * change). This function pointer must be in kernel mode (although,\r
+        * kernel->user or kernel->ring3driver abstraction functions can be used)\r
+        * \r
+        * Axis events depend on the axis limit, if non-zero, the callback fires\r
+        * if the cursor position changes. Otherwise it fires when the axis value\r
+        * (cursor accelleration) changes.\r
+        */\r
+       JOY_IOCTL_SETCALLBACK = 4,\r
+\r
+       /**\r
+        * ioctl(..., int *Argument)\r
+        * \brief Set the argument passed as the first parameter to the callback\r
+        * \note Kernel mode only\r
+        */\r
+       JOY_IOCTL_SETCALLBACKARG,\r
+\r
+       /**\r
+        * ioctl(..., tJoystickNumValue *)\r
+        * \brief Set maximum value for sJoystick_Axis.CursorPos\r
+        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
+        */\r
+       JOY_IOCTL_GETSETAXISLIMIT,\r
+\r
+       /**\r
+        * ioctl(..., tJoystickNumValue *)\r
+        * \brief Set the value of sJoystick_Axis.CursorPos\r
+        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
+        */\r
+       JOY_IOCTL_GETSETAXISPOSITION,\r
+       \r
+       /**\r
+        * ioctl(..., tJoystickNumValue *)\r
+        * \brief Set axis flags\r
+        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
+        * \todo Define flag values\r
+        */\r
+       JOY_IOCTL_GETSETAXISFLAGS,\r
+\r
+       /**\r
+        * ioctl(..., tJoystickNumValue *)\r
+        * \brief Set Button Flags\r
+        * \note If \a Value is equal to -1 (all bits set), the value is not changed\r
+        * \todo Define flag values\r
+        */\r
+       JOY_IOCTL_GETSETBUTTONFLAGS,\r
+};\r
+\r
+/**\r
+ * \brief Symbolic names for Joystick IOCtls\r
+ */\r
+#define        DRV_JOY_IOCTLNAMES      "set_callback", "set_callback_arg", "getset_axis_limit", "getset_axis_position", \\r
+       "getset_axis_flags", "getset_button_flags"\r
+\r
+// === TYPES ===\r
+typedef struct sJoystick_NumValue      tJoystick_NumValue;\r
+typedef struct sJoystick_FileHeader    tJoystick_FileHeader;\r
+typedef struct sJoystick_Axis  tJoystick_Axis;\r
+\r
+/**\r
+ * \brief Number/Value pair for joystick IOCtls\r
+ */\r
+struct sJoystick_NumValue\r
+{\r
+        int    Num;    //!< Axis/Button number\r
+        int    Value;  //!< Value (see IOCtl defs for meaning)\r
+};\r
+\r
+/**\r
+ * \brief Callback type for JOY_IOCTL_SETCALLBACK\r
+ * \param Ident        Ident value passed to JOY_IOCTL_SETCALLBACK\r
+ * \r
+ */\r
+typedef void (*tJoystick_Callback)(int Ident, int bIsAxis, int Num, int Delta);\r
+\r
+/**\r
+ * \struct sJoystick_FileHeader\r
+ * \brief Format of the joystick VFS node's first bytes\r
+ */\r
+struct sJoystick_FileHeader\r
+{\r
+       Uint16  NAxies; //!< Number of Axies\r
+       Uint16  NButtons;       //!< Number of buttons\r
+};\r
+\r
+/**\r
+ * \brief Axis Definition in file data\r
+ *\r
+ * Describes the current state of an axis on the joystick.\r
+ * \a CursorPos is between zero and the current limit set by the\r
+ * JOY_IOCTL_GETSETAXISLIMIT IOCtl, while \a CurValue indicates the\r
+ * current position of the joystick axis. This is defined to be between\r
+ * \a MinValue and \a MaxValue.\r
+ */\r
+struct sJoystick_Axis\r
+{\r
+       Sint16  MinValue;       //!< Minumum value for \a CurValue\r
+       Sint16  MaxValue;       //!< Maximum value for \a CurValue\r
+       Sint16  CurValue;       //!< Current value (joystick position)\r
+       Uint16  CursorPos;      //!< Current state (cursor position)\r
+};\r
+\r
+/**\r
+ * \brief Macro to define a structure for a joystick's node\r
+ * \param _naxies      Number of axies\r
+ * \param _nbuttons    Number of buttons\r
+ * \note This just defines the structure, it's up to the driver to set the\r
+ *       sJoystick_FileHeader.NAxies and sJoystick_FileHeader.NButtons fields.\r
+ */\r
+#define JOY_INFOSTRUCT(_naxies, _nbuttons) struct { \\r
+       Uint16  NAxies, NButtons;\\r
+       tJoystick_Axis  Axies[_naxies];\\r
+       Uint16  Buttons[_nbuttons];\\r
+       }\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/include/api_drv_keyboard.h b/KernelLand/Kernel/include/api_drv_keyboard.h
new file mode 100644 (file)
index 0000000..57ca247
--- /dev/null
@@ -0,0 +1,141 @@
+/**\r
+ * \file api_drv_keyboard.h\r
+ * \brief Keyboard Driver Interface Definitions\r
+ * \author John Hodge (thePowersGang)\r
+ * \r
+ * \section dirs VFS Layout\r
+ * Keyboard drivers consist of only a single node, which is a normal file\r
+ * node with a size of zero. All reads and writes to this node are ignored\r
+ * (tVFS_Node.Read and tVFS_Node.Write are NULL)\r
+ */\r
+#ifndef _API_DRV_KEYBOARD_H\r
+#define _API_DRV_KEYBOARD_H\r
+\r
+#include <api_drv_common.h>\r
+\r
+/**\r
+ * \enum eTplKeyboard_IOCtl\r
+ * \brief Common Keyboard IOCtl Calls\r
+ * \extends eTplDrv_IOCtl\r
+ */\r
+enum eTplKeyboard_IOCtl {\r
+       /**\r
+        * ioctl(..., int *Rate)\r
+        * \brief Get/Set Repeat Rate\r
+        * \param Rate  New repeat rate (pointer)\r
+        * \return Current/New Repeat rate\r
+        * \r
+        * Gets/Set the repeat rate (actually the time in miliseconds between\r
+        * repeats) of a held down key.\r
+        * If the rate is set to zero, repeating will be disabled.\r
+        */\r
+       KB_IOCTL_REPEATRATE = 4,\r
+       \r
+       /**\r
+        * ioctl(..., int *Delay)\r
+        * \brief Get/Set Repeat Delay\r
+        * \param Delay New repeat delay (pointer)\r
+        * \return Current/New repeat delay\r
+        * \r
+        * Gets/Set the time in miliseconds before a key starts repeating\r
+        * after a key is pressed.\r
+        * Setting the delay to a negative number will cause the function to\r
+        * return -1\r
+        */\r
+       KB_IOCTL_REPEATDELAY,\r
+       \r
+       \r
+       /**\r
+        * ioctl(..., tKeybardCallback *Callback)\r
+        * \brief Sets the callback\r
+        * \note Can be called from kernel mode only\r
+        * \r
+        * Sets the function to be called when a key event occurs (press, release\r
+        * or repeat). This function pointer must be in kernel mode (although,\r
+        * kernel->user or kernel->ring3driver abstraction functions can be used)\r
+        *\r
+        * This function is called when a key is pressed, repeated or released.\r
+        * If the raw scancode is to be included with the key event, it should precede\r
+        * the event.\r
+        */\r
+       KB_IOCTL_SETCALLBACK\r
+};\r
+\r
+/**\r
+ * \brief Symbolic names for Keyboard IOCtls\r
+ */\r
+#define DRV_KEYBAORD_IOCTLNAMES        "getset_repeat_rate", "getset_repeat_delay", "set_callback"\r
+\r
+/**\r
+ * \brief Callback type for KB_IOCTL_SETCALLBACK\r
+ * \param Key  Key symbol (Unicode or eTplKeyboard_KeyCodes)\r
+ */\r
+typedef void (*tKeybardCallback)(Uint32 Key);\r
+\r
+/**\r
+ * \name Callback key flags\r
+ * \brief Flags for values passed to the callback\r
+ * \{\r
+ */\r
+#define KEY_CODEPOINT_MASK     0x3FFFFFFF\r
+#define KEY_ACTION_MASK        0xC0000000\r
+#define KEY_ACTION_PRESS       0x00000000      //!< Key pressed\r
+#define KEY_ACTION_RELEASE     0x40000000      //!< Key released\r
+#define KEY_ACTION_REFIRE      0x80000000      //!< Repeated key\r
+#define KEY_ACTION_RAWSYM      0xC0000000      //!< Raw key symbol (comes before a press/repeat/release)\r
+/**\r
+ * \}\r
+ */\r
+\r
+/**\r
+ * \brief Symbolic key codes\r
+ * \r
+ * These key codes represent non-pritable characters and are placed above\r
+ * the Unicode character space.\r
+ * If the using driver recieves a key code with the 31st bit set, it means\r
+ * that that key has been released.\r
+ */\r
+enum eTplKeyboard_KeyCodes {\r
+       KEY_ESC = 0x1B, //!< Escape Character\r
+       \r
+       KEY_NP_MASK = 0x20000000,       //! Mask for non-printable characters\r
+       \r
+       /**\r
+        * \name Special Keys\r
+        * \brief These keys are usually used on their own\r
+        * \{\r
+        */\r
+       KEY_CAPSLOCK,\r
+       KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,\r
+       KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, \r
+       KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,\r
+       KEY_NUMLOCK, KEY_SCROLLLOCK,\r
+       KEY_HOME, KEY_END, KEY_INS, KEY_DEL,\r
+       KEY_PAUSE, KEY_BREAK,\r
+       KEY_PGUP, KEY_PGDOWN,\r
+       KEY_KPENTER, KEY_KPSLASH, KEY_KPMINUS, KEY_KPPLUS, KEY_KPSTAR,\r
+       KEY_KPHOME, KEY_KPUP, KEY_KPPGUP, KEY_KPLEFT, KEY_KP5, KEY_KPRIGHT,\r
+       KEY_KPEND, KEY_KPDOWN, KEY_KPPGDN, KEY_KPINS, KEY_KPDEL,\r
+       KEY_LWIN, KEY_RWIN,\r
+       KEY_MENU,\r
+       /**\r
+        * \}\r
+        */\r
+       \r
+       // Modifiers\r
+       /**\r
+        * \name Modifiers\r
+        * \brief These keye usually alter the character stream sent to the user\r
+        * \{\r
+        */\r
+       KEY_MODIFIERS = 0x30000000,\r
+       KEY_LCTRL, KEY_RCTRL,\r
+       KEY_LALT, KEY_RALT,\r
+       KEY_LSHIFT, KEY_RSHIFT,\r
+       /**\r
+        * \}\r
+        */\r
+};\r
+\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/include/api_drv_network.h b/KernelLand/Kernel/include/api_drv_network.h
new file mode 100644 (file)
index 0000000..6cb8c34
--- /dev/null
@@ -0,0 +1,56 @@
+/**\r
+ * \file api_drv_network.h\r
+ * \brief Network Interface Driver Interface Definitions\r
+ * \r
+ * \section dirs VFS Layout\r
+ * All network drivers must have the following basic VFS structure\r
+ * The root of the driver will only contain files that are named from zero\r
+ * upwards that represent the present network adapters that this driver\r
+ * controls. All VFS nodes must implement ::eTplDrv_IOCtl with\r
+ * DRV_IOCTL_TYPE returning DRV_TYPE_NETWORK.\r
+ * The adapter nodes must also implement ::eTplNetwork_IOCtl fully\r
+ * (unless it is noted in the ::eTplNetwork_IOCtl documentation that a\r
+ * call is optional)\r
+ * \r
+ * \section files Adapter Files\r
+ * \subsection Reading\r
+ * When an adapter file is read from, the driver will block the reading\r
+ * thread until a packet arrives (if there is not already an unhandled\r
+ * packet in the queue) this will then be read into the destination buffer.\r
+ * If the packet does not fit in the buffer, the end of it is discarded.\r
+ * Likewise, if the packet does not completely fill the buffer, the call\r
+ * will still read to the buffer and then return the size of the packet.\r
+ * \subsection Writing\r
+ * When an adapter is written to, the data written is encoded as a packet\r
+ * and sent, if the data is not the correct size to be sent (if the packet\r
+ * is too small, or if it is too large) -1 should be returned and the packet\r
+ * will not be sent.\r
+ */\r
+#ifndef _API_DRV_NETWORK_H\r
+#define _API_DRV_NETWORK_H\r
+\r
+#include <api_drv_common.h>\r
+\r
+/**\r
+ * \enum eTplNetwork_IOCtl\r
+ * \brief Common Network IOCtl Calls\r
+ * \extends eTplDrv_IOCtl\r
+ */\r
+enum eTplNetwork_IOCtl {\r
+       /**\r
+        * ioctl(..., Uint8 *MAC[6])\r
+        * \brief Get the MAC address of the interface\r
+        * \return 1 on success, 0 if the file is the root, -1 on error\r
+        * \r
+        * Copies the six byte Media Access Control (MAC) address of the\r
+        * adapter to the \a MAC array.\r
+       */\r
+       NET_IOCTL_GETMAC = 4\r
+};\r
+\r
+/**\r
+ * \brief IOCtl name strings for use with eTplDrv_IOCtl.DRV_IOCTL_LOOKUP\r
+ */\r
+#define        DRV_NETWORK_IOCTLNAMES  "get_mac_addr"\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/include/api_drv_terminal.h b/KernelLand/Kernel/include/api_drv_terminal.h
new file mode 100644 (file)
index 0000000..3142d33
--- /dev/null
@@ -0,0 +1,166 @@
+/**\r
+ * \file api_drv_terminal.h\r
+ * \brief Terminal Driver Interface Definitions\r
+*/\r
+#ifndef _API_DRV_TERMINAL_H\r
+#define _API_DRV_TERMINAL_H\r
+\r
+#include <api_drv_common.h>\r
+\r
+/**\r
+ * \brief Common Terminal IOCtl Calls\r
+ * \extends eTplDrv_IOCtl\r
+ */\r
+enum eTplTerminal_IOCtl {\r
+       /**\r
+        * ioctl(..., int *mode)\r
+        * \brief Get/Set the current video mode type\r
+        * \param mode Pointer to an integer with the new mode number (or NULL)\r
+        *             If \a mode is non-NULL the current terminal mode is changed/updated\r
+        *             to the mode indicated by \a *mode\r
+        * \note See ::eTplTerminal_Modes\r
+        * \return Current/new terminal mode\r
+       */\r
+       TERM_IOCTL_MODETYPE = 4,\r
+       \r
+       /**\r
+        * ioctl(..., int *width)\r
+        * \brief Get/set the display width\r
+        * \param width Pointer to an integer containing the new width (or NULL)\r
+        * \return Current/new width\r
+        * \r
+        * If \a width is non-NULL the current width is updated (but is not\r
+        * applied until ::TERM_IOCTL_MODETYPE is called with \a mode non-NULL.\r
+        */\r
+       TERM_IOCTL_WIDTH,\r
+       \r
+       /**\r
+        * ioctl(..., int *height)\r
+        * \brief Get/set the display height\r
+        * \param height        Pointer to an integer containing the new height\r
+        * \return Current height\r
+        * \r
+        * If \a height is non-NULL the current height is updated (but is not\r
+        * applied until ::TERM_IOCTL_MODETYPE is called with a non-NULL \a mode.\r
+        */\r
+       TERM_IOCTL_HEIGHT,\r
+       \r
+       /**\r
+        * ioctl(..., tTerm_IOCtl_Mode *info)\r
+        * \brief Queries the current driver about it's native modes\r
+        * \param info  A pointer to a ::tTerm_IOCtl_Mode with \a ID set to\r
+        *        the mode index (or NULL)\r
+        * \return Number of modes\r
+        * \r
+        * If \a info is NULL, the number of avaliable vative display modes\r
+        * is returned. These display modes will have sequential ID numbers\r
+        * from zero up to this value.\r
+        * \r
+        * \note The id field of \a info is not for use with ::TERM_IOCTL_MODETYPE\r
+        *       This field is just for indexing the mode to get its information.\r
+        */\r
+       TERM_IOCTL_QUERYMODE,\r
+       \r
+       /**\r
+        * ioctl(...)\r
+        * \brief Forces the current terminal to be shown\r
+        */\r
+       TERM_IOCTL_FORCESHOW,\r
+       \r
+       /**\r
+        * ioctl(..., tVideo_IOCtl_Pos *pos)\r
+        * \brief Returns the current text cursor position\r
+        * \param pos   New cursor position. If NULL, the position is not changed\r
+        * \return Cursor position (as X+Y*Width)\r
+        */\r
+       TERM_IOCTL_GETSETCURSOR,\r
+       \r
+       /**\r
+        * ioctl(..., tVideo_IOCtl_Bitmap *Bmp)\r
+        * \brief Set the video cursor bitmap\r
+        * \param Bmp   New bitmap (if NULL, the current bitmap is removed)\r
+        * \return Boolean failure\r
+        */\r
+       TERM_IOCTL_SETCURSORBITMAP,\r
+};\r
+\r
+/**\r
+ * \brief Virtual Terminal Mode\r
+ * Describes a VTerm mode to the caller of ::TERM_IOCTL_QUERYMODE\r
+ */\r
+typedef struct sTerm_IOCtl_Mode\r
+{\r
+       short   ID;             //!< Zero Based index of mode\r
+       short   DriverID;       //!< Driver's ID number (from ::tVideo_IOCtl_Mode)\r
+       Uint16  Height; //!< Height\r
+       Uint16  Width;  //!< Width\r
+       Uint8   Depth;  //!< Bits per cell\r
+       struct {\r
+               unsigned bText: 1;      //!< Text Mode marker\r
+               unsigned unused:        7;\r
+       };\r
+} tTerm_IOCtl_Mode;\r
+\r
+/**\r
+ * \brief Terminal Modes\r
+ */\r
+enum eTplTerminal_Modes {\r
+       /**\r
+        * \brief UTF-8 Text Mode\r
+        * Any writes to the terminal file are treated as UTF-8 encoded\r
+        * strings and reads will also return UTF-8 strings.\r
+        */\r
+       TERM_MODE_TEXT,\r
+       \r
+       /**\r
+        * \brief 32bpp Framebuffer\r
+        * Writes to the terminal file will write to the framebuffer.\r
+        * Reads will return UTF-32 characters\r
+        */\r
+       TERM_MODE_FB,\r
+       \r
+       /**\r
+        * \brief 32bpp 2D Accellerated mode\r
+        * Writes to the terminal file will be read as a command stream\r
+        * defined in ::eTplTerminal_2D_Commands\r
+        */\r
+       TERM_MODE_2DACCEL,\r
+       \r
+       /**\r
+        * \brief OpenGL 2D/3D\r
+        * Writes to the terminal file will send 3D commands\r
+        * Reads will return UTF-32 characters\r
+        * \note May or may not stay in the spec\r
+        */\r
+       TERM_MODE_3D,\r
+       \r
+       /**\r
+        * \brief Number of terminal modes\r
+        */\r
+       NUM_TERM_MODES\r
+};\r
+\r
+/**\r
+ * \brief 2D Command IDs\r
+ * \todo Complete this structure\r
+ * \r
+ * Command IDs for when the terminal type is eTplTerminal_Modes.TERM_MODE_2DACCEL\r
+ */\r
+enum eTplTerminal_2D_Commands\r
+{\r
+       /**\r
+        * \brief No Operation - Used for padding\r
+        */\r
+       TERM_2DCMD_NOP,\r
+       \r
+       /**\r
+        * (Uint16 X, Y, W, H, Uint32 Data[])\r
+        * \brief Blits a bitmap to the display\r
+        * \param X,Y   Coordinates of Top-Left corner\r
+        * \param W,H   Dimensions\r
+        * \param Data  32-bpp pixel data\r
+        */\r
+       TERM_2DCMD_PUSH\r
+};\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/include/api_drv_video.h b/KernelLand/Kernel/include/api_drv_video.h
new file mode 100644 (file)
index 0000000..ff9c395
--- /dev/null
@@ -0,0 +1,484 @@
+/**\r
+ * \file api_drv_video.h\r
+ * \brief Video Driver Interface Definitions\r
+ * \note For AcessOS Version 1\r
+ * \r
+ * Video drivers extend the common driver interface api_drv_common.h\r
+ * and must support the IOCtl numbers defined in this file to be\r
+ * compatable with Acess (drivers may implement more IOCtls above\r
+ * DRV_IOCTL_USERMIN).\r
+ * \r
+ * \section IOCtls\r
+ * As said, a compatable driver must implement these calls correctly,\r
+ * but they may choose not to allow direct user access to the framebuffer.\r
+ * \r
+ * \section Screen Contents\r
+ * Writes to the driver's file while in component colour modes\r
+ * must correspond to a change of the contents of the screen. The framebuffer\r
+ * must start at offset 0 in the file.\r
+ * Reading from the screen must either return zero, or read from the\r
+ * framebuffer.\r
+ * \r
+ * \section Mode Support\r
+ * All video drivers must support text output for every resolution (hardware\r
+ * accelerated or software), and at least the _BLIT and _FILL 2D operations\r
+ * (these may be implemented specifically for text mode).\r
+ */\r
+#ifndef _API_DRV_VIDEO_H\r
+#define _API_DRV_VIDEO_H\r
+\r
+#include <api_drv_common.h>\r
+\r
+/**\r
+ * \enum eTplVideo_IOCtl\r
+ * \brief Common Video IOCtl Calls\r
+ * \extends eTplDrv_IOCtl\r
+ */\r
+enum eTplVideo_IOCtl {\r
+       /**\r
+        * ioctl(..., int *mode)\r
+        * \brief Get/Set Mode\r
+        * \return Current mode ID or -1 on error\r
+        * \r
+        * If \a mode is non-NULL, the current video mode is set to \a *mode.\r
+        * This updated ID is then returned to the user.\r
+        */\r
+       VIDEO_IOCTL_GETSETMODE = 4,\r
+       \r
+       /**\r
+        * ioctl(..., tVideo_IOCtl_Mode *info)\r
+        * \brief Find a matching mode\r
+        * \return 1 if a mode was found, 0 otherwise\r
+        * \r
+        * Using avaliable modes matching the \a bpp and \a flags fields\r
+        * set the \a id, \a width and \a heights fields to the closest\r
+        * matching mode.\r
+        */\r
+       VIDEO_IOCTL_FINDMODE,\r
+       \r
+       /**\r
+        * ioctl(..., tVideo_IOCtl_Mode *info)\r
+        * \brief Get mode info\r
+        * \return 1 if the mode exists, 0 otherwise\r
+        * \r
+        * Set \a info's fields to the mode specified by the \a id field.\r
+        */\r
+       VIDEO_IOCTL_MODEINFO,\r
+       \r
+       /**\r
+        * ioctl(..., int *NewFormat)\r
+        * \brief Switches between Text, Framebuffer and 3D modes\r
+        * \param NewFormat     Pointer to the new format code (see eTplVideo_BufFormats)\r
+        * \return Original format\r
+        * \r
+        * Enabes and disables the video text mode, changing the behavior of\r
+        * writes to the device file.\r
+        */\r
+       VIDEO_IOCTL_SETBUFFORMAT,\r
+       \r
+       /**\r
+        * ioctl(..., tVideo_IOCtl_Pos *pos)\r
+        * \brief Sets the cursor position\r
+        * \return Boolean success\r
+        * \r
+        * Set the text mode cursor position (if it is supported)\r
+        * If the \a pos is set to (-1,-1) the cursor is hidden, otherwise\r
+        * \a pos MUST be within the current screen size (as given by the\r
+        * current mode's tVideo_IOCtl_Mode.width and tVideo_IOCtl_Mode.height\r
+        * fields).\r
+        */\r
+       VIDEO_IOCTL_SETCURSOR,\r
+       \r
+       /**\r
+        * ioctl(..., tVideo_IOCtl_Bitmap *Image)\r
+        * \brief Sets the cursor image\r
+        * \return Boolean success\r
+        *\r
+        * Sets the graphics mode cursor image\r
+        */\r
+       VIDEO_IOCTL_SETCURSORBITMAP\r
+};\r
+\r
+/**\r
+ * \brief Symbolic names for Video IOCtls (#4 onwards)\r
+ */\r
+#define DRV_VIDEO_IOCTLNAMES   "getset_mode", "find_mode", "mode_info", "set_buf_format", "set_cursor", "set_cursor_bitmap"\r
+\r
+/**\r
+ * \brief Mode Structure used in IOCtl Calls\r
+ * \r
+ * Defines a video mode supported by (or requested of) this driver (depending\r
+ * on what ioctl call is used)\r
+ */\r
+typedef struct sVideo_IOCtl_Mode\r
+{\r
+       short   id;             //!< Mode ID\r
+       Uint16  width;  //!< Width\r
+       Uint16  height; //!< Height\r
+       Uint8   bpp;    //!< Bits per pixel\r
+       Uint8   flags;  //!< Mode Flags (none defined, should be zero)\r
+}      tVideo_IOCtl_Mode;\r
+\r
+/**\r
+ * \brief Buffer Format Codes\r
+ */\r
+enum eTplVideo_BufFormats\r
+{\r
+       /**\r
+        * \brief Text Mode\r
+        * \r
+        * The device file presents itself as an array of ::tVT_Char\r
+        * each describing a character cell on the screen.\r
+        * These cells are each \a giVT_CharWidth pixels wide and\r
+        * \a giVT_CharHeight high.\r
+        */\r
+       VIDEO_BUFFMT_TEXT,\r
+       /**\r
+        * \brief Framebuffer Mode\r
+        * \r
+        * The device file presents as an array of 32-bpp pixels describing\r
+        * the entire screen. The format of a single pixel is in xRGB format\r
+        * (top 8 bits ignored, next 8 bits red, next 8 bits green and\r
+        * the bottom 8 bits blue)\r
+        */\r
+       VIDEO_BUFFMT_FRAMEBUFFER,\r
+       /**\r
+        * \brief 2D Accelerated Mode\r
+        * \r
+        * The device file acts as a character device, accepting a stream of\r
+        * commands described in eTplVideo_2DCommands when written to.\r
+        */\r
+       VIDEO_BUFFMT_2DSTREAM,\r
+       /**\r
+        * \brief 3D Accelerated Mode\r
+        * \r
+        * The device file acts as a character device, accepting a stream of\r
+        * commands described in eTplVideo_3DCommands when written to.\r
+        */\r
+       VIDEO_BUFFMT_3DSTREAM\r
+};\r
+\r
+/**\r
+ * \brief 2D Accellerated Video Commands\r
+ * \r
+ * Commands passed in the command stream for ::VIDEO_BUFFMT_2DSTREAM\r
+ */\r
+enum eTplVideo_2DCommands\r
+{\r
+       /**\r
+        * \brief No Operation\r
+        */\r
+       VIDEO_2DOP_NOP,\r
+       /**\r
+        * \brief Fill a region\r
+        * \param X     Uint16 - Leftmost pixels of the region\r
+        * \param Y     Uint16 - Topmost pixels of the region\r
+        * \param W     Uint16 - Width of the region\r
+        * \param H     Uint16 - Height of the region\r
+        * \param Colour        Uint32 - Value to fill with\r
+        */\r
+       VIDEO_2DOP_FILL,\r
+       /**\r
+        * \brief Copy a region from one part of the framebuffer to another\r
+        * \param DestX Uint16 - Leftmost pixels of the destination\r
+        * \param DestY Uint16 - Topmost pixels of the destination\r
+        * \param SrcX  Uint16 - Leftmost pixels of the source\r
+        * \param SrcY  Uint16 - Topmost pixels of the source\r
+        * \param Width Uint16 - Width of the region\r
+        * \param Height        Uint16 - Height of the region\r
+        */\r
+       VIDEO_2DOP_BLIT,\r
+\r
+\r
+       /**\r
+        * \brief Copy a region from video memory to the framebuffer\r
+        */\r
+       VIDEO_2DOP_BLITBUF,\r
+\r
+       /**\r
+        * \brief Copy and scale a region from video memory to the framebuffer\r
+        */\r
+       VIDEO_2DOP_BLITSCALEBUF,\r
+\r
+       NUM_VIDEO_2DOPS\r
+};\r
+\r
+/**\r
+ * \brief Describes a position in the video framebuffer\r
+ */\r
+typedef struct sVideo_IOCtl_Pos\r
+{\r
+       Sint16  x;      //!< X Coordinate\r
+       Sint16  y;      //!< Y Coordinate\r
+}      tVideo_IOCtl_Pos;\r
+\r
+/**\r
+ * \brief Bitmap object (out of band image)\r
+ */\r
+typedef struct sVideo_IOCtl_Bitmap\r
+{\r
+       Sint16  W;      //!< Width of image\r
+       Sint16  H;      //!< Height of image\r
+       Sint16  XOfs;   //!< X Offset of center\r
+       Sint16  YOfs;   //!< Y Offset of center\r
+       Uint32  Data[]; //!< Image data (ARGB array)\r
+}      tVideo_IOCtl_Bitmap;\r
+\r
+/**\r
+ * \brief Virtual Terminal Representation of a character\r
+ */\r
+typedef struct sVT_Char\r
+{\r
+       Uint32  Ch;     //!< UTF-32 Character\r
+       union {\r
+               struct {\r
+                       Uint16  BGCol;  //!< 12-bit Foreground Colour\r
+                       Uint16  FGCol;  //!< 12-bit Background Colour\r
+               };\r
+               Uint32  Colour; //!< Compound colour for ease of access\r
+       };\r
+}      tVT_Char;\r
+\r
+/**\r
+ * \name Basic builtin colour definitions\r
+ * \{\r
+ */\r
+#define        VT_COL_BLACK    0x0000\r
+#define        VT_COL_GREY             0x0888\r
+#define        VT_COL_LTGREY   0x0CCC\r
+#define        VT_COL_WHITE    0x0FFF\r
+/**\r
+ * \}\r
+ */\r
+\r
+//! \brief Defines the width of a rendered character\r
+extern int     giVT_CharWidth;\r
+//! \brief Defines the height of a rendered character\r
+extern int     giVT_CharHeight;\r
+/**\r
+ * \name Font rendering\r
+ * \{\r
+ */\r
+/**\r
+ * \brief Driver helper that renders a character to a buffer\r
+ * \param Codepoint    Unicode character to render\r
+ * \param Buffer       Buffer to render to\r
+ * \param Depth        Bit depth of the destination buffer\r
+ * \param Pitch        Number of bytes per line\r
+ * \param BGC  32-bit Background Colour\r
+ * \param FGC  32-bit Foreground Colour\r
+ * \r
+ * This function is provided to help video drivers to support a simple\r
+ * text mode by keeping the character rendering abstracted from the driver,\r
+ * easing the driver development and reducing code duplication.\r
+ */\r
+extern void    VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC);\r
+/**\r
+ * \fn Uint32 VT_Colour12to24(Uint16 Col12)\r
+ * \brief Converts a colour from 12bpp to 24bpp\r
+ * \param Col12        12-bpp input colour\r
+ * \return Expanded 32-bpp (24-bit colour) version of \a Col12\r
+ */\r
+extern Uint32  VT_Colour12to24(Uint16 Col12);\r
+/**\r
+ * \brief Converts a colour from 12bpp to 14bpp\r
+ * \param Col12        12-bpp input colour\r
+ * \return 15 bits per pixel value\r
+ */\r
+extern Uint16  VT_Colour12to15(Uint16 Col12);\r
+/**\r
+ * \brief Converts a colour from 12bpp to 32bpp\r
+ * \param Col12        12-bpp input colour\r
+ * \param Depth        Desired bit depth\r
+ * \return \a Depth bit number, denoting Col12\r
+ * \r
+ * Expands the source colour into a \a Depth bits per pixel representation.\r
+ * The colours are expanded with preference to Green, Blue and Red in that order\r
+ * (so, green gets the first spare pixel, blue gets the next, and red never gets\r
+ * the spare). \n\r
+ * The final bit of each component is used to fill the lower bits of the output.\r
+ */\r
+extern Uint32  VT_Colour12toN(Uint16 Col12, int Depth);\r
+/**\r
+ * \}\r
+ */\r
+\r
+/**\r
+ * \brief Maximum cursor width for using the DrvUtil software cursor\r
+ */\r
+#define DRVUTIL_MAX_CURSOR_W   32\r
+/**\r
+ * \brief Maximum cursor width for using the DrvUtil software cursor\r
+ */\r
+#define DRVUTIL_MAX_CURSOR_H   32\r
+\r
+/**\r
+ * \brief Framebuffer information used by all DrvUtil_Video functions\r
+ */\r
+typedef struct sDrvUtil_Video_BufInfo\r
+{\r
+       /**\r
+        * \name Framebuffer state\r
+        * \{\r
+        */\r
+       /**\r
+        * \brief Framebuffer virtual address\r
+        */\r
+       void    *Framebuffer;\r
+       /**\r
+        * \brief Bytes between the start of each line\r
+        */\r
+        int    Pitch;\r
+       /**\r
+        * \brief Number of pixels in each line\r
+        */\r
+       short   Width;\r
+       /**\r
+        * \brief Total number of lines\r
+        */\r
+       short   Height;\r
+       /**\r
+        * \brief Bit depth of the framebuffer\r
+        */\r
+       short   Depth;\r
+       /*\r
+        * \}\r
+        */\r
+       \r
+       /**\r
+        * \brief Buffer write format\r
+        */\r
+       short   BufferFormat;\r
+       \r
+       /**\r
+        * \name Software cursor controls\r
+        * \{\r
+        */\r
+       /**\r
+        * \brief X coordinate of the cursor\r
+        */\r
+       short   CursorX;\r
+       /**\r
+        * \brief Y coordinate of the cursor\r
+        */\r
+       short   CursorY;\r
+\r
+       /**\r
+        * \brief Cursor bitmap\r
+        */\r
+       tVideo_IOCtl_Bitmap     *CursorBitmap;\r
+       /*\r
+        * \}\r
+        */\r
+\r
+       /*\r
+        * \name Internal fields\r
+        * \{\r
+        */\r
+\r
+       /**\r
+        * \brief Buffer to store the area under the cursor\r
+        */\r
+       void    *CursorSaveBuf;\r
+       \r
+        int    CursorReadX;    //!< X offset in cursor bitmap corresponding to \a CursorDestX\r
+        int    CursorReadY;    //!< Same as \a CursorReadX but for Y\r
+        int    CursorRenderW;  //!< Width of rendered cursor\r
+        int    CursorRenderH;  //!< Height of rendered cursor\r
+        int    CursorDestX;    //!< X coordinate Destination for rendered cursor\r
+        int    CursorDestY;    //!< Y coordinate destination for rendered cursor\r
+\r
+       /*\r
+        * \}\r
+        */\r
+} tDrvUtil_Video_BufInfo;\r
+\r
+/**\r
+ * \brief Handlers for eTplVideo_2DCommands\r
+ */\r
+typedef struct sDrvUtil_Video_2DHandlers\r
+{\r
+       /**\r
+        * \brief No Operation, Ignored\r
+        * \see VIDEO_2DOP_NOP\r
+        */\r
+       void    *Nop;\r
+       /**\r
+        * \brief Fill a buffer region\r
+        * \param X     Lefthand edge\r
+        * \param Y     Top edge\r
+        * \param W     Width\r
+        * \param H     Height\r
+        * \param Colour        Colour to fill with\r
+        * \see VIDEO_2DOP_FILL\r
+        */\r
+       void    (*Fill)(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
+       /**\r
+        * \brief Fill a buffer region\r
+        * \param DestX Lefthand edge of destination\r
+        * \param DestY Top edge of destination\r
+        * \param SrcX  Lefthand edge of source\r
+        * \param SrcY  Top edge of source\r
+        * \param W     Width\r
+        * \param H     Height\r
+        * \see VIDEO_2DOP_BLIT\r
+        */\r
+       void    (*Blit)(void *Ent, Uint16 DestX, Uint16 DestY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);\r
+} tDrvUtil_Video_2DHandlers;\r
+\r
+/**\r
+ * \brief Handle a 2D operation stream for a driver\r
+ * \param Ent  Value to pass to handlers\r
+ * \param Buffer       Stream buffer\r
+ * \param Length       Length of stream\r
+ * \param Handlers     Handlers to use for the stream\r
+ * \param SizeofHandlers       Size of \a tDrvUtil_Video_2DHandlers according\r
+ *        to the driver. Used as version control and error avoidence.\r
+ */\r
+extern int     DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,\r
+       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);\r
+\r
+/**\r
+ * \brief Perform write operations to a LFB\r
+ * \param FBInfo       Framebuffer descriptor, see type for details\r
+ * \param Offset       Offset provided by VFS call\r
+ * \param Length       Length provided by VFS call\r
+ * \param Src  Data from VFS call\r
+ * \return Number of bytes written\r
+ *\r
+ * Handles all write modes in software, using the VT font calls for rendering.\r
+ * \note Calls the cursor clear and redraw if the cursor area is touched\r
+ */\r
+extern int     DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Src);\r
+\r
+/**\r
+ * \name Software cursor rendering\r
+ * \{\r
+ */\r
+/**\r
+ * \brief Set the cursor bitmap for a buffer\r
+ * \param Buf  Framebuffer descriptor\r
+ * \param Bitmap       New cursor bitmap\r
+ */\r
+extern int     DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);\r
+/**\r
+ * \brief Render the cursor at (\a X, \a Y)\r
+ * \param Buf  Framebuffer descriptor, see type for details\r
+ * \param X    X coord of the cursor\r
+ * \param Y    Y coord of the cursor\r
+ */\r
+extern void    DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);\r
+/**\r
+ * \brief Removes the rendered cursor from the screen\r
+ * \param Buf  Framebuffer descriptor, see type for details\r
+ */\r
+extern void    DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);\r
+\r
+/**\r
+ * \brief Text mode cursor image\r
+ */\r
+extern tVideo_IOCtl_Bitmap     gDrvUtil_TextModeCursor;\r
+/**\r
+ * \}\r
+ */\r
+#endif\r
diff --git a/KernelLand/Kernel/include/apidoc/arch_x86.h b/KernelLand/Kernel/include/apidoc/arch_x86.h
new file mode 100644 (file)
index 0000000..7818c8c
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * \file apidoc/arch_x86.h
+ * \brief x86(-64) Specific Functions
+ * \author John Hodge (thePowersGang)
+ *
+ * \section toc        Table of Contents
+ * - \ref portio "Port IO"
+ * - \ref dma "DMA - Direct Memory Access"
+ * 
+ * \section portio Port IO
+ * The x86 architecture has two memory spaces, the first is the system
+ * memory accessable using standard loads and stores. The second is the
+ * 16-bit IO Bus. This bus is accessed using the \a in and \a out opcodes
+ * and is used to configure devices attached to the system.
+ * A driver should not use \a in and \a out directly, but instead use
+ * the provided \a in* and \a out* functions to access the IO Bus.
+ * This allows the kernel to run a driver in userspace if requested without
+ * the binary needing to be altered.
+ * 
+ * \section dma        DMA - Direct Memory Access
+ */
+
+/**
+ * \name IO Bus Access
+ * \{
+ */
+extern Uint8   inb(Uint16 Port);       //!< Read 1 byte from the IO Bus
+extern Uint16  inw(Uint16 Port);       //!< Read 2 bytes from the IO Bus
+extern Uint32  inl(Uint16 Port);       //!< Read 4 bytes from the IO Bus
+extern Uint64  inq(Uint16 Port);       //!< Read 8 bytes from the IO Bus\
+
+extern void    outb(Uint16 Port, Uint8 Value); //!< Write 1 byte to the IO Bus
+extern void    outw(Uint16 Port, Uint16 Value);        //!< Write 2 bytes to the IO Bus
+extern void    outl(Uint16 Port, Uint32 Value);        //!< Write 4 bytes to the IO Bus
+extern void    outq(Uint16 Port, Uint64 Value);        //!< Write 8 bytes to the IO Bus
+/**
+ * \}
+ */
diff --git a/KernelLand/Kernel/include/apidoc_mainpage.h b/KernelLand/Kernel/include/apidoc_mainpage.h
new file mode 100644 (file)
index 0000000..0060baf
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * \file apidoc_mainpage.h
+ * \brief API Documentation Home Page
+ * \author John Hodge (thePowersGang)
+ * 
+ * \mainpage Acess 2 Kernel API Documentation
+ * 
+ * \section intro Introduction
+ * These documents attempt to describe the standard Acess 2 (and hopefully
+ * future versions) Kernel mode API.
+ * The documentation covers filesystem drivers, binary formats and the
+ * various device driver interface standards.
+ * 
+ * \section index      "Sections"
+ * - \ref modules.h "Module Definitions"
+ *  - Describes how a module is defined in Acess
+ * - \ref binary.h     "Binary Formats"
+ *  - Explains how to register a new binary format with the kernel
+ * - \ref vfs.h        "VFS - The Virtual File System"
+ *  - The VFS is the core of Acess's driver architecture
+ * - \ref drivers      "Device Drivers"
+ *  - Describes how drivers should use the VFS to expose themselves to the
+ *    user.
+ *  - Drivers for specific types of hardware must behave in the specific
+ *    way described here.
+ * 
+ * \page drivers Device Drivers
+ * 
+ * \section toc        Contents
+ * - \ref drvintro     "Introduction"
+ * - \ref drv_misc "Miscelanious Devices"
+ * - \ref drv_video    "Video Drivers"
+ * 
+ * \section drvintro   Introduction
+ * All Acess2 device drivers communicate with user-level (and other parts
+ * of the greater kernel) via the VFS. They register themselves in a similar
+ * way to how filesystem drivers do, however instead of registering with
+ * the VFS core, they register with a special filesystem driver called the
+ * \ref fs_devfs.h "Device Filesystem" (devfs). The DevFS provides the
+ * ::DevFS_AddDevice function that takes a ::tDevFS_Driver structure as
+ * an agument. This structure specifies the driver's name and its root
+ * VFS node. This node is used to provide the user access to the
+ * driver's functions via IOCtl calls and Reading or Writing to the driver
+ * file. Drivers are also able to expose a readonly buffer by using
+ * \ref fs_sysfs.h "ProcDev", usually to provide state information or device
+ * capabilities for the the user.
+ * 
+ * The device driver interfaces are all based on the core specifcation
+ * in api_drv_common.h (Common Device Driver definitions).
+ * The following subsections define the various specific types of driver
+ * interfaces. These definitions only define the bare minimum of what the
+ * driver must implement, if the driver author so wants to, they can add
+ * IOCtl calls and/or files (where allowed by the type specifcation) to
+ * their device's VFS layout.
+ * 
+ * \subsection drv_misc Miscelanious Devices
+ * If a device type does not have a specifcation for it, the driver can
+ * identify itself as a miscelanious device by returning DRV_TYPE_MISC
+ * from \ref DRV_IOCTL_TYPE.
+ * A misc device must at least implement the IOCtl calls defined in the
+ * \ref api_drv_common.h "Common Device Driver definitions", allowing it
+ * to be identified easily by the user and for interfacing programs to
+ * utilise the DRV_IOCTL_LOOKUP call.
+ * 
+ * \subsection drv_video Video Devices
+ * Video drivers are based on a framebuffer model (unless in 3D mode,
+ * which is not yet fully standardised, so should be ignored).
+ * The driver will contain only one VFS node, that exposes the video
+ * framebuffer (this may not be the true framebuffer, to allow for double-buffering)
+ * to the user. See the full documentation in api_drv_video.h for the
+ * complete specifcation.
+ * 
+ * \subsection drv_disk Disk/Storage Devices
+ * Storage devices present themselves as a linear collection of bytes.
+ * Reads and writes to the device need not be aligned to the stated block
+ * size, but it is suggested that users of a storage device file align
+ * their accesses to block boundaries.
+ * The functions DrvUtil_ReadBlock and DrvUtil_WriteBlock are provided
+ * to storage drivers to assist in handling non-alinged reads and writes.
+ * 
+ * \see api_drv_common.h Common Spec.
+ * \see api_drv_video.h Video Device Spec.
+ * \see api_drv_keyboard.h Keyboard Device Spec.
+ * \see api_drv_disk.h Disk/Storage Device Spec.
+ * \see api_drv_network.h Network Device Spec.
+ * \see api_drv_terminal.h Virtual Terminal Spec.
+ */
diff --git a/KernelLand/Kernel/include/binary.h b/KernelLand/Kernel/include/binary.h
new file mode 100644 (file)
index 0000000..c94a1b0
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * \file binary.h
+ * \brief Binary Loader Definitions
+ * \author John Hodge (thePowersGang)
+ */
+#ifndef _BINARY_H
+#define _BINARY_H
+
+// === TYPES ===
+/**
+ * \brief Representation of a section in a binary file
+ * 
+ * Tells the binary loader where the page data resides on disk and where
+ * to load it to (relative to the binary base). Once the data is read,
+ * the \a Physical field contains the physical address of the page.
+ */
+typedef struct sBinarySection
+{
+       Uint64  Offset;         //!< File offset of the section
+       tVAddr  Virtual;        //!< Virtual load address
+       size_t  FileSize;       //!< Number of bytes to load from the file
+       size_t  MemSize;        //!< Number of bytes in memory
+       Uint    Flags;  //!< Load Flags
+}      tBinarySection;
+
+/**
+ * \brief Flags for ::tBinarySection.Flags
+ * \name Binary Section Flags
+ * \{
+ */
+//! \brief Read-only
+#define BIN_SECTFLAG_RO                0x0001
+//! \brief Executable
+#define BIN_SECTFLAG_EXEC      0x0002
+/**
+ * \}
+ */
+
+/**
+ * \brief Defines a binary file
+ * 
+ * This structure defines and maintains the state of a binary during and
+ * after loading.
+ * Before the binary is loaded into memory (when it has just been returned
+ * from tBinaryType.Load) the \a Pages array will contain the file offsets
+ * to the page data in the \a Physical fields (or -1 for uninitialised
+ * data) and the \a Size fields define how much data is stored in-file
+ * for the page (to allow partial pages to be loaded from disk)
+ * Once the binary is loaded (NOTE: Drivers do not need to know about this,
+ * it is here for information only) the \a Physical fields now contain the
+ * physical addresses of the pages filled with the data. The \a Virtual
+ * fields contain the preferred virtual address of the pages (a given
+ * process may have these pages mapped to a different location).
+ */
+typedef struct sBinary
+{
+       struct sBinary  *Next;  //!< Pointer used by the kernel
+
+       tMount  MountID;        //!< Mount ID
+       tInode  Inode;          //!< Inode (Used for fast reopen)
+
+       /**
+        * \brief Interpreter used to load the file
+        * \note This can be either requested by the individual file, or a per-driver option
+        */
+       const char      *Interpreter;
+       /**
+        * \brief Entrypoint of the binary (at requested base);
+        */
+       tVAddr  Entry;
+       /**
+        * \brief File's requested load base
+        */
+       tVAddr  Base;
+       /**
+        * \brief Number of times this binary has been mapped
+        */
+        int    ReferenceCount;
+       /**
+        * \brief Number of sections defined in the file
+        */
+        int    NumSections;
+       /**
+        * \brief Array of sections defined by this binary
+        * \note Contains \a NumSections entries
+        */
+       tBinarySection  LoadSections[];
+}      tBinary;
+
+/**
+ * \brief Binary type definition
+ * 
+ * This structure is used to define a loader for a specific binary type
+ * so that the kernel's core binary loader can understand that type.
+ * The tBinaryType.Relocate and tBinaryType.GetSymbol need only be non-NULL
+ * if the binary type is to be used for kernel modules, otherwise it will
+ * only be able to load binaries for user space.
+ */
+typedef struct sBinaryType
+{
+       /**
+        * \brief Pointer used by the kernel
+        * \note Should not be touched by the driver (initialise to NULL)
+        */
+       struct sBinaryType      *Next;
+       /**
+        * \brief Identifying DWord
+        * 
+        * If he first 32-bits of the file match this value (when ANDed with
+        * tBinaryType.Mask), this binary loader will be used to load the file.
+        */
+       Uint32  Ident;
+       Uint32  Mask;   //!< Mask value for tBinaryType.Ident
+       const char      *Name;  //!< Name of this executable type (for debug purpouses)
+       /**
+        * \brief Read a binary from a file
+        * \param FD    VFS File handle to file to load
+        * \return Pointer to a ::tBinary that describes how to load the file
+        * 
+        * This function reads a binary file and returns a ::tBinary pointer
+        * that tells the core binary loader how to read the data from the file
+        * and where to map it to.
+        */
+       tBinary *(*Load)(int FD);
+       
+       /**
+        * \brief Prepares a mapped binary for execution at this address
+        * \param Base  Binary loaded in memory
+        * \return Boolean Success
+        * \note This pointer can be NULL, but then the binary cannot be used
+        *       to load a kernel module.
+        * 
+        * tBinaryType.Relocate takes a binary that was loaded according to
+        * tBinaryType.Load and prepares it to run at the address it is
+        * loaded to, attempting to satisfy any external unresolved symbols
+        * required, if a symbol cannot be located, the function will return
+        * zero.
+        */
+        int    (*Relocate)(void *Base);
+        
+        /**
+         * \brief Gets a symbol's address from a loaded binary
+         * \note The binary pointed to by \a Base may not have been through
+         *       tBinaryType.Relocate at this time, so the driver should
+         *       accomodate this.
+         */
+        int    (*GetSymbol)(void *Base, const char *Name, Uint *Dest);
+} tBinaryType;
+
+/**
+ * \brief Registers an interpreter path with the binary loader
+ * \param Path Path to the requested interpreter (need not be a "true" path)
+ * \return Pointer to the cached string
+ * 
+ * Speeds up checking if the intepreter is loaded in the kernel by allowing
+ * the search to use pointer comparisons instead of string comparisons.
+ */
+extern char    *Binary_RegInterp(char *Path);
+
+/**
+ * \brief Registers a binary type with the kernel's loader
+ * \param Type Pointer to the loader's type structure
+ * \return Boolean success
+ * \note The structure \a Type must be persistant (usually it will be a
+ *       constant global variable)
+ * 
+ * This function tells the binary loader about a new file type, and gives
+ * it the functions to read the type into a ::tBinary structure, relocate
+ * it and to find the value of symbols defined within the binary.
+ */
+extern  int    Binary_RegisterType(tBinaryType *Type);
+
+#endif
diff --git a/KernelLand/Kernel/include/binary_ext.h b/KernelLand/Kernel/include/binary_ext.h
new file mode 100644 (file)
index 0000000..b2fc89d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Acess 2
+ * binary_ext.h
+ * - Exported Symbols from the binary loader
+ */
+#ifndef _BINARY_EXT_H
+#define _BINARY_EXT_H
+
+// === FUNCTIONS ===
+extern void    *Binary_LoadFile(const char *Path);
+extern void    *Binary_LoadKernel(const char *Path);
+extern Uint    Binary_Relocate(void *Mem);
+extern void    Binary_Unload(void *Base);
+extern int     Binary_GetSymbol(const char *Name, Uint *Dest);
+extern Uint    Binary_FindSymbol(void *Base, const char *Name, Uint *Val);
+
+#endif
diff --git a/KernelLand/Kernel/include/drv_pci.h b/KernelLand/Kernel/include/drv_pci.h
new file mode 100644 (file)
index 0000000..33c4a3e
--- /dev/null
@@ -0,0 +1,61 @@
+/**\r
+ * \file drv_pci.h\r
+ * \brief PCI Bus Driver\r
+ * \author John Hodge (thePowersGang)\r
+ */\r
+#ifndef _DRV_PCI_H\r
+#define _DRV_PCI_H\r
+\r
+/**\r
+ * \brief PCI Class Codes\r
+ */\r
+enum ePCIClasses\r
+{\r
+       PCI_CLASS_PRE20 = 0x00,\r
+       PCI_CLASS_STORAGE,\r
+       PCI_CLASS_NETWORK,\r
+       PCI_CLASS_DISPLAY,\r
+       PCI_CLASS_MULTIMEDIA,\r
+       PCI_CLASS_MEMORY,\r
+       PCI_CLASS_BRIDGE,\r
+       PCI_CLASS_COMM,\r
+       PCI_CLASS_PREPH,\r
+       PCI_CLASS_INPUT,\r
+       PCI_CLASS_DOCKING,\r
+       PCI_CLASS_PROCESSORS,\r
+       PCI_CLASS_SERIALBUS,\r
+       PCI_CLASS_MISC = 0xFF\r
+};\r
+\r
+enum ePCIOverClasses\r
+{\r
+       PCI_OC_PCIBRIDGE = 0x060400,\r
+       PCI_OC_SCSI = 0x010000\r
+};\r
+\r
+typedef int    tPCIDev;\r
+\r
+/**\r
+ * \brief Count PCI Devices\r
+ * \r
+ * Counts the number of devices with specified Vendor and Device IDs\r
+ */\r
+extern int     PCI_CountDevices(Uint16 VendorID, Uint16 DeviceID);\r
+extern tPCIDev PCI_GetDevice(Uint16 VendorID, Uint16 DeviceID, int index);\r
+/**\r
+ * \param ClassCode (Class:SubClass:PI)\r
+ */\r
+extern tPCIDev PCI_GetDeviceByClass(Uint32 ClassCode, Uint32 Mask, tPCIDev prev);\r
+\r
+extern int     PCI_GetDeviceInfo(tPCIDev id, Uint16 *Vendor, Uint16 *Device, Uint32 *Class);\r
+extern int     PCI_GetDeviceVersion(tPCIDev id, Uint8 *Revision);\r
+extern int     PCI_GetDeviceSubsys(tPCIDev id, Uint16 *SubsystemVendor, Uint16 *SubsystemID);\r
+\r
+extern Uint32  PCI_ConfigRead(tPCIDev id, int Offset, int Size);\r
+extern void    PCI_ConfigWrite(tPCIDev id, int Offset, int Size, Uint32 Value);\r
+\r
+extern Uint8   PCI_GetIRQ(tPCIDev id);\r
+extern Uint32  PCI_GetBAR(tPCIDev id, int BAR);\r
+//extern Uint16        PCI_AssignPort(tPCIDev id, int bar, int count);\r
+\r
+#endif\r
diff --git a/KernelLand/Kernel/include/drv_pci_int.h b/KernelLand/Kernel/include/drv_pci_int.h
new file mode 100644 (file)
index 0000000..f168141
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv_pci_int.h
+ * - PCI internal definitions
+ */
+#ifndef _DRV_PCI_INT_H
+#define _DRV_PCI_INT_H
+
+#include <acess.h>
+
+extern Uint32  PCI_CfgReadDWord(Uint32 Addr);
+extern void    PCI_CfgWriteDWord(Uint32 Addr, Uint32 data);
+
+#endif
+
diff --git a/KernelLand/Kernel/include/errno.h b/KernelLand/Kernel/include/errno.h
new file mode 100644 (file)
index 0000000..3652f19
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Acess2
+ * errno.h
+ */
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+enum eErrorNums
+{
+       EOK,
+       
+       ENOSYS, // Invalid Instruction
+       EINVAL, // Invalid Paramater
+       ENOMEM, // No free memory
+       EACCES, // Not permitted
+       ENOTFOUND,      // Item not found
+       EREADONLY,      // Read only
+       ENOTIMPL,       // Not implemented
+       ENOENT, // No entry?
+       EEXIST, // Already exists
+       ENFILE, // Too many open files
+       ENOTDIR,        // Not a directory
+       
+       EALREADY,       // Operation was a NOP
+       EINTERNAL,      // Internal Error
+       
+       NUM_ERRS
+};
+
+#endif
diff --git a/KernelLand/Kernel/include/events.h b/KernelLand/Kernel/include/events.h
new file mode 100644 (file)
index 0000000..675c3db
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * events.h
+ * - Thread Events
+ */
+#ifndef _EVENTS_H_
+#define _EVENTS_H_
+
+#include <threads.h>
+
+#define THREAD_EVENT_VFS       0x00000001
+#define THREAD_EVENT_IPCMSG    0x00000002
+#define THREAD_EVENT_SIGNAL    0x00000004
+#define THREAD_EVENT_TIMER     0x00000008
+
+// === FUNCTIONS ===
+extern void    Threads_PostEvent(tThread *Thread, Uint32 EventMask);
+extern Uint32  Threads_WaitEvents(Uint32 EventMask);
+
+#endif
+
diff --git a/KernelLand/Kernel/include/fs_devfs.h b/KernelLand/Kernel/include/fs_devfs.h
new file mode 100644 (file)
index 0000000..c099fc6
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * \file fs_devfs.h
+ * \brief Acess Device Filesystem interface
+ * \author John Hodge (thePowersGang)
+ */
+#ifndef _FS_DEVFS_H
+#define _FS_DEVFS_H
+#include <vfs.h>
+
+// === TYPES ===
+/**
+ * \brief DevFS driver definition
+ */
+typedef struct sDevFS_Driver
+{
+       struct sDevFS_Driver    *Next;  //!< Set to NULL by drivers (used internally)
+       const char      *Name;  //!< Name of the driver file/folder (must be unique)
+       tVFS_Node       RootNode;       //!< Root node of driver
+} tDevFS_Driver;
+
+// === FUNCTIONS ===
+/**
+ * \fn int DevFS_AddDevice(tDevFS_Driver *Device)
+ * \brief Registers a device in the Device Filesystem
+ * \param Device       Pointer to a persistant structure that represents the driver
+ * \return Boolean success
+ */
+extern int     DevFS_AddDevice(tDevFS_Driver *Device);
+
+/**
+ * \brief Unregisters a device with the Device Filesystem
+ */
+extern void    DevFS_DelDevice(tDevFS_Driver *Device);
+
+#endif
diff --git a/KernelLand/Kernel/include/fs_sysfs.h b/KernelLand/Kernel/include/fs_sysfs.h
new file mode 100644 (file)
index 0000000..aac64d9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Acess2
+ * - SysFS Export Header
+ */
+/**
+ * \file fs_sysfs.h
+ * \brief ProcDev/SysFS Interface
+ * \author John Hodge (thePowersGang)
+ * 
+ * 
+ */
+#ifndef _FS_SYSFS_H_
+#define _FS_SYSFS_H_
+
+/**
+ * \brief Registers a file in the SysFS tree
+ * \param Path Path relative to the SysFS root (no .. or .)
+ * \param Data File buffer address
+ * \param Length       Length of the file buffer
+ * \return An ID number to refer to the file, or -1 on error
+ * \note \a Data must be maintained until ::SysFS_UpdateFile is called
+ *       with a different buffer, or ::SysFS_RemoveFile is called.
+ */
+extern int     SysFS_RegisterFile(const char *Path, const char *Data, int Length);
+
+/**
+ * \brief Updates the size/pointer associated with a SysFD file
+ * \param ID   Number returned by ::SysFS_RegisterFile
+ * \param Data New buffer address
+ * \param Length       New length of the file
+ * \return Boolean Success
+ */
+extern int     SysFS_UpdateFile(int ID, const char *Data, int Length);
+
+/**
+ * \brief Removes a file from the SysFS tree
+ * \param ID   Number returned by ::SysFS_RegisterFile
+ */
+extern int     SysFS_RemoveFile(int ID);
+
+#endif
diff --git a/KernelLand/Kernel/include/hal_proc.h b/KernelLand/Kernel/include/hal_proc.h
new file mode 100644 (file)
index 0000000..0f21a1c
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * include/hal_proc.h
+ * - HAL Process management functions
+ * 
+ */
+#ifndef _HAL_PROC_H_
+#define _HAL_PROC_H_
+/**
+ * \file hal_proc.h
+ * \brief Achitecture defined thread/process management functions
+ */
+
+#include <threads_int.h>
+
+/**
+ * \brief Initialise the architecture dependent side of threading
+ */
+extern void    ArchThreads_Init(void);
+/**
+ * \brief Start preemptive multithreading (if needed)
+ */
+extern void    Proc_Start(void);
+/**
+ * \brief Called just before a thread is freed
+ */
+extern void    Proc_ClearThread(tThread *Thread);
+/**
+ * \brief Called just before a process is freed
+ */
+extern void    Proc_ClearProcess(tProcess *Process);
+/**
+ * \brief Get the ID of this CPU
+ * \return Zero based CPU ID
+ */
+extern int     GetCPUNum(void);
+/**
+ * \brief Create a copy of the current process
+ * \param Flags        Options for the clone
+ * \return ID of the new thread/process
+ */
+extern tTID    Proc_Clone(Uint Flags);
+/**
+ * \brief Create a new kernel thread for the process
+ * \param Fnc  Thread root function
+ * \param Ptr  Argument to pass the root function
+ * \return ID of new thread
+ */
+extern tTID    Proc_NewKThread( void (*Fnc)(void*), void *Ptr );
+/**
+ * \brief Start a user task
+ * \param Entrypoint   User entrypoint
+ * \param Base Base of executable (argument for ld-acess)
+ * \param ArgC Number of arguments when the program was invoked
+ * \param ArgV Heap allocated arguments and environment (two NULL terminated lists)
+ * \param DataSize     Size of the \a ArgV buffer in bytes
+ * \note This function should free \a ArgV
+ */
+extern void    Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize) NORETURN;
+/**
+ * \brief Call the fault handler for a thread
+ * \param Thread       Thread that is at fault :)
+ */
+extern void    Proc_CallFaultHandler(tThread *Thread);
+/**
+ * \brief Dump the CPU state for a thread
+ */
+extern void    Proc_DumpThreadCPUState(tThread *Thread);
+/**
+ * \brief Select a new task and run it, suspending this
+ */
+extern void    Proc_Reschedule(void);
+
+/**
+ * \brief Clear the user's memory space back to the minimum required to run
+ */
+extern void    MM_ClearUser(void);
+/**
+ * \brief Dump the address space to the debug channel
+ * \param Start        First address
+ * \param End  Last address
+ */
+extern void    MM_DumpTables(tVAddr Start, tVAddr End);
+
+/**
+ * \brief Check if a buffer is valid (and all user if originally user)
+ * \param Addr Base address
+ * \param Size Size of the buffer in bytes
+ * \return Boolean valid (0: invalid, non-0: Valid)
+ */
+extern int     MM_IsValidBuffer(tVAddr Addr, size_t Size);
+#endif
diff --git a/KernelLand/Kernel/include/heap.h b/KernelLand/Kernel/include/heap.h
new file mode 100644 (file)
index 0000000..b058e8b
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * Acess2 Kernel
+ * heap.h
+ * - Dynamic Memory Allocation exports
+ */
+
+#ifndef _HEAP_H_
+#define _HEAP_H_
+
+extern void    *Heap_Allocate(const char *File, int Line, size_t Bytes);
+extern void    *Heap_AllocateZero(const char *File, int Line, size_t Bytes);
+extern void    *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes);
+extern void    Heap_Deallocate(void *Ptr);
+extern int     Heap_IsHeapAddr(void *Ptr);
+extern void    Heap_Validate(void);
+
+#define malloc(size)   Heap_Allocate(_MODULE_NAME_"/"__FILE__, __LINE__, (size))
+#define calloc(num,size)       Heap_AllocateZero(_MODULE_NAME_"/"__FILE__, __LINE__, (num)*(size))
+#define realloc(ptr,size)      Heap_Reallocate(_MODULE_NAME_"/"__FILE__, __LINE__, (ptr), (size))
+#define        free(ptr)       Heap_Deallocate((ptr))
+#define IsHeap(ptr)    Heap_IsHeapAddr((ptr))
+
+#define strdup(Str)    _strdup(_MODULE_NAME_"/"__FILE__, __LINE__, (Str))
+
+#endif
diff --git a/KernelLand/Kernel/include/heap_int.h b/KernelLand/Kernel/include/heap_int.h
new file mode 100644 (file)
index 0000000..12a709b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * AcessOS Microkernel Version
+ * heap_int.h
+ * - Internal Heap Header
+ */
+#ifndef _HEAP_INT_H
+#define _HEAP_INT_H
+
+typedef struct {
+       Uint    Size;
+        int    ValidSize;
+       const char      *File;
+        int    Line;
+       Uint    Magic;
+       tTime   AllocateTime;
+       char    Data[];
+} tHeapHead;
+
+typedef struct {
+       Uint    Magic;
+       tHeapHead       *Head;
+       tHeapHead       NextHead[];     // Array to make it act like an element, but have no size and refer to the next block
+} tHeapFoot;
+
+#endif
diff --git a/KernelLand/Kernel/include/init.h b/KernelLand/Kernel/include/init.h
new file mode 100644 (file)
index 0000000..9f2fc10
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * AcessOS Microkernel Version
+ * init.h
+ */
+#ifndef _INIT_H
+#define _INIT_H
+
+extern void    Arch_LoadBootModules(void);
+extern void    StartupPrint(const char *String);
+
+#endif
diff --git a/KernelLand/Kernel/include/iocache.h b/KernelLand/Kernel/include/iocache.h
new file mode 100644 (file)
index 0000000..f008a2d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Acess2 Kernel
+ * - IO Cache
+ * 
+ * By thePowersGang (John Hodge)
+ */
+/**
+ * \file iocache.h
+ * \brief I/O Caching Helper Subsystem
+ * 
+ * The IO Cache abstracts caching of disk sectors away from the device
+ * driver to reduce code duplication and allow a central location for
+ * disk cache management that can be flushed simply by the kernel, without
+ * having to ask each driver to do it indivitually.
+ */
+#ifndef _IOCHACHE_H_
+#define _IOCHACHE_H_
+
+// === TYPES ===
+/**
+ * \brief IO Cache Handle
+ */
+typedef struct sIOCache        tIOCache;
+/**
+ * \brief Write Callback
+ * 
+ * Called to write a sector back to the device
+ */
+typedef int    (*tIOCache_WriteCallback)(Uint32 ID, Uint64 Sector, void *Buffer);
+
+// === CONSTANTS ===
+/**
+ * \brief I/O Cache handling modes
+ */
+enum eIOCache_Modess {
+       /**
+        * \brief Writeback
+        * 
+        * Transparently writes data straight to the device when the cache
+        * is written to.
+        */
+       IOCACHE_WRITEBACK,
+       /**
+        * \brief Delay Write
+        * 
+        * Only writes when instructed to (by ::IOCache_Flush) or when a
+        * cached sector is being reallocated.
+        */
+       IOCACHE_DELAYWRITE,
+       /**
+        * \brief Virtual - No Writes
+        * 
+        * Changes to the cache contents are only reflected in memory,
+        * any calls to ::IOCache_Flush will silently return without doing
+        * anything and if a sector is reallocated, all changes will be lost
+        */
+       IOCACHE_VIRTUAL
+};
+
+// === FUNCTIONS ===
+/**
+ * \brief Creates a new IO Cache
+ * \param Write        Function to call to write a sector to the device
+ * \param ID   ID to pass to \a Write
+ * \param SectorSize   Size of a cached sector
+ * \param CacheSize    Maximum number of objects that can be in the cache at one time
+ */
+tIOCache       *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize );
+
+/**
+ * \brief Reads from a cached sector
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \param Sector       Sector's ID number
+ * \param Buffer       Destination for the data read
+ * \return     1 if the data was read, 0 if the sector is not cached, -1 on error
+ */
+ int   IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer );
+
+/**
+ * \brief Adds a sector to the cache
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \param Sector       Sector's ID number
+ * \param Buffer       Data to cache
+ * \return     1 on success, 0 if the sector is already cached, -1 on error
+ */
+ int   IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer );
+
+/**
+ * \brief Writes to a cached sector
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \param Sector       Sector's ID number
+ * \param Buffer       Data to write to the cache
+ * \return     1 if the data was read, 0 if the sector is not cached, -1 on error
+ * 
+ * If the sector is in the cache, it is updated.
+ * Wether the Write callback is called depends on the selected caching
+ * behaviour.
+ */
+ int   IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer );
+
+/**
+ * \brief Flush altered sectors out to the device
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * 
+ * This will call the cache's write callback on each altered sector
+ * to flush the write cache.
+ */
+void   IOCache_Flush( tIOCache *Cache );
+
+/**
+ * \brief Flushes the cache and then removes it
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \note After this is called \a Cache is no longer valid
+ * 
+ * IOCache_Destroy writes all changed sectors to the device and then
+ * deallocates the cache for other systems to use.
+ */
+void   IOCache_Destroy( tIOCache *Cache );
+
+#endif
diff --git a/KernelLand/Kernel/include/lib/keyvalue.h b/KernelLand/Kernel/include/lib/keyvalue.h
new file mode 100644 (file)
index 0000000..ef37d5b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * include/keyvalue.h
+ * - Key/Value pair parsing
+ */
+#ifndef _ACESS_KEYVALUE_H_
+#define _ACESS_KEYVALUE_H_
+
+typedef struct sKeyVal_ParseRules      tKeyVal_ParseRules;
+typedef struct sKeyVal_int_Rule        tKeyVal_int_Rule;
+typedef void (*tKeyVal_UnkCb)(char *String);
+typedef void (*tKeyVal_KeyCb)(const char *Key, char *Value);
+
+/**
+ * \brief Handling rule for a key
+ */
+struct sKeyVal_int_Rule
+{
+       const char      *Key;
+       const char      *Type;  // Acess printf format, with 'F' being a tKeyVal_KeyCb
+       void    *Data;
+};
+
+struct sKeyVal_ParseRules
+{
+       /**
+        * \brief Function to call when no match is found
+        */
+       tKeyVal_UnkCb   Unknown;
+       tKeyVal_int_Rule        Rules[];
+};
+
+/**
+ * \brief Parse a NULL terminated list of strings as Key/Value pairs
+ * \param Rules        Parsing rules
+ * \param Strings      Input string list
+ */
+extern int     KeyVal_ParseNull(tKeyVal_ParseRules *Rules, char **Strings);
+
+#endif
+
diff --git a/KernelLand/Kernel/include/mboot.h b/KernelLand/Kernel/include/mboot.h
new file mode 100644 (file)
index 0000000..c7f33dd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * AcessOS Microkernel Version
+ * mboot.h
+ */
+#ifndef _MBOOT_H
+#define _MBOOT_H
+
+#define MULTIBOOT_MAGIC        0x2BADB002
+
+// === TYPES ===
+typedef struct {
+       Uint32  Flags;
+       Uint32  LowMem;
+       Uint32  HighMem;
+       Uint32  BootDevice;
+       Uint32  CommandLine;
+       Uint32  ModuleCount;
+       Uint32  Modules;
+       Uint32  SymbolInfo[4];  // #32 UNUSED
+       Uint32  MMapLength;
+       Uint32  MMapAddr;               // #40
+} tMBoot_Info;
+
+typedef struct {
+       Uint32  Start;
+       Uint32  End;
+       Uint32  String;
+       Uint32  Resvd;
+} tMBoot_Module;
+
+typedef struct {
+       Uint32  Size;   // (May be at offset -4)
+       Uint64  Base;
+       Uint64  Length;
+       Uint32  Type;   //1:RAM,Else Reserved
+} __attribute__ ((packed)) tMBoot_MMapEnt;
+
+#endif
diff --git a/KernelLand/Kernel/include/modules.h b/KernelLand/Kernel/include/modules.h
new file mode 100644 (file)
index 0000000..d728133
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * AcessOS 2
+ * - Module Loader
+ */
+/**
+ * \file modules.h
+ * \brief Module Handling and Loader Definitions
+ * \author John Hodge (thePowersGang)
+ * 
+ * This file serves two pourposes. First it defines the format for native
+ * Acess2 modules and the functions to create them.
+ * Second, it defines the structure and register function for new module
+ * loaders, allowing Acess to understand many different module / driver
+ * formats.
+ * 
+ * Modules are defined by including this file in the module's main source
+ * file and using the ::MODULE_DEFINE macro to create the module header.
+ * 
+ * To register a new module loader with the kernel, the loader module must
+ * create and populate an instance of ::tModuleLoader then pass it to
+ * ::Module_RegisterLoader
+ */
+#ifndef _MODULE_H
+#define _MODULE_H
+
+/**
+ * \brief Module header magic value
+ */
+#define MODULE_MAGIC   ('A'|('M'<<8)|('D'<<16)|('\2'<<24))
+
+/**
+ * \def MODULE_ARCH_ID
+ * \brief Architecture ID
+ */
+// IA32 - Architecture 1
+#if ARCHDIR == x86
+# define MODULE_ARCH_ID        1
+// IA64 - Architecture 2
+#elif ARCHDIR == x86_64
+# define MODULE_ARCH_ID        2
+#else
+# error "Unknown architecture when determining MODULE_ARCH_ID ('" #ARCHDIR "')"
+#endif
+
+/**
+ * \brief Define a module
+ * \param _flags       Module Flags
+ * \param _ver Module Version
+ * \param _ident       Unique Module Name
+ * \param _entry       Module initialiser / entrypoint
+ * \param _deinit      Module cleanup / unloader
+ * \param _deps        NULL terminated list of this's module's dependencies
+ *                     Contains the identifiers of the required modules.
+ */
+#define MODULE_DEFINE(_flags,_ver,_ident,_entry,_deinit,_deps...) \
+       const char *EXPAND_CONCAT(_DriverDeps_,_ident)[]={_deps};\
+       tModule __attribute__ ((section ("KMODULES"),unused))\
+       EXPAND_CONCAT(_DriverInfo_,_ident)=\
+       {MODULE_MAGIC,MODULE_ARCH_ID,_flags,_ver,NULL,EXPAND_STR(_ident),\
+       _entry,_deinit,EXPAND_CONCAT(_DriverDeps_,_ident)}
+
+/**
+ * \brief Module header
+ * \note There is no reason for a module to touch this structure beyond
+ *       using ::MODULE_DEFINE to create it.
+ */
+typedef struct sModule 
+{
+       Uint32  Magic;  //!< Identifying magic value (See ::MODULE_MAGIC)
+       Uint8   Arch;   //!< Achitecture ID (See ::MODULE_ARCH_ID)
+       Uint8   Flags;  //!< Module Flags
+       Uint16  Version;        //!< Module Version in Major.Minor 8.8 form
+       struct sModule  *Next;  //!< Next module in list (not to be touched by the driver)
+       const char      *Name;  //!< Module Name/Identifier
+        int    (*Init)(char **Arguments);      //!< Module initialiser / entrypoint
+       void    (*Deinit)(void);        //!< Cleanup Function
+       const char      **Dependencies; //!< NULL terminated list of dependencies
+} PACKED tModule;
+
+/**
+ * \brief Return values for tModule.Init
+ */
+enum eModuleErrors
+{
+       MODULE_ERR_OK,  //!< No Error
+       MODULE_ERR_MISC,        //!< Misc Error
+       MODULE_ERR_NOTNEEDED,   //!< Module not needed
+       MODULE_ERR_MALLOC,      //!< Error with malloc/realloc/calloc
+       
+       MODULE_ERR_BADMODULE,   //!< Bad module (only used by loader)
+       MODULE_ERR_MAX  //!< Maximum defined error code
+};
+
+/**
+ * \brief Module Loader definition
+ * 
+ * Allows a module to extend the loader to recognise other module types
+ * E.g. EDI, UDI, Windows, Linux, ...
+ */
+typedef struct sModuleLoader
+{
+       struct sModuleLoader    *Next;  //!< Kernel Only - Next loader in list
+       char    *Name;  //!< Friendly name for the loader
+        int    (*Detector)(void *Base);        //!< Simple detector function
+        int    (*Loader)(void *Base);  //!< Initialises the module
+        int    (*Unloader)(void *Base);        //!< Calls module's cleanup
+} PACKED tModuleLoader;
+
+/**
+ * \brief Registers a tModuleLoader with the kernel
+ * \param Loader       Pointer to loader structure (must be persistent)
+ * \return Boolean Success
+ */
+extern int     Module_RegisterLoader(tModuleLoader *Loader);
+
+/**
+ * \brief Initialises (if needed) a named module
+ * \param Name Module name to initialise
+ * \return -1 on not existing, 0 if the module initialised (or if it was already initialised)
+ */
+extern int     Module_EnsureLoaded(const char *Name);
+
+#endif
diff --git a/KernelLand/Kernel/include/mutex.h b/KernelLand/Kernel/include/mutex.h
new file mode 100644 (file)
index 0000000..326dbd2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Acess2 Kernel
+ * mutex.h
+ * - Mutual Exclusion syncronisation primitive
+ */
+#ifndef _MUTEX_H
+#define _MUTEX_H
+
+#include <acess.h>
+
+typedef struct sMutex  tMutex;
+
+struct sMutex
+{
+       tShortSpinlock  Protector;      //!< Protector for the lock strucure
+       const char      *Name;  //!< Human-readable name
+       struct sThread  *volatile Owner;        //!< Owner of the lock (set upon getting the lock)
+       struct sThread  *Waiting;       //!< Waiting threads
+       struct sThread  *LastWaiting;   //!< Waiting threads
+};
+
+/**
+ * \brief Acquire a heavy mutex
+ * \param Mutex        Mutex to acquire
+ * \return zero on success, -1 if terminated
+ * 
+ * This type of mutex checks if the mutex is avaliable, and acquires it
+ * if it is. Otherwise, the current thread is added to the mutex's wait
+ * queue and the thread suspends. When the holder of the mutex completes,
+ * the oldest thread (top thread) on the queue is given the lock and
+ * restarted.
+ */
+extern int     Mutex_Acquire(tMutex *Mutex);
+
+/**
+ * \brief Release a held mutex
+ * \param Mutex        Mutex to release
+ * \note Releasing a non-held mutex has no effect
+ */
+extern void    Mutex_Release(tMutex *Mutex);
+
+/**
+ * \brief Is this mutex locked?
+ * \param Mutex        Mutex pointer
+ */
+extern int     Mutex_IsLocked(tMutex *Mutex);
+
+#endif
diff --git a/KernelLand/Kernel/include/semaphore.h b/KernelLand/Kernel/include/semaphore.h
new file mode 100644 (file)
index 0000000..db0b279
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Acess2 Kernel
+ * semaphore.h
+ * - Semaphore syncronisation primitive
+ */
+#ifndef _SEMAPHORE_H
+#define _SEMAPHORE_H
+
+#include <acess.h>
+
+/**
+ * \brief Semaphore typedef
+ */
+typedef struct sSemaphore      tSemaphore;
+
+/**
+ * \brief Semaphore structure
+ */
+struct sSemaphore {
+       tShortSpinlock  Protector;      //!< Protector for the lock strucure
+       const char      *ModName;       //!< Human-readable module name
+       const char      *Name;  //!< Human-readable name
+       volatile int    Value;  //!< Current value
+       volatile int    MaxValue;       //!< Maximum value (signal will wait if it will go over this)
+       
+       struct sThread  *Waiting;       //!< Waiting threads
+       struct sThread  *LastWaiting;   //!< Waiting threads
+       struct sThread  *Signaling;     //!< Waiting threads (from Semaphore_Signal)
+       struct sThread  *LastSignaling; //!< Last waiting thread (from Semaphore_Signal)
+};
+
+/**
+ * \brief Initialise the semaphore
+ * \param Sem  Semaphore structure to initialsie
+ * \param InitValue    Initial value of the semaphore
+ * \param MaxValue     Maximum value for the semaphore
+ * \param Module       Module name
+ * \param Name Symbolic name
+ * \note Not always needed, as initialising to 0 is valid, but it is preferred
+ *       if all semaphores have \a Name set
+ * 
+ * \note \a Module and \a Name must be avaliable for as long as the semaphore is used
+ */
+extern void    Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name);
+/**
+ * \brief Acquire items from the semaphore
+ * \param Sem  Semaphore structure to use
+ * \param MaxToTake    Maximum number of items to take off the list (if zero, as much as possible is taken)
+ * \return Number of items fetched
+ * \retval 0   Semaphore interrupted (signal/message)
+ * \retval -1  Unspecified error
+ */
+extern int     Semaphore_Wait(tSemaphore *Sem, int MaxToTake);
+/**
+ * \brief Add an "item" to the semaphore
+ * \param Sem  Semaphore to use
+ * \param AmmountToAdd Number of items to add
+ * \return Actual number of items added
+ * \retval 0   Semaphore interrupted
+ * \retval -1  Unspecified error
+ */
+extern int     Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd);
+/**
+ * \brief Get the number of items waiting in a semaphore
+ * \param Sem  Semaphore to use
+ * \return Number of waiting items
+ */
+extern int     Semaphore_GetValue(tSemaphore *Sem);
+
+#endif
diff --git a/KernelLand/Kernel/include/signal.h b/KernelLand/Kernel/include/signal.h
new file mode 100644 (file)
index 0000000..d97d6dc
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Acess2 Kernel
+ * Signal List
+ */
+#ifndef _SIGNAL_H_
+#define _SIGNAL_H_
+
+enum eSignals {
+       SIGKILL,
+       SIGSTOP,
+       SIGCONT,
+       SIGCHLD,
+       NSIG
+};
+
+#endif
diff --git a/KernelLand/Kernel/include/syscalls.h b/KernelLand/Kernel/include/syscalls.h
new file mode 100644 (file)
index 0000000..5ce2814
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Acess2
+ * syscalls.h
+ * - System Call List
+ *
+ * NOTE: Generated from Kernel/syscalls.lst
+ */
+#ifndef _SYSCALLS_H
+#define _SYSCALLS_H
+
+#define SYS_EXIT       0       // Kill this thread
+#define SYS_CLONE      1       // Create a new thread
+#define SYS_KILL       2       // Send a signal
+#define SYS_SETFAULTHANDLER    3       // Set signal Handler
+#define SYS_YIELD      4       // Yield remainder of timestamp
+#define SYS_SLEEP      5       // Sleep until messaged or signaled
+#define SYS_WAITEVENT  6       // Wait for an event
+#define SYS_WAITTID    7       // Wait for a thread to do something
+#define SYS_SETNAME    8       // Sets the name of the current thread
+#define SYS_GETNAME    9       // Gets the name of a thread
+#define SYS_GETTID     10      // Get current thread ID
+#define SYS_GETPID     11      // Get current thread group ID
+#define SYS_SETPRI     12      // Set process priority
+#define SYS_SENDMSG    13      // Send an IPC message
+#define SYS_GETMSG     14      // Recieve an IPC message
+#define SYS_GETTIME    15      // Get the current timestamp
+#define SYS_SPAWN      16      // Spawn a new process
+#define SYS_EXECVE     17      // Replace the current process
+#define SYS_LOADBIN    18      // Load a binary into the current address space
+#define SYS_UNLOADBIN  19      // Unload a loaded binary
+#define SYS_LOADMOD    20      // Load a module into the kernel
+#define SYS_GETPHYS    32      // Get the physical address of a page
+#define SYS_MAP        33      // Map a physical address
+#define SYS_ALLOCATE   34      // Allocate a page
+#define SYS_UNMAP      35      // Unmap a page
+#define SYS_PREALLOC   36      // Preallocate a page
+#define SYS_SETFLAGS   37      // Set a page's flags
+#define SYS_SHAREWITH  38      // Share a page with another thread
+#define SYS_GETUID     39      // Get current User ID
+#define SYS_GETGID     40      // Get current Group ID
+#define SYS_SETUID     41      // Set current user ID
+#define SYS_SETGID     42      // Set current Group ID
+#define SYS_OPEN       64      // Open a file
+#define SYS_REOPEN     65      // Close a file and reuse its handle
+#define SYS_CLOSE      66      // Close a file
+#define SYS_READ       67      // Read from an open file
+#define SYS_WRITE      68      // Write to an open file
+#define SYS_IOCTL      69      // Perform an IOCtl Call
+#define SYS_SEEK       70      // Seek to a new position in the file
+#define SYS_READDIR    71      // Read from an open directory
+#define SYS_OPENCHILD  72      // Open a child entry in a directory
+#define SYS_GETACL     73      // Get an ACL Value
+#define SYS_SETACL     74      // Set an ACL Value
+#define SYS_FINFO      75      // Get file information
+#define SYS_MKDIR      76      // Create a new directory
+#define SYS_LINK       77      // Create a new link to a file
+#define SYS_SYMLINK    78      // Create a symbolic link
+#define SYS_UNLINK     79      // Delete a file
+#define SYS_TELL       80      // Return the current file position
+#define SYS_CHDIR      81      // Change current directory
+#define SYS_GETCWD     82      // Get current directory
+#define SYS_MOUNT      83      // Mount a filesystem
+#define SYS_SELECT     84      // Wait for file handles
+
+#define NUM_SYSCALLS   85
+#define SYS_DEBUG      0x100
+
+#ifndef __ASSEMBLER__
+static const char *cSYSCALL_NAMES[] = {
+       "SYS_EXIT",
+       "SYS_CLONE",
+       "SYS_KILL",
+       "SYS_SETFAULTHANDLER",
+       "SYS_YIELD",
+       "SYS_SLEEP",
+       "SYS_WAITEVENT",
+       "SYS_WAITTID",
+       "SYS_SETNAME",
+       "SYS_GETNAME",
+       "SYS_GETTID",
+       "SYS_GETPID",
+       "SYS_SETPRI",
+       "SYS_SENDMSG",
+       "SYS_GETMSG",
+       "SYS_GETTIME",
+       "SYS_SPAWN",
+       "SYS_EXECVE",
+       "SYS_LOADBIN",
+       "SYS_UNLOADBIN",
+       "SYS_LOADMOD",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "SYS_GETPHYS",
+       "SYS_MAP",
+       "SYS_ALLOCATE",
+       "SYS_UNMAP",
+       "SYS_PREALLOC",
+       "SYS_SETFLAGS",
+       "SYS_SHAREWITH",
+       "SYS_GETUID",
+       "SYS_GETGID",
+       "SYS_SETUID",
+       "SYS_SETGID",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "",
+       "SYS_OPEN",
+       "SYS_REOPEN",
+       "SYS_CLOSE",
+       "SYS_READ",
+       "SYS_WRITE",
+       "SYS_IOCTL",
+       "SYS_SEEK",
+       "SYS_READDIR",
+       "SYS_OPENCHILD",
+       "SYS_GETACL",
+       "SYS_SETACL",
+       "SYS_FINFO",
+       "SYS_MKDIR",
+       "SYS_LINK",
+       "SYS_SYMLINK",
+       "SYS_UNLINK",
+       "SYS_TELL",
+       "SYS_CHDIR",
+       "SYS_GETCWD",
+       "SYS_MOUNT",
+       "SYS_SELECT",
+
+       ""
+};
+#endif
+
+#endif
diff --git a/KernelLand/Kernel/include/syscalls.inc.asm b/KernelLand/Kernel/include/syscalls.inc.asm
new file mode 100644 (file)
index 0000000..149fe37
--- /dev/null
@@ -0,0 +1,57 @@
+; Acess2
+; System Calls List
+; 
+
+%define SYS_EXIT       0        ;Kill this thread
+%define SYS_CLONE      1        ;Create a new thread
+%define SYS_KILL       2        ;Send a signal
+%define SYS_SETFAULTHANDLER    3        ;Set signal Handler
+%define SYS_YIELD      4        ;Yield remainder of timestamp
+%define SYS_SLEEP      5        ;Sleep until messaged or signaled
+%define SYS_WAITEVENT  6        ;Wait for an event
+%define SYS_WAITTID    7        ;Wait for a thread to do something
+%define SYS_SETNAME    8        ;Sets the name of the current thread
+%define SYS_GETNAME    9        ;Gets the name of a thread
+%define SYS_GETTID     10       ;Get current thread ID
+%define SYS_GETPID     11       ;Get current thread group ID
+%define SYS_SETPRI     12       ;Set process priority
+%define SYS_SENDMSG    13       ;Send an IPC message
+%define SYS_GETMSG     14       ;Recieve an IPC message
+%define SYS_GETTIME    15       ;Get the current timestamp
+%define SYS_SPAWN      16       ;Spawn a new process
+%define SYS_EXECVE     17       ;Replace the current process
+%define SYS_LOADBIN    18       ;Load a binary into the current address space
+%define SYS_UNLOADBIN  19       ;Unload a loaded binary
+%define SYS_LOADMOD    20       ;Load a module into the kernel
+%define SYS_GETPHYS    32       ;Get the physical address of a page
+%define SYS_MAP        33       ;Map a physical address
+%define SYS_ALLOCATE   34       ;Allocate a page
+%define SYS_UNMAP      35       ;Unmap a page
+%define SYS_PREALLOC   36       ;Preallocate a page
+%define SYS_SETFLAGS   37       ;Set a page's flags
+%define SYS_SHAREWITH  38       ;Share a page with another thread
+%define SYS_GETUID     39       ;Get current User ID
+%define SYS_GETGID     40       ;Get current Group ID
+%define SYS_SETUID     41       ;Set current user ID
+%define SYS_SETGID     42       ;Set current Group ID
+%define SYS_OPEN       64       ;Open a file
+%define SYS_REOPEN     65       ;Close a file and reuse its handle
+%define SYS_CLOSE      66       ;Close a file
+%define SYS_READ       67       ;Read from an open file
+%define SYS_WRITE      68       ;Write to an open file
+%define SYS_IOCTL      69       ;Perform an IOCtl Call
+%define SYS_SEEK       70       ;Seek to a new position in the file
+%define SYS_READDIR    71       ;Read from an open directory
+%define SYS_OPENCHILD  72       ;Open a child entry in a directory
+%define SYS_GETACL     73       ;Get an ACL Value
+%define SYS_SETACL     74       ;Set an ACL Value
+%define SYS_FINFO      75       ;Get file information
+%define SYS_MKDIR      76       ;Create a new directory
+%define SYS_LINK       77       ;Create a new link to a file
+%define SYS_SYMLINK    78       ;Create a symbolic link
+%define SYS_UNLINK     79       ;Delete a file
+%define SYS_TELL       80       ;Return the current file position
+%define SYS_CHDIR      81       ;Change current directory
+%define SYS_GETCWD     82       ;Get current directory
+%define SYS_MOUNT      83       ;Mount a filesystem
+%define SYS_SELECT     84       ;Wait for file handles
diff --git a/KernelLand/Kernel/include/threads.h b/KernelLand/Kernel/include/threads.h
new file mode 100644 (file)
index 0000000..9ff7b62
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Acess2 Kernel
+ */
+#ifndef _THREADS_H_
+#define _THREADS_H_
+
+#include <arch.h>
+#include <signal.h>
+//#include <proc.h>
+
+enum eFaultNumbers
+{
+       FAULT_MISC,
+       FAULT_PAGE,
+       FAULT_ACCESS,
+       FAULT_DIV0,
+       FAULT_OPCODE,
+       FAULT_FLOAT
+};
+
+#define GETMSG_IGNORE  ((void*)-1)
+
+typedef struct sThread tThread;
+
+// === FUNCTIONS ===
+extern void    Threads_SetFaultHandler(Uint Handler);
+
+extern int     Threads_SetUID(tUID ID);
+extern int     Threads_SetGID(tUID ID);
+extern tTID    Threads_WaitTID(int TID, int *Status);
+
+
+extern int     *Threads_GetMaxFD(void);
+extern char    **Threads_GetCWD(void);
+extern char    **Threads_GetChroot(void);
+
+extern int     Proc_SendMessage(Uint Dest, int Length, void *Data);
+extern int     Proc_GetMessage(Uint *Source, void *Buffer);
+
+#endif
diff --git a/KernelLand/Kernel/include/threads_int.h b/KernelLand/Kernel/include/threads_int.h
new file mode 100644 (file)
index 0000000..66bb8c1
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Internal Threading header
+ * - Only for use by stuff that needs access to the thread type.
+ */
+#ifndef _THREADS_INT_H_
+#define _THREADS_INT_H_
+
+#include <threads.h>
+#include <proc.h>
+
+
+typedef struct sProcess        tProcess;
+
+/**
+ * \brief IPC Message
+ */
+typedef struct sMessage
+{
+       struct sMessage *Next;  //!< Next message in thread's inbox
+       tTID    Source; //!< Source thread ID
+       Uint    Length; //!< Length of message data in bytes
+       Uint8   Data[]; //!< Message data
+} tMsg;
+
+/**
+ * \brief Process state
+ */
+struct sProcess
+{
+       tPID    PID;
+        int    nThreads;
+       
+       tUID    UID;    //!< User ID
+       tGID    GID;    //!< User and Group
+       tMemoryState    MemState;
+
+        int    MaxFD;
+       char    *CurrentWorkingDir;
+       char    *RootDir;
+};
+
+/**
+ * \brief Core threading structure
+ * 
+ */
+struct sThread
+{
+       // --- threads.c's
+       /**
+        * \brief Next thread in current list
+        * \note Required to be first for linked list hacks to work
+        */
+       struct sThread  *Next;
+       struct sThread  *GlobalNext;    //!< Next thread in global list
+       struct sThread  *GlobalPrev;    //!< Previous thread in global list
+       tShortSpinlock  IsLocked;       //!< Thread's spinlock
+       volatile int    Status;         //!< Thread Status
+       void    *WaitPointer;   //!< What (Mutex/Thread/other) is the thread waiting on
+        int    RetStatus;      //!< Return Status
+       
+       tTID    TID;    //!< Thread ID
+       struct sProcess *Process;       //!< Thread Group / Process
+       struct sThread  *Parent;        //!< Parent Thread
+       char    *ThreadName;    //!< Name of thread
+       
+       // --- arch/proc.c's responsibility
+       //! Kernel Stack Base
+       tVAddr  KernelStack;
+       
+       //! State on task switch
+       tTaskState      SavedState;
+       
+       // --- threads.c's
+        int    CurFaultNum;    //!< Current fault number, 0: none
+       tVAddr  FaultHandler;   //!< Fault Handler
+       
+       tMsg * volatile Messages;       //!< Message Queue
+       tMsg    *LastMessage;   //!< Last Message (speeds up insertion)
+       
+        int    Quantum, Remaining;     //!< Quantum Size and remaining timesteps
+        int    Priority;       //!< Priority - 0: Realtime, higher means less time
+       
+        int    _errno;
+       
+       volatile int    CurCPU;
+       
+       bool    bInstrTrace;
+       
+       // --- event.c
+       Uint32  EventState;
+};
+
+
+enum {
+       THREAD_STAT_NULL,       // Invalid process
+       THREAD_STAT_ACTIVE,     // Running and schedulable process
+       THREAD_STAT_SLEEPING,   // Message Sleep
+       THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
+       THREAD_STAT_SEMAPHORESLEEP,     // Semaphore Sleep
+       THREAD_STAT_QUEUESLEEP, // Queue
+       THREAD_STAT_EVENTSLEEP, // Event sleep
+       THREAD_STAT_WAITING,    // ??? (Waiting for a thread)
+       THREAD_STAT_PREINIT,    // Being created
+       THREAD_STAT_ZOMBIE,     // Died/Killed, but parent not informed
+       THREAD_STAT_DEAD,       // Awaiting burial (free)
+       THREAD_STAT_BURIED      // If it's still on the list here, something's wrong
+};
+static const char * const casTHREAD_STAT[] = {
+       "THREAD_STAT_NULL",
+       "THREAD_STAT_ACTIVE",
+       "THREAD_STAT_SLEEPING",
+       "THREAD_STAT_MUTEXSLEEP",
+       "THREAD_STAT_SEMAPHORESLEEP",
+       "THREAD_STAT_QUEUESLEEP",
+       "THREAD_STAT_EVENTSLEEP",
+       "THREAD_STAT_WAITING",
+       "THREAD_STAT_PREINIT",
+       "THREAD_STAT_ZOMBIE",
+       "THREAD_STAT_DEAD",
+       "THREAD_STAT_BURIED"
+};
+
+// === GLOBALS ===
+extern BOOL    gaThreads_NoTaskSwitch[MAX_CPUS];
+extern tShortSpinlock  glThreadListLock;
+
+// === FUNCTIONS ===
+extern tThread *Proc_GetCurThread(void);
+
+extern tThread *Threads_GetThread(Uint TID);
+extern void    Threads_SetPriority(tThread *Thread, int Pri);
+extern int     Threads_Wake(tThread *Thread);
+extern void    Threads_Kill(tThread *Thread, int Status);
+extern void    Threads_AddActive(tThread *Thread);
+extern tThread *Threads_RemActive(void);
+extern void    Threads_Delete(tThread *Thread);
+extern tThread *Threads_GetNextToRun(int CPU, tThread *Last);
+
+extern tThread *Threads_CloneTCB(Uint Flags);
+extern tThread *Threads_CloneThreadZero(void);
+
+#endif
diff --git a/KernelLand/Kernel/include/timers.h b/KernelLand/Kernel/include/timers.h
new file mode 100644 (file)
index 0000000..22dd5c6
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * timers.h
+ * - Kernel timers
+ */
+#ifndef _KERNEL_TIMERS_H_
+#define _KERNEL_TIMERS_H_
+/**
+ * \file timers.h
+ * \brief Kernel timers
+ */
+
+typedef struct sTimer  tTimer;
+
+/**
+ * \brief Timer callback function
+ */
+typedef void (tTimerCallback)(void *);
+
+/**
+ * \brief Creates a one-shot timer
+ * \param Delta        Period of the timer
+ * \param Callback     Function to call each time
+ * \param Argument     Argument to pass to the callback
+ */
+extern tTimer  *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument);
+/**
+ * \brief Removed an active timer
+ */
+extern void    Time_RemoveTimer(tTimer *Timer);
+/**
+ * \brief Wait for a period of milliseconds
+ */
+extern void    Time_Delay(int Delay);
+
+#endif
+
diff --git a/KernelLand/Kernel/include/tpl_mm_phys_bitmap.h b/KernelLand/Kernel/include/tpl_mm_phys_bitmap.h
new file mode 100644 (file)
index 0000000..39444d9
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Acess2 Core
+ * 
+ * include/tpl_mm_phys_bitmap.h
+ * Physical Memory Manager Template
+ */
+/*
+ * Bitmap Edition
+ * 
+ * Uses 4.125+PtrSize bytes per page
+ */
+
+#define MM_PAGE_REFCOUNTS      MM_PMM_BASE
+#define MM_PAGE_NODES  (MM_PMM_BASE+(MM_MAXPHYSPAGE*sizeof(Uint32)))
+#define MM_PAGE_BITMAP (MM_PAGE_NODES+(MM_MAXPHYSPAGE*sizeof(void*)))
+
+#define PAGE_BITMAP_FREE(__pg) (gaPageBitmaps[(__pg)/32] & (1LL << ((__pg)&31)))
+#define PAGE_BITMAP_SETFREE(__pg)      do{gaPageBitmaps[(__pg)/32] |= (1LL << ((__pg)&31));}while(0)
+#define PAGE_BITMAP_SETUSED(__pg)      do{gaPageBitmaps[(__pg)/32] &= ~(1LL << ((__pg)&31));}while(0)
+
+// === PROTOTYPES ===
+//void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+//tPAddr       MM_AllocPhysRange(int Num, int Bits);
+//tPAddr       MM_AllocPhys(void);
+//void MM_RefPhys(tPAddr PAddr);
+//void MM_DerefPhys(tPAddr PAddr);
+ int   MM_int_GetRangeID( tPAddr Addr );
+ int   MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length );
+void   MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap);
+
+// === GLOBALS ===
+tMutex glPhysicalPages;
+void   **gapPageNodes = (void*)MM_PAGE_NODES;  //!< Associated VFS Node for each page
+Uint32 *gaiPageReferences = (void*)MM_PAGE_REFCOUNTS;  // Reference Counts
+Uint32 *gaPageBitmaps = (void*)MM_PAGE_BITMAP; // Used bitmap (1 == avail)
+Uint64 giMaxPhysPage = 0;      // Maximum Physical page
+ int   gbPMM_Init = 0;
+ int   giPhysFirstFree;
+ int   giPhysLastFree;
+ int   giPhysNumFree;
+
+// === CODE ===
+/**
+ * \brief Initialise the physical memory manager with a passed memory map
+ */
+void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap)
+{
+        int    mapIndex = 0;
+       tPAddr  rangeStart, rangeLen;
+
+       if( MM_PAGE_BITMAP + (MM_MAXPHYSPAGE/8) > MM_PMM_END ) {
+               Log_KernelPanic("PMM", "Config Error, PMM cannot fit data in allocated range");
+       }
+
+       giMaxPhysPage = MaxRAMPage;
+
+//     for( i = 0; i < MM_RANGE_MAX; i ++ )
+//             gaiPhysRangeFirstFree[i] = -1;
+       giPhysFirstFree = -1;
+
+       while( MM_int_GetMapEntry(MemoryMap, mapIndex++, &rangeStart, &rangeLen) )
+       {
+               tVAddr  bitmap_page;
+               
+               LOG("Range %i, %P to %P", mapIndex-1, rangeStart, rangeLen);
+               rangeStart /= PAGE_SIZE;
+               rangeLen /= PAGE_SIZE;
+
+               giPhysNumFree += rangeLen;
+
+               LOG("rangeStart = 0x%x, rangeLen = 0x%x", rangeStart, rangeLen);
+
+               if( giPhysFirstFree == -1 || giPhysFirstFree > rangeStart )
+                       giPhysFirstFree = rangeStart;
+
+               if( giPhysLastFree < rangeStart + rangeLen )
+                       giPhysLastFree = rangeStart + rangeLen;
+
+               LOG("giPhysFirstFree = 0x%x, giPhysLastFree = 0x%x", giPhysFirstFree, giPhysLastFree);
+
+               bitmap_page = (tVAddr)&gaPageBitmaps[rangeStart/32];
+               bitmap_page &= ~(PAGE_SIZE-1);
+
+               // Only need to allocate bitmaps
+               if( !MM_GetPhysAddr( bitmap_page ) ) {
+                       if( !MM_Allocate( bitmap_page ) ) {
+                               Log_KernelPanic("PMM", "Out of memory during init, this is bad");
+                               return ;
+                       }
+//                     memset( (void*)bitmap_page, 0, (rangeStart/8) & ~(PAGE_SIZE-1) );
+                       memset( (void*)bitmap_page, 0, PAGE_SIZE );
+               }
+               
+               // Align to 32 pages
+               for( ; (rangeStart & 31) && rangeLen > 0; rangeStart++, rangeLen-- ) {
+                       gaPageBitmaps[rangeStart / 32] |= 1 << (rangeStart&31);
+                       LOG("gaPageBitmaps[%i] = 0x%x", rangeStart/32, gaPageBitmaps[rangeStart/32]);
+               }
+               // Mark blocks of 32 as avail
+               for( ; rangeLen > 31; rangeStart += 32, rangeLen -= 32 ) {
+                       gaPageBitmaps[rangeStart / 32] = -1;
+               }
+               // Mark the tail
+               for( ; rangeLen > 0; rangeStart ++, rangeLen -- ) {
+                       gaPageBitmaps[rangeStart / 32] |= 1 << (rangeStart&31);
+               }
+       }
+
+       gbPMM_Init = 1;
+
+       LOG("giPhysFirstFree = 0x%x, giPhysLastFree = 0x%x", giPhysFirstFree, giPhysLastFree);
+       LEAVE('-');
+}
+
+/**
+ * \brief Allocate a contiguous range of physical pages with a maximum
+ *        bit size of \a MaxBits
+ * \param Pages        Number of pages to allocate
+ * \param MaxBits      Maximum size of the physical address
+ * \note If \a MaxBits is <= 0, any sized address is used (with preference
+ *       to higher addresses)
+ */
+tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
+{
+       tPAddr  addr, ret;
+        int    nFree = 0, i;
+       
+       ENTER("iPages iBits", Pages, MaxBits);
+       
+       Mutex_Acquire(&glPhysicalPages);
+       
+       // Check if there is enough in the range
+       if(giPhysNumFree >= Pages)
+       {
+               LOG("{0x%x -> 0x%x}", giPhysFirstFree, giPhysLastFree);
+               // Do a cheap scan, scanning upwards from the first free page in
+               // the range
+               nFree = 0;
+               addr = giPhysFirstFree;
+               while( addr <= giPhysLastFree )
+               {
+                       #if USE_SUPER_BITMAP
+                       // Check the super bitmap
+                       if( gaSuperBitmap[addr / (32*32)] == 0 )
+                       {
+                               LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr += (32*32);
+                               addr &= ~(32*32-1);     // (1LL << 6+6) - 1
+                               continue;
+                       }
+                       #endif
+                       LOG("gaPageBitmaps[%i] = 0x%x", addr/32, gaPageBitmaps[addr/32]);
+                       // Check page block (32 pages)
+                       if( gaPageBitmaps[addr / 32] == 0) {
+                               LOG("nFree = %i = 0 (block) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr += 32;
+                               addr &= ~31;
+                               continue;
+                       }
+                       // Check individual page
+                       if( !(gaPageBitmaps[addr / 32] & (1LL << (addr & 31))) )
+                       {
+                               LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr ++;
+                               continue;
+                       }
+                       nFree ++;
+                       addr ++;
+                       LOG("nFree(%i) == %i (1x%x)", nFree, Pages, addr);
+                       if(nFree == Pages)
+                               break;
+               }
+               LOG("nFree = %i", nFree);
+               // If we don't find a contiguous block, nFree will not be equal
+               // to Num, so we set it to zero and do the expensive lookup.
+               if(nFree != Pages)      nFree = 0;
+       }
+       
+       if( !nFree )
+       {
+#if 0
+               // Oops. ok, let's do an expensive check (scan down the list
+               // until a free range is found)
+               nFree = 1;
+               addr = gaiPhysRangeLastFree[ rangeID ];
+               // TODO
+#endif
+               Mutex_Release(&glPhysicalPages);
+               // TODO: Page out
+               // ATM. Just Warning
+               Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
+               Log_Warning("PMM",
+                       "Out of memory (unable to fulfil request for %i pages)",
+                       Pages   
+                       );
+               LEAVE('i', 0);
+               return 0;
+       }
+       LOG("nFree = %i, addr = 0x%08x", nFree, (addr-Pages) << 12);
+       
+       // Mark pages as allocated
+       addr -= Pages;
+       for( i = 0; i < Pages; i++, addr++ )
+       {
+               // Mark as used
+               PAGE_BITMAP_SETUSED(addr);
+               // Maintain first possible free
+               giPhysNumFree --;
+               if(addr == giPhysFirstFree)
+                       giPhysFirstFree += 1;
+       
+               LOG("if( MM_GetPhysAddr( %p ) )", &gaiPageReferences[addr]);
+               // Mark as referenced if the reference count page is valid      
+               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) ) {
+                       gaiPageReferences[addr] = 1;
+               }
+       }
+       ret = addr - Pages;     // Save the return address
+       LOG("ret = %x", ret);   
+
+       #if TRACE_ALLOCS
+       LogF("MM_AllocPhysRange: %P (%i pages)\n", ret, Pages);
+       if(Pages > 1) {
+               LogF(" also");
+               for(i = 1; i < Pages; i++)
+                       LogF(" %P", ret+i);
+               LogF("\n");
+       }
+       #endif
+
+       #if USE_SUPER_BITMAP
+       // Update super bitmap
+       Pages += addr & (32-1);
+       addr &= ~(32-1);
+       Pages = (Pages + (32-1)) & ~(32-1);
+       for( i = 0; i < Pages/32; i++ )
+       {
+               if( gaPageBitmaps[ addr / 32 ] + 1 == 0 )
+                       gaSuperBitmap[addr / (32*32)] |= 1LL << ((addr / 32) & 31);
+       }
+       #endif
+       
+       Mutex_Release(&glPhysicalPages);
+       LEAVE('x', ret << 12);
+       return ret << 12;
+}
+
+/**
+ * \brief Allocate a single physical page, with no preference as to address size.
+ */
+tPAddr MM_AllocPhys(void)
+{
+        int    i;
+
+       if( !gbPMM_Init )
+       {       
+               // Hack to allow allocation during setup
+               for(i = 0; i < NUM_STATIC_ALLOC; i++) {
+                       if( gaiStaticAllocPages[i] ) {
+                               tPAddr  ret = gaiStaticAllocPages[i];
+                               gaiStaticAllocPages[i] = 0;
+                               Log("MM_AllocPhys: Return %x, static alloc %i", ret, i);
+                               return ret;
+                       }
+               }
+               
+               tPAddr  ret = 0;
+               for( ret = 0; ret < giMaxPhysPage; ret ++ )
+               {
+                       if( !MM_GetPhysAddr( (tVAddr)&gaPageBitmaps[ret/32] ) ) {
+                               ret += PAGE_SIZE*8;
+                               continue ;
+                       }
+                       if( gaPageBitmaps[ret/32] == 0 ) {
+                               ret += 32-1;
+                               continue ;
+                       }
+                       if( gaPageBitmaps[ret/32] & (1 << (ret&31)) ) {
+                               gaPageBitmaps[ret/32] &= ~(1 << (ret&31));
+                               return ret * PAGE_SIZE;
+                       }
+               }
+               Log_Error("PMM", "MM_AllocPhys failed duing init");
+               return 0;
+       }
+       #if TRACE_ALLOCS
+       Log("AllocPhys by %p", __builtin_return_address(0));
+       #endif
+       
+       return MM_AllocPhysRange(1, -1);
+}
+
+/**
+ * \brief Reference a physical page
+ */
+void MM_RefPhys(tPAddr PAddr)
+{
+       tPAddr  page = PAddr / PAGE_SIZE;
+       tVAddr  refpage = (tVAddr)&gaiPageReferences[page] & ~(PAGE_SIZE-1);
+       
+       if( page >= giMaxPhysPage )     return ;
+
+       if( PAGE_BITMAP_FREE(page) )
+       {
+               // Allocate
+               PAGE_BITMAP_SETUSED(page);
+               #if USE_SUPER_BITMAP
+               if( gaPageBitmaps[page / 32] == 0 )
+                       gaSuperBitmap[page / (32*32)] &= ~(1LL << ((page / 32) & 31));
+               #endif
+               if( MM_GetPhysAddr( refpage ) )
+                       gaiPageReferences[page] = 1;
+       }
+       else
+       {
+               // Reference again
+               if( !MM_GetPhysAddr( refpage ) )
+               {
+                        int    pages_per_page, basepage, i;
+                       if( MM_Allocate(refpage) == 0 ) {
+                               // Out of memory, can this be resolved?
+                               // TODO: Reclaim memory
+                               Log_Error("PMM", "Out of memory (MM_RefPhys)");
+                               return ;
+                       }
+                       pages_per_page = PAGE_SIZE/sizeof(*gaiPageReferences);
+                       basepage = page & ~(pages_per_page-1);
+                       for( i = 0; i < pages_per_page; i ++ ) {
+                               if( PAGE_BITMAP_FREE(basepage+i) )
+                                       gaiPageReferences[basepage+i] = 0;
+                               else
+                                       gaiPageReferences[basepage+i] = 1;
+                       }
+                       gaiPageReferences[page] = 2;
+               }
+               else
+                       gaiPageReferences[ page ] ++;
+       }
+}
+
+int MM_GetRefCount(tPAddr PAddr)
+{
+       PAddr >>= 12;
+       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+               return gaiPageReferences[PAddr];
+       }
+       
+       if( gaPageBitmaps[ PAddr / 32 ] & (1LL << (PAddr&31)) ) {
+               return 1;
+       }
+       
+       return 0;
+}
+
+/**
+ * \brief Dereference a physical page
+ */
+void MM_DerefPhys(tPAddr PAddr)
+{
+       Uint64  page = PAddr >> 12;
+       
+       if( PAddr >> 12 > giMaxPhysPage )       return ;
+
+       ENTER("PPAddr", PAddr);
+       
+       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+       {
+               if( gaiPageReferences[page] > 0 )
+                       gaiPageReferences[ page ] --;
+               if( gaiPageReferences[ page ] == 0 ) {
+                       gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
+                       // TODO: Catch when all pages in this range have been dereferenced
+               }
+       }
+       else
+               gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
+       // Clear node if needed
+       if( MM_GetPhysAddr( (tVAddr)&gapPageNodes[page] ) ) {
+               gapPageNodes[page] = NULL;
+               // TODO: Catch when all pages in this range are not using nodes
+       }
+       
+       // Update the free counts if the page was freed
+       if( gaPageBitmaps[ page / 32 ] & (1LL << (page&31)) )
+       {
+               giPhysNumFree ++;
+               if( giPhysFirstFree == -1 || giPhysFirstFree > page )
+                       giPhysFirstFree = page;
+               if( giPhysLastFree < page )
+                       giPhysLastFree = page;
+       }
+
+       #if USE_SUPER_BITMAP    
+       // If the bitmap entry is not zero, set the bit free in the super bitmap
+       if(gaPageBitmaps[ page / 32 ] != 0 ) {
+               gaSuperBitmap[page / (32*32)] |= 1LL << ((page / 32) & 31);
+       }
+       #endif
+       LEAVE('-');
+}
+
+int MM_SetPageNode(tPAddr PAddr, void *Node)
+{
+       tPAddr  page = PAddr >> 12;
+       tVAddr  node_page = ((tVAddr)&gapPageNodes[page]) & ~(PAGE_SIZE-1);
+
+       if( !MM_GetRefCount(PAddr) )    return 1;
+       
+       if( !MM_GetPhysAddr(node_page) ) {
+               if( !MM_Allocate(node_page) )
+                       return -1;
+               memset( (void*)node_page, 0, PAGE_SIZE );
+       }
+
+       gapPageNodes[page] = Node;
+       return 0;
+}
+
+int MM_GetPageNode(tPAddr PAddr, void **Node)
+{
+       if( !MM_GetRefCount(PAddr) )    return 1;
+       PAddr >>= 12;
+       
+       if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+               *Node = NULL;
+               return 0;
+       }
+
+       *Node = gapPageNodes[PAddr];
+       return 0;
+}
+
diff --git a/KernelLand/Kernel/include/tpl_mm_phys_stack.h b/KernelLand/Kernel/include/tpl_mm_phys_stack.h
new file mode 100644 (file)
index 0000000..46ceb97
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Acess2 Core
+ * 
+ * include/tpl_mm_phys.h
+ * Physical Memory Manager Template
+ */
+#define DEBUG  0
+
+/**
+ * \file tpl_mm_phys_stack.h
+ * \brief Template physical memory manager
+ *
+ * An extensible physical memory manager
+ *
+ * Usage: Requires NUM_MM_PHYS_RANGES to be set to the number of address
+ * "classes" wanted.
+ * MAX_PHYS_PAGES - Used to calculate structure sizes
+ * PADDR_TYPE
+ */
+
+// === PROTOTYPES ===
+//void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+//tPAddr       MM_AllocPhysRange(int Num, int Bits);
+//tPAddr       MM_AllocPhys(void);
+//void MM_RefPhys(tPAddr PAddr);
+//void MM_DerefPhys(tPAddr PAddr);
+ int   MM_int_GetRangeID( tPAddr Addr );
+ int   MM_int_IsPhysUnavail( tPageNum Page );
+
+// === GLOBALS ===
+tMutex glPhysicalPages;
+//Uint64       *gaPageStacks[NUM_MM_PHYS_RANGES];      // Page stacks
+ int   giPageStackSizes[NUM_MM_PHYS_RANGES];   // Points to the first unused slot
+Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS;     // Reference Counts
+Uint64 giMaxPhysPage = 0;      // Maximum Physical page
+
+// === CODE ===
+/**
+ * \brief Initialise the physical memory map using a Multiboot 1 map
+ */
+void MM_Tpl_InitPhys(int MaxRAMPage)
+{
+       const int       PAGE_SIZE = 0x1000;
+       const int       pagesPerPageOnStack = PAGE_SIZE / sizeof(gaPageStack[0]);
+        int    i;
+       tPageNum        page;
+
+//     ENTER("pMBoot=%p", MBoot);
+       
+       giMaxPhysPage = MaxRAMPage;
+       
+       tPAddr  page = 0;
+       for( i = 0; i < NUM_MM_PHYS_RANGES; i ++ )
+       {
+               for( ; page < giPageRangeMax[i] && page < giMaxPhysPage; page ++ )
+               {
+                        int    rangeSize;
+
+                       rangeSize = MM_int_IsPhysUnavail(page);
+                       if( rangeSize > 0 ) {
+                               page += rangeSize;
+                               continue;
+                       }
+                       // Page is avaliable for use
+       
+                       // Check if the page stack is allocated
+                       tVAddr  stack_page = &gaPageStacks[i][giPageStackSizes[i]&~pagesPerPageOnStack];
+                       if( !MM_GetPhysAddr( stack_page ) ) {
+                               MM_Map( stack_page, page*PAGE_SIZE );
+                       }
+                       else {
+                               gaPageStacks[i][ giPageStackSizes[i] ] = page;
+                               giPageStackSizes[i] ++;
+                       }
+               }
+       }
+       
+       LEAVE('-');
+}
+
+/**
+ * \brief Allocate a contiguous range of physical pages with a maximum
+ *        bit size of \a MaxBits
+ * \param Pages        Number of pages to allocate
+ * \param MaxBits      Maximum size of the physical address
+ * \note If \a MaxBits is <= 0, any sized address is used (with preference
+ *       to higher addresses)
+ */
+tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
+{
+       tPAddr  addr, ret;
+        int    rangeID;
+        int    nFree = 0, i;
+       
+       ENTER("iPages iBits", Pages, MaxBits);
+       
+       if( MaxBits <= 0 || MaxBits >= 64 )     // Speedup for the common case
+               rangeID = MM_PHYS_MAX;
+       else
+               rangeID = MM_int_GetRangeID( (1LL << MaxBits) - 1 );
+       
+       LOG("rangeID = %i", rangeID);
+       
+       Mutex_Acquire(&glPhysicalPages);
+       
+       // Check if the range actually has any free pages
+       while(giPageStackSizes[rangeID] == 0 && rangeID)
+               rangeID --;
+       
+       LOG("rangeID = %i", rangeID);
+       
+       // What the? Oh, man. No free pages
+       if(giPageStackSizes[rangeID] == 0) {
+               Mutex_Release(&glPhysicalPages);
+               // TODO: Page out / attack the cache
+               // ATM. Just Warning
+               Warning(" MM_AllocPhysRange: Out of free pages");
+               Log_Warning("Arch",
+                       "Out of memory (unable to fulfil request for %i pages), zero remaining",
+                       Pages
+                       );
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Check if there is enough in the range
+       if(giPhysRangeFree[rangeID] >= Pages)
+       {
+               LOG("{%i,0x%x -> 0x%x}",
+                       giPhysRangeFree[rangeID],
+                       giPhysRangeFirst[rangeID], giPhysRangeLast[rangeID]
+                       );
+               // Do a cheap scan, scanning upwards from the first free page in
+               // the range
+               nFree = 0;
+               addr = giPhysRangeFirst[ rangeID ];
+               while( addr <= giPhysRangeLast[ rangeID ] )
+               {
+                       //Log(" MM_AllocPhysRange: addr = 0x%x", addr);
+                       // Check the super bitmap
+                       if( gaSuperBitmap[addr >> (6+6)] + 1 == 0 ) {
+                               LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr += 1LL << (6+6);
+                               addr &= ~0xFFF; // (1LL << 6+6) - 1
+                               continue;
+                       }
+                       // Check page block (64 pages)
+                       if( gaMainBitmap[addr >> 6] + 1 == 0) {
+                               LOG("nFree = %i = 0 (main) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr += 1LL << (6);
+                               addr &= ~0x3F;
+                               continue;
+                       }
+                       // Check individual page
+                       if( gaMainBitmap[addr >> 6] & (1LL << (addr & 63)) ) {
+                               LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
+                               nFree = 0;
+                               addr ++;
+                               continue;
+                       }
+                       nFree ++;
+                       addr ++;
+                       LOG("nFree(%i) == %i (0x%x)", nFree, Pages, addr);
+                       if(nFree == Pages)
+                               break;
+               }
+               LOG("nFree = %i", nFree);
+               // If we don't find a contiguous block, nFree will not be equal
+               // to Num, so we set it to zero and do the expensive lookup.
+               if(nFree != Pages)      nFree = 0;
+       }
+       
+       if( !nFree )
+       {
+               // Oops. ok, let's do an expensive check (scan down the list
+               // until a free range is found)
+               nFree = 1;
+               addr = giPhysRangeLast[ rangeID ];
+               // TODO
+               Mutex_Release(&glPhysicalPages);
+               // TODO: Page out
+               // ATM. Just Warning
+               Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
+               Log_Warning("Arch",
+                       "Out of memory (unable to fulfil request for %i pages)",
+                       Pages   
+                       );
+               LEAVE('i', 0);
+               return 0;
+       }
+       LOG("nFree = %i, addr = 0x%08x", nFree, addr);
+       
+       // Mark pages as allocated
+       addr -= Pages;
+       for( i = 0; i < Pages; i++, addr++ )
+       {
+               gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
+               rangeID = MM_int_GetRangeID(addr << 12);
+               giPhysRangeFree[ rangeID ] --;
+               LOG("%x == %x", addr, giPhysRangeFirst[ rangeID ]);
+               if(addr == giPhysRangeFirst[ rangeID ])
+                       giPhysRangeFirst[ rangeID ] += 1;
+       }
+       ret = addr;     // Save the return address
+       
+       // Update super bitmap
+       Pages += addr & (64-1);
+       addr &= ~(64-1);
+       Pages = (Pages + (64-1)) & ~(64-1);
+       for( i = 0; i < Pages/64; i++ )
+       {
+               if( gaMainBitmap[ addr >> 6 ] + 1 == 0 )
+                       gaSuperBitmap[addr>>12] |= 1LL << ((addr >> 6) & 63);
+       }
+       
+       Mutex_Release(&glPhysicalPages);
+       LEAVE('x', ret << 12);
+       return ret << 12;
+}
+
+/**
+ * \brief Allocate a single physical page, with no preference as to address
+ *        size.
+ */
+tPAddr MM_AllocPhys(void)
+{
+        int    i;
+       
+       // Hack to allow allocation during setup
+       for(i = 0; i < NUM_STATIC_ALLOC; i++) {
+               if( gaiStaticAllocPages[i] ) {
+                       tPAddr  ret = gaiStaticAllocPages[i];
+                       gaiStaticAllocPages[i] = 0;
+                       Log("MM_AllocPhys: Return %x, static alloc %i", ret, i);
+                       return ret;
+               }
+       }
+       
+       return MM_AllocPhysRange(1, -1);
+}
+
+/**
+ * \brief Reference a physical page
+ */
+void MM_RefPhys(tPAddr PAddr)
+{
+       Uint64  page = PAddr >> 12;
+       
+       if( PAddr >> 12 > giMaxPhysPage )       return ;
+       
+       if( gaMainBitmap[ page >> 6 ] & (1LL << (page&63)) )
+       {
+               // Reference again
+               gaMultiBitmap[ page >> 6 ] |= 1LL << (page&63);
+               gaiPageReferences[ page ] ++;
+       }
+       else
+       {
+               // Allocate
+               gaMainBitmap[page >> 6] |= 1LL << (page&63);
+               if( gaMainBitmap[page >> 6 ] + 1 == 0 )
+                       gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
+       }
+}
+
+/**
+ * \brief Dereference a physical page
+ */
+void MM_DerefPhys(tPAddr PAddr)
+{
+       Uint64  page = PAddr >> 12;
+       
+       if( PAddr >> 12 > giMaxPhysPage )       return ;
+       
+       if( gaMultiBitmap[ page >> 6 ] & (1LL << (page&63)) ) {
+               gaiPageReferences[ page ] --;
+               if( gaiPageReferences[ page ] == 1 )
+                       gaMultiBitmap[ page >> 6 ] &= ~(1LL << (page&63));
+               if( gaiPageReferences[ page ] == 0 )
+                       gaMainBitmap[ page >> 6 ] &= ~(1LL << (page&63));
+       }
+       else
+               gaMainBitmap[ page >> 6 ] &= ~(1LL << (page&63));
+       
+       // Update the free counts if the page was freed
+       if( !(gaMainBitmap[ page >> 6 ] & (1LL << (page&63))) )
+       {
+                int    rangeID;
+               rangeID = MM_int_GetRangeID( PAddr );
+               giPhysRangeFree[ rangeID ] ++;
+               if( giPhysRangeFirst[rangeID] > page )
+                       giPhysRangeFirst[rangeID] = page;
+               if( giPhysRangeLast[rangeID] < page )
+                       giPhysRangeLast[rangeID] = page;
+       }
+       
+       // If the bitmap entry is not -1, unset the bit in the super bitmap
+       if(gaMainBitmap[ page >> 6 ] + 1 != 0 ) {
+               gaSuperBitmap[page >> 12] &= ~(1LL << ((page >> 6) & 63));
+       }
+}
+
+/**
+ * \brief Takes a physical address and returns the ID of its range
+ * \param Addr Physical address of page
+ * \return Range ID from eMMPhys_Ranges
+ */
+int MM_int_GetRangeID( tPAddr Addr )
+{
+       if(Addr >> 32)
+               return MM_PHYS_MAX;
+       else if(Addr >> 24)
+               return MM_PHYS_32BIT;
+       else if(Addr >> 20)
+               return MM_PHYS_24BIT;
+       else if(Addr >> 16)
+               return MM_PHYS_20BIT;
+       else
+               return MM_PHYS_16BIT;
+}
diff --git a/KernelLand/Kernel/include/vfs.h b/KernelLand/Kernel/include/vfs.h
new file mode 100644 (file)
index 0000000..1aa073b
--- /dev/null
@@ -0,0 +1,503 @@
+/* 
+ * Acess2
+ * VFS Common Header
+ */
+/**
+ * \file vfs.h
+ * \brief Acess VFS Layer
+ * 
+ * The Acess Virtual File System (VFS) provides abstraction of multiple
+ * physical filesystems, network storage and devices (both hardware and
+ * virtual) to the user.
+ * 
+ * The core of the VFS is the concept of a \ref tVFS_Node "VFS Node".
+ * A VFS Node represents a "file" in the VFS tree, this can be any sort
+ * of file (an ordinary file, a directory, a symbolic link or a device)
+ * depending on the bits set in the \ref tVFS_Node.Flags Flags field.
+ * - For more information see "VFS Node Flags"
+ */
+#ifndef _VFS_H
+#define _VFS_H
+
+#include <acess.h>
+
+/**
+ * \brief Thread list datatype for VFS_Select
+ */
+typedef struct sVFS_SelectList tVFS_SelectList;
+
+typedef struct sVFS_NodeType   tVFS_NodeType;
+
+/**
+ * \name tVFS_Node Flags
+ * \brief Flag values for tVFS_Node.Flags
+ * \{
+ */
+//! \todo Is this still needed
+#define VFS_FFLAG_READONLY     0x01    //!< Readonly File
+/**
+ * \brief Directory Flag
+ * 
+ * This flag marks the tVFS_Node as describing a directory, and says
+ * that the tVFS_Node.FindDir, tVFS_Node.ReadDir, tVFS_Node.MkNod and
+ * tVFS_Node.Relink function pointers are valid.
+ * For a directory the tVFS_Node.Size field contains the number of files
+ * within the directory, or -1 for undetermined.
+ */
+#define VFS_FFLAG_DIRECTORY    0x02
+/**
+ * \brief Symbolic Link Flag
+ * 
+ * Marks a file as a symbolic link
+ */
+#define VFS_FFLAG_SYMLINK      0x04
+/**
+ * \brief Set User ID Flag
+ * 
+ * Allows an executable file to change it's executing user to the file's
+ * owner.
+ * In the case of a directory, it means that all immediate children will
+ * inherit the UID of the parent.
+ */
+#define VFS_FFLAG_SETUID       0x08
+/**
+ * \brief Set Group ID Flag
+ * 
+ * Allows an executable file to change it's executing group to the file's
+ * owning group.
+ * In the case of a directory, it means that all immediate children will
+ * inherit the GID of the parent.
+ */
+#define VFS_FFLAG_SETGID       0x10
+
+/**
+ * \brief "Don't do Write-Back" Flag
+ *
+ * Stops the VFS from calling tVFS_Node.Write on dirty pages when a region
+ * is unmapped. Nice for read-only files and memory-only files (or 
+ * pseudo-readonly filesystems)
+ */
+#define VFS_FFLAG_NOWRITEBACK
+/**
+ * \}
+ */
+
+/**
+ * \brief Represents a node (file or directory) in the VFS tree
+ * 
+ * This structure provides the VFS with the functions required to read/write
+ * the file (or directory) that it represents.
+ */
+typedef struct sVFS_Node
+{
+       /**
+        * \name Identifiers
+        * \brief Fields used by the driver to identify what data this node
+        *        corresponds to.
+        * \{
+        */
+       Uint64  Inode;  //!< Inode ID - Must identify the node uniquely if tVFS_Driver.GetNodeFromINode is non-NULL
+       Uint    ImplInt;        //!< Implementation Usable Integer
+       void    *ImplPtr;       //!< Implementation Usable Pointer
+       /**
+        * \}
+        */
+       
+       /**
+        * \name Node State
+        * \brief Stores the misc information about the node
+        * \{
+        */
+        int    ReferenceCount; //!< Number of times the node is used
+       
+       Uint64  Size;   //!< File Size
+       
+       Uint32  Flags;  //!< File Flags
+       
+       /**
+        * \brief Pointer to cached data (FS Specific)
+        * \note The Inode_* functions will free when the node is uncached
+        *       this if needed
+        */
+       void    *Data;
+       
+       /**
+        * \brief Node mutex
+        * \note Provided for the Filesystem driver's use
+        */
+       tMutex  Lock;
+       
+       /**
+        * \}
+        */
+       
+       /**
+        * \name Times
+        * \{
+        */
+       Sint64  ATime;  //!< Last Accessed Time
+       Sint64  MTime;  //!< Last Modified Time
+       Sint64  CTime;  //!< Creation Time
+       /**
+        * \}
+        */
+       
+       /**
+        * \name Access control
+        * \{
+        */
+       tUID    UID;    //!< ID of Owning User
+       tGID    GID;    //!< ID of Owning Group
+       
+        int    NumACLs;        //!< Number of ACL entries
+       tVFS_ACL        *ACLs;  //!< Access Controll List pointer
+       /**
+        * \}
+        */
+       
+       /**
+        * \name VFS_Select() fields
+        * \note Used by the VFS internals, drivers should use VFS_Mark*
+        * \{
+        */
+        int    DataAvaliable;
+       tVFS_SelectList *ReadThreads;   //!< Threads waiting to read
+        int    BufferFull;
+       tVFS_SelectList *WriteThreads;  //!< Threads waiting to write
+        int    ErrorOccurred;
+       tVFS_SelectList *ErrorThreads;  //!< Threads waiting for an error
+       /**
+        * \}
+        */
+
+       /**
+        * \name VFS_MMap() fields
+        * \{
+        */
+       void    *MMapInfo;
+       /**
+        * \}
+        */
+       
+       /**
+        * \brief Functions associated with the node
+        */
+       tVFS_NodeType   *Type;
+} tVFS_Node;
+
+/**
+ * \brief Functions for a specific node type
+ */
+struct sVFS_NodeType
+{
+       /**
+        * \brief Debug name for the type
+        */
+       const char      *TypeName;
+
+       /**
+        * \name Common Functions
+        * \brief Functions that are used no matter the value of .Flags
+        * \{
+        */
+       /**
+        * \brief Reference the node
+        * \param Node Pointer to this node
+        */
+       void    (*Reference)(struct sVFS_Node *Node);
+       /**
+        * \brief Close (dereference) the node
+        * \param Node  Pointer to this node
+        * 
+        * Usually .Close is used to write any changes to the node back to
+        * the persistent storage.
+        */
+       void    (*Close)(struct sVFS_Node *Node);
+       
+       /**
+        * \brief Send an IO Control
+        * \param Node  Pointer to this node
+        * \param Id    IOCtl call number
+        * \param Data  Pointer to data to pass to the driver
+        * \return Implementation defined
+        */
+        int    (*IOCtl)(struct sVFS_Node *Node, int Id, void *Data);
+       
+       /**
+        * \}
+        */
+       
+       /**
+        * \name Buffer Functions
+        * \brief Functions for accessing a buffer-type file (normal file or
+        *        symbolic link)
+        * \{
+        */
+       
+       /**
+        * \brief Read from the file
+        * \param Node  Pointer to this node
+        * \param Offset        Byte offset in the file
+        * \param Length        Number of bytes to read
+        * \param Buffer        Destination for read data
+        * \return Number of bytes read
+        */
+       Uint64  (*Read)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+       /**
+        * \brief Write to the file
+        * \param Node  Pointer to this node
+        * \param Offset        Byte offser in the file
+        * \param Length        Number of bytes to write
+        * \param Buffer        Source of written data
+        * \return Number of bytes read
+        */
+       Uint64  (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+
+       /**
+        * \brief Map a region of a file into memory
+        * \param Node  Pointer to this node
+        * \param Offset        Start of the region (page aligned)
+        * \param Length        Length of the region (page aligned)
+        * \param Dest  Location to which to map
+        * \return Boolean Failure
+        * \note If NULL, the VFS implements it using .Read
+        */
+        int    (*MMap)(struct sVFS_Node *Node, Uint64 Offset, int Length, void *Dest);
+       
+       /**
+        * \}
+        */
+       
+       /**
+        * \name Directory Functions
+        * \{
+        */
+       /**
+        * \brief Find an directory entry by name
+        * \param Node  Pointer to this node
+        * \param Name  Name of the file wanted
+        * \return Pointer to the requested node or NULL if it cannot be found
+        * \note The node returned must be accessable until ::tVFS_Node.Close
+        *       is called and ReferenceCount reaches zero.
+        */
+       struct sVFS_Node        *(*FindDir)(struct sVFS_Node *Node, const char *Name);
+       
+       /**
+        * \brief Read from a directory
+        * \param Node  Pointer to this node
+        * \param Pos   Offset in the directory
+        * \return Pointer to the name of the item on the heap (will be freed
+        *         by the caller). If the directory end has been reached, NULL
+        *         will be returned.
+        *         If an item is required to be skipped either &::NULLNode,
+        *         ::VFS_SKIP or ::VFS_SKIPN(0...1023) will be returned.
+        */
+       char    *(*ReadDir)(struct sVFS_Node *Node, int Pos);
+       
+       /**
+        * \brief Create a node in a directory
+        * \param Node  Pointer to this node
+        * \param Name  Name of the new child
+        * \param Flags Flags to apply to the new child (directory or symlink)
+        * \return Zero on Success, non-zero on error (see errno.h)
+        */
+        int    (*MkNod)(struct sVFS_Node *Node, const char *Name, Uint Flags);
+       
+       /**
+        * \brief Relink (Rename/Remove) a file/directory
+        * \param Node  Pointer to this node
+        * \param OldName       Name of the item to move/delete
+        * \param NewName       New name (or NULL if unlinking is wanted)
+        * \return Zero on Success, non-zero on error (see errno.h)
+        */
+        int    (*Relink)(struct sVFS_Node *Node, const char *OldName, const char *NewName);
+       
+       /**
+        * \brief Link a node to a name
+        * \param Node  Pointer to this node (directory)
+        * \param Child Node to create a new link to
+        * \param NewName       Name for the new link
+        * \retur Zeron on success, non-zero on error (see errno.h)
+        */
+        int    (*Link)(struct sVFS_Node *Node, struct sVFS_Node *Child, const char *NewName);
+        
+        /**
+         * \}
+         */
+};
+
+/**
+ * \brief VFS Driver (Filesystem) Definition
+ */
+typedef struct sVFS_Driver
+{
+       /**
+        * \brief Unique Identifier for this filesystem type
+        */
+       const char      *Name;
+       /**
+        * \brief Flags applying to this driver
+        */
+       Uint    Flags;
+       
+       /**
+        * \brief Callback to mount a device
+        */
+       tVFS_Node       *(*InitDevice)(const char *Device, const char **Options);
+       /**
+        * \brief Callback to unmount a device
+        */
+       void    (*Unmount)(tVFS_Node *Node);
+       /**
+        * \brief Retrieve a VFS node from an inode
+        */
+       tVFS_Node       *(*GetNodeFromINode)(tVFS_Node *RootNode, Uint64 InodeValue);
+       /**
+        * \brief Used internally (next driver in the chain)
+        */
+       struct sVFS_Driver      *Next;
+} tVFS_Driver;
+
+// === GLOBALS ===
+//! \brief Maximum number of elements that can be skipped in one return
+#define        VFS_MAXSKIP     ((void*)1024)
+//! \brief Skip a single entry in readdir
+#define        VFS_SKIP        ((void*)1)
+//! \brief Skip \a n entries in readdir
+#define        VFS_SKIPN(n)    ((void*)(n))
+
+extern tVFS_Node       NULLNode;       //!< NULL VFS Node (Ignored/Skipped)
+/**
+ * \name Static ACLs
+ * \brief Simple ACLs to aid writing drivers
+ * \{
+ */
+extern tVFS_ACL        gVFS_ACL_EveryoneRWX;   //!< Everyone Read/Write/Execute
+extern tVFS_ACL        gVFS_ACL_EveryoneRW;    //!< Everyone Read/Write
+extern tVFS_ACL        gVFS_ACL_EveryoneRX;    //!< Everyone Read/Execute
+extern tVFS_ACL        gVFS_ACL_EveryoneRO;    //!< Everyone Read only
+/**
+ * \}
+ */
+
+// === FUNCTIONS ===
+/**
+ * \fn int VFS_AddDriver(tVFS_Driver *Info)
+ * \brief Registers the driver with the DevFS layer
+ * \param Info Driver information structure
+ */
+extern int     VFS_AddDriver(tVFS_Driver *Info);
+/**
+ * \brief Get the information structure of a driver given its name
+ * \param Name Name of filesystem driver to find
+ */
+extern tVFS_Driver     *VFS_GetFSByName(const char *Name);
+
+
+/**
+ * \brief Prepare a node for use
+ */
+extern void    VFS_InitNode(tVFS_Node *Node);
+
+/**
+ * \brief Clean up a node, ready for deletion
+ * \note This should ALWAYS be called before a node is freed, as it
+ *       cleans up VFS internal structures.
+ */
+extern void    VFS_CleanupNode(tVFS_Node *Node);
+
+/**
+ * \fn tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
+ * \brief Transforms Unix Permssions into Acess ACLs
+ * \param Mode Unix RWXrwxRWX mask
+ * \param Owner        UID of the file's owner
+ * \param Group        GID of the file's owning group
+ * \return An array of 3 Acess ACLs
+ */
+extern tVFS_ACL        *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group);
+
+/**
+ * \brief Flags fro \a TypeFlag of VFS_SelectNode
+ * \{
+ */
+#define VFS_SELECT_READ        0x01
+#define VFS_SELECT_WRITE       0x02
+#define VFS_SELECT_ERROR       0x04
+/**
+ * \}
+ */
+
+/**
+ * \brief Wait for an event on a node
+ * \param Node Node to wait on
+ * \param Type Type of wait
+ * \param Timeout      Time to wait (NULL for infinite wait)
+ * \param Name Name to show in debug output
+ * \return Number of nodes that actioned (0 or 1)
+ */
+extern int     VFS_SelectNode(tVFS_Node *Node, int Type, tTime *Timeout, const char *Name);
+
+/**
+ * \brief Change the full flag on a node
+ */
+extern int     VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull);
+/**
+ * \brief Alter the space avaliable flag on a node
+ */
+extern int     VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable);
+/**
+ * \brief Alter the error flags on a node
+ */
+extern int     VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState);
+
+// --- Node Cache --
+/**
+ * \name Node Cache
+ * \brief Functions to allow a node to be cached in memory by the VFS
+ * 
+ * These functions store a node for the driver, to prevent it from having
+ * to re-generate the node on each call to FindDir. It also allows for
+ * fast cleanup when a filesystem is unmounted.
+ * \{
+ */
+/**
+ * \fn int Inode_GetHandle(void)
+ * \brief Gets a unique handle to the Node Cache
+ * \return A unique handle for use for the rest of the Inode_* functions
+ */
+extern int     Inode_GetHandle(void);
+/**
+ * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+ * \brief Gets an inode from the node cache
+ * \param Handle       A handle returned by Inode_GetHandle()
+ * \param Inode        Value of the Inode field of the ::tVFS_Node you want
+ * \return A pointer to the cached node
+ */
+extern tVFS_Node       *Inode_GetCache(int Handle, Uint64 Inode);
+/**
+ * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+ * \brief Caches a node in the Node Cache
+ * \param Handle       A handle returned by Inode_GetHandle()
+ * \param Node A pointer to the node to be cached (a copy is taken)
+ * \return A pointer to the node in the node cache
+ */
+extern tVFS_Node       *Inode_CacheNode(int Handle, tVFS_Node *Node);
+/**
+ * \fn int Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \brief Dereferences (and removes if needed) a node from the cache
+ * \param Handle       A handle returned by Inode_GetHandle()
+ * \param Inode        Value of the Inode field of the ::tVFS_Node you want to remove
+ */
+extern void    Inode_UncacheNode(int Handle, Uint64 Inode);
+/**
+ * \fn void Inode_ClearCache(int Handle)
+ * \brief Clears the cache for a handle
+ * \param Handle       A handle returned by Inode_GetHandle()
+ */
+extern void    Inode_ClearCache(int Handle);
+
+/**
+ * \}
+ */
+
+#endif
diff --git a/KernelLand/Kernel/include/vfs_ext.h b/KernelLand/Kernel/include/vfs_ext.h
new file mode 100644 (file)
index 0000000..b4d5e2a
--- /dev/null
@@ -0,0 +1,390 @@
+/**
+ * \file vfs_ext.h
+ * \brief Exported VFS Definitions
+ * \author John Hodge (thePowersGang)
+ */
+#ifndef _VFS_EXT_H
+#define _VFS_EXT_H
+
+//! Inode number type
+typedef Uint64 tInode;
+
+//! Mountpoint identifier type
+typedef Uint32 tMount;
+
+// === CONSTANTS ===
+//! Maximum size of a Memory Path generated by VFS_GetMemPath
+#define        VFS_MEMPATH_SIZE        (3 + (BITS/4)*2)
+/**
+ * \name Flags for VFS_Open
+ * \{
+ */
+//! Open for execution
+#define VFS_OPENFLAG_EXEC      0x01
+//! Open for reading
+#define VFS_OPENFLAG_READ      0x02
+//! Open for writing
+#define VFS_OPENFLAG_WRITE     0x04
+//! Do not resolve the final symbolic link
+#define        VFS_OPENFLAG_NOLINK     0x40
+//! Create the file if it doesn't exist
+#define VFS_OPENFLAG_CREATE    0x80
+//! Open as a user
+#define        VFS_OPENFLAG_USER       0x8000
+/**
+ * \}
+ */
+//! Marks a VFS handle as belonging to the kernel
+#define VFS_KERNEL_FLAG        0x40000000
+
+//! Architectual maximum number of file descriptors
+#define MAX_FILE_DESCS 128
+
+/**
+ * \brief VFS_Seek directions
+ */
+enum eVFS_SeekDirs
+{
+       SEEK_SET = 1,   //!< Set the current file offset
+       SEEK_CUR = 0,   //!< Seek relative to the current position
+       SEEK_END = -1   //!< Seek from the end of the file backwards
+};
+
+/**
+ * \name ACL Permissions
+ * \{
+ */
+/**
+ * \brief Readable
+ */
+#define VFS_PERM_READ  0x00000001
+/**
+ * \brief Writeable
+ */
+#define VFS_PERM_WRITE 0x00000002
+/**
+ * \brief Append allowed
+ */
+#define VFS_PERM_APPEND        0x00000004
+/**
+ * \brief Executable
+ */
+#define VFS_PERM_EXECUTE       0x00000008
+/**
+ * \brief All permissions granted
+ */
+#define VFS_PERM_ALL   0x7FFFFFFF      // Mask for permissions
+/**
+ * \brief Denies instead of granting permissions
+ * \note Denials take precedence
+ */
+#define VFS_PERM_DENY  0x80000000      // Inverts permissions
+/**
+ * \}
+ */
+
+/**
+ * \brief MMap protection flags
+ * \{
+ */
+#define MMAP_PROT_READ 0x001   //!< Readable memory
+#define MMAP_PROT_WRITE        0x002   //!< Writable memory
+#define MMAP_PROT_EXEC 0x004   //!< Executable memory
+/**
+ * \}
+ */
+
+/**
+ * \brief MMap mapping flags
+ * \{
+ */
+#define MMAP_MAP_SHARED        0x001   //!< Shared with all other users of the FD
+#define MMAP_MAP_PRIVATE       0x002   //!< Local (COW) copy
+#define MMAP_MAP_FIXED         0x004   //!< Load to a fixed address
+#define MMAP_MAP_ANONYMOUS     0x008   //!< Not associated with a FD
+/**
+ * \}
+ */
+
+// -- System Call Structures ---
+/**
+ * \brief ACL Defintion Structure
+ */
+typedef struct sVFS_ACL
+{
+       struct {
+               unsigned Group: 1;      //!< Group (as opposed to user) flag
+               unsigned ID:    31;     //!< ID of Group/User (-1 for nobody/world)
+       };
+       struct {
+               unsigned Inv:   1;      //!< Invert Permissions
+               unsigned Perms: 31;     //!< Permission Flags
+       };
+} tVFS_ACL;
+
+/**
+ * \brief SYS_FINFO structure
+ */
+typedef struct sFInfo
+{
+       tMount  mount;  //!< Mountpoint ID
+       tInode  inode;  //!< Inode
+       Uint32  uid;    //!< Owning User ID
+       Uint32  gid;    //!< Owning Group ID
+       Uint32  flags;  //!< File flags
+       Uint64  size;   //!< File Size
+       Sint64  atime;  //!< Last Accessed time
+       Sint64  mtime;  //!< Last modified time
+       Sint64  ctime;  //!< Creation time
+       Sint32  numacls;        //!< Total number of ACL entries
+       tVFS_ACL        acls[]; //!< ACL buffer (size is passed in the \a MaxACLs argument to VFS_FInfo)
+} PACKED tFInfo;
+
+/**
+ * \brief fd_set for select()
+ */
+typedef struct
+{
+       //! Bitmap of set file descriptors
+       Uint16  flags[MAX_FILE_DESCS/16];
+}      fd_set;
+
+/**
+ * \brief Clear a descriptor flag in a fd_set
+ * \param fd   File descriptor to clear
+ * \param fdsetp       Set to modify
+ */
+#define FD_CLR(fd, fdsetp) ((fdsetp)->flags[(fd)/16]&=~(1<<((fd)%16)))
+/**
+ * \brief Set a descriptor flag in a fd_set
+ * \param fd   File descriptor to set
+ * \param fdsetp       Set to modify
+ */
+#define FD_SET(fd, fdsetp) ((fdsetp)->flags[(fd)/16]|=~(1<<((fd)%16)))
+/**
+ * \brief Test a descriptor flag in a fd_set
+ * \param fd   File descriptor to test
+ * \param fdsetp       Set to modify
+ */
+#define FD_ISSET(fd, fdsetp) ((fdsetp)->flags[(fd)/16]&(1<<((fd)%16)))
+
+// === FUNCTIONS ===
+/**
+ * \brief Initialise the VFS (called by system.c)
+ * \return Boolean Success
+ */
+extern int     VFS_Init(void);
+
+/**
+ * \brief Open a file
+ * \param Path Absolute or relative path to the file
+ * \param Flags        Flags defining how to open the file
+ * \return VFS Handle (an integer) or -1 if an error occured
+ * \note Calls VFS_OpenEx(Path, Flags, 0)
+ */
+extern int     VFS_Open(const char *Path, Uint Flags);
+/**
+ * \brief Open a file
+ * \param Path Absolute or relative path to the file
+ * \param Flags        Flags defining how to open the file
+ * \param Mode Mode for newly created file (POSIX compatability)
+ * \return VFS Handle (an integer) or -1 if an error occured
+ */
+extern int     VFS_OpenEx(const char *Path, Uint Flags, Uint Mode);
+/**
+ * \brief Opens a file via an open directory
+ * \note The file to open must be a direct child of the parent
+ * \param FD   Parent Directory
+ * \param Name Child name
+ * \param Mode Open mode
+ * \return File handle (same as returned from VFS_Open)
+ */
+extern int     VFS_OpenChild(int FD, const char *Name, Uint Mode);
+/**
+ * \brief Opens a file given a mount ID and an inode number
+ * \param Mount        Mount ID returned by FInfo
+ * \param Inode        Inode number from FInfo
+ * \param Mode Open mode (see VFS_Open)
+ * \return File handle (same as VFS_Open)
+ */
+extern int     VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode);
+
+/**
+ * \brief Close a currently open file
+ * \param FD   Handle returned by ::VFS_Open
+ */
+extern void    VFS_Close(int FD);
+
+/**
+ * \brief Get file information from an open file
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Dest Destination for the read information
+ * \param MaxACLs      Number of ACL slots allocated in the \a Dest structure
+ * \return Boolean Success
+ * 
+ * If the \a NumACLs is smaller than the number of ACLs the node has, only
+ * \a NumACLs will be copied into \a Dest, but the tFInfo.numacls field
+ * will be set to the true ammount of ACLs. It is up to the user to do with
+ * this information how they like.
+ */
+extern int     VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs);
+/**
+ * \brief Gets the permissions appling to a user/group.
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Dest ACL information structure to edit
+ * \return Boolean success
+ * 
+ * This function sets the tVFS_ACL.Inv and tVFS_ACL.Perms fields to what
+ * permissions the user/group specied in tVFS_ACL.ID has on the file.
+ */
+extern int     VFS_GetACL(int FD, tVFS_ACL *Dest);
+/**
+ * \brief Changes the user's current working directory
+ * \param Dest New working directory (either absolute or relative to the current)
+ * \return Boolean Success
+ */
+extern int     VFS_ChDir(const char *Dest);
+/**
+ * \brief Change the current virtual root for the user
+ * \param New New virtual root (same as ::VFS_ChDir but cannot go
+ *            above the current virtual root)
+ * \return Boolean success
+ */
+extern int     VFS_ChRoot(const char *New);
+
+/**
+ * \brief Change the location of the current file pointer
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Offset       Offset within the file to go to
+ * \param Whence       A direction from ::eVFS_SeekDirs
+ * \return Boolean success
+ */
+extern int     VFS_Seek(int FD, Sint64 Offset, int Whence);
+/**
+ * \brief Returns the current file pointer
+ * \param FD   File handle returned by ::VFS_Open
+ * \return Current file position
+ */
+extern Uint64  VFS_Tell(int FD);
+
+/**
+ * \brief Reads data from a file
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Length       Number of bytes to read from the file
+ * \param Buffer       Destination of read data
+ * \return Number of read bytes
+ */
+extern Uint64  VFS_Read(int FD, Uint64 Length, void *Buffer);
+/**
+ * \brief Writes data to a file
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Length       Number of bytes to write to the file
+ * \param Buffer       Source of written data
+ * \return Number of bytes written
+ */
+extern Uint64  VFS_Write(int FD, Uint64 Length, const void *Buffer);
+
+/**
+ * \brief Reads from a specific offset in the file
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Offset       Byte offset in the file
+ * \param Length       Number of bytes to read from the file
+ * \param Buffer       Source of read data
+ * \return Number of bytes read
+ */
+extern Uint64  VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
+/**
+ * \brief Writes to a specific offset in the file
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Offset       Byte offset in the file
+ * \param Length       Number of bytes to write to the file
+ * \param Buffer       Source of written data
+ * \return Number of bytes written
+ */
+extern Uint64  VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer);
+
+/**
+ * \brief Sends an IOCtl request to the driver
+ * \param FD   File handle returned by ::VFS_Open
+ * \param ID   IOCtl call ID (driver specific)
+ * \param Buffer       Data pointer to send to the driver
+ * \return Driver specific response
+ */
+extern int     VFS_IOCtl(int FD, int ID, void *Buffer);
+
+/**
+ * \brief Creates a VFS Memory path from a pointer and size
+ * \param Dest Destination for the created path
+ * \param Base Base of the memory file
+ * \param Length       Length of the memory buffer
+ * \note A maximum of VFS_MEMPATH_SIZE bytes will be required in \a Dest
+ */
+extern void    VFS_GetMemPath(char *Dest, void *Base, Uint Length);
+/**
+ * \brief Gets the canoical (true) path of a file
+ * \param Path File path (may contain symlinks, relative elements etc.)
+ * \return Absolute path with no symlinks
+ */
+extern char    *VFS_GetTruePath(const char *Path);
+
+/**
+ * \brief Mounts a filesystem
+ * \param Device       Device to mount
+ * \param MountPoint   Location to mount
+ * \param Filesystem   Filesystem to use
+ * \param Options      Options string to pass the driver
+ * \return 1 on succes, -1 on error
+ */
+extern int     VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
+/**
+ * \brief Create a new directory
+ * \param Path Path to new directory (absolute or relative)
+ * \return Boolean success
+ * \note The parent of the directory must exist
+ */
+extern int     VFS_MkDir(const char *Path);
+/**
+ * \brief Create a symbolic link
+ * \param Name Name of the symbolic link
+ * \param Link File the symlink points to
+ * \return Boolean success (\a Link is not tested for existence)
+ */
+extern int     VFS_Symlink(const char *Name, const char *Link);
+/**
+ * \brief Read from a directory
+ * \param FD   File handle returned by ::VFS_Open
+ * \param Dest Destination array for the file name (max 255 bytes)
+ * \return Boolean Success
+ */
+extern int     VFS_ReadDir(int FD, char *Dest);
+/**
+ * \brief Wait for an aciton on a file descriptor
+ * \param MaxHandle    Maximum set handle in \a *Handles
+ * \param ReadHandles  Handles to wait for data on
+ * \param WriteHandles Handles to wait to write to
+ * \param ErrHandles   Handle to wait for errors on
+ * \param Timeout      Timeout for select() (if null, there is no timeout), if zero select() is non blocking
+ * \param ExtraEvents  Extra event set to wait on
+ * \param IsKernel     Use kernel handles as opposed to user handles
+ * \return Number of handles that actioned
+ */
+extern int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
+
+/**
+ * \brief Map a file into memory
+ * \param DestHint     Suggested place for read data
+ * \param Length       Size of area to map
+ * \param Protection   Protection type (see `man mmap`)
+ * \param Flags        Mapping flags
+ * \param FD   File descriptor to load from
+ * \param Offset       Start of region
+ */
+extern void    *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset);
+
+/**
+ * \brief Unmap memory allocated by VFS_MMap
+ * \param Addr Address of data to unmap
+ * \param Length       Length of data
+ */
+extern int     VFS_MUnmap(void *Addr, size_t Length);
+#endif
diff --git a/KernelLand/Kernel/include/vfs_int.h b/KernelLand/Kernel/include/vfs_int.h
new file mode 100644 (file)
index 0000000..a8eadb6
--- /dev/null
@@ -0,0 +1,68 @@
+/* 
+ * Acess Micro - VFS Server Ver 1
+ */
+#ifndef _VFS_INT_H
+#define _VFS_INT_H
+
+#include "vfs.h"
+
+// === TYPES ===
+typedef struct sVFS_Mount {
+       struct sVFS_Mount       *Next;
+       char    *MountPoint;
+       size_t  MountPointLen;
+       Uint32  Identifier;
+       char    *Device;
+       char    *Options;
+       tVFS_Driver     *Filesystem;
+       tVFS_Node       *RootNode;
+       char    StrData[];
+} tVFS_Mount;
+
+typedef struct sVFS_Handle {
+       tVFS_Node       *Node;
+       tVFS_Mount      *Mount;
+       Uint64  Position;
+       Uint    Mode;
+} tVFS_Handle;
+
+typedef struct sVFS_Proc {
+       struct sVFS_Proc        *Next;
+        int    ID;
+        int    CwdLen;
+       Uint    UID, GID;
+       char    *Cwd;
+        int    MaxHandles;
+       tVFS_Handle     Handles[];
+} tVFS_Proc;
+
+typedef struct sVFS_MMapPage {
+       Uint64  FileOffset;
+       tPAddr  PAddr;
+} tVFS_MMapPage;
+
+// === GLOBALS ===
+extern tVFS_Mount      *gVFS_Mounts;
+
+// === PROTOTYPES ===
+// --- open.c ---
+extern char    *VFS_GetAbsPath(const char *Path);
+extern tVFS_Node       *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPoint);
+extern tVFS_Handle     *VFS_GetHandle(int FD);
+// --- acls.c ---
+extern int     VFS_CheckACL(tVFS_Node *Node, Uint Permissions);
+// --- mount.c ---
+extern tVFS_Mount      *VFS_GetMountByIdent(Uint32 MountID);
+// --- dir.c ---
+extern int     VFS_MkNod(const char *Path, Uint Flags);
+
+
+// --- VFS Helpers ---
+static inline void _CloseNode(tVFS_Node *Node)
+{
+       if(Node && Node->Type && Node->Type->Close)
+               Node->Type->Close( Node );
+}
+
+
+#endif
diff --git a/KernelLand/Kernel/include/vfs_ramfs.h b/KernelLand/Kernel/include/vfs_ramfs.h
new file mode 100644 (file)
index 0000000..8bbc8b5
--- /dev/null
@@ -0,0 +1,20 @@
+/* 
+ * AcessMicro VFS
+ * - RAM Filesystem Coommon Structures
+ */
+#ifndef _RAMFS_H
+#define _RAMFS_H
+#include <vfs.h>
+
+typedef struct sRamFS_File {
+       struct sRamFS_File      *Next;
+       struct sRamFS_File      *Parent;
+       char    Name[32];
+       tVFS_Node       Node;
+       union {
+               struct sRamFS_File      *FirstChild;
+               char    *Bytes;
+       } Data;
+} tRamFS_File;
+
+#endif 
diff --git a/KernelLand/Kernel/include/vfs_threads.h b/KernelLand/Kernel/include/vfs_threads.h
new file mode 100644 (file)
index 0000000..95ec227
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/vfs_threads.h
+ * - Handle maintainance functions for the VFS used by threading code
+ */
+#ifndef _VFS_THREADS_H_
+#define _VFS_THREADS_H_
+
+// === FUNCTIONS ===
+extern void    VFS_ReferenceUserHandles(void);
+extern void    VFS_CloseAllUserHandles(void);
+
+extern void    *VFS_SaveHandles(int NumFDs, int *FDs);
+extern void    VFS_RestoreHandles(int NumFDs, void *Handles);
+extern void    VFS_FreeSavedHandles(int NumFDs, void *Handles);
+
+#endif
diff --git a/KernelLand/Kernel/include/workqueue.h b/KernelLand/Kernel/include/workqueue.h
new file mode 100644 (file)
index 0000000..ff0c7f4
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * workqueue.h
+ * - FIFO Queue
+ */
+#ifndef _WORKQUEUE_H_
+#define _WORKQUEUE_H_
+
+#include <acess.h>
+
+typedef struct sWorkqueue      tWorkqueue;
+
+struct sWorkqueue
+{
+       tShortSpinlock  Protector;
+       const char      *Name;
+        int    NextOffset;
+       
+       void    *Head;
+       void    *Tail;
+       struct sThread  *Sleeper;
+};
+
+extern void    Workqueue_Init(tWorkqueue *Queue, const char *Name, size_t NextOfset);
+extern void    *Workqueue_GetWork(tWorkqueue *Queue);
+extern void    Workqueue_AddWork(tWorkqueue *Queue, void *Ptr);
+
+#endif
+
diff --git a/KernelLand/Kernel/lib.c b/KernelLand/Kernel/lib.c
new file mode 100644 (file)
index 0000000..60cbd4c
--- /dev/null
@@ -0,0 +1,1084 @@
+/*
+ * Acess2
+ * Common Library Functions
+ */
+#include <acess.h>
+#include <hal_proc.h>
+
+// === CONSTANTS ===
+#define        RANDOM_SEED     0xACE55052
+#define        RANDOM_A        0x00731ADE
+#define        RANDOM_C        12345
+#define        RANDOM_SPRUCE   0xf12b039
+//                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
+const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+#define UNIX_TO_2K     ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
+
+// === PROTOTYPES ===
+#if 0
+ int   atoi(const char *string);
+void   itoa(char *buf, Uint64 num, int base, int minLength, char pad);
+ int   vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
+ int   sprintf(char *__s, const char *__format, ...);
+#endif
+ int   tolower(int c);
+#if 0
+ int   strucmp(const char *Str1, const char *Str2);
+char   *strchr(const char *__s, int __c);
+ int   strpos(const char *Str, char Ch);
+ Uint8 ByteSum(void *Ptr, int Size);
+size_t strlen(const char *__s);
+char   *strcpy(char *__str1, const char *__str2);
+char   *strncpy(char *__str1, const char *__str2, size_t max);
+ int   strcmp(const char *str1, const char *str2);
+ int   strncmp(const char *str1, const char *str2, size_t num);
+char   *_strdup(const char *File, int Line, const char *Str);
+char   **str_split(const char *__str, char __ch);
+ int   strpos8(const char *str, Uint32 Search);
+ int   ReadUTF8(Uint8 *str, Uint32 *Val);
+ int   WriteUTF8(Uint8 *str, Uint32 Val);
+ int   DivUp(int num, int dem);
+Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
+void   format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+ int   rand(void);
+ int   CheckString(char *String);
+ int   CheckMem(void *Mem, int NumBytes);
+ int   ModUtil_LookupString(char **Array, char *Needle);
+ int   ModUtil_SetIdent(char *Dest, char *Value);
+ int   Hex(char *Dest, size_t Size, const Uint8 *SourceData);
+ int   UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
+#endif
+
+// === EXPORTS ===
+EXPORT(atoi);
+EXPORT(itoa);
+EXPORT(vsnprintf);
+EXPORT(sprintf);
+EXPORT(tolower);
+EXPORT(strucmp);
+EXPORT(strchr);
+EXPORT(strpos);
+EXPORT(ByteSum);
+EXPORT(strlen);
+EXPORT(strcpy);
+EXPORT(strncpy);
+EXPORT(strcat);
+EXPORT(strncat);
+EXPORT(strcmp);
+EXPORT(strncmp);
+//EXPORT(strdup);
+EXPORT(_strdup);       // Takes File/Line too
+EXPORT(str_split);
+EXPORT(strpos8);
+EXPORT(DivUp);
+EXPORT(ReadUTF8);
+EXPORT(WriteUTF8);
+EXPORT(timestamp);
+EXPORT(CheckString);
+EXPORT(CheckMem);
+EXPORT(ModUtil_LookupString);
+EXPORT(ModUtil_SetIdent);
+EXPORT(UnHex);
+EXPORT(SwapEndian16);
+EXPORT(SwapEndian32);
+EXPORT(memmove);
+
+// === CODE ===
+/**
+ * \brief Convert a string into an integer
+ */
+int atoi(const char *string)
+{
+       int ret = 0;
+       ParseInt(string, &ret);
+       return ret;
+}
+int ParseInt(const char *string, int *Val)
+{
+        int    ret = 0;
+        int    bNeg = 0;
+       const char *orig_string = string;
+       
+       //Log("atoi: (string='%s')", string);
+       
+       // Clear non-numeric characters
+       while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
+       if( *string == '-' ) {
+               bNeg = 1;
+               while( !('0' <= *string && *string <= '9') )    string++;
+       }
+       
+       if(*string == '0')
+       {
+               string ++;
+               if(*string == 'x')
+               {
+                       // Hex
+                       string ++;
+                       for( ;; string ++ )
+                       {
+                               if('0' <= *string && *string <= '9') {
+                                       ret *= 16;
+                                       ret += *string - '0';
+                               }
+                               else if('A' <= *string && *string <= 'F') {
+                                       ret *= 16;
+                                       ret += *string - 'A' + 10;
+                               }
+                               else if('a' <= *string && *string <= 'f') {
+                                       ret *= 16;
+                                       ret += *string - 'a' + 10;
+                               }
+                               else
+                                       break;
+                       }
+               }
+               else    // Octal
+               {
+                       for( ; '0' <= *string && *string <= '7'; string ++ )
+                       {
+                               ret *= 8;
+                               ret += *string - '0';
+                       }
+               }
+       }
+       else    // Decimal
+       {
+               for( ; '0' <= *string && *string <= '9'; string++)
+               {
+                       ret *= 10;
+                       ret += *string - '0';
+               }
+               // Error check
+               if( ret == 0 )  return 0;
+       }
+       
+       if(bNeg)        ret = -ret;
+       
+       //Log("atoi: RETURN %i", ret);
+       
+       if(Val) *Val = ret;
+       
+       return string - orig_string;
+}
+
+static const char cUCDIGITS[] = "0123456789ABCDEF";
+/**
+ * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+ * \brief Convert an integer into a character string
+ */
+void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+{
+       char    tmpBuf[64+1];
+        int    pos=0, i;
+       Uint64  rem;
+
+       // Sanity check
+       if(!buf)        return;
+       
+       // Sanity Check
+       if(base > 16 || base < 2) {
+               buf[0] = 0;
+               return;
+       }
+       
+       // Convert 
+       while(num > base-1) {
+               num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
+               tmpBuf[pos] = cUCDIGITS[ rem ];
+               pos++;
+       }
+       tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
+       
+       // Put in reverse
+       i = 0;
+       minLength -= pos;
+       while(minLength-- > 0)  buf[i++] = pad;
+       while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
+       buf[i] = 0;
+}
+
+/**
+ * \brief Append a character the the vsnprintf output
+ */
+#define PUTCH(c)       _putch(c)
+#define GETVAL()       do {\
+       if(isLongLong)  val = va_arg(args, Uint64);\
+       else    val = va_arg(args, unsigned int);\
+       }while(0)
+/**
+ * \brief VArg String Number Print Formatted
+ */
+int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
+{
+       char    c, pad = ' ';
+        int    minSize = 0, precision = -1, len;
+       char    tmpBuf[34];     // For Integers
+       const char      *p = NULL;
+        int    isLongLong = 0;
+       Uint64  val;
+       size_t  pos = 0;
+       // Flags
+        int    bPadLeft = 0;
+       
+       auto void _putch(char ch);
+
+       void _putch(char ch)
+       {
+               if(pos < __maxlen)
+               {
+                       if(__s) __s[pos] = ch;
+                       pos ++;
+               }
+       }
+
+       while((c = *__format++) != 0)
+       {
+               // Non control character
+               if(c != '%') { PUTCH(c); continue; }
+
+               c = *__format++;
+               if(c == '\0')   break;
+               
+               // Literal %
+               if(c == '%') { PUTCH('%'); continue; }
+               
+               // Pointer - Done first for debugging
+               if(c == 'p') {
+                       Uint    ptr = va_arg(args, Uint);
+                       PUTCH('*');     PUTCH('0');     PUTCH('x');
+                       for( len = BITS/4; len --; )
+                               PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
+                       continue ;
+               }
+               
+               // - Padding Side Flag
+               if(c == '-') {
+                       bPadLeft = 1;
+                       c = *__format++;
+               }
+               
+               // - Padding
+               if(c == '0') {
+                       pad = '0';
+                       c = *__format++;
+               }
+               else
+                       pad = ' ';
+               
+               // - Minimum length
+               if(c == '*') {  // Dynamic length
+                       minSize = va_arg(args, unsigned int);
+                       c = *__format++;
+               }
+               else if('1' <= c && c <= '9')
+               {
+                       minSize = 0;
+                       while('0' <= c && c <= '9')
+                       {
+                               minSize *= 10;
+                               minSize += c - '0';
+                               c = *__format++;
+                       }
+               }
+               else
+                       minSize = 0;
+               
+               // - Precision
+               precision = -1;
+               if( c == '.' ) {
+                       c = *__format++;
+                       
+                       if(c == '*') {  // Dynamic length
+                               precision = va_arg(args, unsigned int);
+                               c = *__format++;
+                       }
+                       else if('1' <= c && c <= '9')
+                       {
+                               precision = 0;
+                               while('0' <= c && c <= '9')
+                               {
+                                       precision *= 10;
+                                       precision += c - '0';
+                                       c = *__format++;
+                               }
+                       }
+               }
+               
+               // - Default, Long or LongLong?
+               isLongLong = 0;
+               if(c == 'l')    // Long is actually the default on x86
+               {
+                       c = *__format++;
+                       if(c == 'l') {
+                               c = *__format++;
+                               isLongLong = 1;
+                       }
+               }
+               
+               // - Now get the format code
+               p = tmpBuf;
+               switch(c)
+               {
+               case 'd':
+               case 'i':
+                       GETVAL();
+                       if( isLongLong && val >> 63 ) {
+                               PUTCH('-');
+                               val = -val;
+                       }
+                       else if( !isLongLong && val >> 31 ) {
+                               PUTCH('-');
+                               val = -(Sint32)val;
+                       }
+                       itoa(tmpBuf, val, 10, minSize, pad);
+                       goto printString;
+               case 'u':       // Unsigned
+                       GETVAL();
+                       itoa(tmpBuf, val, 10, minSize, pad);
+                       goto printString;
+               case 'P':       // Physical Address
+                       PUTCH('0');
+                       PUTCH('x');
+                       if(sizeof(tPAddr) > 4)  isLongLong = 1;
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+               case 'X':       // Hex
+                       if(BITS == 64)
+                               isLongLong = 1; // TODO: Handle non-x86 64-bit archs
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+                       
+               case 'x':       // Lower case hex
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+               case 'o':       // Octal
+                       GETVAL();
+                       itoa(tmpBuf, val, 8, minSize, pad);
+                       goto printString;
+               case 'b':
+                       GETVAL();
+                       itoa(tmpBuf, val, 2, minSize, pad);
+                       goto printString;
+
+               case 'B':       //Boolean
+                       val = va_arg(args, unsigned int);
+                       if(val) p = "True";
+                       else    p = "False";
+                       goto printString;
+               
+               // String - Null Terminated Array
+               case 's':
+                       p = va_arg(args, char*);        // Get Argument
+                       if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
+               printString:
+                       if(!p)          p = "(null)";
+                       len = strlen(p);
+                       if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
+                       while(*p && precision--)        PUTCH(*p++);
+                       if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
+                       break;
+               
+               case 'C':       // Non-Null Terminated Character Array
+                       p = va_arg(args, char*);
+                       if( !CheckMem(p, minSize) )     continue;       // No #PFs please
+                       if(!p)  goto printString;
+                       while(minSize--)        PUTCH(*p++);
+                       break;
+               
+               // Single Character
+               case 'c':
+               default:
+                       GETVAL();
+                       PUTCH( (Uint8)val );
+                       break;
+               }
+       }
+       
+       if(__s && pos != __maxlen)
+               __s[pos] = '\0';
+       
+       return pos;
+}
+#undef PUTCH
+
+/**
+ */
+int sprintf(char *__s, const char *__format, ...)
+{
+       va_list args;
+        int    ret;
+       
+       va_start(args, __format);
+       ret = vsnprintf(__s, -1, __format, args);
+       va_end(args);
+       
+       return ret;
+}
+
+/**
+ * \fn int tolower(int c)
+ * \brief Converts a character to lower case
+ */
+int tolower(int c)
+{
+       if('A' <= c && c <= 'Z')
+               return c - 'A' + 'a';
+       return c;
+}
+
+/**
+ * \fn int strucmp(const char *Str1, const char *Str2)
+ * \brief Compare \a Str1 and \a Str2 case-insensitively
+ */
+int strucmp(const char *Str1, const char *Str2)
+{
+       while(*Str1 && tolower(*Str1) == tolower(*Str2))
+               Str1++, Str2++;
+       return tolower(*Str1) - tolower(*Str2);
+}
+
+/**
+ * \brief Locate a byte in a string
+ */
+char *strchr(const char *__s, int __c)
+{
+       for( ; *__s; __s ++ )
+       {
+               if( *__s == __c )       return (char*)__s;
+       }
+       return NULL;
+}
+
+/**
+ * \fn int strpos(const char *Str, char Ch)
+ * \brief Search a string for an ascii character
+ */
+int strpos(const char *Str, char Ch)
+{
+        int    pos;
+       for(pos=0;Str[pos];pos++)
+       {
+               if(Str[pos] == Ch)      return pos;
+       }
+       return -1;
+}
+
+/**
+ * \fn Uint8 ByteSum(void *Ptr, int Size)
+ * \brief Adds the bytes in a memory region and returns the sum
+ */
+Uint8 ByteSum(const void *Ptr, int Size)
+{
+       Uint8   sum = 0;
+       const Uint8     *data = Ptr;
+       while(Size--)   sum += *(data++);
+       return sum;
+}
+
+/**
+ * \fn size_t strlen(const char *__str)
+ * \brief Get the length of string
+ */
+size_t strlen(const char *__str)
+{
+       size_t  ret = 0;
+       while(*__str++) ret++;
+       return ret;
+}
+
+/**
+ * \brief Copy a string to a new location
+ */
+char *strcpy(char *__str1, const char *__str2)
+{
+       while(*__str2)
+               *__str1++ = *__str2++;
+       *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \brief Copy a string to a new location
+ * \note Copies at most `max` chars
+ */
+char *strncpy(char *__str1, const char *__str2, size_t __max)
+{
+       while(*__str2 && __max-- >= 1)
+               *__str1++ = *__str2++;
+       if(__max)
+               *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \brief Append a string to another
+ */
+char *strcat(char *__dest, const char *__src)
+{
+       while(*__dest++);
+       __dest--;
+       while(*__src)
+               *__dest++ = *__src++;
+       *__dest = '\0';
+       return __dest;
+}
+
+/**
+ * \brief Append at most \a n chars to a string from another
+ * \note At most n+1 chars are written (the dest is always zero terminated)
+ */
+char *strncat(char *__dest, const char *__src, size_t n)
+{
+       while(*__dest++);
+       while(*__src && n-- >= 1)
+               *__dest++ = *__src++;
+       *__dest = '\0';
+       return __dest;
+}
+
+/**
+ * \fn int strcmp(const char *str1, const char *str2)
+ * \brief Compare two strings return the difference between
+ *        the first non-matching characters.
+ */
+int strcmp(const char *str1, const char *str2)
+{
+       while(*str1 && *str1 == *str2)
+               str1++, str2++;
+       return *str1 - *str2;
+}
+
+/**
+ * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
+ * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
+ */
+int strncmp(const char *Str1, const char *Str2, size_t num)
+{
+       if(num == 0)    return 0;       // TODO: Check what should officially happen here
+       while(--num && *Str1 && *Str1 == *Str2)
+               Str1++, Str2++;
+       return *Str1-*Str2;
+}
+
+#if 0
+/**
+ * \fn char *strdup(const char *Str)
+ * \brief Duplicates a string
+ */
+char *strdup(const char *Str)
+{
+       char    *ret;
+       ret = malloc(strlen(Str)+1);
+       if( !ret )      return NULL;
+       strcpy(ret, Str);
+       return ret;
+}
+#else
+
+/**
+ * \fn char *_strdup(const char *File, int Line, const char *Str)
+ * \brief Duplicates a string
+ */
+char *_strdup(const char *File, int Line, const char *Str)
+{
+       char    *ret;
+       ret = Heap_Allocate(File, Line, strlen(Str)+1);
+       if( !ret )      return NULL;
+       strcpy(ret, Str);
+       return ret;
+}
+#endif
+
+/**
+ * \brief Split a string using the passed character
+ * \return NULL terminated array of strings on the heap
+ * \param __str        String to split
+ * \param __ch Character to split by
+ */
+char **str_split(const char *__str, char __ch)
+{
+        int    i, j;
+        int    len = 1;
+       char    **ret;
+       char    *start;
+       
+       for( i = 0; __str[i]; i++ )
+       {
+               if(__str[i] == __ch)
+                       len ++;
+       }
+       
+       ret = malloc( sizeof(char*)*(len+1) + (i + 1) );
+       if( !ret )      return NULL;
+       
+       j = 1;
+       start = (char *)&ret[len+1];
+       ret[0] = start;
+       for( i = 0; __str[i]; i++ )
+       {
+               if(__str[i] == __ch) {
+                       *start++ = '\0';
+                       ret[j++] = start;
+               }
+               else {
+                       *start++ = __str[i]; 
+               }
+       }
+       *start = '\0';
+       ret[j] = NULL;
+       
+       return ret;
+}
+
+/**
+ * \fn int DivUp(int num, int dem)
+ * \brief Divide two numbers, rounding up
+ * \param num  Numerator
+ * \param dem  Denominator
+ */
+int DivUp(int num, int dem)
+{
+       return (num+dem-1)/dem;
+}
+
+/**
+ * \fn int strpos8(const char *str, Uint32 search)
+ * \brief Search a string for a UTF-8 character
+ */
+int strpos8(const char *str, Uint32 Search)
+{
+        int    pos;
+       Uint32  val = 0;
+       for(pos=0;str[pos];pos++)
+       {
+               // ASCII Range
+               if(Search < 128) {
+                       if(str[pos] == Search)  return pos;
+                       continue;
+               }
+               if(*(Uint8*)(str+pos) < 128)    continue;
+               
+               pos += ReadUTF8( (Uint8*)&str[pos], &val );
+               if(val == Search)       return pos;
+       }
+       return -1;
+}
+
+/**
+ * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
+ * \brief Read a UTF-8 character from a string
+ */
+int ReadUTF8(const Uint8 *str, Uint32 *Val)
+{
+       *Val = 0xFFFD;  // Assume invalid character
+       
+       // ASCII
+       if( !(*str & 0x80) ) {
+               *Val = *str;
+               return 1;
+       }
+       
+       // Middle of a sequence
+       if( (*str & 0xC0) == 0x80 ) {
+               return 1;
+       }
+       
+       // Two Byte
+       if( (*str & 0xE0) == 0xC0 ) {
+               *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
+               str ++;
+               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
+               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               return 2;
+       }
+       
+       // Three Byte
+       if( (*str & 0xF0) == 0xE0 ) {
+               *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
+               str ++;
+               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
+               *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
+               str ++;
+               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
+               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               return 3;
+       }
+       
+       // Four Byte
+       if( (*str & 0xF1) == 0xF0 ) {
+               *Val = (*str & 0x07) << 18;     // Upper 3 Bits
+               str ++;
+               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
+               *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
+               str ++;
+               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
+               *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
+               str ++;
+               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
+               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               return 4;
+       }
+       
+       // UTF-8 Doesn't support more than four bytes
+       return 4;
+}
+
+/**
+ * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
+ * \brief Write a UTF-8 character sequence to a string
+ */
+int WriteUTF8(Uint8 *str, Uint32 Val)
+{
+       // ASCII
+       if( Val < 128 ) {
+               if( str ) {
+                       *str = Val;
+               }
+               return 1;
+       }
+       
+       // Two Byte
+       if( Val < 0x8000 ) {
+               if( str ) {
+                       *str++ = 0xC0 | (Val >> 6);
+                       *str++ = 0x80 | (Val & 0x3F);
+               }
+               return 2;
+       }
+       
+       // Three Byte
+       if( Val < 0x10000 ) {
+               if( str ) {
+                       *str++ = 0xE0 | (Val >> 12);
+                       *str++ = 0x80 | ((Val >> 6) & 0x3F);
+                       *str++ = 0x80 | (Val & 0x3F);
+               }
+               return 3;
+       }
+       
+       // Four Byte
+       if( Val < 0x110000 ) {
+               if( str ) {
+                       *str++ = 0xF0 | (Val >> 18);
+                       *str++ = 0x80 | ((Val >> 12) & 0x3F);
+                       *str++ = 0x80 | ((Val >> 6) & 0x3F);
+                       *str++ = 0x80 | (Val & 0x3F);
+               }
+               return 4;
+       }
+       
+       // UTF-8 Doesn't support more than four bytes
+       return 0;
+}
+
+/**
+ * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
+ * \brief Converts a date into an Acess Timestamp
+ */
+Sint64 timestamp(int sec, int min, int hrs, int day, int month, int year)
+{
+        int    is_leap;
+       Sint64  stamp;
+
+       if( !(0 <= sec && sec < 60) )   return 0;
+       if( !(0 <= min && min < 60) )   return 0;
+       if( !(0 <= hrs && hrs < 24) )   return 0;
+       if( !(0 <= day && day < 31) )   return 0;
+       if( !(0 <= month && month < 12) )       return 0;
+
+       stamp = DAYS_BEFORE[month] + day;
+
+       // Every 4 years
+       // - every 100 years
+       // + every 400 years
+       is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
+       ASSERT(is_leap == 0 || is_leap == 1);
+
+       if( is_leap && month > 1 )      // Leap year and after feb
+               stamp += 1;
+
+       // Get seconds before the first of specified year
+       year -= 2000;   // Base off Y2K
+       // base year days + total leap year days
+       stamp += year*365 + (year/400) - (year/100) + (year/4);
+       
+       stamp *= 3600*24;
+       stamp += UNIX_TO_2K;
+       stamp += sec;
+       stamp += min*60;
+       stamp += hrs*3600;
+       
+       return stamp * 1000;
+}
+
+void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms)
+{
+        int    is_leap = 0, i;
+
+       auto Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R);
+       
+       Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R)
+       {
+               int sign = (N < 0) != (D < 0);
+               if(N < 0)       N = -N;
+               if(D < 0)       D = -D;
+               if(sign)
+                       return -DivMod64U(N, D, (Uint64*)R);
+               else
+                       return DivMod64U(N, D, (Uint64*)R);
+       }
+
+       // Get time
+       // TODO: Leap-seconds?
+       {
+               Sint64  rem;
+               TS = DivMod64( TS, 1000, &rem );
+               *ms = rem;
+               TS = DivMod64( TS, 60, &rem );
+               *sec = rem;
+               TS = DivMod64( TS, 60, &rem );
+               *mins = rem;
+               TS = DivMod64( TS, 24, &rem );
+               *hrs = rem;
+       }
+
+       // Adjust to Y2K
+       TS -= UNIX_TO_2K/(3600*24);
+
+       // Year (400 yr blocks) - (400/4-3) leap years
+       *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS );
+       if( TS < 366 )  // First year in 400 is a leap
+               is_leap = 1;
+       else
+       {
+               // 100 yr blocks - 100/4-1 leap years
+               *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS );
+               if( TS < 366 )  // First year in 100 isn't a leap
+                       is_leap = 0;
+               else
+               {
+                       *year += 4 * DivMod64( TS, 365*4 + 1, &TS );
+                       if( TS < 366 )  // First year in 4 is a leap
+                               is_leap = 1;
+                       else
+                       {
+                               *year += DivMod64( TS, 356, &TS );
+                       }
+               }
+       }
+       *year += 2000;
+
+       ASSERT(TS >= 0);
+       
+       *day = 0;
+       // Month (if after the first of march, which is 29 Feb in a leap year)
+       if( is_leap && TS > DAYS_BEFORE[2] ) {
+               TS -= 1;        // Shifts 29 Feb to 28 Feb
+               *day = 1;
+       }
+       // Get what month it is
+       for( i = 0; i < 12; i ++ ) {
+               if( TS < DAYS_BEFORE[i] )
+                       break;
+       }
+       *month = i - 1;
+       // Get day
+       TS -= DAYS_BEFORE[i-1];
+       *day += TS;     // Plus offset from leap handling above
+}
+
+/**
+ * \fn int rand()
+ * \brief Pseudo random number generator
+ */
+int rand(void)
+{
+       #if 0
+       static Uint     state = RANDOM_SEED;
+       Uint    old = state;
+       // Get the next state value
+       giRandomState = (RANDOM_A*state + RANDOM_C);
+       // Check if it has changed, and if it hasn't, change it
+       if(state == old)        state += RANDOM_SPRUCE;
+       return state;
+       #else
+       // http://en.wikipedia.org/wiki/Xorshift
+       // 2010-10-03
+       static Uint32   x = 123456789;
+       static Uint32   y = 362436069;
+       static Uint32   z = 521288629;
+       static Uint32   w = 88675123; 
+       Uint32  t;
+       t = x ^ (x << 11);
+       x = y; y = z; z = w;
+       return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
+       #endif
+}
+
+/* *
+ * \name Memory Validation
+ * \{
+ */
+/**
+ * \brief Checks if a string resides fully in valid memory
+ */
+int CheckString(const char *String)
+{
+       tVAddr  addr;
+        int    bUser;
+
+       addr = (tVAddr)String;
+
+       if( !MM_GetPhysAddr( addr ) )
+               return 0;
+       
+       // Check 1st page
+       bUser = MM_IsUser( addr );
+       
+       while( *(char*)addr )
+       {
+               if( (addr & (PAGE_SIZE-1)) == 0 )
+               {
+                       if(bUser && !MM_IsUser(addr) )
+                               return 0;
+                       if(!bUser && !MM_GetPhysAddr(addr) )
+                               return 0;
+               }
+               addr ++;
+       }
+       return 1;
+}
+
+/**
+ * \brief Check if a sized memory region is valid memory
+ * \return Boolean success
+ */
+int CheckMem(const void *Mem, int NumBytes)
+{
+       return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
+}
+/* *
+ * \}
+ */
+
+/**
+ * \brief Search a string array for \a Needle
+ * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
+ */
+int ModUtil_LookupString(const char **Array, const char *Needle)
+{
+        int    i;
+       if( !CheckString(Needle) )      return -1;
+       for( i = 0; Array[i]; i++ )
+       {
+               if(strcmp(Array[i], Needle) == 0)       return i;
+       }
+       return -1;
+}
+
+int ModUtil_SetIdent(char *Dest, const char *Value)
+{
+       if( !CheckMem(Dest, 32) )       return -1;
+       strncpy(Dest, Value, 32);
+       return 1;
+}
+
+int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
+{
+        int    i;
+       for( i = 0; i < Size; i ++ )
+       {
+               sprintf(Dest + i*2, "%02x", SourceData[i]);
+       }
+       return i*2;
+}
+
+/**
+ * \brief Convert a string of hexadecimal digits into a byte stream
+ */
+int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
+{
+        int    i;
+       
+       for( i = 0; i < DestSize*2; i += 2 )
+       {
+               Uint8   val = 0;
+               
+               if(SourceString[i] == '\0')     break;
+               
+               if('0' <= SourceString[i] && SourceString[i] <= '9')
+                       val |= (SourceString[i]-'0') << 4;
+               else if('A' <= SourceString[i] && SourceString[i] <= 'F')
+                       val |= (SourceString[i]-'A'+10) << 4;
+               else if('a' <= SourceString[i] && SourceString[i] <= 'f')
+                       val |= (SourceString[i]-'a'+10) << 4;
+                       
+               if(SourceString[i+1] == '\0')   break;
+               
+               if('0' <= SourceString[i+1] && SourceString[i+1] <= '9')
+                       val |= (SourceString[i+1] - '0');
+               else if('A' <= SourceString[i+1] && SourceString[i+1] <= 'F')
+                       val |= (SourceString[i+1] - 'A' + 10);
+               else if('a' <= SourceString[i+1] && SourceString[i+1] <= 'f')
+                       val |= (SourceString[i+1] - 'a' + 10);
+               
+               Dest[i/2] = val;
+       }
+       return i/2;
+}
+
+Uint16 SwapEndian16(Uint16 Val)
+{
+       return ((Val&0xFF)<<8) | ((Val>>8)&0xFF);
+}
+Uint32 SwapEndian32(Uint32 Val)
+{
+       return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
+}
+
+void *memmove(void *__dest, const void *__src, size_t len)
+{
+       size_t  block_size;
+       char    *dest = __dest;
+       const char      *src = __src;
+       void    *ret = __dest;
+
+       if( len == 0 || dest == src )
+               return dest;
+       
+       if( (tVAddr)dest > (tVAddr)src + len )
+               return memcpy(dest, src, len);
+       if( (tVAddr)dest + len < (tVAddr)src )
+               return memcpy(dest, src, len);
+       
+       // NOTE: Assumes memcpy works forward
+       if( (tVAddr)dest < (tVAddr)src )
+               return memcpy(dest, src, len);
+
+       if( (tVAddr)dest < (tVAddr)src )
+               block_size = (tVAddr)src - (tVAddr)dest;
+       else
+               block_size = (tVAddr)dest - (tVAddr)src;
+       
+       block_size &= ~0xF;
+       
+       while(len >= block_size)
+       {
+               memcpy(dest, src, block_size);
+               len -= block_size;
+               dest += block_size;
+               src += block_size;
+       }
+       memcpy(dest, src, len);
+       return ret;
+       
+}
+
diff --git a/KernelLand/Kernel/logging.c b/KernelLand/Kernel/logging.c
new file mode 100644 (file)
index 0000000..b419be3
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Acess 2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * logging.c - Kernel Logging Service
+ */
+#include <acess.h>
+#include <adt.h>
+
+#define CACHE_MESSAGES 0
+#define PRINT_ON_APPEND        1
+#define USE_RING_BUFFER        1
+#define RING_BUFFER_SIZE       4096
+
+// === CONSTANTS ===
+enum eLogLevels
+{
+       LOG_LEVEL_KPANIC,
+       LOG_LEVEL_PANIC,
+       LOG_LEVEL_FATAL,
+       LOG_LEVEL_ERROR,
+       LOG_LEVEL_WARNING,
+       LOG_LEVEL_NOTICE,
+       LOG_LEVEL_LOG,
+       LOG_LEVEL_DEBUG,
+       NUM_LOG_LEVELS
+};
+const char     *csaLevelColours[] = {
+               "\x1B[35m", "\x1B[34m", "\x1B[36m", "\x1B[31m",
+               "\x1B[33m", "\x1B[32m", "\x1B[0m", "\x1B[0m"
+               };
+const char     *csaLevelCodes[] =  {"k","p","f","e","w","n","l","d"};
+
+// === TYPES ===
+typedef struct sLogEntry
+{
+       struct sLogEntry        *Next;
+       struct sLogEntry        *LevelNext;
+       Sint64  Time;
+        int    Level;
+        int    Length;
+       char    Ident[9];
+       char    Data[];
+}      tLogEntry;
+typedef struct sLogList
+{
+       tLogEntry       *Head;
+       tLogEntry       *Tail;
+}      tLogList;
+
+// === PROTOTYPES ===
+void   Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args);
+static void    Log_Int_PrintMessage(tLogEntry *Entry);
+//void Log_KernelPanic(const char *Ident, const char *Message, ...);
+//void Log_Panic(const char *Ident, const char *Message, ...);
+//void Log_Error(const char *Ident, const char *Message, ...);
+//void Log_Warning(const char *Ident, const char *Message, ...);
+//void Log_Notice(const char *Ident, const char *Message, ...);
+//void Log_Log(const char *Ident, const char *Message, ...);
+//void Log_Debug(const char *Ident, const char *Message, ...);
+
+// === EXPORTS ===
+EXPORT(Log_Panic);
+EXPORT(Log_Error);
+EXPORT(Log_Warning);
+EXPORT(Log_Notice);
+EXPORT(Log_Log);
+EXPORT(Log_Debug);
+
+// === GLOBALS ===
+tShortSpinlock glLogOutput;
+#if USE_RING_BUFFER
+Uint8  gaLog_RingBufferData[sizeof(tRingBuffer)+RING_BUFFER_SIZE];
+tRingBuffer    *gpLog_RingBuffer = (void*)gaLog_RingBufferData;
+#else
+tMutex glLog;
+tLogList       gLog;
+tLogList       gLog_Levels[NUM_LOG_LEVELS];
+#endif
+
+// === CODE ===
+/**
+ * \brief Adds an event to the log
+ */
+void Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args)
+{
+        int    len;
+       tLogEntry       *ent;
+       va_list args_tmp;
+       
+       if( Level >= NUM_LOG_LEVELS )   return;
+       
+       va_copy(args_tmp, Args);
+       len = vsnprintf(NULL, 256, Format, args_tmp);
+       
+       //Log("len = %i", len);
+       
+       #if USE_RING_BUFFER || !CACHE_MESSAGES
+       {
+       char    buf[sizeof(tLogEntry)+len+1];
+       ent = (void*)buf;
+       #else
+       ent = malloc(sizeof(tLogEntry)+len+1);
+       #endif
+       ent->Time = now();
+       strncpy(ent->Ident, Ident, 8);
+       ent->Ident[8] = '\0';
+       ent->Level = Level;
+       ent->Length = len;
+       vsnprintf( ent->Data, len+1, Format, Args );
+
+       #if CACHE_MESSAGES
+       # if USE_RING_BUFFER
+       {
+               #define LOG_HDR_LEN     (14+1+2+8+2)
+               char    newData[ LOG_HDR_LEN + len + 2 + 1 ];
+               char    _ident[9];
+               strncpy(_ident, Ident, 9);
+               sprintf( newData, "%014lli%s [%-8s] ",
+                       ent->Time, csaLevelCodes[Level], Ident);
+               strcpy( newData + LOG_HDR_LEN, ent->Data );
+               strcpy( newData + LOG_HDR_LEN + len, "\r\n" );
+               gpLog_RingBuffer->Space = RING_BUFFER_SIZE;     // Needed to init the buffer
+               RingBuffer_Write( gpLog_RingBuffer, newData, LOG_HDR_LEN + len + 2 );
+       }
+       # else
+       Mutex_Acquire( &glLog );
+       
+       ent->Next = gLog.Tail;
+       if(gLog.Head)
+               gLog.Tail = ent;
+       else
+               gLog.Tail = gLog.Head = ent;
+       
+       ent->LevelNext = gLog_Levels[Level].Tail;
+       if(gLog_Levels[Level].Head)
+               gLog_Levels[Level].Tail = ent;
+       else
+               gLog_Levels[Level].Tail = gLog_Levels[Level].Head = ent;
+       
+       Mutex_Release( &glLog );
+       # endif
+       #endif
+       
+       #if PRINT_ON_APPEND || !CACHE_MESSAGES
+       Log_Int_PrintMessage( ent );
+       #endif
+       
+       #if USE_RING_BUFFER || !CACHE_MESSAGES
+       }
+       #endif
+}
+
+/**
+ * \brief Prints a log message to the debug console
+ */
+void Log_Int_PrintMessage(tLogEntry *Entry)
+{
+       SHORTLOCK( &glLogOutput );
+       LogF("%s%014lli%s [%-8s] %i - %s",
+               csaLevelColours[Entry->Level],
+               Entry->Time,
+               csaLevelCodes[Entry->Level],
+               Entry->Ident,
+               Threads_GetTID(),
+               Entry->Data
+               );
+       LogF("\x1B[0m\r\n");    // Separate in case Entry->Data is too long
+       SHORTREL( &glLogOutput );
+}
+
+/**
+ * \brief KERNEL PANIC!!!!
+ */
+void Log_KernelPanic(const char *Ident, const char *Message, ...)
+{
+       va_list args;   
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_KPANIC, Message, args);
+       va_end(args);
+       Panic("Log_KernelPanic - %s", Ident);
+}
+
+/**
+ * \brief Panic Message - Driver Unrecoverable error
+ */
+void Log_Panic(const char *Ident, const char *Message, ...)
+{
+       va_list args;   
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_PANIC, Message, args);
+       va_end(args);
+}
+
+/**
+ * \brief Error Message - Recoverable Error
+ */
+void Log_Error(const char *Ident, const char *Message, ...)
+{
+       va_list args;   
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_ERROR, Message, args);
+       va_end(args);
+}
+
+/**
+ * \brief Warning Message - Something the user should know
+ */
+void Log_Warning(const char *Ident, const char *Message, ...)
+{
+       va_list args;
+       
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_WARNING, Message, args);
+       va_end(args);
+}
+
+/**
+ * \brief Notice Message - Something the user might like to know
+ */
+void Log_Notice(const char *Ident, const char *Message, ...)
+{
+       va_list args;   
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_NOTICE, Message, args);
+       va_end(args);
+}
+
+/**
+ * \brief Log Message - Possibly useful information
+ */
+void Log_Log(const char *Ident, const char *Message, ...)
+{
+       va_list args;   
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_LOG, Message, args);
+       va_end(args);
+}
+
+/**
+ * \brief Debug Message - Only a developer would want this info
+ */
+void Log_Debug(const char *Ident, const char *Message, ...)
+{
+       va_list args;   
+       va_start(args, Message);
+       Log_AddEvent(Ident, LOG_LEVEL_DEBUG, Message, args);
+       va_end(args);
+}
diff --git a/KernelLand/Kernel/messages.c b/KernelLand/Kernel/messages.c
new file mode 100644 (file)
index 0000000..afdcdbd
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * messages.c
+ * - IPC Messages
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <threads.h>
+#include <threads_int.h>
+#include <errno.h>
+#include <events.h>
+
+// === CODE ===
+/**
+ * \fn int Proc_SendMessage(Uint Dest, int Length, void *Data)
+ * \brief Send an IPC message
+ * \param Dest Destination Thread
+ * \param Length       Length of the message
+ * \param Data Message data
+ */
+int Proc_SendMessage(Uint Dest, int Length, void *Data)
+{
+       tThread *thread;
+       tMsg    *msg;
+       
+       ENTER("pErr iDest iLength pData", Err, Dest, Length, Data);
+       
+       if(Length <= 0 || !Data) {
+               errno = -EINVAL;
+               LEAVE_RET('i', -1);
+       }
+       
+       // TODO: Check message length against global/per-thread maximums
+       // TODO: Restrict queue length
+
+       // Get thread
+       thread = Threads_GetThread( Dest );
+       
+       // Error check
+       if(!thread)     LEAVE_RET('i', -1);
+       
+       // Get Spinlock
+       SHORTLOCK( &thread->IsLocked );
+       
+       // Check if thread is still alive
+       if(thread->Status == THREAD_STAT_DEAD) {
+               SHORTREL( &thread->IsLocked );
+               LEAVE_RET('i', -1);
+       }
+       
+       // Create message
+       msg = malloc( sizeof(tMsg)+Length );
+       msg->Next = NULL;
+       msg->Source = Proc_GetCurThread()->TID;
+       msg->Length = Length;
+       memcpy(msg->Data, Data, Length);
+       
+       // If there are already messages
+       if(thread->LastMessage) {
+               thread->LastMessage->Next = msg;
+               thread->LastMessage = msg;
+       } else {
+               thread->Messages = msg;
+               thread->LastMessage = msg;
+       }
+       
+       SHORTREL(&thread->IsLocked);
+
+       // Wake the thread      
+       LOG("Waking %p (%i %s)", thread, thread->TID, thread->ThreadName);
+       Threads_PostEvent( thread, THREAD_EVENT_IPCMSG );
+       
+       LEAVE_RET('i', 0);
+}
+
+/**
+ * \fn int Proc_GetMessage(Uint *Source, void *Buffer)
+ * \brief Gets a message
+ * \param Source       Where to put the source TID
+ * \param Buffer       Buffer to place the message data (set to NULL to just get message length)
+ * \return Message length
+ */
+int Proc_GetMessage(Uint *Source, void *Buffer)
+{
+        int    ret;
+       void    *tmp;
+       tThread *cur = Proc_GetCurThread();
+
+       ENTER("pSource pBuffer", Source, Buffer);
+       
+       // Check if queue has any items
+       if(!cur->Messages) {
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       SHORTLOCK( &cur->IsLocked );
+       
+       if(Source) {
+               *Source = cur->Messages->Source;
+               LOG("*Source = %i", *Source);
+       }
+       
+       // Get message length
+       if( !Buffer ) {
+               ret = cur->Messages->Length;
+               SHORTREL( &cur->IsLocked );
+               LEAVE('i', ret);
+               return ret;
+       }
+       
+       // Get message
+       if(Buffer != GETMSG_IGNORE)
+       {
+               if( !CheckMem( Buffer, cur->Messages->Length ) )
+               {
+                       LOG("Invalid buffer");
+                       errno = -EINVAL;
+                       SHORTREL( &cur->IsLocked );
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               LOG("Copied to buffer");
+               memcpy(Buffer, cur->Messages->Data, cur->Messages->Length);
+       }
+       ret = cur->Messages->Length;
+       
+       // Remove from list
+       tmp = cur->Messages;
+       cur->Messages = cur->Messages->Next;
+       if(cur->Messages == NULL)       cur->LastMessage = NULL;
+       
+       SHORTREL( &cur->IsLocked );
+       
+       free(tmp);      // Free outside of lock
+
+       LEAVE('i', ret);
+       return ret;
+}
diff --git a/KernelLand/Kernel/modules.c b/KernelLand/Kernel/modules.c
new file mode 100644 (file)
index 0000000..98ca1a1
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Acess2
+ * - Module Loader
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>
+
+#define        USE_EDI 0
+#define        USE_UDI 0
+
+// === PROTOTYPES ===
+ int   Module_int_Initialise(tModule *Module, const char *ArgString);
+void   Modules_int_GetBuiltinArray(void);
+void   Modules_LoadBuiltins(void);
+void   Modules_SetBuiltinParams(const char *Name, char *ArgString);
+ int   Modules_InitialiseBuiltin(const char *Name);
+// int Module_RegisterLoader(tModuleLoader *Loader);
+// int Module_LoadMem(void *Buffer, Uint Length, char *ArgString);
+// int Module_LoadFile(char *Path, char *ArgString);
+ int   Module_int_ResolveDeps(tModule *Info);
+ int   Module_IsLoaded(const char *Name);
+// int Module_EnsureLoaded(const char *Name);
+
+// === EXPORTS ===
+EXPORT(Module_RegisterLoader);
+
+// === IMPORTS ===
+#if USE_UDI
+extern int     UDI_LoadDriver(void *Base);
+#endif
+extern void    StartupPrint(const char *Str);
+extern tModule gKernelModules;
+extern tModule gKernelModulesEnd;
+
+// === GLOBALS ===
+ int   giNumBuiltinModules = 0;
+tShortSpinlock glModuleSpinlock;
+tModule        *gLoadedModules = NULL;
+tModuleLoader  *gModule_Loaders = NULL;
+tModule        *gLoadingModules = NULL;
+tModule        **gapBuiltinModules = NULL;
+char   **gasBuiltinModuleArgs;
+
+// === CODE ===
+/**
+ * \brief Initialises a module
+ * \param Module       Pointer to the module header
+ * \param ArgString    Comma separated list of module arguments
+ * \return Zero on success, eModuleErrors or -1 on error
+ * \retval -1  Returned if a dependency fails, or a circular dependency
+ *              exists.
+ * \retval 0   Returned on success
+ * \retval >0  Error code form the module's initialisation function
+ */
+int Module_int_Initialise(tModule *Module, const char *ArgString)
+{
+        int    i, j;
+        int    ret;
+       const char      **deps;
+       char    **args;
+       tModule *mod;
+       
+       ENTER("pModule", Module);
+       LOG("Module->Magic = 0x%x", Module->Magic);
+       if(Module->Magic != MODULE_MAGIC) {
+               Log_Warning(
+                       "Module",
+                       "Module %p is no a valid Acess2 module (0x%08x != 0x%08x)",
+                       Module, Module->Magic, MODULE_MAGIC
+                       );
+               LEAVE('i', MODULE_ERR_BADMODULE);
+               return MODULE_ERR_BADMODULE;
+       }
+       LOG("Module->Name = %p \"%s\"", Module->Name, Module->Name);
+       
+       if(Module->Arch != MODULE_ARCH_ID) {
+               Log_Warning(
+                       "Module",
+                       "Module %p (%s) is for another architecture (%i)",
+                       Module, Module->Name, Module->Arch
+                       );
+       }
+       
+       deps = Module->Dependencies;
+       
+       // Check if the module has been loaded
+       for( mod = gLoadedModules; mod; mod = mod->Next )
+       {
+               if(mod == Module)       LEAVE_RET('i', 0);
+       }
+       
+       // Add to the "loading" (prevents circular deps)
+       Module->Next = gLoadingModules;
+       gLoadingModules = Module;
+       
+       // Scan dependency list
+       for( j = 0; deps && deps[j]; j++ )
+       {
+               // Check if the module is already loaded
+               for( mod = gLoadedModules; mod; mod = mod->Next )
+               {
+                       if(strcmp(deps[j], mod->Name) == 0)
+                               break;
+               }
+               if( mod )       continue;       // Dependency is loaded, check the rest
+               
+               // Ok, check if it's loading
+               for( mod = gLoadingModules->Next; mod; mod = mod->Next )
+               {
+                       if(strcmp(deps[j], mod->Name) == 0)
+                               break;
+               }
+               if( mod ) {
+                       Log_Warning("Module", "Circular dependency detected (%s and %s)",
+                               mod->Name, Module->Name);
+                       LEAVE_RET('i', -1);
+               }
+               
+               // So, if it's not loaded, we better load it then
+               for( i = 0; i < giNumBuiltinModules; i ++ )
+               {
+                       if( strcmp(deps[j], gapBuiltinModules[i]->Name) == 0 )
+                               break;
+               }
+               if( i == giNumBuiltinModules ) {
+                       Log_Warning("Module", "Dependency '%s' for module '%s' failed",
+                               deps[j], Module->Name);
+                       return -1;
+               }
+               
+               // Dependency is not loaded, so load it
+               ret = Module_int_Initialise(
+                       gapBuiltinModules[i],
+                       gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL
+                       );
+               if( ret )
+               {
+                       // The only "ok" error is NOTNEEDED
+                       if(ret != MODULE_ERR_NOTNEEDED)
+                               LEAVE_RET('i', -1);
+               }
+       }
+       
+       // All Dependencies OK? Initialise
+       StartupPrint(Module->Name);
+       Log_Log("Module", "Starting %p '%s' v%i.%i",
+               Module, Module->Name,
+               Module->Version >> 8, Module->Version & 0xFF
+               );
+       
+       if( ArgString )
+               args = str_split( ArgString, ',' );
+       else
+               args = NULL;
+       
+       ret = Module->Init(args);
+       
+       if(args)        free(args);
+       
+       // Remove from loading list
+       gLoadingModules = gLoadingModules->Next;
+       
+       if( ret != MODULE_ERR_OK ) {
+               switch(ret)
+               {
+               case MODULE_ERR_MISC:
+                       Log_Warning("Module", "Unable to load, reason: Miscelanious");
+                       break;
+               case MODULE_ERR_NOTNEEDED:
+                       Log_Debug("Module", "Unable to load, reason: Module not needed");
+                       break;
+               case MODULE_ERR_MALLOC:
+                       Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
+                       break;
+               default:
+                       Log_Warning("Module", "Unable to load reason - Unknown code %i", ret);
+                       break;
+               }
+               LEAVE_RET('i', ret);
+               return ret;
+       }
+       LOG("ret = %i", ret);
+       
+       // Add to loaded list
+       SHORTLOCK( &glModuleSpinlock );
+       Module->Next = gLoadedModules;
+       gLoadedModules = Module;
+       SHORTREL( &glModuleSpinlock );
+       
+       LEAVE_RET('i', 0);
+}
+
+/**
+ * \brief Scans the builtin modules and creates an array of them
+ */
+void Modules_int_GetBuiltinArray(void)
+{
+        int    i;
+       tModule *module;
+       
+       // Count
+       module = &gKernelModules;
+       i = 0;
+       while( (tVAddr)module < (tVAddr)&gKernelModulesEnd )
+       {
+               if(module->Magic == MODULE_MAGIC) {
+                       i ++;
+                       module ++;
+               }
+               else
+                       module = (void*)( (tVAddr)module + 4 );
+       }
+       
+       // Create
+       giNumBuiltinModules = i;
+       gasBuiltinModuleArgs = calloc( giNumBuiltinModules, sizeof(char*) );
+       gapBuiltinModules = malloc( giNumBuiltinModules * sizeof(tModule*) );
+       
+       
+       // Fill
+       module = &gKernelModules;
+       i = 0;
+       while( (tVAddr)module < (tVAddr)&gKernelModulesEnd )
+       {
+               if(module->Magic == MODULE_MAGIC) {
+                       gapBuiltinModules[i] = module;
+                       i ++;
+                       module ++;
+               }
+               else
+                       module = (void*)( (tVAddr)module + 4 );
+       }
+}
+
+/**
+ * \brief Initialises builtin modules
+ */
+void Modules_LoadBuiltins()
+{
+        int    i;
+       
+       if( !gapBuiltinModules )
+               Modules_int_GetBuiltinArray();
+       
+       for( i = 0; i < giNumBuiltinModules; i++ )
+       {
+               Module_int_Initialise(
+                       gapBuiltinModules[i],
+                       (gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL)
+                       );
+       }
+       
+       if( gasBuiltinModuleArgs != NULL )
+               free(gasBuiltinModuleArgs);
+}
+
+/**
+ * \brief Initialise a builtin module given it's name
+ * 
+ * E.g. Used by VTerm to load an alternate video driver at runtime
+ */
+int Modules_InitialiseBuiltin(const char *Name)
+{
+        int    i;
+       
+       // Check if it's loaded
+       if( Module_IsLoaded(Name) )
+               return 0;
+       
+       if( !gapBuiltinModules )
+               Modules_int_GetBuiltinArray();
+       
+       for( i = 0; i < giNumBuiltinModules; i++ )
+       {
+               if( strcmp(gapBuiltinModules[i]->Name, Name) == 0 ) {
+                       return Module_int_Initialise(gapBuiltinModules[i],
+                               (gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL)
+                               );
+               }
+       }
+       return -1;
+}
+
+/**
+ * \brief Sets the parameters for a builtin module
+ */
+void Modules_SetBuiltinParams(const char *Name, char *ArgString)
+{
+        int    i;
+       
+       if( gasBuiltinModuleArgs == NULL )
+       {
+               Modules_int_GetBuiltinArray();
+       }
+       
+       // I hate expensive scans
+       for( i = 0; i < giNumBuiltinModules; i++ )
+       {
+               if(strcmp( gapBuiltinModules[i]->Name, Name ) == 0) {
+                       gasBuiltinModuleArgs[i] = ArgString;
+                       return ;
+               }
+       }
+       
+       Log_Warning("Modules", "Unknown builtin kernel module '%s'", Name);
+}
+
+/**
+ * \brief Registers a tModuleLoader with the kernel
+ * \param Loader       Pointer to loader structure (must be persistent)
+ */
+int Module_RegisterLoader(tModuleLoader *Loader)
+{
+       if(!Loader)     return 1;
+       
+       Loader->Next = gModule_Loaders;
+       gModule_Loaders = Loader;
+       
+       return 0;
+}
+
+/**
+ * \fn int Module_LoadMem(void *Buffer, Uint Length, char *ArgString)
+ * \brief Load a module from a memory location
+ */
+int Module_LoadMem(void *Buffer, Uint Length, const char *ArgString)
+{
+       char    path[VFS_MEMPATH_SIZE];
+       
+       VFS_GetMemPath(path, Buffer, Length);
+       
+       return Module_LoadFile( path, ArgString );
+}
+
+/**
+ * \fn int Module_LoadFile(const char *Path, const char *ArgString)
+ * \brief Load a module from a file
+ */
+int Module_LoadFile(const char *Path, const char *ArgString)
+{
+       void    *base;
+       tModule *info;
+       
+       // Load Binary
+       base = Binary_LoadKernel(Path);
+       
+       // Error check
+       if(base == NULL) {
+               Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
+               return 0;
+       }
+       
+       // Check for Acess Driver
+       if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
+       {
+               tModuleLoader   *tmp;
+               for( tmp = gModule_Loaders; tmp; tmp = tmp->Next)
+               {
+                       if( tmp->Detector(base) == 0 )  continue;
+                       
+                       return tmp->Loader(base);
+               }
+               
+               #if USE_EDI
+               // Check for EDI Driver
+               if( Binary_FindSymbol(base, "driver_init", NULL ) != 0 )
+               {
+                       return Module_InitEDI( base );  // And intialise
+               }
+               #endif
+               
+               // Unknown module type?, return error
+               Binary_Unload(base);
+               #if USE_EDI
+               Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
+               #else
+               Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
+               #endif
+               return 0;
+       }
+       
+       // Initialise (and register)
+       if( Module_int_Initialise( info, ArgString ) )
+       {
+               Binary_Unload(base);
+               return 0;
+       }
+       
+       return 1;
+}
+
+/**
+ * \fn int Module_int_ResolveDeps(tModule *Info)
+ * \brief Resolves the dependencies
+ * \todo Implement
+ * \note Currently does not resolve the dependencies, just checks them
+ */
+int Module_int_ResolveDeps(tModule *Info)
+{
+       const char      **names = Info->Dependencies;
+       
+       // Walk dependencies array
+       for( ; *names; names++ )
+       {
+               // Check if the module is loaded
+               if( !Module_IsLoaded(*names) ) {
+                       Log_Warning("Module", "Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+/**
+ * \fn int Module_IsLoaded(const char *Name)
+ * \brief Checks if a module is loaded
+ * \param Name Name of module to find
+ */
+int Module_IsLoaded(const char *Name)
+{
+       tModule *mod = gLoadedModules;
+       
+       // Scan loaded list
+       for( ; mod; mod = mod->Next )
+       {
+               // If found, return true
+               if(strcmp(mod->Name, Name) == 0)
+                       return 1;
+       }
+       // not found - return false
+       return 0;
+}
+
+/**
+ * \brief Load a module if needed
+ */
+int Module_EnsureLoaded(const char *Name)
+{
+       if( Module_IsLoaded(Name) )
+               return 0;
+
+       if( Modules_InitialiseBuiltin(Name) == 0 )
+               return 0;
+
+       // TODO: Load from a file?
+
+       return -1;
+}
diff --git a/KernelLand/Kernel/mutex.c b/KernelLand/Kernel/mutex.c
new file mode 100644 (file)
index 0000000..597242b
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * mutex.c
+ * - Mutexes
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <mutex.h>
+
+// === PROTOTYPES ===
+#if 0
+ int   Mutex_Acquire(tMutex *Mutex);
+void   Mutex_Release(tMutex *Mutex);
+ int   Mutex_IsLocked(tMutex *Mutex);
+#endif
+
+// === CODE ===
+//
+// Acquire mutex (see mutex.h for documentation)
+//
+int Mutex_Acquire(tMutex *Mutex)
+{
+       tThread *us = Proc_GetCurThread();
+       
+       // Get protector
+       SHORTLOCK( &Mutex->Protector );
+       
+//     Log("Mutex_Acquire: (%p)", Mutex);
+       
+       // Check if the lock is already held
+       if( Mutex->Owner ) {
+               SHORTLOCK( &glThreadListLock );
+               // - Remove from active list
+               us = Threads_RemActive();
+               us->Next = NULL;
+               // - Mark as sleeping
+               us->Status = THREAD_STAT_MUTEXSLEEP;
+               us->WaitPointer = Mutex;
+               
+               // - Add to waiting
+               if(Mutex->LastWaiting) {
+                       Mutex->LastWaiting->Next = us;
+                       Mutex->LastWaiting = us;
+               }
+               else {
+                       Mutex->Waiting = us;
+                       Mutex->LastWaiting = us;
+               }
+               
+               #if DEBUG_TRACE_STATE
+               Log("%p (%i %s) waiting on mutex %p",
+                       us, us->TID, us->ThreadName, Mutex);
+               #endif
+               
+               #if 0
+               {
+                        int    i = 0;
+                       tThread *t;
+                       for( t = Mutex->Waiting; t; t = t->Next, i++ )
+                               Log("[%i] (tMutex)%p->Waiting[%i] = %p (%i %s)", us->TID, Mutex, i,
+                                       t, t->TID, t->ThreadName);
+               }
+               #endif
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Mutex->Protector );
+               while(us->Status == THREAD_STAT_MUTEXSLEEP)     Threads_Yield();
+               // We're only woken when we get the lock
+               us->WaitPointer = NULL;
+       }
+       // Ooh, let's take it!
+       else {
+               Mutex->Owner = us;
+               SHORTREL( &Mutex->Protector );
+       }
+       
+       #if 0
+       extern tMutex   glPhysAlloc;
+       if( Mutex != &glPhysAlloc )
+               LogF("Mutex %p taken by %i %p\n", Mutex, us->TID, __builtin_return_address(0));
+       #endif
+       
+       return 0;
+}
+
+// Release a mutex
+void Mutex_Release(tMutex *Mutex)
+{
+       SHORTLOCK( &Mutex->Protector );
+       //Log("Mutex_Release: (%p)", Mutex);
+       if( Mutex->Waiting ) {
+               Mutex->Owner = Mutex->Waiting;  // Set owner
+               Mutex->Waiting = Mutex->Waiting->Next;  // Next!
+               // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
+               if( Mutex->LastWaiting == Mutex->Owner )
+                       Mutex->LastWaiting = NULL;
+               
+               // Wake new owner
+               if( Mutex->Owner->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(Mutex->Owner);
+       }
+       else {
+               Mutex->Owner = NULL;
+       }
+       SHORTREL( &Mutex->Protector );
+       
+       #if 0
+       extern tMutex   glPhysAlloc;
+       if( Mutex != &glPhysAlloc )
+               LogF("Mutex %p released by %i %p\n", Mutex, Threads_GetTID(), __builtin_return_address(0));
+       #endif
+}
+
+// Check if a mutex is locked
+int Mutex_IsLocked(tMutex *Mutex)
+{
+       return Mutex->Owner != NULL;
+}
+
+// === EXPORTS ===
+EXPORT(Mutex_Acquire);
+EXPORT(Mutex_Release);
+EXPORT(Mutex_IsLocked);
diff --git a/KernelLand/Kernel/semaphore.c b/KernelLand/Kernel/semaphore.c
new file mode 100644 (file)
index 0000000..d4583e7
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * semaphore.c
+ * - Semaphores
+ */
+#include <acess.h>
+#include <semaphore.h>
+#include <threads_int.h>
+
+#define SEMAPHORE_DEBUG        0       // Debug semaphores
+
+// === CODE ===
+//
+// Initialise a semaphore
+//
+void Semaphore_Init(tSemaphore *Sem, int Value, int MaxValue, const char *Module, const char *Name)
+{
+       memset(Sem, 0, sizeof(tSemaphore));
+       Sem->Value = Value;
+       Sem->ModName = Module;
+       Sem->Name = Name;
+       Sem->MaxValue = MaxValue;
+}
+//
+// Wait for items to be avaliable
+//
+int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
+{
+       tThread *us;
+        int    taken;
+       if( MaxToTake < 0 ) {
+               Log_Warning("Threads", "Semaphore_Wait: User bug - MaxToTake(%i) < 0, Sem=%p(%s)",
+                       MaxToTake, Sem, Sem->Name);
+       }
+       
+       SHORTLOCK( &Sem->Protector );
+       
+       // Check if there's already items avaliable
+       if( Sem->Value > 0 )
+       {
+               // Take what we need
+               if( MaxToTake && Sem->Value > MaxToTake )
+                       taken = MaxToTake;
+               else
+                       taken = Sem->Value;
+               Sem->Value -= taken;
+       }
+       else
+       {
+               SHORTLOCK( &glThreadListLock );
+               
+               // - Remove from active list
+               us = Threads_RemActive();
+               us->Next = NULL;
+               // - Mark as sleeping
+               us->Status = THREAD_STAT_SEMAPHORESLEEP;
+               us->WaitPointer = Sem;
+               us->RetStatus = MaxToTake;      // Use RetStatus as a temp variable
+               
+               // - Add to waiting
+               if(Sem->LastWaiting) {
+                       Sem->LastWaiting->Next = us;
+                       Sem->LastWaiting = us;
+               }
+               else {
+                       Sem->Waiting = us;
+                       Sem->LastWaiting = us;
+               }
+               
+               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+               Log("%p (%i %s) waiting on semaphore %p %s:%s",
+                       us, us->TID, us->ThreadName,
+                       Sem, Sem->ModName, Sem->Name);
+               #endif
+               
+               SHORTREL( &Sem->Protector );    // Release first to make sure it is released
+               SHORTREL( &glThreadListLock );
+               while( us->Status == THREAD_STAT_SEMAPHORESLEEP )
+               {
+                       Threads_Yield();
+                       if(us->Status == THREAD_STAT_SEMAPHORESLEEP)
+                               Log_Warning("Threads", "Semaphore %p %s:%s re-schedulued while asleep",
+                                       Sem, Sem->ModName, Sem->Name);
+               }
+               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+               Log("Semaphore %p %s:%s woken", Sem, Sem->ModName, Sem->Name);
+               #endif
+               // We're only woken when there's something avaliable (or a signal arrives)
+               us->WaitPointer = NULL;
+               
+               taken = us->RetStatus;
+               
+               // Get the lock again
+               SHORTLOCK( &Sem->Protector );
+       }
+       
+       // While there is space, and there are thread waiting
+       // wake the first thread and give it what it wants (or what's left)
+       while( (Sem->MaxValue == 0 || Sem->Value < Sem->MaxValue) && Sem->Signaling )
+       {
+                int    given;
+               tThread *toWake = Sem->Signaling;
+               
+               Sem->Signaling = Sem->Signaling->Next;
+               // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
+               if( Sem->Signaling == NULL )
+                       Sem->LastSignaling = NULL;
+               
+               // Figure out how much to give
+               if( toWake->RetStatus && Sem->Value + toWake->RetStatus < Sem->MaxValue )
+                       given = toWake->RetStatus;
+               else
+                       given = Sem->MaxValue - Sem->Value;
+               Sem->Value -= given;
+               
+               
+               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+               Log("%p (%i %s) woken by wait on %p %s:%s",
+                       toWake, toWake->TID, toWake->ThreadName,
+                       Sem, Sem->ModName, Sem->Name);
+               #endif
+               
+               // Save the number we gave to the thread's status
+               toWake->RetStatus = given;
+               
+               // Wake the sleeper
+               SHORTLOCK( &glThreadListLock );
+               if( toWake->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(toWake);
+               SHORTREL( &glThreadListLock );
+       }
+       SHORTREL( &Sem->Protector );
+       
+       #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+       Log("Semaphore %p %s:%s took %i by wait",
+               Sem, Sem->ModName, Sem->Name, taken);
+       #endif
+
+       return taken;
+}
+
+//
+// Add items to a semaphore
+//
+int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
+{
+        int    given;
+        int    added;
+       
+       if( AmmountToAdd < 0 ) {
+               Log_Warning("Threads", "Semaphore_Signal: User bug - AmmountToAdd(%i) < 0, Sem=%p(%s)",
+                       AmmountToAdd, Sem, Sem->Name);
+       }
+       SHORTLOCK( &Sem->Protector );
+       
+       // Check if we have to block
+       if( Sem->MaxValue && Sem->Value == Sem->MaxValue )
+       {
+               tThread *us;
+               #if 0
+               Log_Debug("Threads", "Semaphore_Signal: IDLE Sem = %s:%s", Sem->ModName, Sem->Name);
+               Log_Debug("Threads", "Semaphore_Signal: Sem->Value(%i) == Sem->MaxValue(%i)", Sem->Value, Sem->MaxValue);
+               #endif
+               
+               SHORTLOCK( &glThreadListLock );
+               // - Remove from active list
+               us = Threads_RemActive();
+               us->Next = NULL;
+               // - Mark as sleeping
+               us->Status = THREAD_STAT_SEMAPHORESLEEP;
+               us->WaitPointer = Sem;
+               us->RetStatus = AmmountToAdd;   // Use RetStatus as a temp variable
+               
+               // - Add to waiting
+               if(Sem->LastSignaling) {
+                       Sem->LastSignaling->Next = us;
+                       Sem->LastSignaling = us;
+               }
+               else {
+                       Sem->Signaling = us;
+                       Sem->LastSignaling = us;
+               }
+               
+               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+               Log("%p (%i %s) signaling semaphore %p %s:%s",
+                       us, us->TID, us->ThreadName,
+                       Sem, Sem->ModName, Sem->Name);
+               #endif
+               
+               SHORTREL( &glThreadListLock );  
+               SHORTREL( &Sem->Protector );
+               while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield();
+               // We're only woken when there's something avaliable
+               us->WaitPointer = NULL;
+               
+               added = us->RetStatus;
+               
+               // Get the lock again
+               SHORTLOCK( &Sem->Protector );
+       }
+       // Non blocking
+       else
+       {
+               // Figure out how much we need to take off
+               if( Sem->MaxValue && Sem->Value + AmmountToAdd > Sem->MaxValue)
+                       added = Sem->MaxValue - Sem->Value;
+               else
+                       added = AmmountToAdd;
+               Sem->Value += added;
+       }
+       
+       // While there are items avaliable, and there are thread waiting
+       // wake the first thread and give it what it wants (or what's left)
+       while( Sem->Value && Sem->Waiting )
+       {
+               tThread *toWake = Sem->Waiting;
+               
+               // Remove thread from list (double ended, so clear LastWaiting if needed)
+               Sem->Waiting = Sem->Waiting->Next;
+               if( Sem->Waiting == NULL )
+                       Sem->LastWaiting = NULL;
+               
+               // Figure out how much to give to woken thread
+               // - Requested count is stored in ->RetStatus
+               if( toWake->RetStatus && Sem->Value > toWake->RetStatus )
+                       given = toWake->RetStatus;
+               else
+                       given = Sem->Value;
+               Sem->Value -= given;
+               
+               // Save the number we gave to the thread's status
+               toWake->RetStatus = given;
+               
+               if(toWake->bInstrTrace)
+                       Log("%s(%i) given %i from %p", toWake->ThreadName, toWake->TID, given, Sem);
+               #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+               Log("%p (%i %s) woken by signal on %p %s:%s",
+                       toWake, toWake->TID, toWake->ThreadName,
+                       Sem, Sem->ModName, Sem->Name);
+               #endif
+               
+               // Wake the sleeper
+               if( toWake->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(toWake);
+               else
+                       Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName);
+       }
+       SHORTREL( &Sem->Protector );
+       
+       return added;
+}
+
+//
+// Get the current value of a semaphore
+//
+int Semaphore_GetValue(tSemaphore *Sem)
+{
+       return Sem->Value;
+}
+
+// === EXPORTS ===
+EXPORT(Semaphore_Init);
+EXPORT(Semaphore_Wait);
+EXPORT(Semaphore_Signal);
diff --git a/KernelLand/Kernel/syscalls.c b/KernelLand/Kernel/syscalls.c
new file mode 100644 (file)
index 0000000..5580187
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * AcessOS Microkernel Version
+ * syscalls.c
+ */
+#define DEBUG  0
+
+#include <acess.h>
+#include <syscalls.h>
+#include <proc.h>
+#include <hal_proc.h>
+#include <errno.h>
+#include <threads.h>
+#include <events.h>
+
+#define CHECK_NUM_NULLOK(v,size)       \
+       if((v)&&!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
+#define CHECK_STR_NULLOK(v)    \
+       if((v)&&!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
+#define CHECK_NUM_NONULL(v,size)       \
+       if(!(v)||!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
+#define CHECK_STR_NONULL(v)    \
+       if(!(v)||!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
+#define CHECK_STR_ARRAY(arr)   do {\
+        int    i;\
+       char    **tmp = (char**)arr; \
+       CHECK_NUM_NONULL( tmp, sizeof(char**) ); \
+       for(i=0;tmp[i];i++) { \
+               CHECK_STR_NONULL( tmp[i] ); \
+               CHECK_NUM_NONULL( &tmp[i+1], sizeof(char*) ); \
+       }\
+       if(tmp[i]) break;\
+} while(0)
+
+// === IMPORTS ===
+extern Uint    Binary_Load(const char *file, Uint *entryPoint);
+
+// === PROTOTYPES ===
+void   SyscallHandler(tSyscallRegs *Regs);
+ int   Syscall_ValidString(const char *Addr);
+ int   Syscall_Valid(int Size, const void *Addr);
+
+// === CODE ===
+// TODO: Do sanity checking on arguments, ATM the user can really fuck with the kernel
+void SyscallHandler(tSyscallRegs *Regs)
+{
+       Uint64  ret = 0;
+       Uint    err = -EOK;
+        int    callNum = Regs->Num;
+       
+       #if DEBUG < 2
+       if(callNum != SYS_READ && callNum != SYS_WRITE) {
+       #endif
+       ENTER("iThread iNum", Threads_GetTID(), callNum);
+       if(callNum < NUM_SYSCALLS)
+               LOG("Syscall %s", cSYSCALL_NAMES[callNum]);
+       LOG("Arg1: 0x%x, Arg2: 0x%x, Arg3: 0x%x, Arg4: 0x%x", Regs->Arg1, Regs->Arg2, Regs->Arg3, Regs->Arg4);
+       #if DEBUG < 2
+       }
+       #endif
+       
+       switch(Regs->Num)
+       {
+       // -- Exit the current thread
+       case SYS_EXIT:  Threads_Exit(0, Regs->Arg1);    break;
+       
+       // -- Put the current thread to sleep
+       case SYS_SLEEP: Threads_Sleep();        break;
+       
+       // -- Yield current timeslice
+       case SYS_YIELD: Threads_Yield();        break;
+       
+       // -- Set Error Handler
+       case SYS_SETFAULTHANDLER:
+               Threads_SetFaultHandler(Regs->Arg1);
+               break;
+       
+       // -- Clone the current thread
+       case SYS_CLONE:
+               // Call clone system call
+               ret = Proc_Clone(Regs->Arg1);
+               break;
+       
+       // -- Send a signal
+       case SYS_KILL:
+               err = -ENOSYS;
+               ret = -1;
+               break;
+
+       // -- Wait fr an event  
+       case SYS_WAITEVENT:
+               // Message mask
+               ret = Threads_WaitEvents(Regs->Arg1);
+               break;
+
+       // -- Wait for a thread
+       case SYS_WAITTID:
+               // Sanity Check (Status can be NULL)
+               CHECK_NUM_NULLOK( (int*)Regs->Arg2, sizeof(int) );
+               // TID, *Status
+               ret = Threads_WaitTID(Regs->Arg1, (int*)Regs->Arg2);
+               break;
+       
+       // -- Get the physical address of a page
+       case SYS_GETPHYS:
+               ret = MM_GetPhysAddr(Regs->Arg1);
+               break;
+       
+       // -- Map an address
+       case SYS_MAP:   MM_Map(Regs->Arg1, Regs->Arg2); break;
+       
+       // -- Allocate an address
+       case SYS_ALLOCATE:      ret = MM_Allocate(Regs->Arg1);  break;
+       
+       // -- Unmap an address
+       case SYS_UNMAP:         MM_Deallocate(Regs->Arg1);      break;
+       
+       // -- Get Thread/Process IDs
+       case SYS_GETTID:        ret = Threads_GetTID(); break;
+       case SYS_GETPID:        ret = Threads_GetPID(); break;
+       
+       // -- Get User/Group IDs
+       case SYS_GETUID:        ret = Threads_GetUID(); break;
+       case SYS_GETGID:        ret = Threads_GetGID(); break;
+       
+       // -- Set User/Group IDs
+       case SYS_SETUID:        ret = Threads_SetUID(Regs->Arg1);       break;
+       case SYS_SETGID:        ret = Threads_SetGID(Regs->Arg1);       break;
+       
+       // -- Send Message
+       case SYS_SENDMSG:
+               CHECK_NUM_NONULL( (void*)Regs->Arg3, Regs->Arg2 );
+               // Destination, Size, *Data
+               ret = Proc_SendMessage(Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
+               break;
+       // -- Check for messages
+       case SYS_GETMSG:
+               CHECK_NUM_NULLOK( (Uint*)Regs->Arg1, sizeof(Uint) );
+               // NOTE: Can't do range checking as we don't know the size
+               // - Should be done by Proc_GetMessage
+               if( Regs->Arg2 && Regs->Arg2 != -1 && !MM_IsUser(Regs->Arg2) ) {
+                       err = -EINVAL;  ret = -1;       break;
+               }
+               // *Source, *Data
+               ret = Proc_GetMessage((Uint*)Regs->Arg1, (void*)Regs->Arg2);
+               break;
+       
+       // -- Get the current timestamp
+       case SYS_GETTIME:
+               ret = now();
+               break;
+       
+       // -- Set the thread's name
+       case SYS_SETNAME:
+               CHECK_STR_NONULL( (char*) Regs->Arg1);
+               Threads_SetName( (char*)Regs->Arg1 );
+               break;
+       
+       // ---
+       // Binary Control
+       // ---
+       // -- Create a new process
+       case SYS_SPAWN:
+               CHECK_STR_NONULL((const char*)Regs->Arg1);
+               CHECK_STR_ARRAY((const char**)Regs->Arg2);
+               CHECK_STR_ARRAY((const char**)Regs->Arg3);
+               CHECK_NUM_NONULL((void*)Regs->Arg5, Regs->Arg4*sizeof(int));
+               ret = Proc_SysSpawn(
+                       (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
+                       Regs->Arg4, (int*)Regs->Arg5
+                       );
+               break;
+       // -- Replace the current process with another
+       case SYS_EXECVE:
+               CHECK_STR_NONULL((char*)Regs->Arg1);
+               CHECK_STR_ARRAY( (char**)Regs->Arg2 );
+               if( Regs->Arg3 )
+                       CHECK_STR_ARRAY( (char**)Regs->Arg3 );
+               LEAVE('s', "Assuming 0");
+               // Path, **Argv, **Envp, DataSize (=0 to tell it to create a copy)
+               ret = Proc_Execve(
+                       (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
+                       0
+                       );
+               break;
+       // -- Load a binary into the current process
+       case SYS_LOADBIN:
+               CHECK_STR_NONULL( (char*)Regs->Arg1 );
+               CHECK_NUM_NONULL( (Uint*)Regs->Arg2, sizeof(Uint) );
+               // Path, *Entrypoint
+               ret = Binary_Load((char*)Regs->Arg1, (Uint*)Regs->Arg2);
+               break;
+       
+       // ---
+       // Virtual Filesystem
+       // ---
+       case SYS_OPEN:
+               CHECK_STR_NONULL( (char*)Regs->Arg1 );
+               LOG("VFS_Open(\"%s\", 0x%x)", (char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
+               ret = VFS_Open((char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
+               break;
+       
+       case SYS_CLOSE:
+               LOG("VFS_Close(%i)", Regs->Arg1);
+               VFS_Close( Regs->Arg1 );
+               break;
+       
+       case SYS_SEEK:
+               #if BITS == 64
+               ret = VFS_Seek( Regs->Arg1, Regs->Arg2, Regs->Arg3 );
+               #else
+               ret = VFS_Seek( Regs->Arg1, Regs->Arg2|(((Uint64)Regs->Arg3)<<32), Regs->Arg4 );
+               #endif
+               break;
+               
+       case SYS_TELL:
+               ret = VFS_Tell( Regs->Arg1 );
+               break;
+       
+       case SYS_WRITE:
+               CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 );
+               ret = VFS_Write( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 );
+               break;
+       
+       case SYS_READ:
+               CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 );
+               ret = VFS_Read( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 );
+               break;
+       
+       case SYS_FINFO:
+               CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tFInfo) + Regs->Arg3*sizeof(tVFS_ACL) );
+               // FP, Dest, MaxACLs
+               ret = VFS_FInfo( Regs->Arg1, (void*)Regs->Arg2, Regs->Arg3 );
+               break;
+       
+       // Get ACL Value
+       case SYS_GETACL:
+               CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tVFS_ACL) );
+               ret = VFS_GetACL( Regs->Arg1, (void*)Regs->Arg2 );
+               break;
+       
+       // Read Directory
+       case SYS_READDIR:
+               // TODO: What if the filename is longer?
+               // Maybe force it to be a 256 byte buffer
+               CHECK_NUM_NONULL( (void*)Regs->Arg2, 256 );
+               ret = VFS_ReadDir( Regs->Arg1, (void*)Regs->Arg2 );
+               break;
+       
+       // Open a file that is a entry in an open directory
+       case SYS_OPENCHILD:
+               CHECK_STR_NONULL( (char*)Regs->Arg2 );
+               ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3 | VFS_OPENFLAG_USER);
+               break;
+       
+       // Change Directory
+       case SYS_CHDIR:
+               CHECK_STR_NONULL( (const char*)Regs->Arg1 );
+               ret = VFS_ChDir( (const char*)Regs->Arg1 );
+               break;
+       
+       // IO Control
+       case SYS_IOCTL:
+               // All sanity checking should be done by the driver
+               if( Regs->Arg3 && !MM_IsUser(Regs->Arg3) ) {
+                       err = -EINVAL;  ret = -1;       break;
+               }
+               ret = VFS_IOCtl( Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3 );
+               break;
+       
+       // Mount a filesystem
+       case SYS_MOUNT:
+               // Only root can mount filesystems
+               if(Threads_GetUID() != 0) {
+                       err = -EACCES;
+                       ret = -1;
+                       break;
+               }
+               // Sanity check the paths
+               if(!Syscall_ValidString((char*)Regs->Arg1)
+               || !Syscall_ValidString((char*)Regs->Arg2)
+               || !Syscall_ValidString((char*)Regs->Arg3)
+               || !Syscall_ValidString((char*)Regs->Arg4) ) {
+                       err = -EINVAL;
+                       ret = -1;
+                       break;
+               }
+               ret = VFS_Mount(
+                       (char*)Regs->Arg1,      // Device
+                       (char*)Regs->Arg2,      // Mount point
+                       (char*)Regs->Arg3,      // Filesystem
+                       (char*)Regs->Arg4       // Options
+                       );
+               break;
+               
+       // Wait on a set of handles
+       case SYS_SELECT:
+               // Sanity checks
+               if( (Regs->Arg2 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg2))
+                || (Regs->Arg3 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg3))
+                || (Regs->Arg4 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg4))
+                || (Regs->Arg5 && !Syscall_Valid(sizeof(tTime), (void*)Regs->Arg5)) )
+               {
+                       err = -EINVAL;
+                       ret = -1;
+                       break;
+               }
+               // Perform the call
+               ret = VFS_Select(
+                       Regs->Arg1,     // Max handle
+                       (fd_set *)Regs->Arg2,   // Read
+                       (fd_set *)Regs->Arg3,   // Write
+                       (fd_set *)Regs->Arg4,   // Errors
+                       (tTime *)Regs->Arg5,    // Timeout
+                       (Uint32)Regs->Arg6,     // Extra wakeup events
+                       0       // User handles
+                       );
+               break;
+       
+       // -- Debug
+       //#if DEBUG_BUILD
+       case SYS_DEBUG:
+               CHECK_STR_NONULL( (char*)Regs->Arg1 );
+               LogF("Log: %08lli [%i] ", now(), Threads_GetTID());
+               LogF((const char*)Regs->Arg1,
+                       Regs->Arg2, Regs->Arg3, Regs->Arg4, Regs->Arg5, Regs->Arg6);
+               LogF("\r\n");
+               break;
+       //#endif
+       
+       // -- Default (Return Error)
+       default:
+               Log_Warning("Syscalls", "Unknown System Call %i", Regs->Num);
+               if(Regs->Num < NUM_SYSCALLS)
+                       Log_Warning("Syscall", " named '%s'", cSYSCALL_NAMES[Regs->Num]);
+               err = -ENOSYS;
+               ret = -1;
+               break;
+       }
+
+       if(err == 0)    err = errno;
+       
+       if(err != 0) {
+               LOG("ID: %i, Return errno = %i", Regs->Num, err);
+       }
+       
+       #if BITS < 64
+       Regs->Return = ret&0xFFFFFFFF;
+       Regs->RetHi = ret >> 32;
+       #else
+       Regs->Return = ret;
+       #endif
+       Regs->Error = err;
+       #if DEBUG
+       # if DEBUG < 2
+       if( callNum != SYS_READ && callNum != SYS_WRITE ) {
+       # endif
+       LOG("err = %i", err);
+       if( callNum == SYS_EXECVE )
+               LOG("Actual %i", ret);
+       else
+               LEAVE('x', ret);
+       # if DEBUG < 2
+       }
+       # endif
+       #endif
+}
+
+/**
+ * \fn int Syscall_ValidString(const char *Addr)
+ * \brief Checks if a memory address contains a valid string
+ */
+int Syscall_ValidString(const char *Addr)
+{
+       // Check if the memory is user memory
+       if(!MM_IsUser( (tVAddr) Addr))  return 0;
+       
+       return CheckString( Addr );
+}
+
+/**
+ * \fn int Syscall_Valid(int Size, const void *Addr)
+ * \brief Checks if a memory address is valid
+ */
+int Syscall_Valid(int Size, const void *Addr)
+{
+       if(!MM_IsUser( (tVAddr)Addr ))  return 0;
+       
+       return CheckMem( Addr, Size );
+}
diff --git a/KernelLand/Kernel/syscalls.lst b/KernelLand/Kernel/syscalls.lst
new file mode 100644 (file)
index 0000000..283caf9
--- /dev/null
@@ -0,0 +1,64 @@
+
+0
+SYS_EXIT       Kill this thread
+SYS_CLONE      Create a new thread
+SYS_KILL       Send a signal
+SYS_SETFAULTHANDLER    Set signal Handler
+SYS_YIELD      Yield remainder of timestamp
+SYS_SLEEP      Sleep until messaged or signaled
+SYS_WAITEVENT  Wait for an event
+SYS_WAITTID    Wait for a thread to do something
+
+SYS_SETNAME    Sets the name of the current thread
+SYS_GETNAME    Gets the name of a thread
+SYS_GETTID     Get current thread ID
+SYS_GETPID     Get current thread group ID
+SYS_SETPRI     Set process priority
+
+SYS_SENDMSG    Send an IPC message
+SYS_GETMSG     Recieve an IPC message
+
+SYS_GETTIME    Get the current timestamp
+
+SYS_SPAWN      Spawn a new process
+SYS_EXECVE     Replace the current process
+SYS_LOADBIN    Load a binary into the current address space
+SYS_UNLOADBIN  Unload a loaded binary
+SYS_LOADMOD    Load a module into the kernel
+
+32
+SYS_GETPHYS    Get the physical address of a page
+SYS_MAP                Map a physical address
+SYS_ALLOCATE   Allocate a page
+SYS_UNMAP      Unmap a page
+SYS_PREALLOC   Preallocate a page
+SYS_SETFLAGS   Set a page's flags
+SYS_SHAREWITH  Share a page with another thread
+
+SYS_GETUID     Get current User ID
+SYS_GETGID     Get current Group ID
+SYS_SETUID     Set current user ID
+SYS_SETGID     Set current Group ID
+
+64
+SYS_OPEN       Open a file
+SYS_REOPEN     Close a file and reuse its handle
+SYS_CLOSE      Close a file
+SYS_READ       Read from an open file
+SYS_WRITE      Write to an open file
+SYS_IOCTL      Perform an IOCtl Call
+SYS_SEEK       Seek to a new position in the file
+SYS_READDIR    Read from an open directory
+SYS_OPENCHILD  Open a child entry in a directory
+SYS_GETACL     Get an ACL Value
+SYS_SETACL     Set an ACL Value
+SYS_FINFO      Get file information
+SYS_MKDIR      Create a new directory
+SYS_LINK       Create a new link to a file
+SYS_SYMLINK    Create a symbolic link
+SYS_UNLINK     Delete a file
+SYS_TELL       Return the current file position
+SYS_CHDIR      Change current directory
+SYS_GETCWD     Get current directory
+SYS_MOUNT      Mount a filesystem
+SYS_SELECT     Wait for file handles
diff --git a/KernelLand/Kernel/system.c b/KernelLand/Kernel/system.c
new file mode 100644 (file)
index 0000000..8fc2a1c
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Acess 2 Kernel
+ * - By John Hodge (thePowersGang)
+ * system.c
+ * - Architecture Independent System Init
+ */
+#define DEBUG  0
+#include <acess.h>
+
+// === IMPORTS ===
+extern void    Arch_LoadBootModules(void);
+extern int     Modules_LoadBuiltins(void);
+extern void    Modules_SetBuiltinParams(char *Name, char *ArgString);
+extern void    Debug_SetKTerminal(const char *File);
+
+// === PROTOTYPES ===
+void   System_Init(char *Commandline);
+void   System_ParseCommandLine(char *ArgString);
+void   System_ExecuteCommandLine(void);
+void   System_ParseVFS(char *Arg);
+void   System_ParseModuleArgs(char *Arg);
+void   System_ParseSetting(char *Arg);
+
+// === GLOBALS ===
+const char     *gsInitBinary = "/Acess/SBin/init";
+char   *argv[32];
+ int   argc;
+
+// === CODE ===
+void System_Init(char *CommandLine)
+{
+       // Parse Kernel's Command Line
+       System_ParseCommandLine(CommandLine);
+       
+       // Initialise modules
+       Log_Log("Config", "Initialising builtin modules...");
+       Modules_LoadBuiltins();
+       Arch_LoadBootModules();
+       
+       System_ExecuteCommandLine();
+       
+       // - Execute the Config Script
+       Log_Log("Config", "Spawning init '%s'", gsInitBinary);
+       Proc_Spawn(gsInitBinary);
+       
+       // Set the debug to be echoed to the terminal
+       Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)");
+       Debug_SetKTerminal("/Devices/VTerm/7");
+}
+
+/**
+ * \fn void System_ParseCommandLine(char *ArgString)
+ * \brief Parses the kernel's command line and sets the environment
+ */
+void System_ParseCommandLine(char *ArgString)
+{
+        int    i;
+       char    *str;
+       
+       Log_Log("Config", "Kernel Invocation (%p) \"%s\"", ArgString, ArgString);
+       
+       // --- Get Arguments ---
+       str = ArgString;
+       for( argc = 0; argc < 32; argc++ )
+       {
+               // Eat Whitespace
+               while(*str == ' ')      str++;
+               // Check for the end of the string
+               if(*str == '\0') {      argc--; break;} 
+               argv[argc] = str;
+               if(*str == '"') {
+                       while(*str && !(*str == '"' && str[-1] != '\\'))
+                               str ++;
+               }
+               else {
+                       while(*str && *str != ' ')
+                               str++;
+               }
+               if(*str == '\0')        break;  // Check for EOS
+               *str = '\0';    // Cap off argument string
+               str ++; // and increment the string pointer
+       }
+       if(argc < 32)
+               argc ++;        // Count last argument
+       
+       // --- Parse Arguments (Pass 1) ---
+       for( i = 1; i < argc; i++ )
+       {
+               switch(argv[i][0])
+               {
+               // --- VFS ---
+               // Ignored on this pass
+               case '/':
+                       break;
+               
+               // --- Module Paramaters ---
+               // -VTerm:Width=640,Height=480,Scrollback=2
+               case '-':
+                       System_ParseModuleArgs( argv[i] );
+                       break;
+               // --- Config Options ---
+               // SCRIPT=/Acess/Conf/BootConf.cfg
+               default:
+                       System_ParseSetting( argv[i] );
+                       break;
+               }
+       }
+}
+
+void System_ExecuteCommandLine(void)
+{
+        int    i;
+       if(argc > 0)
+               LOG("Invocation '%s'", argv[0]);
+       for( i = 1; i < argc; i++ )
+       {
+               LOG("argv[%i] = '%s'", i, argv[i]);
+               switch(argv[i][0])
+               {
+               // --- VFS ---
+               // Mount    /System=ext2:/Devices/ATA/A1
+               // Symlink  /Acess=/System/Acess2
+               case '/':
+                       System_ParseVFS( argv[i] );
+                       break;
+               }
+       }
+}
+
+/**
+ * \fn void System_ParseVFS(char *Arg)
+ */
+void System_ParseVFS(char *Arg)
+{
+       char    *value;
+        int    fd;
+       
+       value = Arg;
+       // Search for the '=' token
+       while( *value && *value != '=' )
+               value++;
+       
+       // Check if the equals was found
+       if( *value == '\0' ) {
+               Log_Warning("Config", "Expected '=' in the string '%s'", Arg);
+               return ;
+       }
+       
+       // Edit string
+       *value = '\0';  value ++;
+       
+       // Check assignment type
+       // - Symbolic Link <link>=<destination>
+       if(value[0] == '/')
+       {
+               Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
+               VFS_Symlink(Arg, value);
+       }
+       // - Mount <mountpoint>=<fs>:<device>
+       else
+       {
+               char    *dev = value;
+               // Find colon
+               while(*dev && *dev != ':')      dev++;
+               if(*dev) {
+                       *dev = '\0';
+                       dev++;  // Eat ':'
+               }
+               // Create Mountpoint
+               if( (fd = VFS_Open(Arg, 0)) == -1 ) {
+                       Log_Log("Config", "Creating directory '%s'", Arg, value);
+                       VFS_MkDir( Arg );
+               } else {
+                       VFS_Close(fd);
+               }
+               // Mount
+               Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
+               VFS_Mount(dev, Arg, value, "");
+       }
+}
+
+/**
+ * \brief Parse a module argument string
+ * \param Arg  Argument string
+ */
+void System_ParseModuleArgs(char *Arg)
+{
+       char    *name, *args;
+        int    i;
+       
+       // Remove '-'   
+       name = Arg + 1;
+       
+       // Find the start of the args
+       i = strpos(name, ':');
+       if( i == -1 ) {
+               Log_Warning("Config", "Module spec with no arguments");
+               #if 1
+               return ;
+               #else
+               i = strlen(name);
+               args = name + i;
+               #endif
+       }
+       else {
+               name[i] = '\0';
+               args = name + i + 1;
+       }
+       
+       Log_Log("Config", "Setting boot parameters for '%s' to '%s'", name, args);
+       Modules_SetBuiltinParams(name, args);
+}
+
+/**
+ * \fn void System_ParseSetting(char *Arg)
+ */
+void System_ParseSetting(char *Arg)
+{
+       char    *value;
+       value = Arg;
+
+       // Search for the '=' token
+       while( *value && *value != '=' )
+               value++;
+       
+       // Check for boolean/flag (no '=')
+       if(*value == '\0')
+       {
+               //if(strcmp(Arg, "") == 0) {
+               //} else {
+                       Log_Warning("Config", "Kernel flag '%s' is not recognised", Arg);
+               //}
+       }
+       else
+       {
+               *value = '\0';  // Remove '='
+               value ++;       // and eat it's position
+               
+               if(strcmp(Arg, "INIT") == 0) {
+                       Log_Log("Config", "Init binary: '%s'", value);
+                       if(strlen(value) == 0)
+                               gsInitBinary = NULL;
+                       else
+                               gsInitBinary = value;
+               }
+               else {
+                       Log_Warning("Config", "Kernel config setting '%s' is not recognised", Arg);
+               }
+               
+       }
+}
+
diff --git a/KernelLand/Kernel/threads.c b/KernelLand/Kernel/threads.c
new file mode 100644 (file)
index 0000000..956eede
--- /dev/null
@@ -0,0 +1,1355 @@
+/*
+ * Acess2
+ * threads.c
+ * - Common Thread Control
+ */
+#include <acess.h>
+#include <threads.h>
+#include <threads_int.h>
+#include <errno.h>
+#include <hal_proc.h>
+#include <semaphore.h>
+#include <vfs_threads.h>       // VFS Handle maintainence
+
+// Configuration
+#define DEBUG_TRACE_TICKETS    0       // Trace ticket counts
+#define DEBUG_TRACE_STATE      0       // Trace state changes (sleep/wake)
+
+// --- Schedulers ---
+#define SCHED_UNDEF    0
+#define SCHED_LOTTERY  1       // Lottery scheduler
+#define SCHED_RR_SIM   2       // Single Queue Round Robin
+#define SCHED_RR_PRI   3       // Multi Queue Round Robin
+// Set scheduler type
+#define SCHEDULER_TYPE SCHED_RR_PRI
+
+// === CONSTANTS ===
+#define        DEFAULT_QUANTUM 5
+#define        DEFAULT_PRIORITY        5
+#define MIN_PRIORITY           10
+
+// === IMPORTS ===
+
+// === TYPE ===
+typedef struct
+{
+       tThread *Head;
+       tThread *Tail;
+} tThreadList;
+
+// === PROTOTYPES ===
+void   Threads_Init(void);
+#if 0
+void   Threads_Delete(tThread *Thread);
+ int   Threads_SetName(const char *NewName);
+#endif
+char   *Threads_GetName(tTID ID);
+#if 0
+void   Threads_SetPriority(tThread *Thread, int Pri);
+tThread        *Threads_CloneTCB(Uint *Err, Uint Flags);
+ int   Threads_WaitTID(int TID, int *status);
+tThread        *Threads_GetThread(Uint TID);
+#endif
+tThread        *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread);
+void   Threads_int_AddToList(tThreadList *List, tThread *Thread);
+#if 0
+void   Threads_Exit(int TID, int Status);
+void   Threads_Kill(tThread *Thread, int Status);
+void   Threads_Yield(void);
+void   Threads_Sleep(void);
+ int   Threads_Wake(tThread *Thread);
+void   Threads_AddActive(tThread *Thread);
+tThread        *Threads_RemActive(void);
+#endif
+void   Threads_ToggleTrace(int TID);
+void   Threads_Fault(int Num);
+void   Threads_SegFault(tVAddr Addr);
+#if 0
+ int   Threads_GetPID(void);
+ int   Threads_GetTID(void);
+tUID   Threads_GetUID(void);
+tGID   Threads_GetGID(void);
+ int   Threads_SetUID(Uint *Errno, tUID ID);
+ int   Threads_SetGID(Uint *Errno, tUID ID);
+#endif
+void   Threads_Dump(void);
+void   Threads_DumpActive(void);
+
+// === GLOBALS ===
+// -- Core Thread --
+struct sProcess        gProcessZero = {
+       };
+// Only used for the core kernel
+tThread        gThreadZero = {
+       .Status         = THREAD_STAT_ACTIVE,   // Status
+       .ThreadName     = (char*)"ThreadZero",  // Name
+       .Quantum        = DEFAULT_QUANTUM,      // Default Quantum
+       .Remaining      = DEFAULT_QUANTUM,      // Current Quantum
+       .Priority       = DEFAULT_PRIORITY      // Number of tickets
+       };
+// -- Processes --
+// --- Locks ---
+tShortSpinlock glThreadListLock;       ///\note NEVER use a heap function while locked
+// --- Current State ---
+volatile int   giNumActiveThreads = 0; // Number of threads on the active queue
+volatile Uint  giNextTID = 1;  // Next TID to allocate
+// --- Thread Lists ---
+tThread        *gAllThreads = NULL;            // All allocated threads
+tThreadList    gSleepingThreads;       // Sleeping Threads
+ int   giNumCPUs = 1;  // Number of CPUs
+BOOL     gaThreads_NoTaskSwitch[MAX_CPUS];     // Disables task switches for each core (Pseudo-IF)
+// --- Scheduler Types ---
+#if SCHEDULER_TYPE == SCHED_LOTTERY
+const int      caiTICKET_COUNTS[MIN_PRIORITY+1] = {100,81,64,49,36,25,16,9,4,1,0};
+volatile int   giFreeTickets = 0;      // Number of tickets held by non-scheduled threads
+tThreadList    gActiveThreads;         // Currently Running Threads
+#elif SCHEDULER_TYPE == SCHED_RR_SIM
+tThreadList    gActiveThreads;         // Currently Running Threads
+#elif SCHEDULER_TYPE == SCHED_RR_PRI
+tThreadList    gaActiveThreads[MIN_PRIORITY+1];        // Active threads for each priority level
+#else
+# error "Unkown scheduler type"
+#endif
+
+// === CODE ===
+/**
+ * \fn void Threads_Init(void)
+ * \brief Initialse the thread list
+ */
+void Threads_Init(void)
+{
+       ArchThreads_Init();
+       
+       Log_Debug("Threads", "Offsets of tThread");
+       Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority));
+       Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
+       
+       // Create Initial Task
+//     #if SCHEDULER_TYPE == SCHED_RR_PRI
+//     gaActiveThreads[gThreadZero.Priority].Head = &gThreadZero;
+//     gaActiveThreads[gThreadZero.Priority].Tail = &gThreadZero;
+//     #else
+//     gActiveThreads.Head = &gThreadZero;
+//     gActiveThreads.Tail = &gThreadZero;
+//     #endif
+       
+       gAllThreads = &gThreadZero;
+       giNumActiveThreads = 1;
+       gThreadZero.Process = &gProcessZero;
+               
+       Proc_Start();
+}
+
+void Threads_Delete(tThread *Thread)
+{
+       // Set to dead
+       Thread->Status = THREAD_STAT_BURIED;
+
+       // Clear out process state
+       Proc_ClearThread(Thread);                       
+
+       Thread->Process->nThreads --;
+       if( Thread->Process->nThreads == 0 )
+       {
+               tProcess        *proc = Thread->Process;
+               // VFS Cleanup
+               VFS_CloseAllUserHandles();
+               // Architecture cleanup
+               Proc_ClearProcess( proc );
+               // VFS Configuration strings
+               if( proc->CurrentWorkingDir)
+                       free( proc->CurrentWorkingDir );
+               if( proc->RootDir )
+                       free( proc->RootDir );
+               // Process descriptor
+               free( proc );
+       }
+       
+       // Free name
+       if( IsHeap(Thread->ThreadName) )
+               free(Thread->ThreadName);
+       
+       // Remove from global list
+       // TODO: Lock this too
+       if( Thread == gAllThreads )
+               gAllThreads = Thread->GlobalNext;
+       else
+               Thread->GlobalPrev->GlobalNext = Thread->GlobalNext;
+       
+       free(Thread);
+}
+
+/**
+ * \fn void Threads_SetName(const char *NewName)
+ * \brief Sets the current thread's name
+ * \param NewName      New name for the thread
+ * \return Boolean Failure
+ */
+int Threads_SetName(const char *NewName)
+{
+       tThread *cur = Proc_GetCurThread();
+       char    *oldname = cur->ThreadName;
+       
+       // NOTE: There is a possibility of non-thread safety here
+       // A thread could read the current name pointer before it is zeroed
+       
+       cur->ThreadName = NULL;
+       
+       if( IsHeap(oldname) )   free( oldname );        
+       cur->ThreadName = strdup(NewName);
+
+       Log_Debug("Threads", "Thread renamed to '%s'", NewName);        
+
+       return 0;
+}
+
+/**
+ * \fn char *Threads_GetName(int ID)
+ * \brief Gets a thread's name
+ * \param ID   Thread ID (-1 indicates current thread)
+ * \return Pointer to name
+ * \retval NULL        Failure
+ */
+char *Threads_GetName(tTID ID)
+{
+       if(ID == -1) {
+               return Proc_GetCurThread()->ThreadName;
+       }
+       return Threads_GetThread(ID)->ThreadName;
+}
+
+/**
+ * \fn void Threads_SetPriority(tThread *Thread, int Pri)
+ * \brief Sets the priority of a task
+ * \param Thread       Thread to update ticket count (NULL means current thread)
+ * \param Pri  New priority
+ */
+void Threads_SetPriority(tThread *Thread, int Pri)
+{
+       // Get current thread
+       if(Thread == NULL)      Thread = Proc_GetCurThread();
+       // Bounds checking
+       // - If < 0, set to lowest priority
+       // - Minumum priority is actualy a high number, 0 is highest
+       if(Pri < 0)     Pri = MIN_PRIORITY;
+       if(Pri > MIN_PRIORITY)  Pri = MIN_PRIORITY;
+       
+       // Do we actually have to do anything?
+       if( Pri == Thread->Priority )   return;
+       
+       #if SCHEDULER_TYPE == SCHED_RR_PRI
+       if( Thread != Proc_GetCurThread() )
+       {
+               SHORTLOCK( &glThreadListLock );
+               // Remove from old priority
+               Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
+               // And add to new
+               Threads_int_AddToList( &gaActiveThreads[Pri], Thread );
+               Thread->Priority = Pri;
+               SHORTREL( &glThreadListLock );
+       }
+       else
+               Thread->Priority = Pri;
+       #else
+       // If this isn't the current thread, we need to lock
+       if( Thread != Proc_GetCurThread() )
+       {
+               SHORTLOCK( &glThreadListLock );
+               
+               #if SCHEDULER_TYPE == SCHED_LOTTERY
+               giFreeTickets -= caiTICKET_COUNTS[Thread->Priority] - caiTICKET_COUNTS[Pri];
+               # if DEBUG_TRACE_TICKETS
+               Log("Threads_SetTickets: new giFreeTickets = %i [-%i+%i]",
+                       giFreeTickets,
+                       caiTICKET_COUNTS[Thread->Priority], caiTICKET_COUNTS[Pri]);
+               # endif
+               #endif
+               Thread->Priority = Pri;
+               SHORTREL( &glThreadListLock );
+       }
+       else
+               Thread->Priority = Pri;
+       #endif
+       
+       #if DEBUG_TRACE_STATE
+       Log("Threads_SetPriority: %p(%i %s) pri set %i",
+               Thread, Thread->TID, Thread->ThreadName,
+               Pri);
+       #endif
+}
+
+/**
+ * \brief Clone the TCB of the current thread
+ * \param Flags        Flags for something... (What is this for?)
+ */
+tThread *Threads_CloneTCB(Uint Flags)
+{
+       tThread *cur, *new;
+       cur = Proc_GetCurThread();
+       
+       // Allocate and duplicate
+       new = malloc(sizeof(tThread));
+       if(new == NULL) { errno = -ENOMEM; return NULL; }
+       memcpy(new, cur, sizeof(tThread));
+       
+       new->CurCPU = -1;
+       new->Next = NULL;
+       memset( &new->IsLocked, 0, sizeof(new->IsLocked));
+       new->Status = THREAD_STAT_PREINIT;
+       new->RetStatus = 0;
+       
+       // Get Thread ID
+       new->TID = giNextTID++;
+       new->Parent = cur;
+       new->bInstrTrace = 0;
+       
+       // Clone Name
+       new->ThreadName = strdup(cur->ThreadName);
+       
+       // Set Thread Group ID (PID)
+       if(Flags & CLONE_VM) {
+               tProcess        *newproc, *oldproc;
+               oldproc = cur->Process;
+               new->Process = malloc( sizeof(struct sProcess) );
+               newproc = new->Process;
+               newproc->PID = new->TID;
+               newproc->UID = oldproc->UID;
+               newproc->GID = oldproc->GID;
+               newproc->MaxFD = oldproc->MaxFD;
+               if( oldproc->CurrentWorkingDir )
+                       newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir );
+               else
+                       newproc->CurrentWorkingDir = NULL;
+               if( oldproc->RootDir )
+                       newproc->RootDir = strdup( oldproc->RootDir );
+               else
+                       newproc->RootDir = NULL;
+               newproc->nThreads = 1;
+               // Reference all handles in the VFS
+               VFS_ReferenceUserHandles();
+       }
+       else {
+               new->Process->nThreads ++;
+       }
+       
+       // Messages are not inherited
+       new->Messages = NULL;
+       new->LastMessage = NULL;
+       
+       // Set State
+       new->Remaining = new->Quantum = cur->Quantum;
+       new->Priority = cur->Priority;
+       new->_errno = 0;
+       
+       // Set Signal Handlers
+       new->CurFaultNum = 0;
+       new->FaultHandler = cur->FaultHandler;
+       
+       // Maintain a global list of threads
+       SHORTLOCK( &glThreadListLock );
+       new->GlobalPrev = NULL; // Protect against bugs
+       new->GlobalNext = gAllThreads;
+       gAllThreads->GlobalPrev = new;
+       gAllThreads = new;
+       SHORTREL( &glThreadListLock );
+       
+       return new;
+}
+
+/**
+ * \brief Clone the TCB of the kernel thread
+ */
+tThread *Threads_CloneThreadZero(void)
+{
+       tThread *new;
+       
+       // Allocate and duplicate
+       new = malloc(sizeof(tThread));
+       if(new == NULL) {
+               return NULL;
+       }
+       memcpy(new, &gThreadZero, sizeof(tThread));
+
+       new->Process->nThreads ++;
+       
+       new->CurCPU = -1;
+       new->Next = NULL;
+       memset( &new->IsLocked, 0, sizeof(new->IsLocked));
+       new->Status = THREAD_STAT_PREINIT;
+       new->RetStatus = 0;
+       
+       // Get Thread ID
+       new->TID = giNextTID++;
+       new->Parent = 0;
+       
+       // Clone Name
+       new->ThreadName = NULL;
+       
+       // Messages are not inherited
+       new->Messages = NULL;
+       new->LastMessage = NULL;
+       
+       // Set State
+       new->Remaining = new->Quantum = DEFAULT_QUANTUM;
+       new->Priority = DEFAULT_PRIORITY;
+       new->bInstrTrace = 0;
+       
+       // Set Signal Handlers
+       new->CurFaultNum = 0;
+       new->FaultHandler = 0;
+       
+       // Maintain a global list of threads
+       SHORTLOCK( &glThreadListLock );
+       new->GlobalPrev = NULL; // Protect against bugs
+       new->GlobalNext = gAllThreads;
+       gAllThreads->GlobalPrev = new;
+       gAllThreads = new;
+       SHORTREL( &glThreadListLock );
+       
+       return new;
+}
+
+/**
+ * \brief Wait for a task to change state
+ * \param TID  Thread ID to wait on (-1: Any child thread, 0: Any Child/Sibling, <-1: -PID)
+ * \param Status       Thread return status
+ * \return TID of child that changed state
+ */
+tTID Threads_WaitTID(int TID, int *Status)
+{      
+       // Any Child
+       if(TID == -1) {
+               Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
+               return -1;
+       }
+       
+       // Any peer/child thread
+       if(TID == 0) {
+               Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
+               return -1;
+       }
+       
+       // TGID = abs(TID)
+       if(TID < -1) {
+               Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
+               return -1;
+       }
+       
+       // Specific Thread
+       if(TID > 0) {
+               tThread *t = Threads_GetThread(TID);
+               tTID    ret;
+               
+               // Wait for the thread to die!
+               // TODO: Handle child also being suspended if wanted
+               while(t->Status != THREAD_STAT_ZOMBIE) {
+                       Threads_Sleep();
+                       Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
+                               Threads_GetTID(), t->TID, t->Status);
+               }
+               
+               // Set return status
+               ret = t->TID;
+               switch(t->Status)
+               {
+               case THREAD_STAT_ZOMBIE:
+                       // Kill the thread
+                       t->Status = THREAD_STAT_DEAD;
+                       // TODO: Child return value?
+                       if(Status)      *Status = t->RetStatus;
+                       // add to delete queue
+                       Threads_Delete( t );
+                       break;
+               default:
+                       if(Status)      *Status = -1;
+                       break;
+               }
+               return ret;
+       }
+       
+       return -1;
+}
+
+/**
+ * \brief Gets a thread given its TID
+ * \param TID  Thread ID
+ * \return Thread pointer
+ */
+tThread *Threads_GetThread(Uint TID)
+{
+       tThread *thread;
+       
+       // Search global list
+       for(thread = gAllThreads;
+               thread;
+               thread = thread->GlobalNext)
+       {
+               if(thread->TID == TID)
+                       return thread;
+       }
+
+       Log("Unable to find TID %i on main list\n", TID);
+       
+       return NULL;
+}
+
+/**
+ * \brief Deletes an entry from a list
+ * \param List Pointer to the list head
+ * \param Thread       Thread to find
+ * \return \a Thread
+ */
+tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread)
+{
+       tThread *ret, *prev = NULL;
+       
+       for(ret = List->Head;
+               ret && ret != Thread;
+               prev = ret, ret = ret->Next
+               );
+       
+       // Is the thread on the list
+       if(!ret) {
+               //LogF("%p(%s) is not on list %p\n", Thread, Thread->ThreadName, List);
+               return NULL;
+       }
+       
+       if( !prev ) {
+               List->Head = Thread->Next;
+               //LogF("%p(%s) removed from head of %p\n", Thread, Thread->ThreadName, List);
+       }
+       else {
+               prev->Next = Thread->Next;
+               //LogF("%p(%s) removed from %p (prev=%p)\n", Thread, Thread->ThreadName, List, prev);
+       }
+       if( Thread->Next == NULL )
+               List->Tail = prev;
+       
+       return Thread;
+}
+
+void Threads_int_AddToList(tThreadList *List, tThread *Thread)
+{
+       if( List->Head )
+               List->Tail->Next = Thread;
+       else
+               List->Head = Thread;
+       List->Tail = Thread;
+       Thread->Next = NULL;
+}
+
+/**
+ * \brief Exit the current process (or another?)
+ * \param TID  Thread ID to kill
+ * \param Status       Exit status
+ */
+void Threads_Exit(int TID, int Status)
+{
+       if( TID == 0 )
+               Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
+       else
+               Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
+       
+       // Halt forever, just in case
+       for(;;) HALT();
+}
+
+/**
+ * \fn void Threads_Kill(tThread *Thread, int Status)
+ * \brief Kill a thread
+ * \param Thread       Thread to kill
+ * \param Status       Status code to return to the parent
+ */
+void Threads_Kill(tThread *Thread, int Status)
+{
+       tMsg    *msg;
+        int    isCurThread = Thread == Proc_GetCurThread();
+       
+       // TODO: Disown all children?
+       #if 1
+       {
+               tThread *child;
+               // TODO: I should keep a .Children list
+               for(child = gAllThreads;
+                       child;
+                       child = child->GlobalNext)
+               {
+                       if(child->Parent == Thread)
+                               child->Parent = &gThreadZero;
+               }
+       }
+       #endif
+       
+       ///\note Double lock is needed due to overlap of lock areas
+       
+       // Lock thread (stop us recieving messages)
+       SHORTLOCK( &Thread->IsLocked );
+       
+       // Clear Message Queue
+       while( Thread->Messages )
+       {
+               msg = Thread->Messages->Next;
+               free( Thread->Messages );
+               Thread->Messages = msg;
+       }
+       
+       // Lock thread list
+       SHORTLOCK( &glThreadListLock );
+       
+       switch(Thread->Status)
+       {
+       case THREAD_STAT_PREINIT:       // Only on main list
+               break;
+       
+       // Currently active thread
+       case THREAD_STAT_ACTIVE:
+               if( Thread != Proc_GetCurThread() )
+               {
+                       #if SCHEDULER_TYPE == SCHED_RR_PRI
+                       tThreadList     *list = &gaActiveThreads[Thread->Priority];
+                       #else
+                       tThreadList     *list = &gActiveThreads;
+                       #endif
+                       if( Threads_int_DelFromQueue( list, Thread ) )
+                       {
+                       }
+                       else
+                       {
+                               Log_Warning("Threads",
+                                       "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
+                                       Thread, Thread->TID, Thread->ThreadName
+                                       );
+                       }
+                       #if SCHEDULER_TYPE == SCHED_LOTTERY
+                       giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
+                       #endif
+               }
+               // Ensure that we are not rescheduled
+               Thread->Remaining = 0;  // Clear Remaining Quantum
+               Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
+                       
+               // Update bookkeeping
+               giNumActiveThreads --;
+               break;
+       // Kill it while it sleeps!
+       case THREAD_STAT_SLEEPING:
+               if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) )
+               {
+                       Log_Warning("Threads",
+                               "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list",
+                               Thread, Thread->TID, Thread->ThreadName
+                               );
+               }
+               break;
+       
+       // Brains!... You cannot kill something that is already dead
+       case THREAD_STAT_ZOMBIE:
+               Log_Warning("Threads", "Threads_Kill - Thread %p(%i,%s) is undead, you cannot kill it",
+                       Thread, Thread->TID, Thread->ThreadName);
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Thread->IsLocked );
+               return ;
+       
+       default:
+               Log_Warning("Threads", "Threads_Kill - BUG Un-checked status (%i)",
+                       Thread->Status);
+               break;
+       }
+       
+       // Save exit status
+       Thread->RetStatus = Status;
+
+       SHORTREL( &Thread->IsLocked );
+
+       Thread->Status = THREAD_STAT_ZOMBIE;
+       SHORTREL( &glThreadListLock );
+       // TODO: Send something like SIGCHLD
+       Threads_Wake( Thread->Parent );
+       
+       Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
+       
+       // And, reschedule
+       if(isCurThread)
+       {
+               for( ;; )
+                       Proc_Reschedule();
+       }
+}
+
+/**
+ * \brief Yield remainder of the current thread's timeslice
+ */
+void Threads_Yield(void)
+{
+//     Log("Threads_Yield: by %p", __builtin_return_address(0));
+       Proc_Reschedule();
+}
+
+/**
+ * \fn void Threads_Sleep(void)
+ * \brief Take the current process off the run queue
+ */
+void Threads_Sleep(void)
+{
+       tThread *cur = Proc_GetCurThread();
+       
+       // Acquire Spinlock
+       SHORTLOCK( &glThreadListLock );
+       
+       // Don't sleep if there is a message waiting
+       if( cur->Messages ) {
+               SHORTREL( &glThreadListLock );
+               return;
+       }
+       
+       // Remove us from running queue
+       Threads_RemActive();
+       // Mark thread as sleeping
+       cur->Status = THREAD_STAT_SLEEPING;
+       
+       // Add to Sleeping List (at the top)
+       Threads_int_AddToList( &gSleepingThreads, cur );
+       
+       #if DEBUG_TRACE_STATE
+       Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
+       #endif
+       
+       // Release Spinlock
+       SHORTREL( &glThreadListLock );
+
+       while(cur->Status != THREAD_STAT_ACTIVE) {
+               Proc_Reschedule();
+               if( cur->Status != THREAD_STAT_ACTIVE )
+                       Log("%i - Huh? why am I up? zzzz...", cur->TID);
+       }
+}
+
+
+/**
+ * \brief Wakes a sleeping/waiting thread up
+ * \param Thread       Thread to wake
+ * \return Boolean Failure (Returns ERRNO)
+ * \warning This should ONLY be called with task switches disabled
+ */
+int Threads_Wake(tThread *Thread)
+{
+       if(!Thread)
+               return -EINVAL;
+       
+       switch(Thread->Status)
+       {
+       case THREAD_STAT_ACTIVE:
+               Log("Threads_Wake - Waking awake thread (%i)", Thread->TID);
+               return -EALREADY;
+       
+       case THREAD_STAT_SLEEPING:
+               SHORTLOCK( &glThreadListLock );
+               // Remove from sleeping queue
+               Threads_int_DelFromQueue(&gSleepingThreads, Thread);
+               
+               SHORTREL( &glThreadListLock );
+               Threads_AddActive( Thread );
+               
+               #if DEBUG_TRACE_STATE
+               Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName);
+               #endif
+               return -EOK;
+       
+       case THREAD_STAT_SEMAPHORESLEEP: {
+               tSemaphore      *sem;
+               tThread *th, *prev=NULL;
+               
+               sem = Thread->WaitPointer;
+               
+               SHORTLOCK( &sem->Protector );
+               
+               // Remove from sleeping queue
+               for( th = sem->Waiting; th; prev = th, th = th->Next )
+                       if( th == Thread )      break;
+               if( th )
+               {
+                       if(prev)
+                               prev->Next = Thread->Next;
+                       else
+                               sem->Waiting = Thread->Next;
+                       if(sem->LastWaiting == Thread)
+                               sem->LastWaiting = prev;
+               }
+               else
+               {
+                       prev = NULL;
+                       for( th = sem->Signaling; th; prev = th, th = th->Next )
+                               if( th == Thread )      break;
+                       if( !th ) {
+                               Log_Warning("Threads", "Thread %p(%i %s) is not on semaphore %p(%s:%s)",
+                                       Thread, Thread->TID, Thread->ThreadName,
+                                       sem, sem->ModName, sem->Name);
+                               return -EINTERNAL;
+                       }
+                       
+                       if(prev)
+                               prev->Next = Thread->Next;
+                       else
+                               sem->Signaling = Thread->Next;
+                       if(sem->LastSignaling == Thread)
+                               sem->LastSignaling = prev;
+               }
+               
+               Thread->RetStatus = 0;  // It didn't get anything
+               Threads_AddActive( Thread );
+               
+               #if DEBUG_TRACE_STATE
+               Log("Threads_Sleep: %p(%i %s) woken from semaphore", Thread, Thread->TID, Thread->ThreadName);
+               #endif
+               SHORTREL( &sem->Protector );
+               } return -EOK;
+       
+       case THREAD_STAT_WAITING:
+               Warning("Threads_Wake - Waiting threads are not currently supported");
+               return -ENOTIMPL;
+       
+       case THREAD_STAT_DEAD:
+               Warning("Threads_Wake - Attempt to wake dead thread (%i)", Thread->TID);
+               return -ENOTIMPL;
+       
+       default:
+               Warning("Threads_Wake - Unknown process status (%i)\n", Thread->Status);
+               return -EINTERNAL;
+       }
+}
+
+/**
+ * \brief Wake a thread given the TID
+ * \param TID  Thread ID to wake
+ * \return Boolean Faulure (errno)
+ */
+int Threads_WakeTID(tTID TID)
+{
+       tThread *thread = Threads_GetThread(TID);
+        int    ret;
+       if(!thread)
+               return -ENOENT;
+       ret = Threads_Wake( thread );
+       //Log_Debug("Threads", "TID %i woke %i (%p)", Threads_GetTID(), TID, thread);
+       return ret;
+}
+
+void Threads_ToggleTrace(int TID)
+{
+       tThread *thread = Threads_GetThread(TID);
+       if(!thread)     return ;
+       thread->bInstrTrace = !thread->bInstrTrace;
+}
+
+/**
+ * \brief Adds a thread to the active queue
+ */
+void Threads_AddActive(tThread *Thread)
+{
+       SHORTLOCK( &glThreadListLock );
+       
+       if( Thread->Status == THREAD_STAT_ACTIVE ) {
+               tThread *cur = Proc_GetCurThread();
+               Log_Warning("Threads", "WTF, %p CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
+                       __builtin_return_address(0),
+                       GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName);
+               SHORTREL( &glThreadListLock );
+               return ;
+       }
+       
+       // Set state
+       Thread->Status = THREAD_STAT_ACTIVE;
+//     Thread->CurCPU = -1;
+       // Add to active list
+       {
+               #if SCHEDULER_TYPE == SCHED_RR_PRI
+               tThreadList     *list = &gaActiveThreads[Thread->Priority];
+               #else
+               tThreadList     *list = &gActiveThreads;
+               #endif
+               Threads_int_AddToList( list, Thread );
+       }
+       
+       // Update bookkeeping
+       giNumActiveThreads ++;
+       
+       #if SCHEDULER_TYPE == SCHED_LOTTERY
+       {
+                int    delta;
+               // Only change the ticket count if the thread is un-scheduled
+               if(Thread->CurCPU != -1)
+                       delta = 0;
+               else
+                       delta = caiTICKET_COUNTS[ Thread->Priority ];
+               
+               giFreeTickets += delta;
+               # if DEBUG_TRACE_TICKETS
+               Log("CPU%i %p (%i %s) added, new giFreeTickets = %i [+%i]",
+                       GetCPUNum(), Thread, Thread->TID, Thread->ThreadName,
+                       giFreeTickets, delta
+                       );
+               # endif
+       }
+       #endif
+       
+       SHORTREL( &glThreadListLock );
+}
+
+/**
+ * \brief Removes the current thread from the active queue
+ * \warning This should ONLY be called with the lock held
+ * \return Current thread pointer
+ */
+tThread *Threads_RemActive(void)
+{
+       #if 0
+       tThread *ret = Proc_GetCurThread();
+
+       if( !IS_LOCKED(&glThreadListLock) ) {
+               Log_KernelPanic("Threads", "Threads_RemActive called without lock held");
+               return NULL;
+       }
+       
+       // Delete from active queue
+       #if SCHEDULER_TYPE == SCHED_RR_PRI
+       if( !Threads_int_DelFromQueue(&gaActiveThreads[ret->Priority], ret) )
+       #else
+       if( !Threads_int_DelFromQueue(&gActiveThreads, ret) )
+       #endif
+       {
+               Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue",
+                       ret, ret->TID, ret->ThreadName
+                       );
+               return NULL;
+       }
+       
+       ret->Next = NULL;
+       ret->Remaining = 0;
+       
+       giNumActiveThreads --;
+       // no need to decrement tickets, scheduler did it for us
+       
+       #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
+       Log("CPU%i %p (%i %s) removed, giFreeTickets = %i [nc]",
+               GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets);
+       #endif
+       
+       return ret;
+       #else
+       return Proc_GetCurThread();
+       #endif
+}
+
+/**
+ * \fn void Threads_SetFaultHandler(Uint Handler)
+ * \brief Sets the signal handler for a signal
+ */
+void Threads_SetFaultHandler(Uint Handler)
+{      
+       //Log_Debug("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
+       Proc_GetCurThread()->FaultHandler = Handler;
+}
+
+/**
+ * \fn void Threads_Fault(int Num)
+ * \brief Calls a fault handler
+ */
+void Threads_Fault(int Num)
+{
+       tThread *thread = Proc_GetCurThread();
+       
+       if(!thread)     return ;
+       
+       Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
+       
+       switch(thread->FaultHandler)
+       {
+       case 0: // Panic?
+               Threads_Kill(thread, -1);
+               HALT();
+               return ;
+       case 1: // Dump Core?
+               Threads_Kill(thread, -1);
+               HALT();
+               return ;
+       }
+       
+       // Double Fault? Oh, F**k
+       if(thread->CurFaultNum != 0) {
+               Log_Warning("Threads", "Threads_Fault: Double fault on %i", thread->TID);
+               Threads_Kill(thread, -1);       // For now, just kill
+               HALT();
+       }
+       
+       thread->CurFaultNum = Num;
+       
+       Proc_CallFaultHandler(thread);
+}
+
+/**
+ * \fn void Threads_SegFault(tVAddr Addr)
+ * \brief Called when a Segment Fault occurs
+ */
+void Threads_SegFault(tVAddr Addr)
+{
+       tThread *cur = Proc_GetCurThread();
+       cur->bInstrTrace = 0;
+       Log_Warning("Threads", "Thread #%i committed a segfault at address %p", cur->TID, Addr);
+       MM_DumpTables(0, USER_MAX);
+       Threads_Fault( 1 );
+       //Threads_Exit( 0, -1 );
+}
+
+// --- Process Structure Access Functions ---
+tPID Threads_GetPID(void)
+{
+       return Proc_GetCurThread()->Process->PID;
+}
+tTID Threads_GetTID(void)
+{
+       return Proc_GetCurThread()->TID;
+}
+tUID Threads_GetUID(void)
+{
+       return Proc_GetCurThread()->Process->UID;
+}
+tGID Threads_GetGID(void)
+{
+       return Proc_GetCurThread()->Process->GID;
+}
+
+int Threads_SetUID(tUID ID)
+{
+       tThread *t = Proc_GetCurThread();
+       if( t->Process->UID != 0 ) {
+               errno = -EACCES;
+               return -1;
+       }
+       Log_Debug("Threads", "PID %i's UID set to %i", t->Process->PID, ID);
+       t->Process->UID = ID;
+       return 0;
+}
+
+int Threads_SetGID(tGID ID)
+{
+       tThread *t = Proc_GetCurThread();
+       if( t->Process->UID != 0 ) {
+               errno = -EACCES;
+               return -1;
+       }
+       Log_Debug("Threads", "PID %i's GID set to %i", t->Process->PID, ID);
+       t->Process->GID = ID;
+       return 0;
+}
+
+// --- Per-thread storage ---
+int *Threads_GetErrno(void)
+{
+       return &Proc_GetCurThread()->_errno;
+}
+
+// --- Configuration ---
+int *Threads_GetMaxFD(void)
+{
+       return &Proc_GetCurThread()->Process->MaxFD;
+}
+char **Threads_GetChroot(void)
+{
+       return &Proc_GetCurThread()->Process->RootDir;
+}
+char **Threads_GetCWD(void)
+{
+       return &Proc_GetCurThread()->Process->CurrentWorkingDir;
+}
+// ---
+
+/**
+ * \fn void Threads_Dump(void)
+ */
+void Threads_DumpActive(void)
+{
+       tThread *thread;
+       tThreadList     *list;
+       #if SCHEDULER_TYPE == SCHED_RR_PRI
+        int    i;
+       #endif
+       
+       Log("Active Threads: (%i reported)", giNumActiveThreads);
+       
+       #if SCHEDULER_TYPE == SCHED_RR_PRI
+       for( i = 0; i < MIN_PRIORITY+1; i++ )
+       {
+               list = &gaActiveThreads[i];
+       #else
+               list = &gActiveThreads;
+       #endif
+               for(thread=list->Head;thread;thread=thread->Next)
+               {
+                       Log(" %p %i (%i) - %s (CPU %i)",
+                               thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
+                       if(thread->Status != THREAD_STAT_ACTIVE)
+                               Log("  ERROR State (%i) != THREAD_STAT_ACTIVE (%i)",
+                                       thread->Status, THREAD_STAT_ACTIVE);
+                       Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
+                       Log("  KStack 0x%x", thread->KernelStack);
+                       if( thread->bInstrTrace )
+                               Log("  Tracing Enabled");
+                       Proc_DumpThreadCPUState(thread);
+               }
+       
+       #if SCHEDULER_TYPE == SCHED_RR_PRI
+       }
+       #endif
+}
+
+/**
+ * \fn void Threads_Dump(void)
+ * \brief Dumps a list of currently running threads
+ */
+void Threads_Dump(void)
+{
+       tThread *thread;
+       
+       Log("--- Thread Dump ---");
+       Threads_DumpActive();
+       
+       Log("All Threads:");
+       for(thread=gAllThreads;thread;thread=thread->GlobalNext)
+       {
+               Log(" %p %i (%i) - %s (CPU %i)",
+                       thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
+               Log("  State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
+               switch(thread->Status)
+               {
+               case THREAD_STAT_MUTEXSLEEP:
+                       Log("  Mutex Pointer: %p", thread->WaitPointer);
+                       break;
+               case THREAD_STAT_SEMAPHORESLEEP:
+                       Log("  Semaphore Pointer: %p", thread->WaitPointer);
+                       Log("  Semaphore Name: %s:%s", 
+                               ((tSemaphore*)thread->WaitPointer)->ModName,
+                               ((tSemaphore*)thread->WaitPointer)->Name
+                               );
+                       break;
+               case THREAD_STAT_ZOMBIE:
+                       Log("  Return Status: %i", thread->RetStatus);
+                       break;
+               default:        break;
+               }
+               Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
+               Log("  KStack 0x%x", thread->KernelStack);
+               if( thread->bInstrTrace )
+                       Log("  Tracing Enabled");
+               Proc_DumpThreadCPUState(thread);
+       }
+}
+
+/**
+ * \brief Gets the next thread to run
+ * \param CPU  Current CPU
+ * \param Last The thread the CPU was running
+ */
+tThread *Threads_GetNextToRun(int CPU, tThread *Last)
+{
+       tThread *thread;
+       
+       // If this CPU has the lock, we must let it complete
+       if( CPU_HAS_LOCK( &glThreadListLock ) )
+               return Last;
+       
+       // Don't change threads if the current CPU has switches disabled
+       if( gaThreads_NoTaskSwitch[CPU] )
+               return Last;
+
+       // Lock thread list
+       SHORTLOCK( &glThreadListLock );
+       
+       // Make sure the current (well, old) thread is marked as de-scheduled   
+       if(Last)        Last->CurCPU = -1;
+
+       // No active threads, just take a nap
+       if(giNumActiveThreads == 0) {
+               SHORTREL( &glThreadListLock );
+               #if DEBUG_TRACE_TICKETS
+               Log("No active threads");
+               #endif
+               return NULL;
+       }
+
+       #if 0   
+       #if SCHEDULER_TYPE != SCHED_RR_PRI
+       // Special case: 1 thread
+       if(giNumActiveThreads == 1) {
+               if( gActiveThreads.Head->CurCPU == -1 )
+                       gActiveThreads.Head->CurCPU = CPU;
+               
+               SHORTREL( &glThreadListLock );
+               
+               if( gActiveThreads.Head->CurCPU == CPU )
+                       return gActiveThreads.Head;
+               
+               return NULL;    // CPU has nothing to do
+       }
+       #endif
+       #endif  
+
+       // Allow the old thread to be scheduled again
+       if( Last ) {
+               if( Last->Status == THREAD_STAT_ACTIVE ) {
+                       tThreadList     *list;
+                       #if SCHEDULER_TYPE == SCHED_LOTTERY
+                       giFreeTickets += caiTICKET_COUNTS[ Last->Priority ];
+                       # if DEBUG_TRACE_TICKETS
+                       LogF("Log: CPU%i released %p (%i %s) into the pool (%i [+%i] tickets in pool)\n",
+                               CPU, Last, Last->TID, Last->ThreadName, giFreeTickets,
+                               caiTICKET_COUNTS[ Last->Priority ]);
+                       # endif
+                       #endif
+                       
+                       #if SCHEDULER_TYPE == SCHED_RR_PRI
+                       list = &gaActiveThreads[ Last->Priority ];
+                       #else
+                       list = &gActiveThreads;
+                       #endif
+                       // Add to end of list
+                       Threads_int_AddToList( list, Last );
+               }
+               #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
+               else
+                       LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released,not in pool)\n",
+                               CPU, Last, Last->TID, Last->ThreadName, Last->Status);
+               #endif
+               Last->CurCPU = -1;
+       }
+       
+       // ---
+       // Lottery Scheduler
+       // ---
+       #if SCHEDULER_TYPE == SCHED_LOTTERY
+       {
+                int    ticket, number;
+               # if 1
+               number = 0;
+               for(thread = gActiveThreads.Head; thread; thread = thread->Next)
+               {
+                       if(thread->Status != THREAD_STAT_ACTIVE)
+                               Panic("Bookkeeping fail - %p %i(%s) is on the active queue with a status of %i",
+                                       thread, thread->TID, thread->ThreadName, thread->Status);
+                       if(thread->Next == thread) {
+                               Panic("Bookkeeping fail - %p %i(%s) loops back on itself",
+                                       thread, thread->TID, thread->ThreadName, thread->Status);
+                       }
+                       number += caiTICKET_COUNTS[ thread->Priority ];
+               }
+               if(number != giFreeTickets) {
+                       Panic("Bookkeeping fail (giFreeTickets(%i) != number(%i)) - CPU%i",
+                               giFreeTickets, number, CPU);
+               }
+               # endif
+               
+               // No free tickets (all tasks delegated to cores)
+               if( giFreeTickets == 0 ) {
+                       SHORTREL(&glThreadListLock);
+                       return NULL;
+               }
+               
+               // Get the ticket number
+               ticket = number = rand() % giFreeTickets;
+               
+               // Find the next thread
+               for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
+               {
+                       if( caiTICKET_COUNTS[ thread->Priority ] > number)      break;
+                       number -= caiTICKET_COUNTS[ thread->Priority ];
+               }
+               
+               // If we didn't find a thread, something went wrong
+               if(thread == NULL)
+               {
+                       number = 0;
+                       for(thread=gActiveThreads;thread;thread=thread->Next) {
+                               if(thread->CurCPU >= 0) continue;
+                               number += caiTICKET_COUNTS[ thread->Priority ];
+                       }
+                       Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
+                               giFreeTickets, number);
+               }
+
+               // Remove
+               if(prev)
+                       prev->Next = thread->Next;
+               else
+                       gActiveThreads.Head = thread->Next;
+               if(!thread->Next)
+                       gActiveThreads.Tail = prev;             
+
+               giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ];
+               # if DEBUG_TRACE_TICKETS
+               LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n",
+                       CPU, thread, thread->TID, thread->ThreadName,
+                       giFreeTickets, caiTICKET_COUNTS[ thread->Priority ]);
+               # endif
+       }
+       
+       // ---
+       // Priority based round robin scheduler
+       // ---
+       #elif SCHEDULER_TYPE == SCHED_RR_PRI
+       {
+                int    i;
+               thread = NULL;
+               for( i = 0; i < MIN_PRIORITY + 1; i ++ )
+               {
+                       if( !gaActiveThreads[i].Head )
+                               continue ;
+       
+                       thread = gaActiveThreads[i].Head;
+                       
+                       // Remove from head
+                       gaActiveThreads[i].Head = thread->Next;
+                       if(!thread->Next)
+                               gaActiveThreads[i].Tail = NULL;
+                       thread->Next = NULL;
+                       break;
+               }
+               
+               // Anything to do?
+               if( !thread ) {
+                       SHORTREL(&glThreadListLock);
+                       return NULL;
+               }
+               if( thread->Status != THREAD_STAT_ACTIVE ) {
+                       LogF("Oops, Thread %i (%s) is not active\n", thread->TID, thread->ThreadName);
+               }
+       }
+       #elif SCHEDULER_TYPE == SCHED_RR_SIM
+       {
+               // Get the next thread off the list
+               thread = gActiveThreads.Head;   
+               gActiveThreads.Head = thread->Next;
+               if(!thread->Next)
+                       gaActiveThreads.Tail = NULL;
+               thread->Next = NULL;
+               
+               // Anything to do?
+               if( !thread ) {
+                       SHORTREL(&glThreadListLock);
+                       return NULL;
+               }
+       }
+       #else
+       # error "Unimplemented scheduling algorithm"
+       #endif
+       
+       // Make the new thread non-schedulable
+       thread->CurCPU = CPU;
+       thread->Remaining = thread->Quantum;
+       
+       SHORTREL( &glThreadListLock );
+       
+       return thread;
+}
+
+// === EXPORTS ===
+EXPORT(Threads_GetUID);
+EXPORT(Threads_GetGID);
diff --git a/KernelLand/Kernel/time.c b/KernelLand/Kernel/time.c
new file mode 100644 (file)
index 0000000..2c83fa3
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Acess 2
+ * - By John Hodge (thePowersGang) 
+ *
+ * Timer Code
+ */
+#include <acess.h>
+#include <timers.h>
+#include <events.h>
+#include <hal_proc.h>  // Proc_GetCurThread
+
+// === CONSTANTS ===
+#define        NUM_TIMERS      8
+
+// === TYPEDEFS ===
+struct sTimer {
+       tTimer  *Next;
+       Sint64  FiresAfter;
+       void    (*Callback)(void*);
+       void    *Argument;
+};
+
+// === PROTOTYPES ===
+void   Timer_CallTimers(void);
+
+// === GLOBALS ===
+volatile Uint64        giTicks = 0;
+volatile Sint64        giTimestamp = 0;
+volatile Uint64        giPartMiliseconds = 0;
+tTimer *gTimers;       // TODO: Replace by a ring-list timer
+
+// === CODE ===
+/**
+ * \fn void Timer_CallTimers()
+ */
+void Timer_CallTimers()
+{
+       while( gTimers && gTimers->FiresAfter < now() )
+       {
+               tTimer  *next;
+       
+               if( gTimers->Callback )
+                       gTimers->Callback(gTimers->Argument);
+               else
+                       Threads_PostEvent(gTimers->Argument, THREAD_EVENT_TIMER);
+               
+               next = gTimers->Next;
+               free(gTimers);
+               gTimers = next;
+       }
+}
+
+/**
+ * \brief Schedule an action
+ */
+tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument)
+{
+       tTimer  *ret;
+       tTimer  *t, *p;
+       
+       if(Callback == NULL)
+               Argument = Proc_GetCurThread();
+
+       // TODO: Use a pool instead?
+       ret = malloc(sizeof(tTimer));
+       
+       ret->Callback = Callback;
+       ret->FiresAfter = now() + Delta;
+       ret->Argument = Argument;
+
+       // Add into list (sorted)
+       for( p = (tTimer*)&gTimers, t = gTimers; t; p = t, t = t->Next )
+       {
+               if( t->FiresAfter > ret->FiresAfter )   break;
+       }
+       ret->Next = t;
+       p->Next = ret;
+
+       return ret;
+}
+
+/**
+ * \brief Delete a timer
+ */
+void Time_RemoveTimer(tTimer *Timer)
+{
+       tTimer  *t, *p;
+       for( p = (tTimer*)&gTimers, t = gTimers; t; p = t, t = t->Next )
+       {
+               if( t == Timer )
+               {
+                       p->Next = t->Next;
+                       free(Timer);
+                       return ;
+               }
+       }
+}
+
+/**
+ * \fn void Time_Delay(int Delay)
+ * \brief Delay for a small ammount of time
+ */
+void Time_Delay(int Delay)
+{
+//     tTime   dest = now() + Delay;
+//     while(dest > now())     Threads_Yield();
+       Time_CreateTimer(Delay, NULL, NULL);
+       Threads_WaitEvents(THREAD_EVENT_TIMER);
+}
+
+// === EXPORTS ===
+EXPORT(Time_CreateTimer);
+EXPORT(Time_RemoveTimer);
+EXPORT(Time_Delay);
diff --git a/KernelLand/Kernel/vfs/acls.c b/KernelLand/Kernel/vfs/acls.c
new file mode 100644 (file)
index 0000000..ab88b98
--- /dev/null
@@ -0,0 +1,157 @@
+/* 
+ * Acess Micro VFS
+ */
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === GLOBALS ===
+tVFS_ACL       gVFS_ACL_EveryoneRWX = { {1,-1}, {0,VFS_PERM_ALL} };
+tVFS_ACL       gVFS_ACL_EveryoneRW = { {1,-1}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE} };
+tVFS_ACL       gVFS_ACL_EveryoneRX = { {1,-1}, {0,VFS_PERM_READ|VFS_PERM_EXECUTE} };
+tVFS_ACL       gVFS_ACL_EveryoneRO = { {1,-1}, {0,VFS_PERM_READ} };
+
+// === CODE ===
+/**
+ * \fn int VFS_CheckACL(tVFS_Node *Node, Uint Permissions)
+ * \brief Checks the permissions on a file
+ */
+int VFS_CheckACL(tVFS_Node *Node, Uint Permissions)
+{
+        int    i;
+        int    uid = Threads_GetUID();
+        int    gid = Threads_GetGID();
+       
+       // Root can do anything
+       if(uid == 0)    return 1;
+       
+       // Root only file?, fast return
+       if( Node->NumACLs == 0 ) {
+               Log("VFS_CheckACL - %p inaccesable, NumACLs = 0, uid=%i", Node, uid);
+               return 0;
+       }
+       
+       // Check Deny Permissions
+       for(i=0;i<Node->NumACLs;i++)
+       {
+               if(!Node->ACLs[i].Inv)  continue;       // Ignore ALLOWs
+               if(Node->ACLs[i].ID != 0x7FFFFFFF)
+               {
+                       if(!Node->ACLs[i].Group && Node->ACLs[i].ID != uid)     continue;
+                       if(Node->ACLs[i].Group && Node->ACLs[i].ID != gid)      continue;
+               }
+               
+               //Log("Deny %x", Node->ACLs[i].Perms);
+               
+               if(Node->ACLs[i].Perms & Permissions) {
+                       Log("VFS_CheckACL - %p inaccesable, %x denied",
+                               Node, Node->ACLs[i].Perms & Permissions);
+                       return 0;
+               }
+       }
+       
+       // Check for allow permissions
+       for(i=0;i<Node->NumACLs;i++)
+       {
+               if(Node->ACLs[i].Inv)   continue;       // Ignore DENYs
+               if(Node->ACLs[i].ID != 0x7FFFFFFF)
+               {
+                       if(!Node->ACLs[i].Group && Node->ACLs[i].ID != uid)     continue;
+                       if(Node->ACLs[i].Group && Node->ACLs[i].ID != gid)      continue;
+               }
+               
+               //Log("Allow %x", Node->ACLs[i].Perms);
+               
+               if((Node->ACLs[i].Perms & Permissions) == Permissions)  return 1;
+       }
+       
+       Log("VFS_CheckACL - %p inaccesable, %x not allowed", Node, Permissions);
+       return 0;
+}
+/**
+ * \fn int VFS_GetACL(int FD, tVFS_ACL *Dest)
+ */
+int VFS_GetACL(int FD, tVFS_ACL *Dest)
+{
+        int    i;
+       tVFS_Handle     *h = VFS_GetHandle(FD);
+       
+       // Error check
+       if(!h) {
+               return -1;
+       }
+       
+       // Root can do anything
+       if(Dest->Group == 0 && Dest->ID == 0) {
+               Dest->Inv = 0;
+               Dest->Perms = -1;
+               return 1;
+       }
+       
+       // Root only file?, fast return
+       if( h->Node->NumACLs == 0 ) {
+               Dest->Inv = 0;
+               Dest->Perms = 0;
+               return 0;
+       }
+       
+       // Check Deny Permissions
+       for(i=0;i<h->Node->NumACLs;i++)
+       {
+               if(h->Node->ACLs[i].Group != Dest->Group)       continue;
+               if(h->Node->ACLs[i].ID != Dest->ID)     continue;
+               
+               Dest->Inv = h->Node->ACLs[i].Inv;
+               Dest->Perms = h->Node->ACLs[i].Perms;
+               return 1;
+       }
+       
+       
+       Dest->Inv = 0;
+       Dest->Perms = 0;
+       return 0;
+}
+
+/**
+ * \fn tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
+ * \brief Converts UNIX permissions to three Acess ACL entries
+ */
+tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
+{
+       tVFS_ACL        *ret = malloc(sizeof(tVFS_ACL)*3);
+       
+       // Error Check
+       if(!ret)        return NULL;
+       
+       // Owner
+       ret[0].Group = 0;       ret[0].ID = Owner;
+       ret[0].Inv = 0;         ret[0].Perms = 0;
+       if(Mode & 0400) ret[0].Perms |= VFS_PERM_READ;
+       if(Mode & 0200) ret[0].Perms |= VFS_PERM_WRITE;
+       if(Mode & 0100) ret[0].Perms |= VFS_PERM_EXECUTE;
+       
+       // Group
+       ret[1].Group = 1;       ret[1].ID = Group;
+       ret[1].Inv = 0;         ret[1].Perms = 0;
+       if(Mode & 0040) ret[1].Perms |= VFS_PERM_READ;
+       if(Mode & 0020) ret[1].Perms |= VFS_PERM_WRITE;
+       if(Mode & 0010) ret[1].Perms |= VFS_PERM_EXECUTE;
+       
+       // Global
+       ret[2].Group = 1;       ret[2].ID = -1;
+       ret[2].Inv = 0;         ret[2].Perms = 0;
+       if(Mode & 0004) ret[2].Perms |= VFS_PERM_READ;
+       if(Mode & 0002) ret[2].Perms |= VFS_PERM_WRITE;
+       if(Mode & 0001) ret[2].Perms |= VFS_PERM_EXECUTE;
+       
+       // Return buffer
+       return ret;
+}
+
+// === EXPORTS ===
+// --- Variables ---
+EXPORTV(gVFS_ACL_EveryoneRWX);
+EXPORTV(gVFS_ACL_EveryoneRW);
+EXPORTV(gVFS_ACL_EveryoneRX);
+// --- Functions ---
+EXPORT(VFS_UnixToAcessACL);
diff --git a/KernelLand/Kernel/vfs/dir.c b/KernelLand/Kernel/vfs/dir.c
new file mode 100644 (file)
index 0000000..d4c1530
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Acess2 VFS
+ * - Directory Management Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_int.h>
+
+// === IMPORTS ===
+extern tVFS_Mount      *gRootMount;
+
+// === PROTOTYPES ===
+#if 0
+ int   VFS_MkDir(const char *Path);
+ int   VFS_MkNod(const char *Path, Uint Flags);
+ int   VFS_Symlink(const char *Name, const char *Link);
+#endif
+
+// === CODE ===
+/**
+ * \fn int VFS_MkDir(char *Path)
+ * \brief Create a new node
+ * \param Path Path of directory to create
+ */
+int VFS_MkDir(const char *Path)
+{
+       return VFS_MkNod(Path, VFS_FFLAG_DIRECTORY);
+}
+
+/**
+ * \fn int VFS_MkNod(char *Path, Uint Flags)
+ * \brief Create a new node in a directory
+ * \param Path Path of new node
+ * \param Flags        Flags to apply to the node
+ */
+int VFS_MkNod(const char *Path, Uint Flags)
+{
+       char    *absPath, *name;
+        int    pos = 0, oldpos = 0;
+        int    next = 0;
+       tVFS_Node       *parent;
+        int    ret;
+       
+       ENTER("sPath xFlags", Path, Flags);
+       
+       absPath = VFS_GetAbsPath(Path);
+       LOG("absPath = '%s'", absPath);
+       
+       while( (next = strpos(&absPath[pos+1], '/')) != -1 ) {
+               LOG("next = %i", next);
+               pos += next+1;
+               LOG("pos = %i", pos);
+               oldpos = pos;
+       }
+       absPath[oldpos] = '\0'; // Mutilate path
+       name = &absPath[oldpos+1];
+       
+       LOG("absPath = '%s', name = '%s'", absPath, name);
+       
+       // Check for root
+       if(absPath[0] == '\0')
+               parent = VFS_ParsePath("/", NULL, NULL);
+       else
+               parent = VFS_ParsePath(absPath, NULL, NULL);
+       
+       LOG("parent = %p", parent);
+       
+       if(!parent) {
+               LEAVE('i', -1);
+               return -1;      // Error Check
+       }
+       
+       // Permissions Check
+       if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
+               _CloseNode(parent);
+               free(absPath);
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       LOG("parent = %p", parent);
+       
+       if(!parent->Type || !parent->Type->MkNod) {
+               Warning("VFS_MkNod - Directory has no MkNod method");
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       // Create node
+       ret = parent->Type->MkNod(parent, name, Flags);
+       
+       // Free allocated string
+       free(absPath);
+       
+       // Free Parent
+       _CloseNode(parent);
+       
+       // Error Check
+       if(ret == 0) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn int VFS_Symlink(const char *Name, const char *Link)
+ * \brief Creates a symlink called \a Name to \a Link
+ * \param Name Name of symbolic link
+ * \param Link Destination of symbolic link
+ */
+int VFS_Symlink(const char *Name, const char *Link)
+{
+       char    *realLink;
+        int    fp;
+       
+       ENTER("sName sLink", Name, Link);
+       
+       // Get absolue path name
+       realLink = VFS_GetAbsPath( Link );
+       if(!realLink) {
+               Log_Warning("VFS", "Path '%s' is badly formed", Link);
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       LOG("realLink = '%s'", realLink);
+
+       // Make node
+       if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
+               Log_Warning("VFS", "Unable to create link node '%s'", Name);
+               free(realLink);
+               LEAVE('i', -2);
+               return -2;      // Make link node
+       }
+       
+       // Write link address
+       fp = VFS_Open(Name, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_NOLINK);
+       VFS_Write(fp, strlen(realLink), realLink);
+       VFS_Close(fp);
+       
+       free(realLink);
+       
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \fn int VFS_ReadDir(int FD, char *Dest)
+ * \brief Read from a directory
+ */
+int VFS_ReadDir(int FD, char *Dest)
+{
+       tVFS_Handle     *h = VFS_GetHandle(FD);
+       char    *tmp;
+       
+       //ENTER("ph pDest", h, Dest);
+       
+       if(!h || !h->Node->Type || !h->Node->Type->ReadDir) {
+               //LEAVE('i', 0);
+               return 0;
+       }
+       
+       if(h->Node->Size != -1 && h->Position >= h->Node->Size) {
+               //LEAVE('i', 0);
+               return 0;
+       }
+       
+       do {
+               tmp = h->Node->Type->ReadDir(h->Node, h->Position);
+               if((Uint)tmp < (Uint)VFS_MAXSKIP)
+                       h->Position += (Uint)tmp;
+               else
+                       h->Position ++;
+       } while(tmp != NULL && (Uint)tmp < (Uint)VFS_MAXSKIP);
+       
+       //LOG("tmp = '%s'", tmp);
+       
+       if(!tmp) {
+               //LEAVE('i', 0);
+               return 0;
+       }
+       
+       strcpy(Dest, tmp);
+       free(tmp);
+       
+       //LEAVE('i', 1);
+       return 1;
+}
diff --git a/KernelLand/Kernel/vfs/fs/devfs.c b/KernelLand/Kernel/vfs/fs/devfs.c
new file mode 100644 (file)
index 0000000..b3f4a57
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Acess 2
+ * Device Filesystem (DevFS)
+ * - vfs/fs/devfs.c
+ */
+#include <acess.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+
+// === PROTOTYPES ===
+#if 0
+ int   DevFS_AddDevice(tDevFS_Driver *Device);
+void   DevFS_DelDevice(tDevFS_Driver *Device);
+#endif
+tVFS_Node      *DevFS_InitDevice(const char *Device, const char **Options);
+char   *DevFS_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *DevFS_FindDir(tVFS_Node *Node, const char *Name);
+
+// === GLOBALS ===
+tVFS_Driver    gDevFS_Info = {
+       "devfs", 0, DevFS_InitDevice, NULL, NULL
+       };
+tVFS_NodeType  gDevFS_DirType = {
+       .TypeName = "DevFS-Dir",
+       .ReadDir = DevFS_ReadDir,
+       .FindDir = DevFS_FindDir
+       };
+tVFS_Node      gDevFS_RootNode = {
+       .Size = 0,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Type = &gDevFS_DirType
+       };
+tDevFS_Driver  *gDevFS_Drivers = NULL;
+ int   giDevFS_NextID = 1;
+tShortSpinlock glDevFS_ListLock;
+
+// === CODE ===
+/**
+ * \fn int DevFS_AddDevice(tDevFS_Driver *Device)
+ */
+int DevFS_AddDevice(tDevFS_Driver *Device)
+{
+        int    ret = 0;
+       tDevFS_Driver   *dev;
+       
+       SHORTLOCK( &glDevFS_ListLock );
+       
+       // Check if the device is already registered or the name is taken
+       for( dev = gDevFS_Drivers; dev; dev = dev->Next )
+       {
+               if(dev == Device)       break;
+               if(strcmp(dev->Name, Device->Name) == 0)        break;
+       }
+       
+       if(dev) {
+               if(dev == Device)
+                       Log_Warning("DevFS", "Device %p '%s' attempted to register itself twice",
+                               dev, dev->Name);
+               else
+                       Log_Warning("DevFS", "Device %p attempted to register '%s' which was owned by %p",
+                               Device, dev->Name, dev);
+               ret = 0;        // Error
+       }
+       else {
+               Device->Next = gDevFS_Drivers;
+               gDevFS_Drivers = Device;
+               gDevFS_RootNode.Size ++;
+               ret = giDevFS_NextID ++;
+       }
+       SHORTREL( &glDevFS_ListLock );
+       
+       return ret;
+}
+
+/**
+ * \brief Delete a device from the DevFS folder
+ */
+void DevFS_DelDevice(tDevFS_Driver *Device)
+{
+       tDevFS_Driver   *prev = NULL, *dev;
+       
+       SHORTLOCK( &glDevFS_ListLock );
+       // Search list for device
+       for(dev = gDevFS_Drivers;
+               dev && dev != Device;
+               prev = dev, dev = dev->Next
+               );
+       
+       // Check if it was found
+       if(dev)
+       {
+               if(prev)
+                       prev->Next = Device->Next;
+               else
+                       gDevFS_Drivers = Device->Next;
+       }
+       else
+               Log_Warning("DevFS", "Attempted to unregister device %p '%s' which was not registered",
+                       Device, Device->Name);
+       
+       SHORTREL( &glDevFS_ListLock );
+}
+
+/**
+ * \brief Initialise the DevFS and detect double-mounting, or just do nothing
+ * \note STUB
+ */
+tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options)
+{
+       return &gDevFS_RootNode;
+}
+
+/**
+ * \fn char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
+ */
+char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tDevFS_Driver   *dev;
+       
+       if(Pos < 0)     return NULL;
+       
+       for(dev = gDevFS_Drivers;
+               dev && Pos--;
+               dev = dev->Next
+               );
+       
+       if(dev)
+               return strdup(dev->Name);
+       else
+               return NULL;
+}
+
+/**
+ * \fn tVFS_Node *DevFS_FindDir(tVFS_Node *Node, const char *Name)
+ * \brief Get an entry from the devices directory
+ */
+tVFS_Node *DevFS_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tDevFS_Driver   *dev;
+       
+       //ENTER("pNode sName", Node, Name);
+       
+       for(dev = gDevFS_Drivers;
+               dev;
+               dev = dev->Next
+               )
+       {
+               //LOG("dev = %p", dev);
+               //LOG("dev->Name = '%s'", dev->Name);
+               if(strcmp(dev->Name, Name) == 0) {
+                       //LEAVE('p', &dev->RootNode);
+                       return &dev->RootNode;
+               }
+       }
+       
+       //LEAVE('n');
+       return NULL;
+}
+
+// --- EXPORTS ---
+EXPORT(DevFS_AddDevice);
+EXPORT(DevFS_DelDevice);
diff --git a/KernelLand/Kernel/vfs/fs/root.c b/KernelLand/Kernel/vfs/fs/root.c
new file mode 100644 (file)
index 0000000..9fa1732
--- /dev/null
@@ -0,0 +1,255 @@
+/* 
+ * AcessMicro VFS
+ * - Root Filesystem Driver
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_ramfs.h>
+
+// === CONSTANTS ===
+#define MAX_FILES      64
+#define        MAX_FILE_SIZE   1024
+
+// === PROTOTYPES ===
+tVFS_Node      *Root_InitDevice(const char *Device, const char **Options);
+ int   Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+tVFS_Node      *Root_FindDir(tVFS_Node *Node, const char *Name);
+char   *Root_ReadDir(tVFS_Node *Node, int Pos);
+Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+tRamFS_File    *Root_int_AllocFile(void);
+
+// === GLOBALS ===
+tVFS_Driver    gRootFS_Info = {
+       "rootfs", 0, Root_InitDevice, NULL, NULL
+       };
+tRamFS_File    RootFS_Files[MAX_FILES];
+tVFS_ACL       RootFS_DirACLs[3] = {
+       {{0,0}, {0,VFS_PERM_ALL}},      // Owner (Root)
+       {{1,0}, {0,VFS_PERM_ALL}},      // Group (Root)
+       {{0,-1}, {0,VFS_PERM_ALL^VFS_PERM_WRITE}}       // World (Nobody)
+};
+tVFS_ACL       RootFS_FileACLs[3] = {
+       {{0,0}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE}},     // Owner (Root)
+       {{1,0}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE}},     // Group (Root)
+       {{0,-1}, {0,VFS_PERM_READ}}     // World (Nobody)
+};
+tVFS_NodeType  gRootFS_DirType = {
+       .TypeName = "RootFS-Dir",
+       .ReadDir = Root_ReadDir,
+       .FindDir = Root_FindDir,
+       .MkNod = Root_MkNod
+};
+tVFS_NodeType  gRootFS_FileType = {
+       .TypeName = "RootFS-File",
+       .Read = Root_Read,
+       .Write = Root_Write,
+};
+
+// === CODE ===
+/**
+ * \brief Initialise the root filesystem
+ */
+tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
+{
+       tRamFS_File     *root;
+       if(strcmp(Device, "root") != 0) {
+               return NULL;
+       }
+       
+       // Create Root Node
+       root = &RootFS_Files[0];
+       
+       root->Node.ImplPtr = root;
+       
+       root->Node.CTime
+               = root->Node.MTime
+               = root->Node.ATime = now();
+       root->Node.NumACLs = 3;
+       root->Node.ACLs = RootFS_DirACLs;
+
+       root->Node.Type = &gRootFS_DirType;
+       
+       return &root->Node;
+}
+
+/**
+ * \fn int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+ * \brief Create an entry in the root directory
+ */
+int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+       tRamFS_File     *parent = Node->ImplPtr;
+       tRamFS_File     *child;
+       tRamFS_File     *prev = (tRamFS_File *) &parent->Data.FirstChild;
+       
+       ENTER("pNode sName xFlags", Node, Name, Flags);
+       
+       LOG("%i > %i", strlen(Name)+1, sizeof(child->Name));
+       if(strlen(Name) + 1 > sizeof(child->Name))
+               LEAVE_RET('i', 0);
+       
+       // Find last child, while we're at it, check for duplication
+       for( child = parent->Data.FirstChild; child; prev = child, child = child->Next )
+       {
+               if(strcmp(child->Name, Name) == 0) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+       }
+       
+       child = Root_int_AllocFile();
+       memset(child, 0, sizeof(tRamFS_File));
+       
+       strcpy(child->Name, Name);
+       
+       child->Parent = parent;
+       child->Next = NULL;
+       child->Data.FirstChild = NULL;
+       
+       child->Node.ImplPtr = child;
+       child->Node.Flags = Flags;
+       child->Node.NumACLs = 3;
+       child->Node.Size = 0;
+       
+       if(Flags & VFS_FFLAG_DIRECTORY)
+       {
+               child->Node.ACLs = RootFS_DirACLs;
+               child->Node.Type = &gRootFS_DirType;
+       } else {
+               if(Flags & VFS_FFLAG_SYMLINK)
+                       child->Node.ACLs = RootFS_DirACLs;
+               else
+                       child->Node.ACLs = RootFS_FileACLs;
+               child->Node.Type = &gRootFS_FileType;
+       }
+       
+       prev->Next = child;
+       
+       parent->Node.Size ++;
+       
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \fn tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
+ * \brief Find an entry in the filesystem
+ */
+tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tRamFS_File     *parent = Node->ImplPtr;
+       tRamFS_File     *child = parent->Data.FirstChild;
+       
+       //Log("Root_FindDir: (Node=%p, Name='%s')", Node, Name);
+       
+       for(;child;child = child->Next)
+       {
+               //Log(" Root_FindDir: strcmp('%s', '%s')", child->Node.Name, Name);
+               if(strcmp(child->Name, Name) == 0)      return &child->Node;
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn char *Root_ReadDir(tVFS_Node *Node, int Pos)
+ * \brief Get an entry from the filesystem
+ */
+char *Root_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tRamFS_File     *parent = Node->ImplPtr;
+       tRamFS_File     *child = parent->Data.FirstChild;
+       
+       for( ; child && Pos--; child = child->Next ) ;
+       
+       if(child)       return strdup(child->Name);
+       
+       return NULL;
+}
+
+/**
+ * \fn Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a file in the root directory
+ */
+Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tRamFS_File     *file = Node->ImplPtr;
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       if(Offset > Node->Size) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       if(Length > Node->Size) Length = Node->Size;
+       
+       if(Offset+Length > Node->Size)
+               Length = Node->Size - Offset;
+       
+       memcpy(Buffer, file->Data.Bytes+Offset, Length);
+       LOG("Buffer = '%.*s'", (int)Length, Buffer);
+
+       LEAVE('i', Length);
+       return Length;
+}
+
+/**
+ * \fn Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a file in the root directory
+ */
+Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tRamFS_File     *file = Node->ImplPtr;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+       if(Offset > Node->Size) {
+               LEAVE('i', -1);
+               return -1;
+       }       
+
+       if(Offset + Length > MAX_FILE_SIZE)
+       {
+               Length = MAX_FILE_SIZE - Offset;
+       }
+
+       LOG("Buffer = '%.*s'", (int)Length, Buffer);
+       
+       // Check if buffer needs to be expanded
+       if(Offset + Length > Node->Size)
+       {
+               void *tmp = realloc( file->Data.Bytes, Offset + Length );
+               if(tmp == NULL) {
+                       Warning("Root_Write - Increasing buffer size failed");
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               file->Data.Bytes = tmp;
+               Node->Size = Offset + Length;
+               LOG("Expanded buffer to %i bytes", (int)Node->Size);
+       }
+       
+       memcpy(file->Data.Bytes+Offset, Buffer, Length);
+       LOG("File - '%.*s'", Node->Size, file->Data.Bytes);
+       
+       LEAVE('i', Length);
+       return Length;
+}
+
+/**
+ * \fn tRamFS_File *Root_int_AllocFile(void)
+ * \brief Allocates a file from the pool
+ */
+tRamFS_File *Root_int_AllocFile(void)
+{
+        int    i;
+       for( i = 0; i < MAX_FILES; i ++ )
+       {
+               if( RootFS_Files[i].Name[0] == '\0' )
+               {
+                       return &RootFS_Files[i];
+               }
+       }
+       return NULL;
+}
diff --git a/KernelLand/Kernel/vfs/handle.c b/KernelLand/Kernel/vfs/handle.c
new file mode 100644 (file)
index 0000000..d22f965
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Acess2 VFS
+ * - AllocHandle, GetHandle
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <mm_virt.h>
+#include "vfs.h"
+#include "vfs_int.h"
+#include "vfs_ext.h"
+#include <threads.h>   // GetMaxFD
+#include <vfs_threads.h>       // Handle maintainance
+
+// === CONSTANTS ===
+#define MAX_KERNEL_FILES       128
+
+// === PROTOTYPES ===
+#if 0
+tVFS_Handle    *VFS_GetHandle(int FD);
+#endif
+ int   VFS_AllocHandle(int FD, tVFS_Node *Node, int Mode);
+
+// === GLOBALS ===
+tVFS_Handle    *gaUserHandles = (void*)MM_PPD_HANDLES;
+tVFS_Handle    *gaKernelHandles = (void*)MM_KERNEL_VFS;
+
+// === CODE ===
+/**
+ * \fn tVFS_Handle *VFS_GetHandle(int FD)
+ * \brief Gets a pointer to the handle information structure
+ */
+tVFS_Handle *VFS_GetHandle(int FD)
+{
+       tVFS_Handle     *h;
+       
+       //Log_Debug("VFS", "VFS_GetHandle: (FD=0x%x)", FD);
+       
+       if(FD < 0)      return NULL;
+       
+       if(FD & VFS_KERNEL_FLAG) {
+               FD &= (VFS_KERNEL_FLAG - 1);
+               if(FD >= MAX_KERNEL_FILES)      return NULL;
+               h = &gaKernelHandles[ FD ];
+       } else {
+               if(FD >= *Threads_GetMaxFD())   return NULL;
+               h = &gaUserHandles[ FD ];
+       }
+       
+       if(h->Node == NULL)     return NULL;
+       //Log_Debug("VFS", "VFS_GetHandle: RETURN %p", h);
+       return h;
+}
+
+int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
+{
+        int    i;
+       
+       // Check for a user open
+       if(bIsUser)
+       {
+                int    max_handles = *Threads_GetMaxFD();
+               // Allocate Buffer
+               if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               {
+                       Uint    addr, size;
+                       size = max_handles * sizeof(tVFS_Handle);
+                       for(addr = 0; addr < size; addr += 0x1000)
+                       {
+                               if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
+                               {
+                                       Warning("OOM - VFS_AllocHandle");
+                                       Threads_Exit(0, 0xFF);  // Terminate user
+                               }
+                       }
+                       memset( gaUserHandles, 0, size );
+               }
+               // Get a handle
+               for( i = 0; i < max_handles; i ++ )
+               {
+                       if(gaUserHandles[i].Node)       continue;
+                       gaUserHandles[i].Node = Node;
+                       gaUserHandles[i].Position = 0;
+                       gaUserHandles[i].Mode = Mode;
+                       return i;
+               }
+       }
+       else
+       {
+               // Allocate space if not already
+               if( MM_GetPhysAddr( (tVAddr)gaKernelHandles ) == 0 )
+               {
+                       Uint    addr, size;
+                       size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
+                       for(addr = 0; addr < size; addr += 0x1000)
+                       {
+                               if( !MM_Allocate( (tVAddr)gaKernelHandles + addr ) )
+                               {
+                                       Panic("OOM - VFS_AllocHandle");
+                                       Threads_Exit(0, 0xFF);  // Terminate application (get some space back)
+                               }
+                       }
+                       memset( gaKernelHandles, 0, size );
+               }
+               // Get a handle
+               for(i=0;i<MAX_KERNEL_FILES;i++)
+               {
+                       if(gaKernelHandles[i].Node)     continue;
+                       gaKernelHandles[i].Node = Node;
+                       gaKernelHandles[i].Position = 0;
+                       gaKernelHandles[i].Mode = Mode;
+                       return i|VFS_KERNEL_FLAG;
+               }
+       }
+       
+       return -1;
+}
+
+void VFS_ReferenceUserHandles(void)
+{
+        int    i;
+        int    max_handles = *Threads_GetMaxFD();
+
+       // Check if this process has any handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               return ;
+       
+       for( i = 0; i < max_handles; i ++ )
+       {
+               tVFS_Handle     *h;
+               h = &gaUserHandles[i];
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Reference )
+                       h->Node->Type->Reference( h->Node );
+       }
+}
+
+void VFS_CloseAllUserHandles(void)
+{
+        int    i;
+        int    max_handles = *Threads_GetMaxFD();
+
+       // Check if this process has any handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               return ;
+       
+       for( i = 0; i < max_handles; i ++ )
+       {
+               tVFS_Handle     *h;
+               h = &gaUserHandles[i];
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Close )
+                       h->Node->Type->Close( h->Node );
+       }
+}
+
+/**
+ * \brief Take a backup of a set of file descriptors
+ */
+void *VFS_SaveHandles(int NumFDs, int *FDs)
+{
+       tVFS_Handle     *ret;
+        int    i;
+        int    max_handles = *Threads_GetMaxFD();
+       
+       // Check if this process has any handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               return NULL;
+
+       // Allocate
+       ret = malloc( NumFDs * sizeof(tVFS_Handle) );
+       if( !ret )
+               return NULL;    
+
+       if( NumFDs > max_handles )
+               NumFDs = max_handles;
+
+       // Take copies of the handles
+       for( i = 0; i < NumFDs; i ++ )
+       {
+               tVFS_Handle     *h;
+               if( FDs == NULL )
+                       h = &gaUserHandles[i];
+               else {
+                       h = VFS_GetHandle(FDs[i] & (VFS_KERNEL_FLAG - 1));
+                       if(!h) {
+                               Log_Warning("VFS", "VFS_SaveHandles - Invalid FD %i",
+                                       FDs[i] & (VFS_KERNEL_FLAG - 1) );
+                               free(ret);
+                               return NULL;
+                       }
+               }
+               memcpy( &ret[i], h, sizeof(tVFS_Handle) );
+               
+               // Reference node
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Reference )
+                       h->Node->Type->Reference( h->Node );
+       }       
+
+       return ret;
+}
+
+void VFS_RestoreHandles(int NumFDs, void *Handles)
+{
+       tVFS_Handle     *handles = Handles;
+        int    i;
+
+       // NULL = nothing to do
+       if( !Handles )
+               return ;        
+
+       // Check if there is already a set of handles
+       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
+               return ;
+       
+       
+       // Allocate user handle area
+       {
+               Uint    addr, size;
+                int    max_handles = *Threads_GetMaxFD();
+               size = max_handles * sizeof(tVFS_Handle);
+               for(addr = 0; addr < size; addr += 0x1000)
+               {
+                       if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
+                       {
+                               Warning("OOM - VFS_AllocHandle");
+                               Threads_Exit(0, 0xFF);  // Terminate user
+                       }
+               }
+               memset( gaUserHandles, 0, size );
+       }
+       
+       // Restore handles
+       memcpy( gaUserHandles, handles, NumFDs * sizeof(tVFS_Handle) );
+       // Reference when copied
+       for( i = 0; i < NumFDs; i ++ )
+       {
+               tVFS_Handle     *h = &handles[i];
+       
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Reference )
+                       h->Node->Type->Reference( h->Node );
+       }
+}
+
+void VFS_FreeSavedHandles(int NumFDs, void *Handles)
+{
+       tVFS_Handle     *handles = Handles;
+        int    i;
+
+       // NULL = nothing to do
+       if( !Handles )
+               return ;        
+       
+       // Dereference all saved nodes
+       for( i = 0; i < NumFDs; i ++ )
+       {
+               tVFS_Handle     *h = &handles[i];
+       
+               if( !h->Node )
+                       continue ;
+               if( h->Node->Type && h->Node->Type->Close )
+                       h->Node->Type->Close( h->Node );
+       }
+       free( Handles );
+}
diff --git a/KernelLand/Kernel/vfs/io.c b/KernelLand/Kernel/vfs/io.c
new file mode 100644 (file)
index 0000000..e7a2a06
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * AcessMicro VFS
+ * - File IO Passthru's
+ */
+#define DEBUG  0
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === CODE ===
+/**
+ * \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
+ * \brief Read data from a node (file)
+ */
+Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
+{
+       tVFS_Handle     *h;
+       Uint64  ret;
+       
+       ENTER("iFD XLength pBuffer", FD, Length, Buffer);
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  LEAVE_RET('i', -1);
+       
+       if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
+               LEAVE_RET('i', -1);
+
+       if(!h->Node->Type || !h->Node->Type->Read)      LEAVE_RET('i', 0);
+       
+       ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
+       if(ret == -1)   LEAVE_RET('i', -1);
+       
+       h->Position += ret;
+       LEAVE('X', ret);
+       return ret;
+}
+
+/**
+ * \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read data from a given offset (atomic)
+ */
+Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tVFS_Handle     *h;
+       Uint64  ret;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+       
+       if( !(h->Mode & VFS_OPENFLAG_READ) )    return -1;
+       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
+
+       if( !h->Node->Type || !h->Node->Type->Read) {
+               Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
+               return 0;
+       }
+       ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
+       if(ret == -1)   return -1;
+       return ret;
+}
+
+/**
+ * \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
+ * \brief Read data from a node (file)
+ */
+Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
+{
+       tVFS_Handle     *h;
+       Uint64  ret;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+       
+       if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
+       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
+
+       if( !h->Node->Type || !h->Node->Type->Write )   return 0;
+       
+       ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
+       if(ret == -1)   return -1;
+
+       h->Position += ret;
+       return ret;
+}
+
+/**
+ * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
+ * \brief Write data to a file at a given offset
+ */
+Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tVFS_Handle     *h;
+       Uint64  ret;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+       
+       if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
+       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
+
+       if(!h->Node->Type || !h->Node->Type->Write)     return 0;
+       ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
+
+       if(ret == -1)   return -1;
+       return ret;
+}
+
+/**
+ * \fn Uint64 VFS_Tell(int FD)
+ * \brief Returns the current file position
+ */
+Uint64 VFS_Tell(int FD)
+{
+       tVFS_Handle     *h;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+       
+       return h->Position;
+}
+
+/**
+ * \fn int VFS_Seek(int FD, Sint64 Offset, int Whence)
+ * \brief Seek to a new location
+ * \param FD   File descriptor
+ * \param Offset       Where to go
+ * \param Whence       From where
+ */
+int VFS_Seek(int FD, Sint64 Offset, int Whence)
+{
+       tVFS_Handle     *h;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+       
+       //Log_Debug("VFS", "VFS_Seek: (fd=0x%x, Offset=0x%llx, Whence=%i)",
+       //      FD, Offset, Whence);
+       
+       // Set relative to current position
+       if(Whence == 0) {
+               h->Position += Offset;
+               return 0;
+       }
+       
+       // Set relative to end of file
+       if(Whence < 0) {
+               if( h->Node->Size == -1 )       return -1;
+
+               h->Position = h->Node->Size - Offset;
+               return 0;
+       }
+       
+       // Set relative to start of file
+       h->Position = Offset;
+       return 0;
+}
+
+/**
+ * \fn int VFS_IOCtl(int FD, int ID, void *Buffer)
+ * \brief Call an IO Control on a file
+ */
+int VFS_IOCtl(int FD, int ID, void *Buffer)
+{
+       tVFS_Handle     *h;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+
+       if(!h->Node->Type || !h->Node->Type->IOCtl)     return -1;
+       return h->Node->Type->IOCtl(h->Node, ID, Buffer);
+}
+
+/**
+ * \fn int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
+ * \brief Retrieve file information
+ * \return Number of ACLs stored
+ */
+int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
+{
+       tVFS_Handle     *h;
+        int    max;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+
+       if( h->Mount )
+               Dest->mount = h->Mount->Identifier;
+       else
+               Dest->mount = 0;
+       Dest->inode = h->Node->Inode;   
+       Dest->uid = h->Node->UID;
+       Dest->gid = h->Node->GID;
+       Dest->size = h->Node->Size;
+       Dest->atime = h->Node->ATime;
+       Dest->ctime = h->Node->MTime;
+       Dest->mtime = h->Node->CTime;
+       Dest->numacls = h->Node->NumACLs;
+       
+       Dest->flags = 0;
+       if(h->Node->Flags & VFS_FFLAG_DIRECTORY)        Dest->flags |= 0x10;
+       if(h->Node->Flags & VFS_FFLAG_SYMLINK)  Dest->flags |= 0x20;
+       
+       max = (MaxACLs < h->Node->NumACLs) ? MaxACLs : h->Node->NumACLs;
+       memcpy(&Dest->acls, h->Node->ACLs, max*sizeof(tVFS_ACL));
+       
+       return max;
+}
+
+// === EXPORTS ===
+EXPORT(VFS_Read);
+EXPORT(VFS_Write);
+EXPORT(VFS_ReadAt);
+EXPORT(VFS_WriteAt);
+EXPORT(VFS_IOCtl);
+EXPORT(VFS_Seek);
+EXPORT(VFS_Tell);
diff --git a/KernelLand/Kernel/vfs/main.c b/KernelLand/Kernel/vfs/main.c
new file mode 100644 (file)
index 0000000..5ff0e7c
--- /dev/null
@@ -0,0 +1,166 @@
+/* 
+ * Acess 2
+ * Virtual File System
+ */
+#include <acess.h>
+#include <fs_sysfs.h>
+#include <threads.h>
+#include <vfs.h>
+#include <vfs_int.h>
+#include <vfs_ext.h>
+
+// === IMPORTS ===
+extern tVFS_Driver     gRootFS_Info;
+extern tVFS_Driver     gDevFS_Info;
+
+// === PROTOTYPES ===
+#if 0
+ int   VFS_Init(void);
+char   *VFS_GetTruePath(const char *Path);
+void   VFS_GetMemPath(char *Dest, void *Base, Uint Length);
+tVFS_Driver    *VFS_GetFSByName(const char *Name);
+ int   VFS_AddDriver(tVFS_Driver *Info);
+#endif
+void   VFS_UpdateDriverFile(void);
+
+// === EXPORTS ===
+EXPORT(VFS_AddDriver);
+
+// === GLOBALS ===
+tVFS_Node      NULLNode = {0};
+tShortSpinlock slDriverListLock;
+tVFS_Driver    *gVFS_Drivers = NULL;
+char   *gsVFS_DriverFile = NULL;
+ int   giVFS_DriverFileID = 0;
+
+char   *gsVFS_MountFile = NULL;
+ int   giVFS_MountFileID = 0;
+
+// === CODE ===
+/**
+ * \fn int VFS_Init(void)
+ * \brief Initialises the VFS for use by the kernel and user
+ */
+int VFS_Init(void)
+{
+       // Core Drivers
+       gVFS_Drivers = &gRootFS_Info;
+       gVFS_Drivers->Next = &gDevFS_Info;
+       VFS_UpdateDriverFile();
+       
+       // Register with SysFS
+       giVFS_MountFileID = SysFS_RegisterFile("VFS/Mounts", NULL, 0);
+       giVFS_DriverFileID = SysFS_RegisterFile("VFS/Drivers", NULL, 0);
+       
+       if( VFS_Mount("root", "/", "rootfs", "") != 0 ) {
+               Log_KernelPanic("VFS", "Unable to mount root (Where the **** is rootfs?)");
+               return -1;
+       }
+       VFS_MkDir("/Devices");
+       VFS_MkDir("/Mount");
+       VFS_Mount("dev", "/Devices", "devfs", "");
+               
+       Log_Debug("VFS", "Setting max files");
+       *Threads_GetMaxFD() = 32;
+       return 0;
+}
+
+/**
+ * \fn char *VFS_GetTruePath(const char *Path)
+ * \brief Gets the true path (non-symlink) of a file
+ */
+char *VFS_GetTruePath(const char *Path)
+{
+       tVFS_Node       *node;
+       char    *ret, *tmp;
+       
+       tmp = VFS_GetAbsPath(Path);
+       if(tmp == NULL) return NULL;
+       //Log(" VFS_GetTruePath: tmp = '%s'", tmp);
+       node = VFS_ParsePath(tmp, &ret, NULL);
+       free(tmp);
+       //Log(" VFS_GetTruePath: node=%p, ret='%s'", node, ret);
+       
+       if(!node)       return NULL;
+       if(node->Type->Close)   node->Type->Close(node);
+       
+       return ret;
+}
+
+/**
+ * \fn void VFS_GetMemPath(char *Dest, void *Base, Uint Length)
+ * \brief Create a VFS memory pointer path
+ */
+void VFS_GetMemPath(char *Dest, void *Base, Uint Length)
+{
+       Dest[0] = '$';
+       itoa( &Dest[1], (tVAddr)Base, 16, BITS/4, '0' );
+       Dest[BITS/4+1] = ':';
+       itoa( &Dest[BITS/4+2], Length, 16, BITS/4, '0' );
+       Dest[BITS/2+2] = '\0';
+}
+
+/**
+ * \fn tVFS_Driver *VFS_GetFSByName(const char *Name)
+ * \brief Gets a filesystem structure given a name
+ */
+tVFS_Driver *VFS_GetFSByName(const char *Name)
+{
+       tVFS_Driver     *drv = gVFS_Drivers;
+       
+       for(;drv;drv=drv->Next)
+       {
+//             Log("strcmp('%s' (%p), '%s') == 0?", drv->Name, drv->Name, Name);
+               if(strcmp(drv->Name, Name) == 0)
+                       return drv;
+       }
+       return NULL;
+}
+
+/**
+ * \fn int VFS_AddDriver(tVFS_Driver *Info)
+ */
+int VFS_AddDriver(tVFS_Driver *Info)
+{
+       if(!Info)       return  -1;
+       
+       SHORTLOCK( &slDriverListLock );
+       Info->Next = gVFS_Drivers;
+       gVFS_Drivers = Info;
+       SHORTREL( &slDriverListLock );
+       
+       VFS_UpdateDriverFile();
+       
+       return 0;
+}
+
+/**
+ * \fn void VFS_UpdateDriverFile(void)
+ * \brief Updates the driver list file
+ */
+void VFS_UpdateDriverFile(void)
+{
+       tVFS_Driver     *drv;
+        int    len = 0;
+       char    *buf;
+       
+       // Format:
+       // <name>\n
+       for( drv = gVFS_Drivers; drv; drv = drv->Next )
+       {
+               len += 1 + strlen(drv->Name);
+       }
+       buf = malloc(len+1);
+       len = 0;
+       for( drv = gVFS_Drivers; drv; drv = drv->Next )
+       {
+               strcpy( &buf[len], drv->Name );
+               len += strlen(drv->Name);
+               buf[len++] = '\n';
+       }
+       buf[len] = '\0';
+       
+       SysFS_UpdateFile( giVFS_DriverFileID, buf, len );
+       if(gsVFS_DriverFile)    free(gsVFS_DriverFile);
+       gsVFS_DriverFile = buf;
+}
diff --git a/KernelLand/Kernel/vfs/memfile.c b/KernelLand/Kernel/vfs/memfile.c
new file mode 100644 (file)
index 0000000..14b3948
--- /dev/null
@@ -0,0 +1,135 @@
+/* 
+ * Acess 2
+ * Virtual File System
+ * - Memory Pseudo Files
+ */
+#include <acess.h>
+#include <vfs.h>
+
+// === PROTOTYPES ===
+tVFS_Node      *VFS_MemFile_Create(const char *Path);
+void   VFS_MemFile_Close(tVFS_Node *Node);
+Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+
+// === GLOBALS ===
+tVFS_NodeType  gVFS_MemFileType = {
+       .Close = VFS_MemFile_Close,
+       .Read = VFS_MemFile_Read,
+       .Write = VFS_MemFile_Write
+       };
+
+// === CODE ===
+/**
+ * \fn tVFS_Node *VFS_MemFile_Create(const char *Path)
+ */
+tVFS_Node *VFS_MemFile_Create(const char *Path)
+{
+       Uint    base, size;
+       const char      *str = Path;
+       tVFS_Node       *ret;
+       
+       str++;  // Eat '$'
+       
+       // Read Base address
+       base = 0;
+       for( ; ('0' <= *str && *str <= '9') || ('A' <= *str && *str <= 'F'); str++ )
+       {
+               base *= 16;
+               if('A' <= *str && *str <= 'F')
+                       base += *str - 'A' + 10;
+               else
+                       base += *str - '0';
+       }
+       
+       // Check separator
+       if(*str++ != ':')       return NULL;
+       
+       // Read buffer size
+       size = 0;
+       for( ; ('0' <= *str && *str <= '9') || ('A' <= *str && *str <= 'F'); str++ )
+       {
+               size *= 16;
+               if('A' <= *str && *str <= 'F')
+                       size += *str - 'A' + 10;
+               else
+                       size += *str - '0';
+       }
+       
+       // Check for NULL byte
+       if(*str != '\0')        return NULL;
+       
+       // Allocate and fill node
+       ret = malloc(sizeof(tVFS_Node));
+       memset(ret, 0, sizeof(tVFS_Node));
+       
+       // State
+       ret->ImplPtr = (void*)base;
+       ret->Size = size;
+       
+       // ACLs
+       ret->NumACLs = 1;
+       ret->ACLs = &gVFS_ACL_EveryoneRWX;
+       
+       // Functions
+       ret->Type = &gVFS_MemFileType;
+       
+       return ret;
+}
+
+/**
+ * \fn void VFS_MemFile_Close(tVFS_Node *Node)
+ * \brief Dereference and clean up a memory file
+ */
+void VFS_MemFile_Close(tVFS_Node *Node)
+{
+       Node->ReferenceCount --;
+       if( Node->ReferenceCount == 0 ) {
+               Node->ImplPtr = NULL;
+               free(Node);
+       }
+}
+
+/**
+ * \fn Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a memory file
+ */
+Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       // Check for use of free'd file
+       if(Node->ImplPtr == NULL)       return 0;
+       
+       // Check for out of bounds read
+       if(Offset > Node->Size) return 0;
+       
+       // Truncate data read if needed
+       if(Offset + Length > Node->Size)
+               Length = Node->Size - Offset;
+       
+       // Copy Data
+       memcpy(Buffer, (Uint8*)Node->ImplPtr + Offset, Length);
+       
+       return Length;
+}
+
+/**
+ * \fn Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a memory file
+ */
+Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       // Check for use of free'd file
+       if(Node->ImplPtr == NULL)       return 0;
+       
+       // Check for out of bounds read
+       if(Offset > Node->Size) return 0;
+       
+       // Truncate data read if needed
+       if(Offset + Length > Node->Size)
+               Length = Node->Size - Offset;
+       
+       // Copy Data
+       memcpy((Uint8*)Node->ImplPtr + Offset, Buffer, Length);
+       
+       return Length;
+}
diff --git a/KernelLand/Kernel/vfs/mmap.c b/KernelLand/Kernel/vfs/mmap.c
new file mode 100644 (file)
index 0000000..9fe9282
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Acess2 Kernel VFS
+ * - By John Hodge (thePowersGang)
+ *
+ * mmap.c
+ * - VFS_MMap support
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_ext.h>
+#include <vfs_int.h>
+
+#define MMAP_PAGES_PER_BLOCK   16
+
+// === STRUCTURES ===
+typedef struct sVFS_MMapPageBlock      tVFS_MMapPageBlock;
+struct sVFS_MMapPageBlock
+{
+       tVFS_MMapPageBlock      *Next;
+       Uint64  BaseOffset;     // Must be a multiple of MMAP_PAGES_PER_BLOCK*PAGE_SIZE
+       tPAddr  PhysAddrs[MMAP_PAGES_PER_BLOCK];
+};
+
+// === CODE ===
+void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset)
+{
+       tVFS_Handle     *h;
+       tVAddr  mapping_dest, mapping_base;
+        int    npages, pagenum;
+       tVFS_MMapPageBlock      *pb, *prev;
+
+       ENTER("pDestHint iLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset);
+
+       if( Flags & MMAP_MAP_ANONYMOUS )
+               Offset = (tVAddr)DestHint & 0xFFF;
+       
+       npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
+       pagenum = Offset / PAGE_SIZE;
+
+       mapping_base = (tVAddr)DestHint;
+       mapping_dest = mapping_base & ~(PAGE_SIZE-1);
+
+       // TODO: Locate space for the allocation
+
+       // Handle anonymous mappings
+       if( Flags & MMAP_MAP_ANONYMOUS )
+       {
+               size_t  ofs = 0;
+               LOG("%i pages anonymous to %p", npages, mapping_dest);
+               for( ; npages --; mapping_dest += PAGE_SIZE, ofs += PAGE_SIZE )
+               {
+                       if( MM_GetPhysAddr(mapping_dest) ) {
+                               // TODO: Set flags to COW if needed (well, if shared)
+                               MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
+                               LOG("clear from %p, %i bytes", (void*)(mapping_base + ofs),
+                                       PAGE_SIZE - (mapping_base & (PAGE_SIZE-1))
+                                       );
+                               memset( (void*)(mapping_base + ofs), 0, PAGE_SIZE - (mapping_base & (PAGE_SIZE-1)));
+                       }
+                       else {
+                               LOG("New empty page");
+                               // TODO: Map a COW zero page instead
+                               if( !MM_Allocate(mapping_dest) ) {
+                                       // TODO: Error
+                                       Log_Warning("VFS", "VFS_MMap: Anon alloc to %p failed", mapping_dest);
+                               }
+                               memset((void*)mapping_dest, 0, PAGE_SIZE);
+                               LOG("Anon map to %p", mapping_dest);
+                       }
+               }
+               LEAVE_RET('p', (void*)mapping_base);
+       }
+
+       h = VFS_GetHandle(FD);
+       if( !h || !h->Node )    LEAVE_RET('n', NULL);
+
+       LOG("h = %p", h);
+       
+       Mutex_Acquire( &h->Node->Lock );
+
+       // Search for existing mapping for each page
+       // - Sorted list of 16 page blocks
+       for(
+               pb = h->Node->MMapInfo, prev = NULL;
+               pb && pb->BaseOffset + MMAP_PAGES_PER_BLOCK < pagenum;
+               prev = pb, pb = pb->Next
+               );
+
+       LOG("pb = %p, pb->BaseOffset = %X", pb, pb ? pb->BaseOffset : 0);
+
+       // - Allocate a block if needed
+       if( !pb || pb->BaseOffset > pagenum )
+       {
+               void    *old_pb = pb;
+               pb = malloc( sizeof(tVFS_MMapPageBlock) );
+               if(!pb) {
+                       Mutex_Release( &h->Node->Lock );
+                       LEAVE_RET('n', NULL);
+               }
+               pb->Next = old_pb;
+               pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK;
+               memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
+               if(prev)
+                       prev->Next = pb;
+               else
+                       h->Node->MMapInfo = pb;
+       }
+
+       // - Map (and allocate) pages
+       while( npages -- )
+       {
+               if( MM_GetPhysAddr(mapping_dest) == 0 )
+               {
+                       if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
+                       {
+                               tVFS_NodeType   *nt = h->Node->Type;
+                               if( !nt ) 
+                               {
+                                       // TODO: error
+                               }
+                               else if( nt->MMap )
+                                       nt->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+                               else
+                               {
+                                        int    read_len;
+                                       // Allocate pages and read data
+                                       if( MM_Allocate(mapping_dest) == 0 ) {
+                                               // TODO: Unwrap
+                                               Mutex_Release( &h->Node->Lock );
+                                               LEAVE('n');
+                                               return NULL;
+                                       }
+                                       // TODO: Clip read length
+                                       read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+//                                     if( read_len != PAGE_SIZE ) {
+//                                             memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
+//                                     }
+                               }
+                               pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
+                               MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node );
+                               MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                               LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
+                                       pb->PhysAddrs[pagenum - pb->BaseOffset]);
+                       }
+                       else
+                       {
+                               MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                               MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                               LOG("Cached map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
+                                       pb->PhysAddrs[pagenum - pb->BaseOffset]);
+                       }
+                       h->Node->ReferenceCount ++;
+               
+                       // Set flags
+                       if( !(Protection & MMAP_PROT_WRITE) ) {
+                               MM_SetFlags(mapping_dest, MM_PFLAG_RO, MM_PFLAG_RO);
+                       }
+                       else {
+                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
+                       }
+                       
+                       if( Protection & MMAP_PROT_EXEC ) {
+                               MM_SetFlags(mapping_dest, MM_PFLAG_EXEC, MM_PFLAG_EXEC);
+                       }
+                       else {
+                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_EXEC);
+                       }
+               }
+               else
+               {
+                       LOG("Flag update on %p", mapping_dest);
+                       if( (MM_GetFlags(mapping_dest) & MM_PFLAG_RO) && (Protection & MMAP_PROT_WRITE) )
+                       {
+                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
+                       }
+               }
+               if( Flags & MMAP_MAP_PRIVATE )
+                       MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
+               pagenum ++;
+               mapping_dest += PAGE_SIZE;
+
+               // Roll on to next block if needed
+               if(pagenum - pb->BaseOffset == MMAP_PAGES_PER_BLOCK)
+               {
+                       if( pb->Next && pb->Next->BaseOffset == pagenum )
+                               pb = pb->Next;
+                       else
+                       {
+                               tVFS_MMapPageBlock      *oldpb = pb;
+                               pb = malloc( sizeof(tVFS_MMapPageBlock) );
+                               pb->Next = oldpb->Next;
+                               pb->BaseOffset = pagenum;
+                               memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
+                               oldpb->Next = pb;
+                       }
+                       pagenum = 0;
+               }
+       }
+       
+       Mutex_Release( &h->Node->Lock );
+
+       LEAVE('p', mapping_base);
+       return (void*)mapping_base;
+}
+
+int VFS_MUnmap(void *Addr, size_t Length)
+{
+       return 0;
+}
diff --git a/KernelLand/Kernel/vfs/mount.c b/KernelLand/Kernel/vfs/mount.c
new file mode 100644 (file)
index 0000000..1773218
--- /dev/null
@@ -0,0 +1,176 @@
+/* 
+ * Acess Micro - VFS Server version 1
+ */
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_int.h>
+#include <fs_sysfs.h>
+
+// === IMPORTS ===
+extern int     giVFS_MountFileID;
+extern char    *gsVFS_MountFile;
+
+// === PROTOTYPES ===
+#if 0
+ int   VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
+#endif
+void   VFS_UpdateMountFile(void);
+
+// === GLOBALS ===
+tMutex glVFS_MountList;
+tVFS_Mount     *gVFS_Mounts;
+tVFS_Mount     *gVFS_RootMount = NULL;
+Uint32 giVFS_NextMountIdent = 1;
+
+// === CODE ===
+/**
+ * \brief Mount a device
+ * \param Device       Device string to mount
+ * \param MountPoint   Destination for the mount
+ * \param Filesystem   Filesystem to use for the mount
+ * \param Options              Options to be passed to the filesystem
+ * \return -1 on Invalid FS, -2 on No Mem, 0 on success
+ * 
+ * Mounts the filesystem on \a Device at \a MountPoint using the driver
+ * \a Filesystem. The options in the string \a Options is passed to the
+ * driver's mount.
+ */
+int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
+{
+       tVFS_Mount      *mnt;
+       tVFS_Driver     *fs;
+        int    deviceLen = strlen(Device);
+        int    mountLen = strlen(MountPoint);
+        int    argLen = strlen(Options);
+       
+       // Get the filesystem
+       fs = VFS_GetFSByName(Filesystem);
+       if(!fs) {
+               Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
+               return -1;
+       }
+       
+       // Create mount information
+       mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
+       if(!mnt) {
+               return -2;
+       }
+       
+       // HACK: Forces VFS_ParsePath to fall back on root  
+       if(mountLen == 1 && MountPoint[0] == '/')
+               mnt->MountPointLen = 0;
+       else
+               mnt->MountPointLen = mountLen;
+       
+       // Fill Structure
+       mnt->Filesystem = fs;
+       
+       mnt->Device = &mnt->StrData[0];
+       memcpy( mnt->Device, Device, deviceLen+1 );
+       
+       mnt->MountPoint = &mnt->StrData[deviceLen+1];
+       memcpy( mnt->MountPoint, MountPoint, mountLen+1 );
+       
+       mnt->Options = &mnt->StrData[deviceLen+1+mountLen+1];
+       memcpy( mnt->Options, Options, argLen+1 );
+       
+       // Initialise Volume
+       mnt->RootNode = fs->InitDevice(Device, NULL);   //&ArgString);
+       if(!mnt->RootNode) {
+               free(mnt);
+               return -2;
+       }
+
+       mnt->Identifier = giVFS_NextMountIdent++;
+       #if 0
+       // Ensure identifiers don't repeat
+       // - Only a problem if there have been 4 billion mounts
+       while( giVFS_NextMountIdent == 0 || VFS_GetMountByIdent(giVFS_NextMountIdent) )
+               giVFS_NextMountIdent ++;
+       #endif
+       
+       // Set root
+       if(!gVFS_RootMount)     gVFS_RootMount = mnt;
+       
+       // Add to mount list
+       Mutex_Acquire( &glVFS_MountList );
+       {
+               tVFS_Mount      *tmp;
+               mnt->Next = NULL;
+               if(gVFS_Mounts) {
+                       for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
+                       tmp->Next = mnt;
+               }
+               else {
+                       gVFS_Mounts = mnt;
+               }
+       }
+       Mutex_Release( &glVFS_MountList );
+       
+       Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
+       
+       VFS_UpdateMountFile();
+       
+       return 0;
+}
+
+/**
+ * \brief Gets a mount point given the identifier
+ */
+tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
+{
+       tVFS_Mount      *mnt;
+       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
+       {
+               if(mnt->Identifier == MountID)
+                       return mnt;
+       }
+       return NULL;
+}
+
+/**
+ * \brief Updates the mount file buffer
+ * 
+ * Updates the ProcFS mounts file buffer to match the current mounts list.
+ */
+void VFS_UpdateMountFile(void)
+{
+        int    len = 0;
+       char    *buf;
+       tVFS_Mount      *mnt;
+       
+       // Format:
+       // <device>\t<location>\t<type>\t<options>\n
+       
+       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
+       {
+               len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
+                       + strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
+       }
+       
+       buf = malloc( len + 1 );
+       len = 0;
+       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
+       {
+               strcpy( &buf[len], mnt->Device );
+               len += strlen(mnt->Device);
+               buf[len++] = '\t';
+               
+               strcpy( &buf[len], mnt->MountPoint );
+               len += strlen(mnt->MountPoint);
+               buf[len++] = '\t';
+               
+               strcpy( &buf[len], mnt->Filesystem->Name );
+               len += strlen(mnt->Filesystem->Name);
+               buf[len++] = '\t';
+               
+               strcpy( &buf[len], mnt->Options );
+               len += strlen(mnt->Options);
+               buf[len++] = '\n';
+       }
+       buf[len] = 0;
+       
+       SysFS_UpdateFile( giVFS_MountFileID, buf, len );
+       if( gsVFS_MountFile )   free( gsVFS_MountFile );
+       gsVFS_MountFile = buf;
+}
diff --git a/KernelLand/Kernel/vfs/nodecache.c b/KernelLand/Kernel/vfs/nodecache.c
new file mode 100644 (file)
index 0000000..d2796c1
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * AcessMicro VFS
+ * - File IO Passthru's
+ */
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === TYPES ===
+typedef struct sCachedInode {
+       struct sCachedInode     *Next;
+       tVFS_Node       Node;
+} tCachedInode;
+typedef struct sInodeCache {
+       struct sInodeCache      *Next;
+        int    Handle;
+       tCachedInode    *FirstNode;     // Sorted List
+       Uint64  MaxCached;              // Speeds up Searching
+} tInodeCache;
+
+// === PROTOTYPES ===
+tInodeCache    *Inode_int_GetFSCache(int Handle);
+
+// === GLOBALS ===
+ int   gVFS_NextInodeHandle = 1;
+tShortSpinlock glVFS_InodeCache;
+tInodeCache    *gVFS_InodeCache = NULL;
+
+// === CODE ===
+/**
+ * \fn int Inode_GetHandle()
+ */
+int Inode_GetHandle()
+{
+       tInodeCache     *ent;
+       
+       ent = malloc( sizeof(tInodeCache) );
+       ent->MaxCached = 0;
+       ent->Handle = gVFS_NextInodeHandle++;
+       ent->Next = NULL;       ent->FirstNode = NULL;
+       
+       // Add to list
+       SHORTLOCK( &glVFS_InodeCache );
+       ent->Next = gVFS_InodeCache;
+       gVFS_InodeCache = ent;
+       SHORTREL( &glVFS_InodeCache );
+       
+       return gVFS_NextInodeHandle-1;
+}
+
+/**
+ * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+ * \brief Gets a node from the cache
+ */
+tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+{
+       tInodeCache     *cache;
+       tCachedInode    *ent;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return NULL;
+       
+       if(Inode > cache->MaxCached)    return NULL;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       for( ; ent; ent = ent->Next )
+       {
+               if(ent->Node.Inode < Inode)     continue;
+               if(ent->Node.Inode > Inode)     return NULL;
+               ent->Node.ReferenceCount ++;
+               return &ent->Node;
+       }
+       
+       return NULL;    // Should never be reached
+}
+
+/**
+ * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+ */
+tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+{
+       tInodeCache     *cache;
+       tCachedInode    *newEnt, *ent, *prev;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return NULL;
+       
+       if(Node->Inode > cache->MaxCached)
+               cache->MaxCached = Node->Inode;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       prev = (tCachedInode*) &cache->FirstNode;
+       for( ; ent; prev = ent, ent = ent->Next )
+       {
+               if(ent->Node.Inode < Node->Inode)       continue;
+               if(ent->Node.Inode == Node->Inode) {
+                       ent->Node.ReferenceCount ++;
+                       return &ent->Node;
+               }
+               break;
+       }
+       
+       // Create new entity
+       newEnt = malloc(sizeof(tCachedInode));
+       newEnt->Next = ent;
+       memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
+       prev->Next = newEnt;
+               
+       return &newEnt->Node;
+}
+
+/**
+ * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \brief Dereferences/Removes a cached node
+ */
+void Inode_UncacheNode(int Handle, Uint64 Inode)
+{
+       tInodeCache     *cache;
+       tCachedInode    *ent, *prev;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return ;
+       
+       if(Inode > cache->MaxCached)    return ;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       prev = (tCachedInode*) &cache->FirstNode;       // Special case removal
+       for( ; ent; prev = ent, ent = ent->Next )
+       {
+               if(ent->Node.Inode < Inode)     continue;
+               if(ent->Node.Inode > Inode)     return;
+               ent->Node.ReferenceCount --;
+               // Check if node needs to be freed
+               if(ent->Node.ReferenceCount == 0)
+               {
+                       prev->Next = ent->Next;
+                       if(ent->Node.Inode == cache->MaxCached)
+                       {
+                               if(ent != cache->FirstNode)
+                                       cache->MaxCached = prev->Node.Inode;
+                               else
+                                       cache->MaxCached = 0;
+                       }
+                               
+                       free(ent);
+               }
+               return ;
+       }
+       
+       return ;
+}
+
+/**
+ * \fn void Inode_ClearCache(int Handle)
+ * \brief Removes a cache
+ */
+void Inode_ClearCache(int Handle)
+{
+       tInodeCache     *cache;
+       tInodeCache     *prev = NULL;
+       tCachedInode    *ent, *next;
+       
+       // Find the cache
+       for(
+               cache = gVFS_InodeCache;
+               cache && cache->Handle < Handle;
+               prev = cache, cache = cache->Next
+               );
+       if(!cache || cache->Handle != Handle)   return;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       while( ent )
+       {
+               ent->Node.ReferenceCount = 1;
+               next = ent->Next;
+               
+               if(ent->Node.Type && ent->Node.Type->Close)
+                       ent->Node.Type->Close( &ent->Node );
+               free(ent);
+               
+               ent = next;
+       }
+       
+       // Free Cache
+       if(prev == NULL)
+               gVFS_InodeCache = cache->Next;
+       else
+               prev->Next = cache->Next;
+       free(cache);
+}
+
+/**
+ * \fn tInodeCache *Inode_int_GetFSCache(int Handle)
+ * \brief Gets a cache given it's handle
+ */
+tInodeCache *Inode_int_GetFSCache(int Handle)
+{
+       tInodeCache     *cache = gVFS_InodeCache;
+       // Find Cache
+       for( ; cache; cache = cache->Next )
+       {
+               if(cache->Handle > Handle)      continue;
+               if(cache->Handle < Handle) {
+                       Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle);
+                       return NULL;
+               }
+               break;
+       }
+       if(!cache) {
+               Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle);
+               return NULL;
+       }
+       
+       return cache;
+}
diff --git a/KernelLand/Kernel/vfs/open.c b/KernelLand/Kernel/vfs/open.c
new file mode 100644 (file)
index 0000000..1536d1a
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * Acess2 VFS
+ * - Open, Close and ChDir
+ */
+#define DEBUG  0
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+#include "vfs_ext.h"
+#include <threads.h>
+
+// === CONSTANTS ===
+#define        OPEN_MOUNT_ROOT 1
+#define MAX_PATH_SLASHES       256
+#define MAX_NESTED_LINKS       4
+#define MAX_PATH_LEN   255
+
+// === IMPORTS ===
+extern tVFS_Mount      *gVFS_RootMount;
+extern int     VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode);
+extern tVFS_Node       *VFS_MemFile_Create(const char *Path);
+
+// === PROTOTYPES ===
+ int   VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode );
+
+// === CODE ===
+/**
+ * \fn char *VFS_GetAbsPath(const char *Path)
+ * \brief Create an absolute path from a relative one
+ */
+char *VFS_GetAbsPath(const char *Path)
+{
+       char    *ret;
+        int    pathLen = strlen(Path);
+       char    *pathComps[MAX_PATH_SLASHES];
+       char    *tmpStr;
+       int             iPos = 0;
+       int             iPos2 = 0;
+       const char      *chroot = *Threads_GetChroot();
+        int    chrootLen;
+       const char      *cwd = *Threads_GetCWD();
+        int    cwdLen;
+       
+       ENTER("sPath", Path);
+       
+       // Memory File
+       if(Path[0] == '$') {
+               ret = malloc(strlen(Path)+1);
+               if(!ret) {
+                       Log_Warning("VFS", "VFS_GetAbsPath: malloc() returned NULL");
+                       return NULL;
+               }
+               strcpy(ret, Path);
+               LEAVE('p', ret);
+               return ret;
+       }
+       
+       // - Fetch ChRoot
+       if( chroot == NULL )
+               chroot = "";
+       chrootLen = strlen(chroot);
+       
+       // Check if the path is already absolute
+       if(Path[0] == '/') {
+               ret = malloc(chrootLen + pathLen + 1);
+               if(!ret) {
+                       Log_Warning("VFS", "VFS_GetAbsPath: malloc() returned NULL");
+                       return NULL;
+               }
+               strcpy(ret + chrootLen, Path);
+       }
+       else {
+               if(cwd == NULL) {
+                       cwd = "/";
+                       cwdLen = 1;
+               }
+               else {
+                       cwdLen = strlen(cwd);
+               }
+               // Prepend the current directory
+               ret = malloc(chrootLen + cwdLen + 1 + pathLen + 1 );
+               strcpy(ret+chrootLen, cwd);
+               ret[cwdLen] = '/';
+               strcpy(ret+chrootLen+cwdLen+1, Path);
+               //Log("ret = '%s'", ret);
+       }
+       
+       // Parse Path
+       pathComps[iPos++] = tmpStr = ret+chrootLen+1;
+       while(*tmpStr)
+       {
+               if(*tmpStr++ == '/')
+               {
+                       pathComps[iPos++] = tmpStr;
+                       if(iPos == MAX_PATH_SLASHES) {
+                               LOG("Path '%s' has too many elements", Path);
+                               free(ret);
+                               LEAVE('n');
+                               return NULL;
+                       }
+               }
+       }
+       pathComps[iPos] = NULL;
+       
+       // Cleanup
+       iPos2 = iPos = 0;
+       while(pathComps[iPos])
+       {
+               tmpStr = pathComps[iPos];
+               // Always Increment iPos
+               iPos++;
+               // ..
+               if(tmpStr[0] == '.' && tmpStr[1] == '.' && (tmpStr[2] == '/' || tmpStr[2] == '\0') )
+               {
+                       if(iPos2 != 0)
+                               iPos2 --;
+                       continue;
+               }
+               // .
+               if(tmpStr[0] == '.' && (tmpStr[1] == '/' || tmpStr[1] == '\0') )
+               {
+                       continue;
+               }
+               // Empty
+               if(tmpStr[0] == '/' || tmpStr[0] == '\0')
+               {
+                       continue;
+               }
+               
+               // Set New Position
+               pathComps[iPos2] = tmpStr;
+               iPos2++;
+       }
+       pathComps[iPos2] = NULL;
+       
+       // Build New Path
+       iPos2 = chrootLen + 1;  iPos = 0;
+       ret[0] = '/';
+       while(pathComps[iPos])
+       {
+               tmpStr = pathComps[iPos];
+               while(*tmpStr && *tmpStr != '/')
+               {
+                       ret[iPos2++] = *tmpStr;
+                       tmpStr++;
+               }
+               ret[iPos2++] = '/';
+               iPos++;
+       }
+       if(iPos2 > 1)
+               ret[iPos2-1] = 0;
+       else
+               ret[iPos2] = 0;
+
+       // Prepend the chroot
+       if(chrootLen)
+               memcpy( ret, chroot, chrootLen );
+       
+       LEAVE('s', ret);
+//     Log_Debug("VFS", "VFS_GetAbsPath: RETURN '%s'", ret);
+       return ret;
+}
+
+/**
+ * \fn char *VFS_ParsePath(const char *Path, char **TruePath)
+ * \brief Parses a path, resolving sysmlinks and applying permissions
+ */
+tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPoint)
+{
+       tVFS_Mount      *mnt, *longestMount;
+        int    cmp, retLength = 0;
+        int    ofs, nextSlash;
+        int    iNestedLinks = 0;
+       tVFS_Node       *curNode, *tmpNode;
+       char    *tmp;
+       char    path_buffer[MAX_PATH_LEN+1];
+       
+       ENTER("sPath pTruePath", Path, TruePath);
+       
+       // HACK: Memory File
+       if(Threads_GetUID() == 0 && Path[0] == '$') {
+               if(TruePath) {
+                       *TruePath = malloc(strlen(Path)+1);
+                       strcpy(*TruePath, Path);
+               }
+               curNode = VFS_MemFile_Create(Path);
+               if(MountPoint) {
+                       *MountPoint = NULL;
+               }
+               LEAVE('p', curNode);
+               return curNode;
+       }
+
+restart_parse: 
+       // For root we always fast return
+       if(Path[0] == '/' && Path[1] == '\0') {
+               if(TruePath) {
+                       *TruePath = malloc( gVFS_RootMount->MountPointLen+1 );
+                       strcpy(*TruePath, gVFS_RootMount->MountPoint);
+               }
+               if(MountPoint)  *MountPoint = gVFS_RootMount;
+               LEAVE('p', gVFS_RootMount->RootNode);
+               return gVFS_RootMount->RootNode;
+       }
+       
+       // Check if there is anything mounted
+       if(!gVFS_Mounts) {
+               Log_Error("VFS", "VFS_ParsePath - No filesystems mounted");
+               return NULL;
+       }
+       
+       // Find Mountpoint
+       longestMount = gVFS_RootMount;
+       for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
+       {
+               // Quick Check
+               if( Path[mnt->MountPointLen] != '/' && Path[mnt->MountPointLen] != '\0')
+                       continue;
+               // Length Check - If the length is smaller than the longest match sofar
+               if(mnt->MountPointLen < longestMount->MountPointLen)    continue;
+               // String Compare
+               cmp = strcmp(Path, mnt->MountPoint);
+               
+               #if OPEN_MOUNT_ROOT
+               // Fast Break - Request Mount Root
+               if(cmp == 0) {
+                       if(TruePath) {
+                               *TruePath = malloc( mnt->MountPointLen+1 );
+                               strcpy(*TruePath, mnt->MountPoint);
+                       }
+                       if(MountPoint)
+                               *MountPoint = mnt;
+                       LEAVE('p', mnt->RootNode);
+                       return mnt->RootNode;
+               }
+               #endif
+               // Not a match, continue
+               if(cmp != '/')  continue;
+               longestMount = mnt;
+       }
+       
+       // Save to shorter variable
+       mnt = longestMount;
+       
+       LOG("mnt = {MountPoint:\"%s\"}", mnt->MountPoint);
+       
+       // Initialise String
+       if(TruePath)
+       {
+               // Assumes that the resultant path (here) will not be > strlen(Path) + 1
+               *TruePath = malloc( strlen(Path) + 1 );
+               strcpy(*TruePath, mnt->MountPoint);
+               retLength = mnt->MountPointLen;
+       }
+       
+       curNode = mnt->RootNode;
+       curNode->ReferenceCount ++;     
+       // Parse Path
+       ofs = mnt->MountPointLen+1;
+       for(; (nextSlash = strpos(&Path[ofs], '/')) != -1; ofs += nextSlash + 1)
+       {
+               char    pathEle[nextSlash+1];
+               
+               // Empty String
+               if(nextSlash == 0)      continue;
+               
+               memcpy(pathEle, &Path[ofs], nextSlash);
+               pathEle[nextSlash] = 0;
+       
+               // Check permissions on root of filesystem
+               if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
+                       //Log("Permissions fail on '%s'", Path);
+                       goto _error;
+               }
+               
+               // Check if the node has a FindDir method
+               if( !curNode->Type->FindDir )
+               {
+                       //Log("FindDir fail on '%s'", Path);
+                       goto _error;
+               }
+               LOG("FindDir{=%p}(%p, '%s')", curNode->Type->FindDir, curNode, pathEle);
+               // Get Child Node
+               tmpNode = curNode->Type->FindDir(curNode, pathEle);
+               LOG("tmpNode = %p", tmpNode);
+               _CloseNode( curNode );
+               curNode = tmpNode;
+               
+               // Error Check
+               if(!curNode) {
+                       LOG("Node '%s' not found in dir '%s'", pathEle, Path);
+                       goto _error;
+               }
+               
+               // Handle Symbolic Links
+               if(curNode->Flags & VFS_FFLAG_SYMLINK) {
+                       if(TruePath) {
+                               free(*TruePath);
+                               *TruePath = NULL;
+                       }
+                       if(!curNode->Type || !curNode->Type->Read) {
+                               Log_Warning("VFS", "VFS_ParsePath - Read of symlink node %p'%s' is NULL",
+                                       curNode, Path);
+                               goto _error;
+                       }
+                       
+                       if(iNestedLinks > MAX_NESTED_LINKS) {
+                               Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded");
+                               goto _error;
+                       }
+                       
+                       // Parse Symlink Path
+                       // - Just update the path variable and restart the function
+                       // > Count nested symlinks and limit to some value (counteracts loops)
+                       {
+                                int    remlen = strlen(Path) - (ofs + nextSlash);
+                               if( curNode->Size + remlen > MAX_PATH_LEN ) {
+                                       Log_Warning("VFS", "VFS_ParsePath - Symlinked path too long");
+                                       goto _error;
+                               }
+                               curNode->Type->Read( curNode, 0, curNode->Size, path_buffer );
+                               path_buffer[ curNode->Size ] = '\0';
+                               LOG("path_buffer = '%s'", path_buffer);
+                               strcat(path_buffer, Path + ofs+nextSlash);
+                               
+                               Path = path_buffer;
+//                             Log_Debug("VFS", "VFS_ParsePath: Symlink translated to '%s'", Path);
+                               iNestedLinks ++;
+                       }
+
+                       // EVIL: Goto :)
+                       LOG("Symlink -> '%s', restart", Path);
+                       goto restart_parse;
+               }
+               
+               // Handle Non-Directories
+               if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) )
+               {
+                       Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory");
+                       goto _error;
+               }
+               
+               // Check if path needs extending
+               if(!TruePath)   continue;
+               
+               // Increase buffer space
+               tmp = realloc( *TruePath, retLength + strlen(pathEle) + 1 + 1 );
+               // Check if allocation succeeded
+               if(!tmp) {
+                       Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer");
+                       goto _error;
+               }
+               *TruePath = tmp;
+               // Append to path
+               (*TruePath)[retLength] = '/';
+               strcpy(*TruePath+retLength+1, pathEle);
+               
+               LOG("*TruePath = '%s'", *TruePath);
+               
+               // - Extend Path
+               retLength += nextSlash + 1;
+       }
+
+       // Check final finddir call     
+       if( !curNode->Type || !curNode->Type->FindDir ) {
+               Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path);
+               goto _error;
+       }
+       
+       // Get last node
+       LOG("FindDir(%p, '%s')", curNode, &Path[ofs]);
+       tmpNode = curNode->Type->FindDir(curNode, &Path[ofs]);
+       LOG("tmpNode = %p", tmpNode);
+       // Check if file was found
+       if(!tmpNode) {
+               LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
+               goto _error;
+       }
+       _CloseNode( curNode );
+       
+       if(TruePath)
+       {
+               // Increase buffer space
+               tmp = realloc(*TruePath, retLength + strlen(&Path[ofs]) + 1 + 1);
+               // Check if allocation succeeded
+               if(!tmp) {
+                       Log_Warning("VFS", "VFS_ParsePath -  Unable to reallocate true path buffer");
+                       goto _error;
+               }
+               *TruePath = tmp;
+               // Append to path
+               (*TruePath)[retLength] = '/';
+               strcpy(*TruePath + retLength + 1, &Path[ofs]);
+               // - Extend Path
+               //retLength += strlen(tmpNode->Name) + 1;
+       }
+
+       if( MountPoint ) {
+               *MountPoint = mnt;
+       }
+       
+       LEAVE('p', tmpNode);
+       return tmpNode;
+
+_error:
+       _CloseNode( curNode );
+       
+       if(TruePath && *TruePath) {
+               free(*TruePath);
+               *TruePath = NULL;
+       }
+       LEAVE('n');
+       return NULL;
+}
+
+/**
+ * \brief Create and return a handle number for the given node and mode
+ */
+int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode )
+{
+        int    i;
+       
+       ENTER("pNode pMount xMode", Node, Mount, Mode);
+
+       i = 0;
+       i |= (Mode & VFS_OPENFLAG_EXEC) ? VFS_PERM_EXECUTE : 0;
+       i |= (Mode & VFS_OPENFLAG_READ) ? VFS_PERM_READ : 0;
+       i |= (Mode & VFS_OPENFLAG_WRITE) ? VFS_PERM_WRITE : 0;
+       
+       LOG("i = 0b%b", i);
+       
+       // Permissions Check
+       if( !VFS_CheckACL(Node, i) ) {
+               _CloseNode( Node );
+               Log_Log("VFS", "VFS_int_CreateHandle: Permissions Failed");
+               errno = EACCES;
+               LEAVE_RET('i', -1);
+       }
+       
+       i = VFS_AllocHandle( !!(Mode & VFS_OPENFLAG_USER), Node, Mode );
+       if( i < 0 ) {
+               Log_Notice("VFS", "VFS_int_CreateHandle: Out of handles");
+               errno = ENFILE;
+               LEAVE_RET('i', -1);
+       }
+
+       VFS_GetHandle(i)->Mount = Mount;
+
+       LEAVE_RET('x', i);
+}
+
+/**
+ * \fn int VFS_Open(const char *Path, Uint Mode)
+ * \brief Open a file
+ */
+int VFS_Open(const char *Path, Uint Flags)
+{
+       return VFS_OpenEx(Path, Flags, 0);
+}
+
+int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
+{
+       tVFS_Node       *node;
+       tVFS_Mount      *mnt;
+       char    *absPath;
+       
+       ENTER("sPath xFlags oMode", Path, Flags);
+       
+       // Get absolute path
+       absPath = VFS_GetAbsPath(Path);
+       if(absPath == NULL) {
+               Log_Warning("VFS", "VFS_Open: Path expansion failed '%s'", Path);
+               LEAVE_RET('i', -1);
+       }
+       LOG("absPath = \"%s\"", absPath);
+       
+       // Parse path and get mount point
+       node = VFS_ParsePath(absPath, NULL, &mnt);
+       
+       // Create file if requested and it doesn't exist
+       if( !node && (Flags & VFS_OPENFLAG_CREATE) )
+       {
+               // TODO: Translate `Mode` into ACL and node flags
+               // Get parent, create node
+               VFS_MkNod(absPath, 0);
+               node = VFS_ParsePath(absPath, NULL, &mnt);
+       }
+       
+       // Free generated path
+       free(absPath);
+       
+       // Check for error
+       if(!node)
+       {
+               LOG("Cannot find node");
+               errno = ENOENT;
+               LEAVE_RET('i', -1);
+       }
+       
+       // Check for symlinks
+       if( !(Flags & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
+       {
+               char    tmppath[node->Size+1];
+               if( node->Size > MAX_PATH_LEN ) {
+                       Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size);
+                       LEAVE_RET('i', -1);
+               }
+               if( !node->Type || !node->Type->Read ) {
+                       Log_Warning("VFS", "VFS_Open - No read method on symlink");
+                       LEAVE_RET('i', -1);
+               }
+               // Read symlink's path
+               node->Type->Read( node, 0, node->Size, tmppath );
+               tmppath[ node->Size ] = '\0';
+               _CloseNode( node );
+               // Open the target
+               node = VFS_ParsePath(tmppath, NULL, &mnt);
+               if(!node) {
+                       LOG("Cannot find symlink target node (%s)", tmppath);
+                       errno = ENOENT;
+                       LEAVE_RET('i', -1);
+               }
+       }
+
+       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Flags));
+}
+
+
+/**
+ * \brief Open a file from an open directory
+ */
+int VFS_OpenChild(int FD, const char *Name, Uint Mode)
+{
+       tVFS_Handle     *h;
+       tVFS_Node       *node;
+       
+       ENTER("xFD sName xMode", FD, Name, Mode);
+
+       // Get handle
+       h = VFS_GetHandle(FD);
+       if(h == NULL) {
+               Log_Warning("VFS", "VFS_OpenChild - Invalid file handle 0x%x", FD);
+               errno = EINVAL;
+               LEAVE_RET('i', -1);
+       }
+       
+       // Check for directory
+       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+               Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory");
+               errno = ENOTDIR;
+               LEAVE_RET('i', -1);
+       }
+
+       // Sanity check
+       if( !h->Node->Type || !h->Node->Type->FindDir ) {
+               Log_Error("VFS", "VFS_OpenChild - Node does not have a type/is missing FindDir");
+               errno = ENOTDIR;
+               LEAVE_RET('i', -1);
+       }
+       
+       // Find Child
+       node = h->Node->Type->FindDir(h->Node, Name);
+       if(!node) {
+               errno = ENOENT;
+               LEAVE_RET('i', -1);
+       }
+
+       LEAVE_RET('x', VFS_int_CreateHandle(node, h->Mount, Mode));
+}
+
+int VFS_OpenInode(Uint32 Mount, Uint64 Inode, int Mode)
+{
+       tVFS_Mount      *mnt;
+       tVFS_Node       *node;
+
+       ENTER("iMount XInode xMode", Mount, Inode, Mode);
+       
+       // Get mount point
+       mnt = VFS_GetMountByIdent(Mount);
+       if( !mnt ) {
+               LOG("Mount point ident invalid");
+               errno = ENOENT;
+               LEAVE_RET('i', -1);
+       }
+       
+       // Does the filesystem support this?
+       if( !mnt->Filesystem->GetNodeFromINode ) {
+               LOG("Filesystem does not support inode accesses");
+               errno = ENOENT;
+               LEAVE_RET('i', -1);
+       }
+
+       // Get node
+       node = mnt->Filesystem->GetNodeFromINode(mnt->RootNode, Inode);
+       if( !node ) {
+               LOG("Unable to find inode");
+               errno = ENOENT;
+               LEAVE_RET('i', -1);
+       }
+       
+       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Mode));
+}
+
+/**
+ * \fn void VFS_Close(int FD)
+ * \brief Closes an open file handle
+ */
+void VFS_Close(int FD)
+{
+       tVFS_Handle     *h;
+       
+       // Get handle
+       h = VFS_GetHandle(FD);
+       if(h == NULL) {
+               Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD);
+               return;
+       }
+       
+       #if VALIDATE_VFS_FUNCTIPONS
+       if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) {
+               Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)",
+                       h->Node, h->Node->Close);
+               return ;
+       }
+       #endif
+       
+       _CloseNode(h->Node);
+       
+       h->Node = NULL;
+}
+
+/**
+ * \brief Change current working directory
+ */
+int VFS_ChDir(const char *Dest)
+{
+       char    *buf;
+        int    fd;
+       tVFS_Handle     *h;
+       
+       // Create Absolute
+       buf = VFS_GetAbsPath(Dest);
+       if(buf == NULL) {
+               Log_Notice("VFS", "VFS_ChDir: Path expansion failed");
+               return -1;
+       }
+       
+       // Check if path exists
+       fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
+       if(fd == -1) {
+               Log_Notice("VFS", "VFS_ChDir: Path is invalid");
+               return -1;
+       }
+       
+       // Get node so we can check for directory
+       h = VFS_GetHandle(fd);
+       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+               Log("VFS_ChDir: Path is not a directory");
+               VFS_Close(fd);
+               return -1;
+       }
+       
+       // Close file
+       VFS_Close(fd);
+       
+       {
+               char    **cwdptr = Threads_GetCWD();
+               // Free old working directory
+               if( *cwdptr )   free( *cwdptr );
+               // Set new
+               *cwdptr = buf;
+       }
+       
+       Log("Updated CWD to '%s'", buf);
+       
+       return 1;
+}
+
+/**
+ * \fn int VFS_ChRoot(char *New)
+ * \brief Change current root directory
+ */
+int VFS_ChRoot(const char *New)
+{
+       char    *buf;
+        int    fd;
+       tVFS_Handle     *h;
+       
+       if(New[0] == '/' && New[1] == '\0')
+               return 1;       // What a useless thing to ask!
+       
+       // Create Absolute
+       buf = VFS_GetAbsPath(New);
+       if(buf == NULL) {
+               LOG("Path expansion failed");
+               return -1;
+       }
+       
+       // Check if path exists
+       fd = VFS_Open(buf, VFS_OPENFLAG_EXEC);
+       if(fd == -1) {
+               LOG("Path is invalid");
+               return -1;
+       }
+       
+       // Get node so we can check for directory
+       h = VFS_GetHandle(fd);
+       if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+               LOG("Path is not a directory");
+               VFS_Close(fd);
+               return -1;
+       }
+       
+       // Close file
+       VFS_Close(fd);
+
+       // Update       
+       {
+               char    **chroot_ptr = Threads_GetChroot();
+               if( *chroot_ptr )       free( *chroot_ptr );
+               *chroot_ptr = buf;
+       }
+       
+       LOG("Updated Root to '%s'", buf);
+       
+       return 1;
+}
+
+// === EXPORTS ===
+EXPORT(VFS_Open);
+EXPORT(VFS_Close);
diff --git a/KernelLand/Kernel/vfs/select.c b/KernelLand/Kernel/vfs/select.c
new file mode 100644 (file)
index 0000000..439afc0
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Acess2 VFS
+ * - By thePowersGang (John Hodge)
+ * 
+ * select.c
+ * - Implements the select() system call (and supporting code)
+ *
+ * TODO: Implment timeouts (via an alarm event?)
+ * TODO: Remove malloc for read/write queues
+ */
+#define DEBUG  0
+#include <acess.h>
+#include "vfs.h"
+#include "vfs_int.h"
+#include "vfs_ext.h"
+#include <semaphore.h>
+#include <threads.h>
+#include <events.h>
+
+// === CONSTANTS ===
+#define        NUM_THREADS_PER_ALLOC   4
+
+// === IMPORTS ===
+extern tThread *Proc_GetCurThread(void);
+
+// === TYPES ===
+typedef struct sVFS_SelectListEnt      tVFS_SelectListEnt;
+
+// === STRUCTURES ===
+struct sVFS_SelectListEnt
+{
+       tVFS_SelectListEnt      *Next;
+       tThread *Threads[NUM_THREADS_PER_ALLOC];
+};
+
+// NOTE: Typedef is in vfs.h
+struct sVFS_SelectList
+{
+       tMutex  Lock;
+       tVFS_SelectListEnt      FirstEnt;
+};
+
+// === PROTOTYPES ===
+// int VFS_SelectNode(tVFS_Node *Node, enum eVFS_SelectTypes Type, tTime *Timeout);
+// int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
+// int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull);
+// int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable);
+// int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState);
+ int   VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, int **Flag, int *WantedFlag, int *MaxAllowed);
+ int   VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
+ int   VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
+ int   VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed);
+void   VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread);
+void   VFS_int_Select_SignalAll(tVFS_SelectList *List);
+
+// === GLOBALS ===
+
+// === FUNCTIONS ===
+int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *Name)
+{
+       tThread *thisthread = Proc_GetCurThread();
+        int    ret, type;
+       
+       ENTER("pNode iTypeFlags pTimeout sName", Node, TypeFlags, Timeout, Name);
+       
+       // Initialise
+       for( type = 0; type < 3; type ++ )
+       {
+               tVFS_SelectList **list;
+                int    *flag, wanted, maxAllowed;
+               if( !(TypeFlags & (1 << type)) )        continue;
+               if( VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed) ) {
+                       LEAVE('i', -1);
+                       return -1;
+               }
+       
+               // Alloc if needed
+               if( !*list )    *list = calloc(1, sizeof(tVFS_SelectList));
+       
+               VFS_int_Select_AddThread(*list, thisthread, maxAllowed);
+               if( *flag == wanted )
+               {
+                       VFS_int_Select_RemThread(*list, thisthread);
+                       LEAVE('i', 1);
+                       return 1;
+               }
+       }
+
+       // - Fast return for polling
+       if( Timeout && *Timeout == 0 )  return 0;
+
+       // Wait for things      
+       if( !Timeout || *Timeout > 0 )
+       {
+               LOG("Semaphore_Wait()");
+               // TODO: Actual timeout
+               Threads_WaitEvents( THREAD_EVENT_VFS );
+       }
+       
+       // Get return value
+       ret = 0;
+       for( type = 0; type < 3; type ++ )
+       {
+               tVFS_SelectList **list;
+                int    *flag, wanted, maxAllowed;
+               if( !(TypeFlags & (1 << type)) )        continue;
+               VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed);
+               LOG("VFS_int_Select_RemThread()");
+               VFS_int_Select_RemThread(*list, thisthread);
+               ret = ret || *flag == wanted;
+       }
+       
+       LEAVE('i', ret);
+       return ret;
+}
+
+int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel)
+{
+       tThread *thisthread = Proc_GetCurThread();
+        int    ret;
+       
+       ENTER("iMaxHandle pReadHandles pWriteHandles pErrHandles pTimeout bIsKernel",
+               MaxHandle, ReadHandles, WriteHandles, ErrHandles, Timeout, IsKernel);
+       
+       // Notes: The idea is to make sure we only enter wait (Threads_WaitEvents)
+       // if we are going to be woken up (either by an event at a later time,
+       // or by an event that happened while or before we were registering).
+       // Hence, register must happen _before_ we check the state flag
+       // (See VFS_int_Select_Register), that way either we pick up the flag,
+       // or the semaphore is incremeneted (or both, but never none)
+       
+       // Register with nodes
+       ret  = VFS_int_Select_Register(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+       ret += VFS_int_Select_Register(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+       ret += VFS_int_Select_Register(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+       
+       LOG("Register ret = %i", ret);
+       
+       // If there were events waiting, de-register and return
+       if( ret > 0 )
+       {
+               ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+               ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+               ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+               LEAVE('i', ret);
+               return ret;
+       }
+       
+       // TODO: Implement timeout
+       LOG("Timeout = %p", Timeout);
+       
+       // Wait (only if there is no timeout, or it is greater than zero
+       if( !Timeout || *Timeout > 0 )
+       {
+               // TODO: Timeout
+               // TODO: Allow extra events to be waited upon
+               Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
+       }
+       
+       // Fill output (modify *Handles)
+       // - Also, de-register
+       ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+       ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+       ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+       LEAVE('i', ret);
+       return ret;
+}
+
+// Mark a node as having data ready for reading
+int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable)
+{
+       ENTER("pNode bIsDataAvaliable", Node, IsDataAvaliable);
+       Node->DataAvaliable = !!IsDataAvaliable;
+       if( Node->DataAvaliable )
+               VFS_int_Select_SignalAll(Node->ReadThreads);
+       LEAVE('i', 0);
+       return 0;
+}
+
+// Mark a node as having a full buffer
+int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
+{
+       ENTER("pNode bIsBufferFull", Node, IsBufferFull);
+       Node->BufferFull = !!IsBufferFull;
+       if( !Node->BufferFull )
+               VFS_int_Select_SignalAll(Node->WriteThreads);
+       LEAVE('i', 0);
+       return 0;
+}
+
+// Mark a node as errored
+int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState)
+{
+       ENTER("pNode bIsErrorState", Node, IsErrorState);
+       Node->ErrorOccurred = !!IsErrorState;
+       if( Node->ErrorOccurred )
+               VFS_int_Select_SignalAll(Node->ErrorThreads);
+       LEAVE('i', 0);
+       return 0;
+}
+
+// --- Internal ---
+int VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, int **Flag, int *WantedFlag, int *MaxAllowed)
+{
+       // Get the type of the listen
+       switch(Type)
+       {
+       case 0: // Read
+               if(List)        *List = &Node->ReadThreads;
+               if(Flag)        *Flag = &Node->DataAvaliable;
+               if(WantedFlag)  *WantedFlag = 1;
+               if(MaxAllowed)  *MaxAllowed = 1;        // Max of 1 for read
+               break;
+       case 1: // Write
+               if(List)        *List = &Node->WriteThreads;
+               if(Flag)        *Flag = &Node->BufferFull;
+               if(WantedFlag)  *WantedFlag = 0;
+               if(MaxAllowed)  *MaxAllowed = 1;        // Max of 1 for write
+               break;
+       case 2: // Error
+               if(List)        *List = &Node->ErrorThreads;
+               if(Flag)        *Flag = &Node->ErrorOccurred;
+               if(WantedFlag)  *WantedFlag = 1;
+               if(MaxAllowed)  *MaxAllowed = -1;       // No max for error listeners
+               break;
+       default:
+               Log_Error("VFS", "VFS_int_Select_GetType: BUG CHECK, Unknown Type %i", Type);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * \return Number of files with an action
+ */
+int VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
+{
+        int    i, numFlagged = 0;
+       tVFS_SelectList **list;
+        int    *flag, wantedFlagValue;
+        int    maxAllowed;
+       
+       if( !Handles )  return 0;
+       
+       ENTER("pThread iMaxHandle pHandles iType iIsKernel", Thread, MaxHandle, Handles, Type, IsKernel);
+       
+       for( i = 0; i < MaxHandle; i ++ )
+       {
+               tVFS_Handle     *handle;
+               
+               // Is the descriptor set
+               if( !FD_ISSET(i, Handles) )     continue;
+               LOG("FD #%i", i);
+               
+               handle = VFS_GetHandle( i | (IsKernel?VFS_KERNEL_FLAG:0) );
+               // Is the handle valid?
+               if( !handle || !handle->Node )
+               {
+                       if( Type == 2 ) {       // Bad FD counts as an error
+                               numFlagged ++;
+                       }
+                       else {
+                               FD_CLR(i, Handles);
+                       }
+                       continue;
+               }
+       
+               // Get the type of the listen
+               if( VFS_int_Select_GetType(Type, handle->Node, &list, &flag, &wantedFlagValue, &maxAllowed) ) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               
+               // Alloc if needed
+               if( !*list ) {
+                       *list = calloc(1, sizeof(tVFS_SelectList));
+               }
+               
+               // Register
+               if( VFS_int_Select_AddThread(*list, Thread, maxAllowed ) )
+               {
+                       // Oops, error (or just no space)
+                       FD_CLR(i, Handles);
+               }
+               
+               // Check for the flag
+               if( !!*flag == !!wantedFlagValue )
+                       numFlagged ++;
+       }
+       
+       LEAVE('i', numFlagged);
+       
+       return numFlagged;
+}
+/**
+ * \return Number of files with an action
+ */
+int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
+{
+        int    i, numFlagged = 0;
+       tVFS_SelectList **list;
+        int    *flag, wantedFlagValue;
+       
+       if( !Handles )  return 0;
+       
+       ENTER("pThread iMaxHandle pHandles iType iIsKernel", Thread, MaxHandle, Handles, Type, IsKernel);
+       
+       for( i = 0; i < MaxHandle; i ++ )
+       {
+               tVFS_Handle     *handle;
+               
+               // Is the descriptor set
+               if( !FD_ISSET(i, Handles) )     continue;
+               LOG("FD #%i", i);
+               
+               handle = VFS_GetHandle( i | (IsKernel?VFS_KERNEL_FLAG:0) );
+               // Is the handle valid?
+               if( !handle || !handle->Node )
+               {
+                       if( Type == 2 ) {       // Bad FD counts as an error
+                               numFlagged ++;
+                       }
+                       else {
+                               FD_CLR(i, Handles);
+                       }
+                       continue;
+               }
+       
+               // Get the type of the listen
+       
+               // Get the type of the listen
+               if( VFS_int_Select_GetType(Type, handle->Node, &list, &flag, &wantedFlagValue, NULL) ) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               
+               // Remove
+               VFS_int_Select_RemThread(*list, Thread );
+               
+               // Check for the flag
+               if( !!*flag == !!wantedFlagValue ) {
+                       numFlagged ++;
+               }
+               else {
+                       FD_CLR(i, Handles);
+               }
+       }
+       
+       LEAVE('i', numFlagged);
+       
+       return numFlagged;
+}
+
+/**
+ * \return Boolean failure
+ */
+int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed)
+{
+        int    i, count = 0;
+       tVFS_SelectListEnt      *block, *prev;
+       
+       ENTER("pList pThread iMaxAllowed", List, Thread, MaxAllowed);
+       
+       // Lock to avoid concurrency issues
+       Mutex_Acquire(&List->Lock);
+       
+       block = &List->FirstEnt;
+       
+       // Look for free space
+       do
+       {
+               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
+               {
+                       if( block->Threads[i] == NULL )
+                       {
+                               block->Threads[i] = Thread;
+                               Mutex_Release(&List->Lock);
+                               LEAVE('i', 0);
+                               return 0;
+                       }
+                       count ++;
+                       if( MaxAllowed && count >= MaxAllowed ) {
+                               LEAVE('i', 1);
+                               return 1;
+                       }
+               }
+               
+               prev = block;
+               block = block->Next;
+       } while(block);
+       
+       LOG("New block");
+       
+       // Create new block
+       block = malloc( sizeof(tVFS_SelectListEnt) );
+       if( !block ) {
+               Log_Warning("VFS", "VFS_int_Select_AddThread: malloc() failed");
+               Mutex_Release(&List->Lock);
+               return -1;
+       }
+       block->Next = NULL;
+       block->Threads[0] = Thread;
+       for( i = 1; i < NUM_THREADS_PER_ALLOC; i ++ )
+       {
+               block->Threads[i] = NULL;
+       }
+       
+       // Add to list
+       prev->Next = block;
+       
+       // Release
+       Mutex_Release(&List->Lock);
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
+{
+        int    i;
+       tVFS_SelectListEnt      *block, *prev = NULL;
+       
+       ENTER("pList pThread", List, Thread);
+       
+       // Lock to avoid concurrency issues
+       Mutex_Acquire(&List->Lock);
+       
+       block = &List->FirstEnt;
+       
+       // Look for the thread
+       do
+       {
+               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
+               {
+                       if( block->Threads[i] == Thread )
+                       {
+                               block->Threads[i] = NULL;
+                               
+                               // Check if this block is empty
+                               if( block != &List->FirstEnt )
+                               {
+                                       for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
+                                               if( block->Threads[i] )
+                                                       break;
+                                       // If empty, free it
+                                       if( i == NUM_THREADS_PER_ALLOC ) {
+                                               LOG("Deleting block");
+                                               prev->Next = block->Next;
+                                               free(block);
+                                       }
+                                       //TODO: If not empty, check if it can be merged downwards
+                               }
+                               
+                               Mutex_Release(&List->Lock);
+                               LEAVE('-');
+                               return ;
+                       }
+               }
+               
+               prev = block;
+               block = block->Next;
+       } while(block);
+       
+       // Not on list, is this an error?
+       
+       Mutex_Release(&List->Lock);
+       
+       LOG("Not on list");
+       LEAVE('-');
+}
+
+/**
+ * \brief Signal all threads on a list
+ */
+void VFS_int_Select_SignalAll(tVFS_SelectList *List)
+{
+        int    i;
+       tVFS_SelectListEnt      *block;
+       
+       if( !List )     return ;
+       
+       ENTER("pList", List);
+       
+       // Lock to avoid concurrency issues
+       Mutex_Acquire(&List->Lock);
+       
+       block = &List->FirstEnt;
+       
+       // Look for the thread
+       do
+       {
+               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
+               {
+                       if( block->Threads[i]  )
+                       {
+                               LOG("block(%p)->Threads[%i] = %p", block, i, block->Threads[i]);
+                               Threads_PostEvent( block->Threads[i], THREAD_EVENT_VFS );
+                       }
+               }
+               
+               block = block->Next;
+       } while(block);
+       
+       Mutex_Release(&List->Lock);
+       
+       LEAVE('-');
+}
diff --git a/KernelLand/Kernel/workqueue.c b/KernelLand/Kernel/workqueue.c
new file mode 100644 (file)
index 0000000..b1a6385
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * workqueue.c
+ * - Worker FIFO Queue (Single Consumer, Interrupt Producer)
+ */
+#include <acess.h>
+#include <workqueue.h>
+#include <threads_int.h>
+
+// === CODE ===
+void Workqueue_Init(tWorkqueue *Queue, const char *Name, size_t NextOfset)
+{
+       Queue->Name = Name;
+       Queue->NextOffset = NextOfset;
+}
+
+void *Workqueue_GetWork(tWorkqueue *Queue)
+{
+       tThread *us;
+
+       for( ;; )
+       {
+               // Check for work
+               SHORTLOCK(&Queue->Protector);
+               if(Queue->Head)
+               {
+                       void *ret = Queue->Head;
+                       Queue->Head = *( (void**)ret + Queue->NextOffset/sizeof(void*) );
+                       if(Queue->Tail == ret)
+                               Queue->Tail = NULL;
+                       SHORTREL(&Queue->Protector);    
+                       return ret;
+               }
+               
+               // Go to sleep
+               SHORTLOCK(&glThreadListLock);
+               us = Threads_RemActive();
+               us->WaitPointer = Queue;
+               us->Status = THREAD_STAT_QUEUESLEEP;
+               Queue->Sleeper = us;
+               SHORTREL(&Queue->Protector);    
+               SHORTREL(&glThreadListLock);
+               
+               // Yield and sleep
+               Threads_Yield();
+               if(us->Status == THREAD_STAT_QUEUESLEEP) {
+                       // Why are we awake?!
+               }
+
+               us->WaitPointer = NULL;
+       }
+}
+
+void Workqueue_AddWork(tWorkqueue *Queue, void *Ptr)
+{
+       SHORTLOCK(&Queue->Protector);
+
+       if( Queue->Tail )
+               *( (void**)Queue->Tail + Queue->NextOffset/sizeof(void*) ) = Ptr;
+       else
+               Queue->Head = Ptr;
+       Queue->Tail = Ptr;
+       
+       if( Queue->Sleeper )
+       {       
+               if( Queue->Sleeper->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(Queue->Sleeper);
+               Queue->Sleeper = NULL;
+       }
+       SHORTREL(&Queue->Protector);
+}
diff --git a/KernelLand/Modules/Display/BochsGA/Makefile b/KernelLand/Modules/Display/BochsGA/Makefile
new file mode 100644 (file)
index 0000000..2df219a
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = bochsvbe.o
+NAME = BochsGA
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Display/BochsGA/bochsvbe.c b/KernelLand/Modules/Display/BochsGA/bochsvbe.c
new file mode 100644 (file)
index 0000000..806c1c1
--- /dev/null
@@ -0,0 +1,362 @@
+/**\r
+ * Acess2 Bochs graphics adapter Driver\r
+ * - By John Hodge (thePowersGang)\r
+ *\r
+ * bochsvbe.c\r
+ * - Driver core\r
+ */\r
+#define DEBUG  0\r
+#define VERSION        VER2(0,10)\r
+\r
+#include <acess.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <api_drv_video.h>\r
+\r
+// === TYPES ===\r
+typedef struct sBGA_Mode {\r
+       Uint16  width;\r
+       Uint16  height;\r
+       Uint16  bpp;\r
+       Uint32  fbSize;\r
+}      tBGA_Mode;\r
+\r
+// === CONSTANTS ===\r
+#define        BGA_LFB_MAXSIZE (1024*768*4)\r
+#define        VBE_DISPI_BANK_ADDRESS  0xA0000\r
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000\r
+#define VBE_DISPI_IOPORT_INDEX 0x01CE\r
+#define        VBE_DISPI_IOPORT_DATA   0x01CF\r
+#define        VBE_DISPI_DISABLED      0x00\r
+#define VBE_DISPI_ENABLED      0x01\r
+#define        VBE_DISPI_LFB_ENABLED   0x40\r
+#define        VBE_DISPI_NOCLEARMEM    0x80\r
+enum {\r
+       VBE_DISPI_INDEX_ID,\r
+       VBE_DISPI_INDEX_XRES,\r
+       VBE_DISPI_INDEX_YRES,\r
+       VBE_DISPI_INDEX_BPP,\r
+       VBE_DISPI_INDEX_ENABLE,\r
+       VBE_DISPI_INDEX_BANK,\r
+       VBE_DISPI_INDEX_VIRT_WIDTH,\r
+       VBE_DISPI_INDEX_VIRT_HEIGHT,\r
+       VBE_DISPI_INDEX_X_OFFSET,\r
+       VBE_DISPI_INDEX_Y_OFFSET\r
+};\r
+\r
+extern void MM_DumpTables(tVAddr Start, tVAddr End);\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int   BGA_Install(char **Arguments);\r
+void   BGA_Uninstall();\r
+// Internal\r
+void   BGA_int_WriteRegister(Uint16 reg, Uint16 value);\r
+Uint16 BGA_int_ReadRegister(Uint16 reg);\r
+void   BGA_int_SetBank(Uint16 bank);\r
+void   BGA_int_SetMode(Uint16 width, Uint16 height);\r
+ int   BGA_int_UpdateMode(int id);\r
+ int   BGA_int_FindMode(tVideo_IOCtl_Mode *info);\r
+ int   BGA_int_ModeInfo(tVideo_IOCtl_Mode *info);\r
+ int   BGA_int_MapFB(void *Dest);\r
+// Filesystem\r
+Uint64 BGA_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 BGA_Write(tVFS_Node *Node, Uint64 off, Uint64 len, const void *buffer);\r
+ int   BGA_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, BochsGA, BGA_Install, NULL, "PCI", NULL);\r
+tVFS_NodeType  gBGA_NodeType = {\r
+       .Read = BGA_Read,\r
+       .Write = BGA_Write,\r
+       .IOCtl = BGA_IOCtl\r
+       };\r
+tDevFS_Driver  gBGA_DriverStruct = {\r
+       NULL, "BochsGA",\r
+       {.Type = &gBGA_NodeType}\r
+       };\r
+ int   giBGA_CurrentMode = -1;\r
+tVideo_IOCtl_Pos       gBGA_CursorPos = {-1,-1};\r
+Uint   *gBGA_Framebuffer;\r
+const tBGA_Mode        *gpBGA_CurrentMode;\r
+const tBGA_Mode        gBGA_Modes[] = {\r
+       {640,480,32, 640*480*4},\r
+       {800,600,32, 800*600*4},\r
+       {1024,768,32, 1024*768*4}\r
+};\r
+#define        BGA_MODE_COUNT  (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0]))\r
+tDrvUtil_Video_BufInfo gBGA_DrvUtil_BufInfo;\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int BGA_Install(char **Arguments)\r
+ */\r
+int BGA_Install(char **Arguments)\r
+{\r
+        int    version = 0;\r
+       tPAddr  base;\r
+       tPCIDev dev;\r
+       \r
+       // Check BGA Version\r
+       version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
+       LOG("version = 0x%x", version);\r
+       \r
+       // NOTE: This driver was written for BGA versions >= 0xBOC2\r
+       // NOTE: However, Qemu is braindead and doesn't return the actual version\r
+       if( version != 0xB0C0 && ((version & 0xFFF0) != 0xB0C0 || version < 0xB0C2) ) {\r
+               Log_Warning("BGA", "Bochs Adapter Version is not compatible (need >= 0xB0C2), instead 0x%x", version);\r
+               return MODULE_ERR_NOTNEEDED;\r
+       }\r
+\r
+       // Get framebuffer base \r
+       dev = PCI_GetDevice(0x1234, 0x1111, 0);\r
+       if(dev == -1)\r
+               base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;\r
+       else\r
+               base = PCI_GetBAR(dev, 0);\r
+\r
+       // Map Framebuffer to hardware address\r
+       gBGA_Framebuffer = (void *) MM_MapHWPages(base, 768);   // 768 pages (3Mb)\r
+\r
+       // Install Device\r
+       if( DevFS_AddDevice( &gBGA_DriverStruct ) == -1 )\r
+       {\r
+               Log_Warning("BGA", "Unable to register with DevFS, maybe already loaded?");\r
+               return MODULE_ERR_MISC;\r
+       }\r
+               \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \brief Clean up driver resources before destruction\r
+ */\r
+void BGA_Uninstall(void)\r
+{\r
+       DevFS_DelDevice( &gBGA_DriverStruct );\r
+       MM_UnmapHWPages( (tVAddr)gBGA_Framebuffer, 768 );\r
+}\r
+\r
+/**\r
+ * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+ * \brief Read from the framebuffer\r
+ */\r
+Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       // Check Mode\r
+       if(giBGA_CurrentMode == -1)     return -1;\r
+       \r
+       // Check Offset and Length against Framebuffer Size\r
+       if(off+len > gpBGA_CurrentMode->fbSize)\r
+               return -1;\r
+       \r
+       // Copy from Framebuffer\r
+       memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);\r
+       return len;\r
+}\r
+\r
+/**\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 BGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
+{\r
+       if( giBGA_CurrentMode == -1 )   BGA_int_UpdateMode(0);\r
+       return DrvUtil_Video_WriteLFB(&gBGA_DrvUtil_BufInfo, Offset, Length, Buffer);\r
+}\r
+\r
+const char *csaBGA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
+/**\r
+ * \brief Handle messages to the device\r
+ */\r
+int BGA_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+        int    ret = -2;\r
+       ENTER("pNode iId pData", Node, ID, Data);\r
+       \r
+       switch(ID)\r
+       {\r
+       BASE_IOCTLS(DRV_TYPE_VIDEO, "BochsGA", VERSION, csaBGA_IOCtls);\r
+\r
+       case VIDEO_IOCTL_GETSETMODE:\r
+               if( Data )      BGA_int_UpdateMode(*(int*)(Data));\r
+               ret = giBGA_CurrentMode;\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_FINDMODE:\r
+               ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)Data);\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_MODEINFO:\r
+               ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_SETBUFFORMAT:\r
+               DrvUtil_Video_RemoveCursor( &gBGA_DrvUtil_BufInfo );\r
+               ret = gBGA_DrvUtil_BufInfo.BufferFormat;\r
+               if(Data)\r
+                       gBGA_DrvUtil_BufInfo.BufferFormat = *(int*)Data;\r
+               if(gBGA_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_SetCursor( &gBGA_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_SETCURSOR:\r
+               DrvUtil_Video_RemoveCursor( &gBGA_DrvUtil_BufInfo );\r
+               gBGA_CursorPos.x = ((tVideo_IOCtl_Pos*)Data)->x;\r
+               gBGA_CursorPos.y = ((tVideo_IOCtl_Pos*)Data)->y;\r
+               if(gBGA_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gBGA_DrvUtil_BufInfo,\r
+                               gBGA_CursorPos.x*giVT_CharWidth,\r
+                               gBGA_CursorPos.y*giVT_CharHeight\r
+                               );\r
+               else\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gBGA_DrvUtil_BufInfo,\r
+                               gBGA_CursorPos.x, gBGA_CursorPos.y\r
+                               );\r
+               break;\r
+       \r
+       default:\r
+               LEAVE('i', -2);\r
+               return -2;\r
+       }\r
+       \r
+       LEAVE('i', ret);\r
+       return ret;\r
+}\r
+\r
+//== Internal Functions ==\r
+/**\r
+ * \brief Writes to a BGA register\r
+ */\r
+void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
+{\r
+       outw(VBE_DISPI_IOPORT_INDEX, reg);\r
+       outw(VBE_DISPI_IOPORT_DATA, value);\r
+}\r
+\r
+Uint16 BGA_int_ReadRegister(Uint16 reg)\r
+{\r
+       outw(VBE_DISPI_IOPORT_INDEX, reg);\r
+       return inw(VBE_DISPI_IOPORT_DATA);\r
+}\r
+\r
+/**\r
+ * \brief Sets the video mode (32bpp only)\r
+ */\r
+void BGA_int_SetMode(Uint16 Width, Uint16 Height)\r
+{\r
+       ENTER("iWidth iHeight", Width, Height);\r
+       BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\r
+       BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, Width);\r
+       BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, Height);\r
+       BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP, 32);\r
+       BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_UpdateMode(int id)\r
+ * \brief Set current vide mode given a mode id\r
+ */\r
+int BGA_int_UpdateMode(int id)\r
+{\r
+       // Sanity Check\r
+       if(id < 0 || id >= BGA_MODE_COUNT)      return -1;\r
+       \r
+       BGA_int_SetMode(\r
+               gBGA_Modes[id].width,\r
+               gBGA_Modes[id].height);\r
+       \r
+       gBGA_DrvUtil_BufInfo.Framebuffer = gBGA_Framebuffer;\r
+       gBGA_DrvUtil_BufInfo.Pitch = gBGA_Modes[id].width * 4;\r
+       gBGA_DrvUtil_BufInfo.Width = gBGA_Modes[id].width;\r
+       gBGA_DrvUtil_BufInfo.Height = gBGA_Modes[id].height;\r
+       gBGA_DrvUtil_BufInfo.Depth = gBGA_Modes[id].bpp;\r
+\r
+       giBGA_CurrentMode = id;\r
+       gpBGA_CurrentMode = &gBGA_Modes[id];\r
+       return id;\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
+ * \brief Find a mode matching the given options\r
+ */\r
+int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
+{\r
+        int    i;\r
+        int    best = 0, bestFactor = 1000;\r
+        int    tmp;\r
+        int    rqdProduct = info->width * info->height;\r
+       \r
+       ENTER("pinfo", info);\r
+       LOG("info = {width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);\r
+       \r
+       for(i = 0; i < BGA_MODE_COUNT; i++)\r
+       {\r
+               #if DEBUG >= 2\r
+               LOG("Mode %i (%ix%i,%ibpp), ", i, gBGA_Modes[i].width, gBGA_Modes[i].height, gBGA_Modes[i].bpp);\r
+               #endif\r
+\r
+               if( gBGA_Modes[i].bpp != info->bpp )\r
+                       continue ;              \r
+               \r
+               // Ooh! A perfect match\r
+               if(gBGA_Modes[i].width == info->width && gBGA_Modes[i].height == info->height)\r
+               {\r
+                       #if DEBUG >= 2\r
+                       LOG("Perfect");\r
+                       #endif\r
+                       best = i;\r
+                       break;\r
+               }\r
+\r
+\r
+               // If not, how close are we?\r
+               tmp = gBGA_Modes[i].width * gBGA_Modes[i].height - rqdProduct;\r
+               tmp = tmp < 0 ? -tmp : tmp;     // tmp = ABS(tmp)\r
+               \r
+               #if DEBUG >= 2\r
+               LOG("tmp = %i", tmp);\r
+               #endif\r
+               \r
+               if(tmp < bestFactor)\r
+               {\r
+                       bestFactor = tmp;\r
+                       best = i;\r
+               }\r
+       }\r
+       \r
+       info->id = best;\r
+       info->width = gBGA_Modes[best].width;\r
+       info->height = gBGA_Modes[best].height;\r
+       info->bpp = gBGA_Modes[best].bpp;\r
+\r
+       LEAVE('i', best);       \r
+       return best;\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
+ * \brief Get mode information\r
+ */\r
+int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
+{\r
+       // Sanity Check\r
+       //if( !MM_IsUser( (Uint)info, sizeof(tVideo_IOCtl_Mode) ) ) {\r
+       //      return -EINVAL;\r
+       //}\r
+       \r
+       if(info->id < 0 || info->id >= BGA_MODE_COUNT)  return -1;\r
+       \r
+       info->width = gBGA_Modes[info->id].width;\r
+       info->height = gBGA_Modes[info->id].height;\r
+       info->bpp = gBGA_Modes[info->id].bpp;\r
+       \r
+       return 1;\r
+}\r
+\r
diff --git a/KernelLand/Modules/Display/Makefile.tpl b/KernelLand/Modules/Display/Makefile.tpl
new file mode 100644 (file)
index 0000000..b543160
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = Video
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/Display/PL110/Makefile b/KernelLand/Modules/Display/PL110/Makefile
new file mode 100644 (file)
index 0000000..0f90347
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o
+NAME = PL110
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Display/PL110/main.c b/KernelLand/Modules/Display/PL110/main.c
new file mode 100644 (file)
index 0000000..c3b6e52
--- /dev/null
@@ -0,0 +1,345 @@
+/**\r
+ * Acess2 ARM PrimeCell Colour LCD Controller (PL110) Driver\r
+ * - By John Hodge (thePowersGang)\r
+ *\r
+ * main.c\r
+ * - Driver core\r
+ *\r
+ *\r
+ * NOTE: The PL110 is set to 24bpp, but these are stored as 32-bit words.\r
+ *       This corresponds to the Acess 32bpp mode, as the Acess 24bpp is packed\r
+ */\r
+#define DEBUG  0\r
+#define VERSION        ((0<<8)|10)\r
+#include <acess.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <api_drv_video.h>\r
+#include <lib/keyvalue.h>\r
+#include <options.h>   // ARM Arch\r
+\r
+#define ABS(a) ((a)>0?(a):-(a))\r
+\r
+// === TYPEDEFS ===\r
+typedef struct sPL110  tPL110;\r
+\r
+struct sPL110\r
+{\r
+       Uint32  LCDTiming0;\r
+       Uint32  LCDTiming1;\r
+       Uint32  LCDTiming2;\r
+       Uint32  LCDTiming3;\r
+       \r
+       Uint32  LCDUPBase;\r
+       Uint32  LCDLPBase;\r
+       Uint32  LCDIMSC;\r
+       Uint32  LCDControl;\r
+       Uint32  LCDRIS;\r
+       Uint32  LCDMIS;\r
+       Uint32  LCDICR;\r
+       Uint32  LCDUPCurr;\r
+       Uint32  LCDLPCurr;\r
+};\r
+\r
+#ifndef PL110_BASE\r
+#define PL110_BASE     0x10020000      // Integrator\r
+#endif\r
+\r
+// === CONSTANTS ===\r
+const struct {\r
+       short W, H;\r
+}      caPL110_Modes[] = {\r
+       {640,480},\r
+       {800,600},\r
+       {1024,768}      // MAX\r
+};\r
+const int      ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int   PL110_Install(char **Arguments);\r
+void   PL110_Uninstall();\r
+// Internal\r
+// Filesystem\r
+Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, const void *buffer);\r
+ int   PL110_IOCtl(tVFS_Node *node, int id, void *data);\r
+// -- Internals\r
+ int   PL110_int_SetResolution(int W, int H);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
+tVFS_NodeType  gPL110_DevNodeType = {\r
+       .Read = PL110_Read,\r
+       .Write = PL110_Write,\r
+       .IOCtl = PL110_IOCtl\r
+       };\r
+tDevFS_Driver  gPL110_DriverStruct = {\r
+       NULL, "PL110",\r
+       {.Type = &gPL110_DevNodeType}\r
+};\r
+// -- Options\r
+tPAddr gPL110_PhysBase = PL110_BASE;\r
+ int   gbPL110_IsVersatile = 1;\r
+// -- KeyVal parse rules\r
+const tKeyVal_ParseRules       gPL110_KeyValueParser = {\r
+       NULL,\r
+       {\r
+               {"Base", "P", &gPL110_PhysBase},\r
+               {"IsVersatile", "i", &gbPL110_IsVersatile},\r
+               {NULL, NULL, NULL}\r
+       }\r
+};\r
+// -- Driver state\r
+ int   giPL110_CurrentMode = 0;\r
+ int   giPL110_BufferMode;\r
+ int   giPL110_Width = 640;\r
+ int   giPL110_Height = 480;\r
+size_t giPL110_FramebufferSize;\r
+tPL110 *gpPL110_IOMem;\r
+tPAddr gPL110_FramebufferPhys;\r
+void   *gpPL110_Framebuffer;\r
+// -- Misc\r
+tDrvUtil_Video_BufInfo gPL110_DrvUtil_BufInfo;\r
+tVideo_IOCtl_Pos       gPL110_CursorPos;\r
+\r
+// === CODE ===\r
+/**\r
+ */\r
+int PL110_Install(char **Arguments)\r
+{\r
+//     KeyVal_Parse(&gPL110_KeyValueParser, Arguments);\r
+       \r
+       gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);\r
+\r
+       PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);\r
+\r
+       DevFS_AddDevice( &gPL110_DriverStruct );\r
+\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Clean up resources for driver unloading\r
+ */\r
+void PL110_Uninstall()\r
+{\r
+}\r
+\r
+/**\r
+ * \brief Read from the framebuffer\r
+ */\r
+Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
+{\r
+       gPL110_DrvUtil_BufInfo.BufferFormat = giPL110_BufferMode;\r
+       return DrvUtil_Video_WriteLFB(&gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
+}\r
+\r
+const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
+\r
+/**\r
+ * \brief Handle messages to the device\r
+ */\r
+int PL110_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+        int    ret = -2;\r
+       ENTER("pNode iID pData", Node, ID, Data);\r
+       \r
+       switch(ID)\r
+       {\r
+       BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaPL110_IOCtls);\r
+\r
+       case VIDEO_IOCTL_SETBUFFORMAT:\r
+               DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
+               ret = giPL110_BufferMode;\r
+               if(Data)        giPL110_BufferMode = *(int*)Data;\r
+               if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_SetCursor( &gPL110_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_GETSETMODE:\r
+               if(Data)\r
+               {\r
+                        int    newMode;\r
+                       \r
+                       if( !CheckMem(Data, sizeof(int)) )\r
+                               LEAVE_RET('i', -1);\r
+                       \r
+                       newMode = *(int*)Data;\r
+                       \r
+                       if(newMode < 0 || newMode >= ciPL110_ModeCount)\r
+                               LEAVE_RET('i', -1);\r
+\r
+                       if(newMode != giPL110_CurrentMode)\r
+                       {\r
+                               giPL110_CurrentMode = newMode;\r
+                               PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );\r
+                       }\r
+               }\r
+               ret = giPL110_CurrentMode;\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_FINDMODE:\r
+               {\r
+               tVideo_IOCtl_Mode *mode = Data;\r
+                int    closest, closestArea, reqArea = 0;\r
+               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
+                       LEAVE_RET('i', -1);\r
+               if( mode->bpp != 32 )\r
+                       LEAVE_RET('i', 0);\r
+               if( mode->flags != 0 )\r
+                       LEAVE_RET('i', 0);\r
+\r
+               ret = 0;\r
+\r
+               for( int i = 0; i < ciPL110_ModeCount; i ++ )\r
+               {\r
+                        int    area;\r
+                       if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {\r
+                               mode->id = i;\r
+                               ret = 1;\r
+                               break;\r
+                       }\r
+                       \r
+                       area = caPL110_Modes[i].W * caPL110_Modes[i].H;\r
+                       if(!reqArea) {\r
+                               reqArea = mode->width * mode->height;\r
+                               closest = i;\r
+                               closestArea = area;\r
+                       }\r
+                       else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
+                               closest = i;\r
+                               closestArea = area;\r
+                       }\r
+               }\r
+               \r
+               if( ret == 0 )\r
+               {\r
+                       mode->id = closest;\r
+                       ret = 1;\r
+               }\r
+               mode->width = caPL110_Modes[mode->id].W;\r
+               mode->height = caPL110_Modes[mode->id].H;\r
+               break;\r
+               }\r
+       \r
+       case VIDEO_IOCTL_MODEINFO:\r
+               {\r
+               tVideo_IOCtl_Mode *mode = Data;\r
+               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
+                       LEAVE_RET('i', -1);\r
+               if(mode->id < 0 || mode->id >= ciPL110_ModeCount)\r
+                       LEAVE_RET('i', 0);\r
+               \r
+\r
+               mode->bpp = 32;\r
+               mode->flags = 0;\r
+               mode->width = caPL110_Modes[mode->id].W;\r
+               mode->height = caPL110_Modes[mode->id].H;\r
+\r
+               ret = 1;\r
+               break;\r
+               }\r
+       \r
+       case VIDEO_IOCTL_SETCURSOR:\r
+               if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
+                       LEAVE_RET('i', -1);\r
+\r
+               DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
+               \r
+               gPL110_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
+               if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gPL110_DrvUtil_BufInfo,\r
+                               gPL110_CursorPos.x*giVT_CharWidth,\r
+                               gPL110_CursorPos.y*giVT_CharHeight\r
+                               );\r
+               else\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gPL110_DrvUtil_BufInfo,\r
+                               gPL110_CursorPos.x,\r
+                               gPL110_CursorPos.y\r
+                               );\r
+               break;\r
+       \r
+       default:\r
+               LEAVE('i', -2);\r
+               return -2;\r
+       }\r
+       \r
+       LEAVE('i', ret);\r
+       return ret;\r
+}\r
+\r
+//\r
+//\r
+//\r
+\r
+/**\r
+ * \brief Set the LCD controller resolution\r
+ * \param W    Width (aligned to 16 pixels, cipped to 1024)\r
+ * \param H    Height (clipped to 768)\r
+ * \return Boolean failure\r
+ */\r
+int PL110_int_SetResolution(int W, int H)\r
+{\r
+       W = (W + 15) & ~0xF;\r
+       if(W <= 0 || H <= 0) {\r
+               Log_Warning("PL110", "Attempted to set invalid resolution (%ix%i)", W, H);\r
+               return 1;\r
+       }\r
+       if(W > 1024)    W = 1024;\r
+       if(H > 768)     H = 768;\r
+\r
+       gpPL110_IOMem->LCDTiming0 = ((W/16)-1) << 2;\r
+       gpPL110_IOMem->LCDTiming1 = H-1;\r
+       gpPL110_IOMem->LCDTiming2 = (14 << 27);\r
+       gpPL110_IOMem->LCDTiming3 = 0;\r
+\r
+       if( gpPL110_Framebuffer ) {\r
+               MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);\r
+       }\r
+       giPL110_FramebufferSize = W*H*4;\r
+\r
+       gpPL110_Framebuffer = (void*)MM_AllocDMA( (giPL110_FramebufferSize+0xFFF)>>12, 32, &gPL110_FramebufferPhys );\r
+       gpPL110_IOMem->LCDUPBase = gPL110_FramebufferPhys;\r
+       gpPL110_IOMem->LCDLPBase = 0;\r
+\r
+       // Power on, BGR mode, ???, ???, enabled\r
+       Uint32  controlWord = (1 << 11)|(1 << 8)|(1 << 5)|(5 << 1)|1;\r
+       // According to qemu, the Versatile version has these two the wrong\r
+       // way around\r
+       if( gbPL110_IsVersatile )\r
+       {\r
+               gpPL110_IOMem->LCDIMSC = controlWord;   // Actually LCDControl\r
+               gpPL110_IOMem->LCDControl = 0;  // Actually LCDIMSC\r
+       }\r
+       else\r
+       {\r
+               gpPL110_IOMem->LCDIMSC = 0;\r
+               gpPL110_IOMem->LCDControl = controlWord;\r
+       }\r
+\r
+       giPL110_Width = W;\r
+       giPL110_Height = H;\r
+\r
+       // Update the DrvUtil buffer info\r
+       gPL110_DrvUtil_BufInfo.Framebuffer = gpPL110_Framebuffer;\r
+       gPL110_DrvUtil_BufInfo.Pitch = W * 4;\r
+       gPL110_DrvUtil_BufInfo.Width = W;\r
+       gPL110_DrvUtil_BufInfo.Height = H;\r
+       gPL110_DrvUtil_BufInfo.Depth = 32;\r
+       \r
+       return 0;\r
+}\r
diff --git a/KernelLand/Modules/Display/Tegra2Vid/Makefile b/KernelLand/Modules/Display/Tegra2Vid/Makefile
new file mode 100644 (file)
index 0000000..ecab050
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o
+NAME = Tegra2Vid
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Display/Tegra2Vid/main.c b/KernelLand/Modules/Display/Tegra2Vid/main.c
new file mode 100644 (file)
index 0000000..d9405be
--- /dev/null
@@ -0,0 +1,326 @@
+/**\r
+ * main.c\r
+ * - Driver core\r
+ */\r
+#define DEBUG  0\r
+#define VERSION        ((0<<8)|10)\r
+#include <acess.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <api_drv_video.h>\r
+#include <lib/keyvalue.h>\r
+#include <options.h>   // ARM Arch\r
+#include "tegra2.h"\r
+\r
+#define ABS(a) ((a)>0?(a):-(a))\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int   Tegra2Vid_Install(char **Arguments);\r
+void   Tegra2Vid_Uninstall();\r
+// Internal\r
+// Filesystem\r
+Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+ int   Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);\r
+// -- Internals\r
+ int   Tegra2Vid_int_SetMode(int Mode);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, Tegra2Vid, Tegra2Vid_Install, NULL, NULL);\r
+tDevFS_Driver  gTegra2Vid_DriverStruct = {\r
+       NULL, "Tegra2Vid",\r
+       {\r
+       .Read = Tegra2Vid_Read,\r
+       .Write = Tegra2Vid_Write,\r
+       .IOCtl = Tegra2Vid_IOCtl\r
+       }\r
+};\r
+// -- Options\r
+tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE;\r
+ int   gbTegra2Vid_IsVersatile = 1;\r
+// -- KeyVal parse rules\r
+const tKeyVal_ParseRules       gTegra2Vid_KeyValueParser = {\r
+       NULL,\r
+       {\r
+               {"Base", "P", &gTegra2Vid_PhysBase},\r
+               {NULL, NULL, NULL}\r
+       }\r
+};\r
+// -- Driver state\r
+ int   giTegra2Vid_CurrentMode = 0;\r
+ int   giTegra2Vid_BufferMode;\r
+size_t giTegra2Vid_FramebufferSize;\r
+Uint32 *gpTegra2Vid_IOMem;\r
+tPAddr gTegra2Vid_FramebufferPhys;\r
+void   *gpTegra2Vid_Framebuffer;\r
+// -- Misc\r
+tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;\r
+tVideo_IOCtl_Pos       gTegra2Vid_CursorPos;\r
+\r
+// === CODE ===\r
+/**\r
+ */\r
+int Tegra2Vid_Install(char **Arguments)\r
+{\r
+//     KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);\r
+\r
+       gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);\r
+       {\r
+               Log_Debug("Tegra2Vid", "Display CMD Registers");\r
+               for( int i = 0x000; i <= 0x01A; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+               for( int i = 0x028; i <= 0x043; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+               Log_Debug("Tegra2Vid", "Display COM Registers");\r
+               for( int i = 0x300; i <= 0x329; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+               Log_Debug("Tegra2Vid", "Display DISP Registers");\r
+               for( int i = 0x400; i <= 0x446; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+               for( int i = 0x480; i <= 0x484; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+               for( int i = 0x4C0; i <= 0x4C1; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+\r
+               Log_Debug("Tegra2Vid", "WINC_A Registers");\r
+               for( int i = 0x700; i <= 0x714; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+               Log_Debug("Tegra2Vid", "WINBUF_A");\r
+               for( int i = 0x800; i <= 0x80A; i ++ )\r
+                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
+       }\r
+//     return 1;\r
+       \r
+       giTegra2Vid_FramebufferSize =\r
+               (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF)\r
+               *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4;\r
+\r
+       Log_Debug("Tegra2Vid", "giTegra2Vid_FramebufferSize = 0x%x", giTegra2Vid_FramebufferSize);\r
+       gpTegra2Vid_Framebuffer = MM_MapHWPages(\r
+               gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0],\r
+               (giTegra2Vid_FramebufferSize+PAGE_SIZE-1)/PAGE_SIZE\r
+               );\r
+       memset(gpTegra2Vid_Framebuffer, 0x1F, 0x1000);\r
+\r
+\r
+//     Tegra2Vid_int_SetMode(4);\r
+\r
+       DevFS_AddDevice( &gTegra2Vid_DriverStruct );\r
+\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Clean up resources for driver unloading\r
+ */\r
+void Tegra2Vid_Uninstall()\r
+{\r
+}\r
+\r
+/**\r
+ * \brief Read from the framebuffer\r
+ */\r
+Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+       gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;\r
+       return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);\r
+}\r
+\r
+const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
+\r
+/**\r
+ * \brief Handle messages to the device\r
+ */\r
+int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+        int    ret = -2;\r
+       ENTER("pNode iID pData", Node, ID, Data);\r
+       \r
+       switch(ID)\r
+       {\r
+       BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);\r
+\r
+       case VIDEO_IOCTL_SETBUFFORMAT:\r
+               DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
+               ret = giTegra2Vid_BufferMode;\r
+               if(Data)        giTegra2Vid_BufferMode = *(int*)Data;\r
+               if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_GETSETMODE:\r
+               if(Data)\r
+               {\r
+                        int    newMode;\r
+                       \r
+                       if( !CheckMem(Data, sizeof(int)) )\r
+                               LEAVE_RET('i', -1);\r
+                       \r
+                       newMode = *(int*)Data;\r
+                       \r
+                       if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)\r
+                               LEAVE_RET('i', -1);\r
+\r
+                       if(newMode != giTegra2Vid_CurrentMode)\r
+                       {\r
+                               giTegra2Vid_CurrentMode = newMode;\r
+                               Tegra2Vid_int_SetMode( newMode );\r
+                       }\r
+               }\r
+               ret = giTegra2Vid_CurrentMode;\r
+               break;\r
+       \r
+       case VIDEO_IOCTL_FINDMODE:\r
+               {\r
+               tVideo_IOCtl_Mode *mode = Data;\r
+                int    closest, closestArea, reqArea = 0;\r
+               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
+                       LEAVE_RET('i', -1);\r
+               if( mode->bpp != 32 )\r
+                       LEAVE_RET('i', 0);\r
+               if( mode->flags != 0 )\r
+                       LEAVE_RET('i', 0);\r
+\r
+               ret = 0;\r
+\r
+               for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )\r
+               {\r
+                        int    area;\r
+                       if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {\r
+                               mode->id = i;\r
+                               ret = 1;\r
+                               break;\r
+                       }\r
+                       \r
+                       area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;\r
+                       if(!reqArea) {\r
+                               reqArea = mode->width * mode->height;\r
+                               closest = i;\r
+                               closestArea = area;\r
+                       }\r
+                       else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
+                               closest = i;\r
+                               closestArea = area;\r
+                       }\r
+               }\r
+               \r
+               if( ret == 0 )\r
+               {\r
+                       mode->id = closest;\r
+                       ret = 1;\r
+               }\r
+               mode->width = caTegra2Vid_Modes[mode->id].W;\r
+               mode->height = caTegra2Vid_Modes[mode->id].H;\r
+               break;\r
+               }\r
+       \r
+       case VIDEO_IOCTL_MODEINFO:\r
+               {\r
+               tVideo_IOCtl_Mode *mode = Data;\r
+               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
+                       LEAVE_RET('i', -1);\r
+               if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)\r
+                       LEAVE_RET('i', 0);\r
+               \r
+\r
+               mode->bpp = 32;\r
+               mode->flags = 0;\r
+               mode->width = caTegra2Vid_Modes[mode->id].W;\r
+               mode->height = caTegra2Vid_Modes[mode->id].H;\r
+\r
+               ret = 1;\r
+               break;\r
+               }\r
+       \r
+       case VIDEO_IOCTL_SETCURSOR:\r
+               if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
+                       LEAVE_RET('i', -1);\r
+\r
+               DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
+               \r
+               gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
+               if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gTegra2Vid_DrvUtil_BufInfo,\r
+                               gTegra2Vid_CursorPos.x*giVT_CharWidth,\r
+                               gTegra2Vid_CursorPos.y*giVT_CharHeight\r
+                               );\r
+               else\r
+                       DrvUtil_Video_DrawCursor(\r
+                               &gTegra2Vid_DrvUtil_BufInfo,\r
+                               gTegra2Vid_CursorPos.x,\r
+                               gTegra2Vid_CursorPos.y\r
+                               );\r
+               break;\r
+       \r
+       default:\r
+               LEAVE('i', -2);\r
+               return -2;\r
+       }\r
+       \r
+       LEAVE('i', ret);\r
+       return ret;\r
+}\r
+\r
+//\r
+//\r
+//\r
+\r
+int Tegra2Vid_int_SetMode(int Mode)\r
+{\r
+       const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];\r
+        int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; \r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0)  = (mode->HS << 16)  | mode->HS;\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0)  = (mode->VBP << 16) | mode->HBP;\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16)   | mode->W;\r
+\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (mode->H << 16) | mode->W;\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8;     // BASE888\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12;    // Could be 13 (BGR/RGB)\r
+       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (mode->H << 16) | mode->W;\r
+\r
+       Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);\r
+\r
+       if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )\r
+       {\r
+               if( gpTegra2Vid_Framebuffer )\r
+               {\r
+                       // TODO: Free framebuffer for reallocation\r
+               }\r
+\r
+               giTegra2Vid_FramebufferSize = w*h*4;            \r
+\r
+               gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(\r
+                       (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,\r
+                       32,\r
+                       &gTegra2Vid_FramebufferPhys\r
+                       );\r
+               // TODO: Catch allocation failures\r
+               Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",\r
+                               giTegra2Vid_FramebufferSize,\r
+                               gpTegra2Vid_Framebuffer,\r
+                               gTegra2Vid_FramebufferPhys\r
+                               );\r
+               \r
+               // Tell hardware\r
+               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;\r
+               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0;        // Y offset\r
+               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0;        // X offset\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/KernelLand/Modules/Display/Tegra2Vid/tegra2.h b/KernelLand/Modules/Display/Tegra2Vid/tegra2.h
new file mode 100644 (file)
index 0000000..a3f126b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Acess2 NVidia Tegra2 Display Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * tegra2.h
+ * - Driver definitions
+ */
+#ifndef _TEGRA2_DISP_H_
+#define _TEGRA2_DISP_H_
+
+#define TEGRA2VID_BASE 0x54200000      // 0x40000 Large (256 KB)
+
+const struct sTegra2_Disp_Mode
+{
+       Uint16  W,   H;
+       Uint16  HFP, VFP;
+       Uint16  HS,  VS;
+       Uint16  HBP, VBP;
+}      caTegra2Vid_Modes[] = {
+       // TODO: VESA timings
+       {720,  487,  16,33,   63, 33,   59, 133},       // NTSC 2
+       {720,  576,  12,33,   63, 33,   69, 193},       // PAL 2 (VFP shown as 2/33, used 33)
+       {720,  483,  16, 6,   63,  6,   59,  30},       // 480p
+       {1280, 720,  70, 5,  804,  6,  220,  20},       // 720p
+       {1920,1080,  44, 4,  884,  5,  148,  36},       // 1080p
+       // TODO: Can all but HA/VA be constant and those select the resolution?
+};
+const int ciTegra2Vid_ModeCount = sizeof(caTegra2Vid_Modes)/sizeof(caTegra2Vid_Modes[0]);
+
+enum eTegra2_Disp_Regs
+{
+       DC_DISP_DISP_SIGNAL_OPTIONS0_0 = 0x400,
+       DC_DISP_DISP_SIGNAL_OPTIONS1_0, // 401
+       DC_DISP_DISP_WIN_OPTIONS_0,     // 402
+       DC_DISP_MEM_HIGH_PRIORITY_0,    // 403
+       DC_DISP_MEM_HIGH_PRIORITY_TIMER_0,      // 404
+       DC_DISP_DISP_TIMING_OPTIONS_0,  // 405
+       DC_DISP_REF_TO_SYNC_0,          // 406 (TrimSlice 0x0001 000B)
+       DC_DISP_SYNC_WIDTH_0,           // 407 (TrimSlice 0x0004 003A)
+       DC_DISP_BACK_PORCH_0,           // 408 (TrimSlice 0x0004 003A)
+       DC_DISP_DISP_ACTIVE_0,          // 409 (TrimSlice 0x0300 0400)
+       DC_DISP_FRONT_PORCH_0,          // 40A (TrimSlice 0x0004 003A)
+
+       DC_DISP_H_PULSE0_CONTROL_0,     // 40B
+
+       DC_DISP_DISP_COLOR_CONTROL_0 = 0x430,
+       
+       DC_WINC_A_COLOR_PALETTE_0 = 0x500,
+       DC_WINC_A_PALETTE_COLOR_EXT_0 = 0x600,
+       DC_WIN_A_WIN_OPTIONS_0 = 0x700,
+       DC_WIN_A_BYTE_SWAP_0,           // 701
+       DC_WIN_A_BUFFER_CONTROL_0,      // 702
+       DC_WIN_A_COLOR_DEPTH_0,         // 703
+       DC_WIN_A_POSITION_0,            // 704
+       DC_WIN_A_SIZE_0,                // 705 (TrimSlice 0x0300 0400)
+       DC_WIN_A_PRESCALED_SIZE_0,
+       DC_WIN_A_H_INITIAL_DDA_0,
+       DC_WIN_A_V_INITIAL_DDA_0,
+       DC_WIN_A_DDA_INCREMENT_0,
+       DC_WIN_A_LINE_STRIDE_0,
+       DC_WIN_A_BUF_STRIDE_0,
+       DC_WIN_A_BUFFER_ADDR_MODE_0,
+       DC_WIN_A_DV_CONTROL_0,
+       DC_WIN_A_BLEND_NOKEY_0,
+       
+       DC_WINBUF_A_START_ADDR_0 = 0x800,
+       DC_WINBUF_A_START_ADDR_NS_0,
+       DC_WINBUF_A_ADDR_H_OFFSET_0,
+       DC_WINBUF_A_ADDR_H_OFFSET_NS_0,
+       DC_WINBUF_A_ADDR_V_OFFSET_0,
+       DC_WINBUF_A_ADDR_V_OFFSET_NS_0,
+};
+
+#endif
+
diff --git a/KernelLand/Modules/Display/VESA/Makefile b/KernelLand/Modules/Display/VESA/Makefile
new file mode 100644 (file)
index 0000000..d8da233
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o
+NAME = VESA
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Display/VESA/common.h b/KernelLand/Modules/Display/VESA/common.h
new file mode 100644 (file)
index 0000000..eeaddd5
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+// === TYPES ===
+typedef struct sFarPtr
+{
+       Uint16  ofs;
+       Uint16  seg;
+}      tFarPtr;
+
+typedef struct sVesa_Mode
+{
+       Uint16  code;
+       Uint16  width, height;
+       Uint16  pitch, bpp;
+       Uint16  flags;
+       Uint32  fbSize;
+       Uint32  framebuffer;
+}      tVesa_Mode;
+
+typedef struct sVesa_CallModeInfo
+{
+       Uint16  attributes;
+       Uint8   winA,winB;
+       Uint16  granularity;
+       Uint16  winsize;
+       Uint16  segmentA, segmentB;
+       tFarPtr realFctPtr;
+       Uint16  pitch;  // Bytes per scanline
+
+       Uint16  Xres, Yres;
+       Uint8   Wchar, Ychar, planes, bpp, banks;
+       Uint8   memory_model, bank_size, image_pages;
+       Uint8   reserved0;
+
+       Uint8   red_mask, red_position;
+       Uint8   green_mask, green_position;
+       Uint8   blue_mask, blue_position;
+       Uint8   rsv_mask, rsv_position;
+       Uint8   directcolor_attributes;
+
+       Uint32  physbase;  // Your LFB address ;)
+       Uint32  reserved1;
+       Sint16  reserved2;
+}      tVesa_CallModeInfo;
+
+typedef struct sVesa_CallInfo
+{
+   char                signature[4];           // == "VESA"
+   Uint16      Version;        // == 0x0300 for Vesa 3.0
+   tFarPtr     OEMString;      // isa vbeFarPtr
+   Uint8       Capabilities[4];        
+   tFarPtr     VideoModes;     // isa vbeParPtr
+   Uint16      TotalMemory;    // as # of 64KB blocks
+}      tVesa_CallInfo;
+
+#endif
diff --git a/KernelLand/Modules/Display/VESA/main.c b/KernelLand/Modules/Display/VESA/main.c
new file mode 100644 (file)
index 0000000..a85d313
--- /dev/null
@@ -0,0 +1,418 @@
+/*\r
+ * AcessOS 1\r
+ * Video BIOS Extensions (Vesa) Driver\r
+ */\r
+#define DEBUG  0\r
+#define VERSION        0x100\r
+\r
+#include <acess.h>\r
+#include <vfs.h>\r
+#include <api_drv_video.h>\r
+#include <fs_devfs.h>\r
+#include <modules.h>\r
+#include <vm8086.h>\r
+#include "common.h"\r
+\r
+// === CONSTANTS ===\r
+#define        FLAG_LFB        0x1\r
+#define VESA_DEFAULT_FRAMEBUFFER       (KERNEL_BASE|0xA0000)\r
+#define BLINKING_CURSOR        1\r
+#if BLINKING_CURSOR\r
+# define VESA_CURSOR_PERIOD    1000\r
+#endif\r
+\r
+// === PROTOTYPES ===\r
+ int   Vesa_Install(char **Arguments);\r
+Uint64 Vesa_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);\r
+ int   Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+ int   Vesa_Int_SetMode(int Mode);\r
+ int   Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
+ int   Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
+void   Vesa_int_HideCursor(void);\r
+void   Vesa_int_ShowCursor(void);\r
+void   Vesa_FlipCursor(void *Arg);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
+tVFS_NodeType  gVesa_NodeType = {\r
+       .Read = Vesa_Read,\r
+       .Write = Vesa_Write,\r
+       .IOCtl = Vesa_IOCtl\r
+       };\r
+tDevFS_Driver  gVesa_DriverStruct = {\r
+       NULL, "Vesa",\r
+       {.Type = &gVesa_NodeType}\r
+       };\r
+tMutex glVesa_Lock;\r
+tVM8086        *gpVesa_BiosState;\r
+ int   giVesaDriverId = -1;\r
+// --- Video Modes ---\r
+ int   giVesaCurrentMode = 0;\r
+tVesa_Mode     *gVesa_Modes;\r
+tVesa_Mode     *gpVesaCurMode;\r
+ int   giVesaModeCount = 0;\r
+ int   gbVesaModesChecked;\r
+// --- Framebuffer ---\r
+char   *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;\r
+ int   giVesaPageCount = 0;    //!< Framebuffer size in pages\r
+// --- Cursor Control ---\r
+ int   giVesaCursorX = -1;\r
+ int   giVesaCursorY = -1;\r
+ int   giVesaCursorTimer = -1; // Invalid timer\r
+ int   gbVesa_CursorVisible = 0;\r
+// --- 2D Video Stream Handlers ---\r
+tDrvUtil_Video_BufInfo gVesa_BufInfo;\r
+\r
+// === CODE ===\r
+int Vesa_Install(char **Arguments)\r
+{\r
+       tVesa_CallInfo  *info;\r
+       tFarPtr infoPtr;\r
+       Uint16  *modes;\r
+       int     i;\r
+       \r
+       // Allocate Info Block\r
+       gpVesa_BiosState = VM8086_Init();\r
+       info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
+       // Set Requested Version\r
+       memcpy(info->signature, "VBE2", 4);\r
+       // Set Registers\r
+       gpVesa_BiosState->AX = 0x4F00;\r
+       gpVesa_BiosState->ES = infoPtr.seg;     gpVesa_BiosState->DI = infoPtr.ofs;\r
+       // Call Interrupt\r
+       VM8086_Int(gpVesa_BiosState, 0x10);\r
+       if(gpVesa_BiosState->AX != 0x004F) {\r
+               Log_Warning("VESA", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
+               return MODULE_ERR_NOTNEEDED;\r
+       }\r
+       \r
+       //Log_Debug("VESA", "info->VideoModes = %04x:%04x", info->VideoModes.seg, info->VideoModes.ofs);\r
+       modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);\r
+       \r
+       // Read Modes\r
+       for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ );\r
+       gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
+       \r
+       Log_Debug("VESA", "%i Modes", giVesaModeCount);\r
+       \r
+       // Insert Text Mode\r
+       gVesa_Modes[0].width = 80;\r
+       gVesa_Modes[0].height = 25;\r
+       gVesa_Modes[0].bpp = 12;\r
+       gVesa_Modes[0].code = 0x3;\r
+       gVesa_Modes[0].flags = 1;\r
+       gVesa_Modes[0].fbSize = 80*25*2;\r
+       gVesa_Modes[0].framebuffer = 0xB8000;\r
+       \r
+       for( i = 1; i < giVesaModeCount; i++ )\r
+       {\r
+               gVesa_Modes[i].code = modes[i];\r
+       }\r
+\r
+//     VM8086_Deallocate( info );\r
+       \r
+       // Install Device\r
+       giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );\r
+       if(giVesaDriverId == -1)        return MODULE_ERR_MISC;\r
+       \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+void Vesa_int_FillModeList(void)\r
+{\r
+       if( !gbVesaModesChecked )\r
+       {\r
+                int    i;\r
+               tVesa_CallModeInfo      *modeinfo;\r
+               tFarPtr modeinfoPtr;\r
+               \r
+               modeinfo = VM8086_Allocate(gpVesa_BiosState, 512, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
+               for( i = 1; i < giVesaModeCount; i ++ )\r
+               {\r
+                       // Get Mode info\r
+                       gpVesa_BiosState->AX = 0x4F01;\r
+                       gpVesa_BiosState->CX = gVesa_Modes[i].code;\r
+                       gpVesa_BiosState->ES = modeinfoPtr.seg;\r
+                       gpVesa_BiosState->DI = modeinfoPtr.ofs;\r
+                       VM8086_Int(gpVesa_BiosState, 0x10);\r
+                       \r
+                       // Parse Info\r
+                       gVesa_Modes[i].flags = 0;\r
+                       if ( (modeinfo->attributes & 0x90) == 0x90 )\r
+                       {\r
+                               gVesa_Modes[i].flags |= FLAG_LFB;\r
+                               gVesa_Modes[i].framebuffer = modeinfo->physbase;\r
+                               gVesa_Modes[i].fbSize = modeinfo->Yres*modeinfo->pitch;\r
+                       } else {\r
+                               gVesa_Modes[i].framebuffer = 0;\r
+                               gVesa_Modes[i].fbSize = 0;\r
+                       }\r
+                       \r
+                       gVesa_Modes[i].pitch = modeinfo->pitch;\r
+                       gVesa_Modes[i].width = modeinfo->Xres;\r
+                       gVesa_Modes[i].height = modeinfo->Yres;\r
+                       gVesa_Modes[i].bpp = modeinfo->bpp;\r
+                       \r
+                       #if DEBUG\r
+                       Log_Log("VESA", "0x%x - %ix%ix%i",\r
+                               gVesa_Modes[i].code, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
+                       #endif\r
+               }\r
+       \r
+//             VM8086_Deallocate( modeinfo );\r
+               \r
+               gbVesaModesChecked = 1;\r
+       }\r
+}\r
+\r
+/* Read from the framebuffer\r
+ */\r
+Uint64 Vesa_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       #if DEBUG >= 2\r
+       Log("Vesa_Read: () - NULL\n");\r
+       #endif\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
+{\r
+       if( gVesa_Modes[giVesaCurrentMode].framebuffer == 0 ) {\r
+               Log_Warning("VESA", "Vesa_Write - Non-LFB Modes not yet supported.");\r
+               return 0;\r
+       }\r
+\r
+       return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);\r
+}\r
+\r
+const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
+/**\r
+ * \brief Handle messages to the device\r
+ */\r
+int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+        int    ret;\r
+       //Log_Debug("VESA", "Vesa_Ioctl: (Node=%p, ID=%i, Data=%p)", Node, ID, Data);\r
+       switch(ID)\r
+       {\r
+       BASE_IOCTLS(DRV_TYPE_VIDEO, "VESA", VERSION, csaVESA_IOCtls);\r
+\r
+       case VIDEO_IOCTL_GETSETMODE:\r
+               if( !Data )     return giVesaCurrentMode;\r
+               return Vesa_Int_SetMode( *(int*)Data );\r
+       \r
+       case VIDEO_IOCTL_FINDMODE:\r
+               return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);\r
+       case VIDEO_IOCTL_MODEINFO:\r
+               return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
+       \r
+       case VIDEO_IOCTL_SETBUFFORMAT:\r
+               Vesa_int_HideCursor();\r
+               ret = gVesa_BufInfo.BufferFormat;\r
+               if(Data)        gVesa_BufInfo.BufferFormat = *(int*)Data;\r
+               if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+                       DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );\r
+               Vesa_int_ShowCursor();\r
+               return ret;\r
+       \r
+       case VIDEO_IOCTL_SETCURSOR:     // Set cursor position\r
+               Vesa_int_HideCursor();\r
+               giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;\r
+               giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;\r
+               Vesa_int_ShowCursor();\r
+               return 0;\r
+       \r
+       case VIDEO_IOCTL_SETCURSORBITMAP:\r
+               DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );\r
+               return 0;\r
+       }\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Updates the video mode\r
+ */\r
+int Vesa_Int_SetMode(int mode)\r
+{      \r
+       // Sanity Check values\r
+       if(mode < 0 || mode > giVesaModeCount)  return -1;\r
+\r
+       // Check for fast return\r
+       if(mode == giVesaCurrentMode)   return 1;\r
+       \r
+       Vesa_int_FillModeList();\r
+\r
+       Time_RemoveTimer(giVesaCursorTimer);\r
+       giVesaCursorTimer = -1;\r
+       \r
+       Mutex_Acquire( &glVesa_Lock );\r
+       \r
+       gpVesa_BiosState->AX = 0x4F02;\r
+       gpVesa_BiosState->BX = gVesa_Modes[mode].code;\r
+       if(gVesa_Modes[mode].flags & FLAG_LFB) {\r
+               gpVesa_BiosState->BX |= 0x4000; // Bit 14 - Use LFB\r
+       }\r
+       \r
+       // Set Mode\r
+       VM8086_Int(gpVesa_BiosState, 0x10);\r
+       \r
+       // Map Framebuffer\r
+       if( (tVAddr)gpVesa_Framebuffer != VESA_DEFAULT_FRAMEBUFFER )\r
+               MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);\r
+       giVesaPageCount = (gVesa_Modes[mode].fbSize + 0xFFF) >> 12;\r
+       gpVesa_Framebuffer = (void*)MM_MapHWPages(gVesa_Modes[mode].framebuffer, giVesaPageCount);\r
+       \r
+       Log_Log("VESA", "Setting mode to %i (%ix%i %ibpp) %p[0x%x] maps %P",\r
+               mode,\r
+               gVesa_Modes[mode].width, gVesa_Modes[mode].height,\r
+               gVesa_Modes[mode].bpp,\r
+               gpVesa_Framebuffer, giVesaPageCount << 12, gVesa_Modes[mode].framebuffer\r
+               );\r
+       \r
+       // Record Mode Set\r
+       giVesaCurrentMode = mode;\r
+       gpVesaCurMode = &gVesa_Modes[giVesaCurrentMode];\r
+       \r
+       Mutex_Release( &glVesa_Lock );\r
+\r
+       gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
+       gVesa_BufInfo.Pitch = gVesa_Modes[mode].pitch;\r
+       gVesa_BufInfo.Width = gVesa_Modes[mode].width;\r
+       gVesa_BufInfo.Height = gVesa_Modes[mode].height;\r
+       gVesa_BufInfo.Depth = gVesa_Modes[mode].bpp;    \r
+\r
+       return 1;\r
+}\r
+\r
+int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
+{\r
+        int    i;\r
+        int    best = -1, bestFactor = 1000;\r
+        int    factor, tmp;\r
+       \r
+       ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
+\r
+       Vesa_int_FillModeList();\r
+       \r
+       for(i=0;i<giVesaModeCount;i++)\r
+       {\r
+               LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
+       \r
+               if(gVesa_Modes[i].width == data->width && gVesa_Modes[i].height == data->height)\r
+               {\r
+                       //if( (data->bpp == 32 || data->bpp == 24)\r
+                       // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
+                       if( data->bpp == gVesa_Modes[i].bpp )\r
+                       {\r
+                               LOG("Perfect!");\r
+                               best = i;\r
+                               break;\r
+                       }\r
+               }\r
+               \r
+               tmp = gVesa_Modes[i].width * gVesa_Modes[i].height;\r
+               tmp -= data->width * data->height;\r
+               tmp = tmp < 0 ? -tmp : tmp;\r
+               factor = tmp * 1000 / (data->width * data->height);\r
+               \r
+               if( data->bpp == 8 && gVesa_Modes[i].bpp != 8 ) continue;\r
+               if( data->bpp == 16 && gVesa_Modes[i].bpp != 16 )       continue;\r
+               \r
+               if( (data->bpp == 32 || data->bpp == 24)\r
+                && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
+               {\r
+                       if( data->bpp == gVesa_Modes[i].bpp )\r
+                               factor /= 2;\r
+               }\r
+               else {\r
+                       if( data->bpp != gVesa_Modes[i].bpp )\r
+                               continue ;\r
+               }\r
+               \r
+               LOG("factor = %i", factor);\r
+               \r
+               if(factor < bestFactor)\r
+               {\r
+                       bestFactor = factor;\r
+                       best = i;\r
+               }\r
+       }\r
+       data->id = best;\r
+       data->width = gVesa_Modes[best].width;\r
+       data->height = gVesa_Modes[best].height;\r
+       data->bpp = gVesa_Modes[best].bpp;\r
+       LEAVE('i', best);\r
+       return best;\r
+}\r
+\r
+int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)\r
+{\r
+       if(data->id < 0 || data->id > giVesaModeCount)  return -1;\r
+\r
+       Vesa_int_FillModeList();\r
+\r
+       data->width = gVesa_Modes[data->id].width;\r
+       data->height = gVesa_Modes[data->id].height;\r
+       data->bpp = gVesa_Modes[data->id].bpp;\r
+       return 1;\r
+}\r
+\r
+void Vesa_int_HideCursor(void)\r
+{\r
+       DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
+       #if BLINKING_CURSOR\r
+       if(giVesaCursorTimer != -1) {\r
+               Time_RemoveTimer(giVesaCursorTimer);\r
+               giVesaCursorTimer = -1;\r
+       }\r
+       #endif\r
+}\r
+\r
+void Vesa_int_ShowCursor(void)\r
+{\r
+       gbVesa_CursorVisible = (giVesaCursorX >= 0);\r
+       if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
+       {\r
+               DrvUtil_Video_DrawCursor(\r
+                       &gVesa_BufInfo,\r
+                       giVesaCursorX*giVT_CharWidth,\r
+                       giVesaCursorY*giVT_CharHeight\r
+                       );\r
+               #if BLINKING_CURSOR\r
+               giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, NULL);\r
+               #endif\r
+       }\r
+       else\r
+               DrvUtil_Video_DrawCursor(\r
+                       &gVesa_BufInfo,\r
+                       giVesaCursorX,\r
+                       giVesaCursorY\r
+                       );\r
+}\r
+\r
+/**\r
+ * \brief Swaps the text cursor on/off\r
+ */\r
+void Vesa_FlipCursor(void *Arg)\r
+{\r
+       if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )\r
+               return ;\r
+\r
+       if( gbVesa_CursorVisible )\r
+               DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);\r
+       else\r
+               DrvUtil_Video_DrawCursor(&gVesa_BufInfo,\r
+                       giVesaCursorX*giVT_CharWidth,\r
+                       giVesaCursorY*giVT_CharHeight\r
+                       );\r
+       gbVesa_CursorVisible = !gbVesa_CursorVisible;\r
+               \r
+       #if BLINKING_CURSOR\r
+       giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, Arg);\r
+       #endif\r
+}\r
+\r
diff --git a/KernelLand/Modules/Filesystems/Ext2/Makefile b/KernelLand/Modules/Filesystems/Ext2/Makefile
new file mode 100644 (file)
index 0000000..471ba49
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = ext2.o read.o dir.o write.o
+NAME = Ext2
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/Ext2/dir.c b/KernelLand/Modules/Filesystems/Ext2/dir.c
new file mode 100644 (file)
index 0000000..5eb476f
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file dir.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG  1
+#define VERBOSE        0
+#include "ext2_common.h"
+
+// === MACROS ===
+#define BLOCK_DIR_OFS(_data, _block)   ((Uint16*)(_data)[(_block)])
+
+// === PROTOTYPES ===
+char   *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
+ int   Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+ int   Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
+// --- Helpers ---
+tVFS_Node      *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
+
+// === GLOBALS ===
+tVFS_NodeType  gExt2_DirType = {
+       .TypeName = "ext2-dir",
+       .ReadDir = Ext2_ReadDir,
+       .FindDir = Ext2_FindDir,
+       .MkNod = Ext2_MkNod,
+       .Relink = Ext2_Relink,
+       .Link = Ext2_Link,
+       .Close = Ext2_CloseFile
+       };
+tVFS_NodeType  gExt2_FileType = {
+       .TypeName = "ext2-file",
+       .Read = Ext2_Read,
+       .Write = Ext2_Write,
+       .Close = Ext2_CloseFile
+       };
+
+// === CODE ===
+/**
+ * \brief Reads a directory entry
+ * \param Node Directory node
+ * \param Pos  Position of desired element
+ */
+char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tExt2_Inode     inode;
+       tExt2_DirEnt    dirent;
+       Uint64  Base;   // Block's Base Address
+        int    block = 0;
+       Uint    ofs = 0;
+        int    entNum = 0;
+       tExt2_Disk      *disk = Node->ImplPtr;
+       Uint    size;
+       
+       ENTER("pNode iPos", Node, Pos);
+       
+       // Read directory's inode
+       Ext2_int_ReadInode(disk, Node->Inode, &inode);
+       size = inode.i_size;
+       
+       LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
+       
+       // Find Entry
+       // Get First Block
+       // - Do this ourselves as it is a simple operation
+       Base = inode.i_block[0] * disk->BlockSize;
+       // Scan directory
+       while(Pos -- && size > 0)
+       {
+               VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+               ofs += dirent.rec_len;
+               size -= dirent.rec_len;
+               entNum ++;
+               
+               if(ofs >= disk->BlockSize) {
+                       block ++;
+                       if( ofs > disk->BlockSize ) {
+                               Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
+                                       entNum-1, Node->Inode);
+                       }
+                       ofs = 0;
+                       Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+               }
+       }
+       
+       // Check for the end of the list
+       if(size <= 0) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Read Entry
+       VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
+       //LOG("dirent.inode = %i", dirent.inode);
+       //LOG("dirent.rec_len = %i", dirent.rec_len);
+       //LOG("dirent.name_len = %i", dirent.name_len);
+       dirent.name[ dirent.name_len ] = '\0';  // Cap off string
+       
+       
+       // Ignore . and .. (these are done in the VFS)
+       if( (dirent.name[0] == '.' && dirent.name[1] == '\0')
+       ||  (dirent.name[0] == '.' && dirent.name[1] == '.' && dirent.name[2]=='\0')) {
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;        // Skip
+       }
+       
+       LEAVE('s', dirent.name);
+       // Create new node
+       return strdup(dirent.name);
+}
+
+/**
+ * \brief Gets information about a file
+ * \param Node Parent Node
+ * \param Filename     Name of wanted file
+ * \return VFS Node of file
+ */
+tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename)
+{
+       tExt2_Disk      *disk = Node->ImplPtr;
+       tExt2_Inode     inode;
+       tExt2_DirEnt    dirent;
+       Uint64  Base;   // Block's Base Address
+        int    block = 0;
+       Uint    ofs = 0;
+        int    entNum = 0;
+       Uint    size;
+        int    filenameLen = strlen(Filename);
+       
+       // Read directory's inode
+       Ext2_int_ReadInode(disk, Node->Inode, &inode);
+       size = inode.i_size;
+       
+       // Get First Block
+       // - Do this ourselves as it is a simple operation
+       Base = inode.i_block[0] * disk->BlockSize;
+       // Find File
+       while(size > 0)
+       {
+               VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+               dirent.name[ dirent.name_len ] = '\0';  // Cap off string
+               // If it matches, create a node and return it
+               if(dirent.name_len == filenameLen && strcmp(dirent.name, Filename) == 0)
+                       return Ext2_int_CreateNode( disk, dirent.inode );
+               // Increment pointers
+               ofs += dirent.rec_len;
+               size -= dirent.rec_len;
+               entNum ++;
+               
+               // Check for end of block
+               if(ofs >= disk->BlockSize) {
+                       block ++;
+                       if( ofs > disk->BlockSize ) {
+                               Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
+                                       entNum-1, Node->Inode);
+                       }
+                       ofs = 0;
+                       Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+               }
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
+ * \brief Create a new node
+ */
+int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
+{
+       #if 0
+       tVFS_Node       *child;
+       Uint64  inodeNum;
+       tExt2_Inode     inode;
+       inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
+       
+       memset(&inode, 0, sizeof(tExt2_Inode));
+       
+       // File type
+       inode.i_mode = 0664;
+       if( Flags & VFS_FFLAG_READONLY )
+               inode.i_mode &= ~0222;
+       if( Flags & VFS_FFLAG_SYMLINK )
+               inode.i_mode |= EXT2_S_IFLNK;
+       else if( Flags & VFS_FFLAG_DIRECTORY )
+               inode.i_mode |= EXT2_S_IFDIR | 0111;
+       
+       inode.i_uid = Threads_GetUID();
+       inode.i_gid = Threads_GetGID();
+       inode.i_ctime =
+               inode.i_mtime =
+               inode.i_atime = now() / 1000;
+       
+       child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
+       return Ext2_Link(Parent, child, Name);
+       #else
+       return 1;
+       #endif
+}
+
+/**
+ * \brief Rename a file
+ * \param Node This (directory) node
+ * \param OldName      Old name of file
+ * \param NewName      New name for file
+ * \return Boolean Failure - See ::tVFS_Node.Relink for info
+ */
+int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+{
+       return 1;
+}
+
+/**
+ * \brief Links an existing node to a new name
+ * \param Parent       Parent (directory) node
+ * \param Node Node to link
+ * \param Name New name for the node
+ * \return Boolean Failure - See ::tVFS_Node.Link for info
+ */
+int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
+{      
+       #if 0
+       tExt2_Disk      *disk = Node->ImplPtr;
+       tExt2_Inode     inode;
+       tExt2_DirEnt    dirent;
+       tExt2_DirEnt    newEntry;
+       Uint64  Base;   // Block's Base Address
+        int    block = 0, ofs = 0;
+       Uint    size;
+       void    *blockData;
+        int    bestMatch = -1, bestSize, bestBlock, bestOfs;
+        int    nEntries;
+       
+       blockData = malloc(disk->BlockSize);
+       
+       // Read child inode (get's the file type)
+       Ext2_int_ReadInode(disk, Child->Inode, &inode);
+       
+       // Create a stub entry
+       newEntry.inode = Child->Inode;
+       newEntry.name_len = strlen(Name);
+       newEntry.rec_len = (newEntry.name_len+3+8)&~3;
+       newEntry.type = inode.i_mode >> 12;
+       memcpy(newEntry.name, Name, newEntry.name_len);
+       
+       // Read directory's inode
+       Ext2_int_ReadInode(disk, Node->Inode, &inode);
+       size = inode.i_size;
+       
+       // Get a lock on the inode
+       Ext2_int_LockInode(disk, Node->Inode);
+       
+       // Get First Block
+       // - Do this ourselves as it is a simple operation
+       base = inode.i_block[0] * disk->BlockSize;
+       VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
+       block = 0;
+       // Find File
+       while(size > 0)
+       {
+               dirent = blockData + ofs;
+               // Sanity Check the entry
+               if(ofs + dirent->rec_len > disk->BlockSize) {
+                       Log_Warning("EXT2",
+                               "Directory entry %i of inode 0x%x extends over a block boundary",
+                               nEntries, (Uint)Node->Inode);
+               }
+               else {
+               
+                       // Free entry
+                       if(dirent->type == 0) {
+                               if( dirent->rec_len >= newEntry.rec_len
+                                && (bestMatch == -1 || bestSize > dirent->rec_len) )
+                               {
+                                       bestMatch = nEntries;
+                                       bestSize = dirent->rec_len;
+                                       bestBlock = block;
+                                       bestOfs = ofs;
+                               }
+                       }
+                       // Non free - check name to avoid duplicates
+                       else {
+                               if(strncmp(Name, dirent->name, dirent->name_len) == 0) {
+                                       Ext2_int_UnlockInode(disk, Node->Inode);
+                                       return 1;       // ERR_???
+                               }
+                       }
+               }
+               
+               // Increment the pointer
+               nEntries ++;
+               ofs += dirent->rec_len;
+               if( ofs >= disk->BlockSize ) {
+                       // Read the next block if needed
+                       BLOCK_DIR_OFS(Node->Data, block) = nEntries;
+                       block ++;
+                       ofs = 0;
+                       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+                       VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
+               }
+       }
+       
+       // Check if a free slot was found
+       if( bestMatch >= 0 ) {
+               // Read-Modify-Write
+               bestBlock = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock);
+               if( block > 0 )
+                       bestMatch = BLOCK_DIR_OFS(Node->Data, bestBlock);
+               VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
+               dirent = blockData + bestOfs;
+               memcpy(dirent, newEntry, newEntry.rec_len);
+               VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData );
+       }
+       else {
+               // Allocate block, Write
+               block = Ext2_int_AllocateBlock(Disk, block);
+               Log_Warning("EXT2", "");
+       }
+
+       Ext2_int_UnlockInode(disk, Node->Inode);
+       return 0;
+       #else
+       return 1;
+       #endif
+}
+
+// ---- INTERNAL FUNCTIONS ----
+/**
+ * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
+ * \brief Create a new VFS Node
+ */
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
+{
+       tExt2_Inode     inode;
+       tVFS_Node       retNode;
+       tVFS_Node       *tmpNode;
+       
+       if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
+               return NULL;
+       
+       if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
+               return tmpNode;
+       
+       
+       // Set identifiers
+       retNode.Inode = InodeID;
+       retNode.ImplPtr = Disk;
+       
+       // Set file length
+       retNode.Size = inode.i_size;
+       retNode.Data = NULL;
+       
+       // Set Access Permissions
+       retNode.UID = inode.i_uid;
+       retNode.GID = inode.i_gid;
+       retNode.NumACLs = 3;
+       retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
+       
+       //  Set Function Pointers
+       retNode.Type = &gExt2_FileType;
+       
+       switch(inode.i_mode & EXT2_S_IFMT)
+       {
+       // Symbolic Link
+       case EXT2_S_IFLNK:
+               retNode.Flags = VFS_FFLAG_SYMLINK;
+               break;
+       // Regular File
+       case EXT2_S_IFREG:
+               retNode.Flags = 0;
+               retNode.Size |= (Uint64)inode.i_dir_acl << 32;
+               break;
+       // Directory
+       case EXT2_S_IFDIR:
+               retNode.Type = &gExt2_DirType;
+               retNode.Flags = VFS_FFLAG_DIRECTORY;
+               retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );
+               break;
+       // Unknown, Write protect it to be safe 
+       default:
+               retNode.Flags = VFS_FFLAG_READONLY;
+               break;
+       }
+       
+       // Set Timestamps
+       retNode.ATime = inode.i_atime * 1000;
+       retNode.MTime = inode.i_mtime * 1000;
+       retNode.CTime = inode.i_ctime * 1000;
+       
+       // Save in node cache and return saved node
+       return Inode_CacheNode(Disk->CacheID, &retNode);
+}
diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2.c b/KernelLand/Modules/Filesystems/Ext2/ext2.c
new file mode 100644 (file)
index 0000000..7c4bf97
--- /dev/null
@@ -0,0 +1,337 @@
+/*\r
+ * Acess OS\r
+ * Ext2 Driver Version 1\r
+ */\r
+/**\r
+ * \file fs/ext2.c\r
+ * \brief Second Extended Filesystem Driver\r
+ * \todo Implement file full write support\r
+ */\r
+#define DEBUG  1\r
+#define VERBOSE        0\r
+#include "ext2_common.h"\r
+#include <modules.h>\r
+\r
+// === IMPORTS ===\r
+extern tVFS_NodeType   gExt2_DirType;\r
+\r
+// === PROTOTYPES ===\r
+ int   Ext2_Install(char **Arguments);\r
+// Interface Functions\r
+tVFS_Node      *Ext2_InitDevice(const char *Device, const char **Options);\r
+void           Ext2_Unmount(tVFS_Node *Node);\r
+void           Ext2_CloseFile(tVFS_Node *Node);\r
+// Internal Helpers\r
+ int           Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
+Uint64         Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
+Uint32         Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
+void           Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
+\r
+// === SEMI-GLOBALS ===\r
+MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
+tExt2_Disk     gExt2_disks[6];\r
+ int   giExt2_count = 0;\r
+tVFS_Driver    gExt2_FSInfo = {\r
+       "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
+       };\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int Ext2_Install(char **Arguments)\r
+ * \brief Install the Ext2 Filesystem Driver\r
+ */\r
+int Ext2_Install(char **Arguments)\r
+{\r
+       VFS_AddDriver( &gExt2_FSInfo );\r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ \brief Initializes a device to be read by by the driver\r
+ \param Device String - Device to read from\r
+ \param Options        NULL Terminated array of option strings\r
+ \return Root Node\r
+*/\r
+tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)\r
+{\r
+       tExt2_Disk      *disk;\r
+        int    fd;\r
+        int    groupCount;\r
+       tExt2_SuperBlock        sb;\r
+       tExt2_Inode     inode;\r
+       \r
+       ENTER("sDevice pOptions", Device, Options);\r
+       \r
+       // Open Disk\r
+       fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);            //Open Device\r
+       if(fd == -1) {\r
+               Log_Warning("EXT2", "Unable to open '%s'", Device);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Read Superblock at offset 1024\r
+       VFS_ReadAt(fd, 1024, 1024, &sb);        // Read Superblock\r
+       \r
+       // Sanity Check Magic value\r
+       if(sb.s_magic != 0xEF53) {\r
+               Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)",\r
+                       Device, sb.s_magic);\r
+               VFS_Close(fd);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Get Group count\r
+       groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
+       LOG("groupCount = %i", groupCount);\r
+       \r
+       // Allocate Disk Information\r
+       disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
+       if(!disk) {\r
+               Log_Warning("EXT2", "Unable to allocate disk structure");\r
+               VFS_Close(fd);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       disk->FD = fd;\r
+       memcpy(&disk->SuperBlock, &sb, 1024);\r
+       disk->GroupCount = groupCount;\r
+       \r
+       // Get an inode cache handle\r
+       disk->CacheID = Inode_GetHandle();\r
+       \r
+       // Get Block Size\r
+       LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
+       disk->BlockSize = 1024 << sb.s_log_block_size;\r
+       \r
+       // Read Group Information\r
+       VFS_ReadAt(\r
+               disk->FD,\r
+               sb.s_first_data_block * disk->BlockSize + 1024,\r
+               sizeof(tExt2_Group)*groupCount,\r
+               disk->Groups\r
+               );\r
+       \r
+       #if VERBOSE\r
+       LOG("Block Group 0");\r
+       LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
+       LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
+       LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
+       LOG("Block Group 1");\r
+       LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
+       LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
+       LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
+       #endif\r
+       \r
+       // Get root Inode\r
+       Ext2_int_ReadInode(disk, 2, &inode);\r
+       \r
+       // Create Root Node\r
+       memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
+       disk->RootNode.Inode = 2;       // Root inode ID\r
+       disk->RootNode.ImplPtr = disk;  // Save disk pointer\r
+       disk->RootNode.Size = -1;       // Fill in later (on readdir)\r
+       disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
+\r
+       disk->RootNode.Type = &gExt2_DirType;\r
+       \r
+       // Complete root node\r
+       disk->RootNode.UID = inode.i_uid;\r
+       disk->RootNode.GID = inode.i_gid;\r
+       disk->RootNode.NumACLs = 1;\r
+       disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
+       \r
+       #if DEBUG\r
+       LOG("inode.i_size = 0x%x", inode.i_size);\r
+       LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
+       #endif\r
+       \r
+       LEAVE('p', &disk->RootNode);\r
+       return &disk->RootNode;\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_Unmount(tVFS_Node *Node)\r
+ * \brief Close a mounted device\r
+ */\r
+void Ext2_Unmount(tVFS_Node *Node)\r
+{\r
+       tExt2_Disk      *disk = Node->ImplPtr;\r
+       \r
+       VFS_Close( disk->FD );\r
+       Inode_ClearCache( disk->CacheID );\r
+       memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
+       free(disk);\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
+ * \brief Close a file (Remove it from the cache)\r
+ */\r
+void Ext2_CloseFile(tVFS_Node *Node)\r
+{\r
+       tExt2_Disk      *disk = Node->ImplPtr;\r
+       Inode_UncacheNode(disk->CacheID, Node->Inode);\r
+       return ;\r
+}\r
+\r
+//==================================\r
+//=       INTERNAL FUNCTIONS       =\r
+//==================================\r
+/**\r
+ * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
+ * \brief Read an inode into memory\r
+ */\r
+int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
+{\r
+        int    group, subId;\r
+       \r
+       ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
+       \r
+       if(InodeId == 0)        return 0;\r
+       \r
+       InodeId --;     // Inodes are numbered starting at 1\r
+       \r
+       group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
+       subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
+       \r
+       LOG("group=%i, subId = %i", group, subId);\r
+       \r
+       // Read Inode\r
+       VFS_ReadAt(Disk->FD,\r
+               Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
+               sizeof(tExt2_Inode),\r
+               Inode);\r
+       \r
+       LEAVE('i', 1);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \brief Write a modified inode out to disk\r
+ */\r
+int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
+{\r
+        int    group, subId;\r
+       ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
+       \r
+       if(InodeId == 0) {\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       \r
+       InodeId --;     // Inodes are numbered starting at 1\r
+       \r
+       group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
+       subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
+       \r
+       LOG("group=%i, subId = %i", group, subId);\r
+       \r
+       // Write Inode\r
+       VFS_WriteAt(Disk->FD,\r
+               Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
+               sizeof(tExt2_Inode),\r
+               Inode\r
+               );\r
+       \r
+       LEAVE('i', 1);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
+ * \brief Get the address of a block from an inode's list\r
+ * \param Disk Disk information structure\r
+ * \param Blocks       Pointer to an inode's block list\r
+ * \param BlockNum     Block index in list\r
+ */\r
+Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
+{\r
+       Uint32  *iBlocks;\r
+        int    dwPerBlock = Disk->BlockSize / 4;\r
+       \r
+       // Direct Blocks\r
+       if(BlockNum < 12)\r
+               return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
+       \r
+       // Single Indirect Blocks\r
+       iBlocks = malloc( Disk->BlockSize );\r
+       VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+       \r
+       BlockNum -= 12;\r
+       if(BlockNum < dwPerBlock)\r
+       {\r
+               BlockNum = iBlocks[BlockNum];\r
+               free(iBlocks);\r
+               return (Uint64)BlockNum * Disk->BlockSize;\r
+       }\r
+       \r
+       BlockNum -= dwPerBlock;\r
+       // Double Indirect Blocks\r
+       if(BlockNum < dwPerBlock*dwPerBlock)\r
+       {\r
+               VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+               VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+               BlockNum = iBlocks[BlockNum%dwPerBlock];\r
+               free(iBlocks);\r
+               return (Uint64)BlockNum * Disk->BlockSize;\r
+       }\r
+       \r
+       BlockNum -= dwPerBlock*dwPerBlock;\r
+       // Triple Indirect Blocks\r
+       VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+       BlockNum = iBlocks[BlockNum%dwPerBlock];\r
+       free(iBlocks);\r
+       return (Uint64)BlockNum * Disk->BlockSize;\r
+}\r
+\r
+/**\r
+ * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
+ * \brief Allocate an inode (from the current group preferably)\r
+ * \param Disk EXT2 Disk Information Structure\r
+ * \param Parent       Inode ID of the parent (used to locate the child nearby)\r
+ */\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
+{\r
+//     Uint    block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
+       Log_Warning("EXT2", "Ext2_int_AllocateInode is unimplemented");\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
+ * \brief Updates the superblock\r
+ */\r
+void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
+{\r
+        int    bpg = Disk->SuperBlock.s_blocks_per_group;\r
+        int    ngrp = Disk->SuperBlock.s_blocks_count / bpg;\r
+        int    i;\r
+        \r
+       // Update Primary\r
+       VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
+       \r
+       // Secondaries\r
+       // at Block Group 1, 3^n, 5^n, 7^n\r
+       \r
+       // 1\r
+       if(ngrp <= 1)   return;\r
+       VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+       \r
+       #define INT_MAX (((long long int)1<<(sizeof(int)*8))-1)\r
+       \r
+       // Powers of 3\r
+       for( i = 3; i < ngrp && i < INT_MAX/3; i *= 3 )\r
+               VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+       \r
+       // Powers of 5\r
+       for( i = 5; i < ngrp && i < INT_MAX/5; i *= 5 )\r
+               VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+       \r
+       // Powers of 7\r
+       for( i = 7; i < ngrp && i < INT_MAX/7; i *= 7 )\r
+               VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+}\r
diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2_common.h b/KernelLand/Modules/Filesystems/Ext2/ext2_common.h
new file mode 100644 (file)
index 0000000..6ef9d7c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file ext2_common.h
+ * \brief Second Extended Filesystem Driver
+ */
+#ifndef _EXT2_COMMON_H
+#define _EXT2_COMMON_H
+#include <acess.h>
+#include <vfs.h>
+#include "ext2fs.h"
+
+#define EXT2_UPDATE_WRITEBACK  1
+
+// === STRUCTURES ===
+typedef struct {
+        int    FD;
+        int    CacheID;
+       tVFS_Node       RootNode;
+       
+       tExt2_SuperBlock        SuperBlock;
+       Uint    BlockSize;
+        
+        int    GroupCount;
+       tExt2_Group             Groups[];
+} tExt2_Disk;
+
+// === FUNCTIONS ===
+// --- Common ---
+extern void    Ext2_CloseFile(tVFS_Node *Node);
+extern Uint64  Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
+extern void    Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
+extern int     Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
+extern int     Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
+// --- Dir ---
+extern char    *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+extern tVFS_Node       *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
+extern int     Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+extern int     Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
+// --- Read ---
+extern Uint64  Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+// --- Write ---
+extern Uint64  Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, const void *buffer);
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2fs.h b/KernelLand/Modules/Filesystems/Ext2/ext2fs.h
new file mode 100644 (file)
index 0000000..a3aa301
--- /dev/null
@@ -0,0 +1,162 @@
+/**\r
+ * Acess2\r
+ * \file ext2fs.h\r
+ * \brief EXT2 Filesystem Driver\r
+ */\r
+#ifndef _EXT2FS_H_\r
+#define _EXT2FS_H_\r
+\r
+/**\r
+ \name Inode Flag Values\r
+ \{\r
+*/\r
+#define EXT2_S_IFMT            0xF000  //!< Format Mask\r
+#define EXT2_S_IFSOCK  0xC000  //!< Socket\r
+#define EXT2_S_IFLNK   0xA000  //!< Symbolic Link\r
+#define EXT2_S_IFREG   0x8000  //!< Regular File\r
+#define EXT2_S_IFBLK   0x6000  //!< Block Device\r
+#define EXT2_S_IFDIR   0x4000  //!< Directory\r
+#define EXT2_S_IFCHR   0x2000  //!< Character Device\r
+#define EXT2_S_IFIFO   0x1000  //!< FIFO\r
+#define EXT2_S_ISUID   0x0800  //!< SUID\r
+#define EXT2_S_ISGID   0x0400  //!< SGID\r
+#define EXT2_S_ISVTX   0x0200  //!< sticky bit\r
+#define EXT2_S_IRWXU   0700    //!< user access rights mask\r
+#define EXT2_S_IRUSR   0400    //!< Owner Read\r
+#define EXT2_S_IWUSR   0200    //!< Owner Write\r
+#define EXT2_S_IXUSR   0100    //!< Owner Execute\r
+#define EXT2_S_IRWXG   0070    //!< Group Access rights mask\r
+#define EXT2_S_IRGRP   0040    //!< Group Read\r
+#define EXT2_S_IWGRP   0020    //!< Group Write\r
+#define EXT2_S_IXGRP   0010    //!< Group Execute\r
+#define EXT2_S_IRWXO   0007    //!< Global Access rights mask\r
+#define EXT2_S_IROTH   0004    //!< Global Read\r
+#define EXT2_S_IWOTH   0002    //!< Global Write\r
+#define EXT2_S_IXOTH   0001    //!< Global Execute\r
+//! \}\r
+\r
+#define EXT2_NAME_LEN 255      //!< Maximum Name Length\r
+\r
+// === TYPEDEFS ===\r
+typedef struct ext2_inode_s                    tExt2_Inode;    //!< Inode Type\r
+typedef struct ext2_super_block_s      tExt2_SuperBlock;       //!< Superblock Type\r
+typedef struct ext2_group_desc_s       tExt2_Group;    //!< Group Descriptor Type\r
+typedef struct ext2_dir_entry_s                tExt2_DirEnt;   //!< Directory Entry Type\r
+\r
+// === STRUCTURES ===\r
+/**\r
+ * \brief EXT2 Superblock Structure\r
+ */\r
+struct ext2_super_block_s {\r
+       Uint32  s_inodes_count;         //!< Inodes count\r
+       Uint32  s_blocks_count;         //!< Blocks count\r
+       Uint32  s_r_blocks_count;       //!< Reserved blocks count\r
+       Uint32  s_free_blocks_count;    //!< Free blocks count\r
+       \r
+       Uint32  s_free_inodes_count;    //!< Free inodes count\r
+       Uint32  s_first_data_block;     //!< First Data Block\r
+       Uint32  s_log_block_size;       //!< Block size\r
+       Sint32  s_log_frag_size;        //!< Fragment size\r
+       \r
+       Uint32  s_blocks_per_group;     //!< Number Blocks per group\r
+       Uint32  s_frags_per_group;      //!< Number Fragments per group\r
+       Uint32  s_inodes_per_group;     //!< Number Inodes per group\r
+       Uint32  s_mtime;                        //!< Mount time\r
+       \r
+       Uint32  s_wtime;                        //!< Write time\r
+       Uint16  s_mnt_count;            //!< Mount count\r
+       Sint16  s_max_mnt_count;        //!< Maximal mount count\r
+       Uint16  s_magic;                        //!< Magic signature\r
+       Uint16  s_state;                        //!< File system state\r
+       Uint16  s_errors;                       //!< Behaviour when detecting errors\r
+       Uint16  s_pad;                          //!< Padding\r
+       \r
+       Uint32  s_lastcheck;            //!< time of last check\r
+       Uint32  s_checkinterval;        //!< max. time between checks\r
+       Uint32  s_creator_os;           //!< Formatting OS\r
+       Uint32  s_rev_level;            //!< Revision level\r
+       \r
+       Uint16  s_def_resuid;           //!< Default uid for reserved blocks\r
+       Uint16  s_def_resgid;           //!< Default gid for reserved blocks\r
+       Uint32  s_reserved[235];        //!< Padding to the end of the block\r
+};\r
+\r
+/**\r
+ * \struct ext2_inode_s\r
+ * \brief EXT2 Inode Definition\r
+ */\r
+struct ext2_inode_s {\r
+       Uint16 i_mode;  //!< File mode\r
+       Uint16 i_uid;   //!< Owner Uid\r
+       Uint32 i_size;  //!< Size in bytes\r
+       Uint32 i_atime; //!< Access time\r
+       Uint32 i_ctime; //!< Creation time\r
+       Uint32 i_mtime; //!< Modification time\r
+       Uint32 i_dtime; //!< Deletion Time\r
+       Uint16 i_gid;   //!< Group Id\r
+       Uint16 i_links_count;   //!< Links count\r
+       Uint32 i_blocks;        //!< Number of blocks allocated for the file\r
+       Uint32 i_flags; //!< File flags\r
+       union {\r
+               Uint32 linux_reserved1; //!< Linux: Reserved\r
+               Uint32 hurd_translator; //!< HURD: Translator\r
+               Uint32 masix_reserved1; //!< Masix: Reserved\r
+       } osd1; //!< OS dependent 1\r
+       Uint32 i_block[15];     //!< Pointers to blocks\r
+       Uint32 i_version;       //!< File version (for NFS)\r
+       Uint32 i_file_acl;      //!< File ACL\r
+       Uint32 i_dir_acl;       //!< Directory ACL / Extended File Size\r
+       Uint32 i_faddr;         //!< Fragment address\r
+       union {\r
+               struct {\r
+                       Uint8 l_i_frag; //!< Fragment number\r
+                       Uint8 l_i_fsize;        //!< Fragment size\r
+                       Uint16 i_pad1;  //!< Padding\r
+                       Uint32 l_i_reserved2[2];        //!< Reserved\r
+               } linux2;\r
+               struct {\r
+                       Uint8 h_i_frag; //!< Fragment number\r
+                       Uint8 h_i_fsize; //!< Fragment size\r
+                       Uint16 h_i_mode_high;   //!< Mode High Bits\r
+                       Uint16 h_i_uid_high;    //!< UID High Bits\r
+                       Uint16 h_i_gid_high;    //!< GID High Bits\r
+                       Uint32 h_i_author;      //!< Creator ID\r
+               } hurd2;\r
+               struct {\r
+                       Uint8 m_i_frag; //!< Fragment number\r
+                       Uint8 m_i_fsize;        //!< Fragment size\r
+                       Uint16 m_pad1;  //!< Padding\r
+                       Uint32 m_i_reserved2[2];        //!< reserved\r
+               } masix2;\r
+       } osd2; //!< OS dependent 2\r
+};\r
+\r
+/**\r
+ * \struct ext2_group_desc_s\r
+ * \brief EXT2 Group Descriptor\r
+ */\r
+struct ext2_group_desc_s {\r
+       Uint32  bg_block_bitmap;        //!< Blocks bitmap block\r
+       Uint32  bg_inode_bitmap;        //!< Inodes bitmap block\r
+       Uint32  bg_inode_table; //!< Inodes table block\r
+       Uint16  bg_free_blocks_count;   //!< Free blocks count\r
+       Uint16  bg_free_inodes_count;   //!< Free inodes count\r
+       Uint16  bg_used_dirs_count;     //!< Directories count\r
+       Uint16  bg_pad; //!< Padding\r
+       Uint32  bg_reserved[3]; //!< Reserved\r
+};\r
+\r
+/**\r
+ * \brief EXT2 Directory Entry\r
+ * \note The name may take up less than 255 characters\r
+ */\r
+struct ext2_dir_entry_s {\r
+       Uint32  inode;          //!< Inode number\r
+       Uint16  rec_len;        //!< Directory entry length\r
+       Uint8   name_len;       //!< Short Name Length\r
+       Uint8   type;           //!< File Type (Duplicate of ext2_inode_s.i_mode)\r
+       char    name[EXT2_NAME_LEN+1];          //!< File name\r
+};\r
+#define EXT2_DIRENT_SIZE       (sizeof(struct ext2_dir_entry_s)-EXT2_NAME_LEN+1)\r
+\r
+#endif\r
diff --git a/KernelLand/Modules/Filesystems/Ext2/read.c b/KernelLand/Modules/Filesystems/Ext2/read.c
new file mode 100644 (file)
index 0000000..81f5ee6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file read.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG  1
+#define VERBOSE        0
+#include "ext2_common.h"
+
+// === PROTOTYPES ===
+Uint64         Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+
+// === CODE ===
+/**
+ * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a file
+ */
+Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tExt2_Disk      *disk = Node->ImplPtr;
+       tExt2_Inode     inode;
+       Uint64  base;
+       Uint    block;
+       Uint64  remLen;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       // Get Inode
+       Ext2_int_ReadInode(disk, Node->Inode, &inode);
+       
+       // Sanity Checks
+       if(Offset >= inode.i_size) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       if(Offset + Length > inode.i_size)
+               Length = inode.i_size - Offset;
+       
+       block = Offset / disk->BlockSize;
+       Offset = Offset / disk->BlockSize;
+       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+       if(base == 0) {
+               Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Read only block
+       if(Length <= disk->BlockSize - Offset)
+       {
+               VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);
+               LEAVE('X', Length);
+               return Length;
+       }
+       
+       // Read first block
+       remLen = Length;
+       VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);
+       remLen -= disk->BlockSize - Offset;
+       Buffer += disk->BlockSize - Offset;
+       block ++;
+       
+       // Read middle blocks
+       while(remLen > disk->BlockSize)
+       {
+               base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+               if(base == 0) {
+                       Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);
+               Buffer += disk->BlockSize;
+               remLen -= disk->BlockSize;
+               block ++;
+       }
+       
+       // Read last block
+       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+       VFS_ReadAt( disk->FD, base, remLen, Buffer);
+       
+       LEAVE('X', Length);
+       return Length;
+}
diff --git a/KernelLand/Modules/Filesystems/Ext2/write.c b/KernelLand/Modules/Filesystems/Ext2/write.c
new file mode 100644 (file)
index 0000000..03109e8
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file write.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG  1
+#define VERBOSE        0
+#include "ext2_common.h"
+
+// === PROTOYPES ===
+Uint32         Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
+void   Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
+ int   Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
+
+// === CODE ===
+/**
+ * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a file
+ */
+Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tExt2_Disk      *disk = Node->ImplPtr;
+       tExt2_Inode     inode;
+       Uint64  base;
+       Uint64  retLen;
+       Uint    block;
+       Uint64  allocSize;
+        int    bNewBlocks = 0;
+       
+       Debug_HexDump("Ext2_Write", Buffer, Length);
+       
+       Ext2_int_ReadInode(disk, Node->Inode, &inode);
+       
+       // Get the ammount of space already allocated
+       // - Round size up to block size
+       // - block size is a power of two, so this will work
+       allocSize = (inode.i_size + disk->BlockSize-1) & ~(disk->BlockSize-1);
+       
+       // Are we writing to inside the allocated space?
+       if( Offset > allocSize )        return 0;
+       
+       if( Offset < allocSize )
+       {
+               // Will we go out of it?
+               if(Offset + Length > allocSize) {
+                       bNewBlocks = 1;
+                       retLen = allocSize - Offset;
+               } else
+                       retLen = Length;
+               
+               // Within the allocated space
+               block = Offset / disk->BlockSize;
+               Offset %= disk->BlockSize;
+               base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+               
+               // Write only block (if only one)
+               if(Offset + retLen <= disk->BlockSize) {
+                       VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);
+                       if(!bNewBlocks) return Length;
+                       goto addBlocks; // Ugh! A goto, but it seems unavoidable
+               }
+               
+               // Write First Block
+               VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);
+               Buffer += disk->BlockSize-Offset;
+               retLen -= disk->BlockSize-Offset;
+               block ++;
+               
+               // Write middle blocks
+               while(retLen > disk->BlockSize)
+               {
+                       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+                       VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
+                       Buffer += disk->BlockSize;
+                       retLen -= disk->BlockSize;
+                       block ++;
+               }
+               
+               // Write last block
+               base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+               VFS_WriteAt(disk->FD, base, retLen, Buffer);
+               if(!bNewBlocks) return Length;  // Writing in only allocated space
+       }
+       else
+               base = Ext2_int_GetBlockAddr(disk, inode.i_block, allocSize/disk->BlockSize-1);
+       
+addBlocks:
+       Log_Notice("EXT2", "File extending is untested");
+       
+       // Allocate blocks and copy data to them
+       retLen = Length - (allocSize-Offset);
+       while( retLen > disk->BlockSize )
+       {
+               // Allocate a block
+               block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
+               if(!block)      return Length - retLen;
+               // Add it to this inode
+               if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+                       Ext2_int_DeallocateBlock(disk, block);
+                       goto ret;
+               }
+               // Copy data to the node
+               base = block * disk->BlockSize;
+               VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
+               // Update pointer and size remaining
+               inode.i_size += disk->BlockSize;
+               Buffer += disk->BlockSize;
+               retLen -= disk->BlockSize;
+       }
+       // Last block :D
+       block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
+       if(!block)      goto ret;
+       if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+               Ext2_int_DeallocateBlock(disk, block);
+               goto ret;
+       }
+       base = block * disk->BlockSize;
+       VFS_WriteAt(disk->FD, base, retLen, Buffer);
+       inode.i_size += retLen;
+       retLen = 0;
+
+ret:   // Makes sure the changes to the inode are committed
+       Ext2_int_WriteInode(disk, Node->Inode, &inode);
+       return Length - retLen;
+}
+
+/**
+ * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
+ * \brief Allocate a block from the best possible location
+ * \param Disk EXT2 Disk Information Structure
+ * \param PrevBlock    Previous block ID in the file
+ */
+Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
+{
+        int    bpg = Disk->SuperBlock.s_blocks_per_group;
+       Uint    blockgroup = PrevBlock / bpg;
+       Uint    bitmap[Disk->BlockSize/sizeof(Uint)];
+       Uint    bitsperblock = 8*Disk->BlockSize;
+        int    i, j = 0;
+       Uint    block;
+       
+       // Are there any free blocks?
+       if(Disk->SuperBlock.s_free_blocks_count == 0)   return 0;
+       
+       if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
+       {
+               // Search block group's bitmap
+               for(i = 0; i < bpg; i++)
+               {
+                       // Get the block in the bitmap block
+                       j = i & (bitsperblock-1);
+                       
+                       // Read in if needed
+                       if(j == 0) {
+                               VFS_ReadAt(
+                                       Disk->FD,
+                                       (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
+                                       Disk->BlockSize,
+                                       bitmap
+                                       );
+                       }
+                       
+                       // Fast Check
+                       if( bitmap[j/32] == 0xFFFFFFFF ) {
+                               j = (j + 31) & ~31;
+                               continue;
+                       }
+                       
+                       // Is the bit set?
+                       if( bitmap[j/32] & (1 << (j%32)) )
+                               continue;
+                       
+                       // Ooh! We found one
+                       break;
+               }
+               if( i < bpg ) {
+                       Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
+                       goto    checkAll;       // Search the entire filesystem for a free block
+                       // Goto needed for neatness
+               }
+               
+               // Mark as used
+               bitmap[j/32] |= (1 << (j%32));
+               VFS_WriteAt(
+                       Disk->FD,
+                       (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
+                       Disk->BlockSize,
+                       bitmap
+                       );
+               block = i;
+               Disk->Groups[blockgroup].bg_free_blocks_count --;
+               #if EXT2_UPDATE_WRITEBACK
+               //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
+               #endif
+       }
+       else
+       {
+       checkAll:
+               Log_Warning("EXT2", "TODO - Implement using blocks outside the current block group");
+               return 0;
+       }
+       
+       // Reduce global count
+       Disk->SuperBlock.s_free_blocks_count --;
+       #if EXT2_UPDATE_WRITEBACK
+       Ext2_int_UpdateSuperblock(Disk);
+       #endif
+       
+       return block;
+}
+
+/**
+ * \brief Deallocates a block
+ */
+void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block)
+{
+}
+
+/**
+ * \brief Append a block to an inode
+ */
+int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
+{
+        int    nBlocks;
+        int    dwPerBlock = Disk->BlockSize / 4;
+       Uint32  *blocks;
+       Uint32  id1, id2;
+       
+       nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize;
+       
+       // Direct Blocks
+       if( nBlocks < 12 ) {
+               Inode->i_block[nBlocks] = Block;
+               return 0;
+       }
+       
+       blocks = malloc( Disk->BlockSize );
+       if(!blocks)     return 1;
+       
+       nBlocks -= 12;
+       // Single Indirect
+       if( nBlocks < dwPerBlock)
+       {
+               // Allocate/Get Indirect block
+               if( nBlocks == 0 ) {
+                       Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+                       if( !Inode->i_block[12] ) {
+                               free(blocks);
+                               return 1;
+                       }
+                       memset(blocks, 0, Disk->BlockSize); 
+               }
+               else
+                       VFS_ReadAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks);
+               
+               blocks[nBlocks] = Block;
+               
+               VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks);
+               free(blocks);
+               return 0;
+       }
+       
+       nBlocks += dwPerBlock;
+       // Double Indirect
+       if( nBlocks < dwPerBlock*dwPerBlock )
+       {
+               // Allocate/Get Indirect block
+               if( nBlocks == 0 ) {
+                       Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+                       if( !Inode->i_block[13] ) {
+                               free(blocks);
+                               return 1;
+                       }
+                       memset(blocks, 0, Disk->BlockSize);
+               }
+               else
+                       VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks);
+               
+               // Allocate / Get Indirect lvl2 Block
+               if( nBlocks % dwPerBlock == 0 ) {
+                       id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+                       if( !id1 ) {
+                               free(blocks);
+                               return 1;
+                       }
+                       blocks[nBlocks/dwPerBlock] = id1;
+                       // Write back indirect 1 block
+                       VFS_WriteAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks);
+                       memset(blocks, 0, Disk->BlockSize);
+               }
+               else {
+                       id1 = blocks[nBlocks / dwPerBlock];
+                       VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+               }
+               
+               blocks[nBlocks % dwPerBlock] = Block;
+               
+               VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+               free(blocks);
+               return 0;
+       }
+       
+       nBlocks -= dwPerBlock*dwPerBlock;
+       // Triple Indirect
+       if( nBlocks < dwPerBlock*dwPerBlock*dwPerBlock )
+       {
+               // Allocate/Get Indirect block
+               if( nBlocks == 0 ) {
+                       Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+                       if( !Inode->i_block[14] ) {
+                               free(blocks);
+                               return 1;
+                       }
+                       memset(blocks, 0, Disk->BlockSize);
+               }
+               else
+                       VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks);
+               
+               // Allocate / Get Indirect lvl2 Block
+               if( (nBlocks/dwPerBlock) % dwPerBlock == 0 && nBlocks % dwPerBlock == 0 )
+               {
+                       id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+                       if( !id1 ) {
+                               free(blocks);
+                               return 1;
+                       }
+                       blocks[nBlocks/dwPerBlock] = id1;
+                       // Write back indirect 1 block
+                       VFS_WriteAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks);
+                       memset(blocks, 0, Disk->BlockSize);
+               }
+               else {
+                       id1 = blocks[nBlocks / (dwPerBlock*dwPerBlock)];
+                       VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+               }
+               
+               // Allocate / Get Indirect Level 3 Block
+               if( nBlocks % dwPerBlock == 0 ) {
+                       id2 = Ext2_int_AllocateBlock(Disk, id1);
+                       if( !id2 ) {
+                               free(blocks);
+                               return 1;
+                       }
+                       blocks[(nBlocks/dwPerBlock)%dwPerBlock] = id2;
+                       // Write back indirect 1 block
+                       VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+                       memset(blocks, 0, Disk->BlockSize);
+               }
+               else {
+                       id2 = blocks[(nBlocks/dwPerBlock)%dwPerBlock];
+                       VFS_ReadAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks);
+               }
+               
+               blocks[nBlocks % dwPerBlock] = Block;
+               
+               VFS_WriteAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks);
+               free(blocks);
+               return 0;
+       }
+       
+       Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used");
+       free(blocks);
+       return 1;
+}
diff --git a/KernelLand/Modules/Filesystems/FAT/Makefile b/KernelLand/Modules/Filesystems/FAT/Makefile
new file mode 100644 (file)
index 0000000..dfa290b
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = fat.o
+NAME = FAT
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/FAT/fat.c b/KernelLand/Modules/Filesystems/FAT/fat.c
new file mode 100644 (file)
index 0000000..f5d1916
--- /dev/null
@@ -0,0 +1,1538 @@
+/*\r
+ * Acess 2\r
+ * FAT12/16/32 Driver Version (Incl LFN)\r
+ * \r
+ * NOTE: This driver will only support _reading_ long file names, not\r
+ * writing. I don't even know why I'm adding write-support. FAT sucks.\r
+ * \r
+ * Known Bugs:\r
+ * - LFN Is buggy in FAT_ReadDir\r
+ * \r
+ * Notes:\r
+ * - There's hard-coded 512 byte sectors everywhere, that needs to be\r
+ *   cleaned.\r
+ * - Thread safety is out the window with the write and LFN code\r
+ */\r
+/**\r
+ * \todo Implement changing of the parent directory when a file is written to\r
+ * \todo Implement file creation / deletion\r
+ */\r
+#define DEBUG  0\r
+#define VERBOSE        1\r
+\r
+#define CACHE_FAT      0       //!< Caches the FAT in memory\r
+#define USE_LFN                1       //!< Enables the use of Long File Names\r
+#define        SUPPORT_WRITE   0       //!< Enables write support\r
+\r
+#include <acess.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include "fs_fat.h"\r
+\r
+#define FAT_FLAG_DIRTY 0x10000\r
+#define FAT_FLAG_DELETE        0x20000\r
+\r
+// === TYPES ===\r
+#if USE_LFN\r
+/**\r
+ * \brief Long-Filename cache entry\r
+ */\r
+typedef struct sFAT_LFNCacheEnt\r
+{\r
+        int    ID;\r
+       // TODO: Handle UTF16 names correctly\r
+       char    Data[256];\r
+}      tFAT_LFNCacheEnt;\r
+/**\r
+ * \brief Long-Filename cache\r
+ */\r
+typedef struct sFAT_LFNCache\r
+{\r
+        int    NumEntries;\r
+       tFAT_LFNCacheEnt        Entries[];\r
+}      tFAT_LFNCache;\r
+#endif\r
+\r
+// === PROTOTYPES ===\r
+// --- Driver Core\r
+ int   FAT_Install(char **Arguments);\r
+tVFS_Node      *FAT_InitDevice(const char *device, const char **options);\r
+void   FAT_Unmount(tVFS_Node *Node);\r
+// --- Helpers\r
+ int   FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);\r
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
+#if SUPPORT_WRITE\r
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);\r
+#endif\r
+void   FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
+// --- File IO\r
+Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+#if SUPPORT_WRITE\r
+void   FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
+Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+#endif\r
+// --- Directory IO\r
+char   *FAT_ReadDir(tVFS_Node *Node, int ID);\r
+tVFS_Node      *FAT_FindDir(tVFS_Node *Node, const char *Name);\r
+tVFS_Node      *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);\r
+#if SUPPORT_WRITE\r
+ int   FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);\r
+ int   FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);\r
+#endif\r
+void   FAT_CloseFile(tVFS_Node *node);\r
+\r
+// === Options ===\r
+ int   giFAT_MaxCachedClusters = 1024*512/4;\r
+\r
+// === SEMI-GLOBALS ===\r
+MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
+tFAT_VolInfo   gFAT_Disks[8];\r
+ int   giFAT_PartCount = 0;\r
+tVFS_Driver    gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
+tVFS_NodeType  gFAT_DirType = {\r
+       .TypeName = "FAT-Dir",\r
+       .ReadDir = FAT_ReadDir,\r
+       .FindDir = FAT_FindDir,\r
+       #if SUPPORT_WRITE\r
+       .MkNod = FAT_Mknod,\r
+       .Relink = FAT_Relink,\r
+       #endif\r
+       .Close = FAT_CloseFile\r
+       };\r
+tVFS_NodeType  gFAT_FileType = {\r
+       .TypeName = "FAT-File",\r
+       .Read = FAT_Read,\r
+       #if SUPPORT_WRITE\r
+       .Write = FAT_Write,\r
+       #endif\r
+       .Close = FAT_CloseFile\r
+       };\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int FAT_Install(char **Arguments)\r
+ * \brief Install the FAT Driver\r
+ */\r
+int FAT_Install(char **Arguments)\r
+{\r
+       VFS_AddDriver( &gFAT_FSInfo );\r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \brief Reads the boot sector of a disk and prepares the structures for it\r
+ */\r
+tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)\r
+{\r
+       fat_bootsect *bs;\r
+        int    i;\r
+       Uint32  FATSz, RootDirSectors, TotSec;\r
+       tVFS_Node       *node = NULL;\r
+       tFAT_VolInfo    *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
+       \r
+       // Temporary Pointer\r
+       bs = &diskInfo->bootsect;\r
+       \r
+       // Open device and read boot sector\r
+       diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);\r
+       if(diskInfo->fileHandle == -1) {\r
+               Log_Notice("FAT", "Unable to open device '%s'", Device);\r
+               return NULL;\r
+       }\r
+       \r
+       VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
+       \r
+       if(bs->bps == 0 || bs->spc == 0) {\r
+               Log_Notice("FAT", "Error in FAT Boot Sector");\r
+               return NULL;\r
+       }\r
+       \r
+       // FAT Type Determining\r
+       // - From Microsoft FAT Specifcation\r
+       RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps;\r
+       \r
+       if(bs->fatSz16 != 0)\r
+               FATSz = bs->fatSz16;\r
+       else\r
+               FATSz = bs->spec.fat32.fatSz32;\r
+       \r
+       if(bs->totalSect16 != 0)\r
+               TotSec = bs->totalSect16;\r
+       else\r
+               TotSec = bs->totalSect32;\r
+       \r
+       diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
+       \r
+       if(diskInfo->ClusterCount < 4085)\r
+               diskInfo->type = FAT12;\r
+       else if(diskInfo->ClusterCount < 65525)\r
+               diskInfo->type = FAT16;\r
+       else\r
+               diskInfo->type = FAT32;\r
+       \r
+       #if VERBOSE\r
+       {\r
+               char    *sFatType, *sSize;\r
+               Uint    iSize = diskInfo->ClusterCount * bs->spc * bs->bps / 1024;\r
+               \r
+               switch(diskInfo->type)\r
+               {\r
+               case FAT12:     sFatType = "FAT12";     break;\r
+               case FAT16:     sFatType = "FAT16";     break;\r
+               case FAT32:     sFatType = "FAT32";     break;\r
+               default:        sFatType = "UNKNOWN";   break;\r
+               }\r
+               if(iSize <= 2*1024) {\r
+                       sSize = "KiB";\r
+               }\r
+               else if(iSize <= 2*1024*1024) {\r
+                       sSize = "MiB";\r
+                       iSize >>= 10;\r
+               }\r
+               else {\r
+                       sSize = "GiB";\r
+                       iSize >>= 20;\r
+               }\r
+               Log_Notice("FAT", "'%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
+       }\r
+       #endif\r
+       \r
+       // Get Name\r
+       if(diskInfo->type == FAT32) {\r
+               for(i=0;i<11;i++)\r
+                       diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]);\r
+       }\r
+       else {\r
+               for(i=0;i<11;i++)\r
+                       diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]);\r
+       }\r
+       diskInfo->name[11] = '\0';\r
+       \r
+       // Compute Root directory offset\r
+       if(diskInfo->type == FAT32)\r
+               diskInfo->rootOffset = bs->spec.fat32.rootClust;\r
+       else\r
+               diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc;\r
+       \r
+       diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;\r
+       \r
+       //Allow for Caching the FAT\r
+       #if CACHE_FAT\r
+       if( diskInfo->ClusterCount <= giFAT_MaxCachedClusters )\r
+       {\r
+               Uint32  Ofs;\r
+               diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
+               if(diskInfo->FATCache == NULL) {\r
+                       Log_Warning("FAT", "Heap Exhausted");\r
+                       return NULL;\r
+               }\r
+               Ofs = bs->resvSectCount*512;\r
+               if(diskInfo->type == FAT12)\r
+               {\r
+                       Uint32  val;\r
+                        int    j;\r
+                       char    buf[1536];\r
+                       for(i = 0; i < diskInfo->ClusterCount/2; i++) {\r
+                               j = i & 511;    //%512\r
+                               if( j == 0 ) {\r
+                                       VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf);\r
+                                       Ofs += 3*512;\r
+                               }\r
+                               val = *((int*)(buf+j*3));\r
+                               diskInfo->FATCache[i*2] = val & 0xFFF;\r
+                               diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF;\r
+                       }\r
+               }\r
+               else if(diskInfo->type == FAT16)\r
+               {\r
+                       Uint16  buf[256];\r
+                       for(i=0;i<diskInfo->ClusterCount;i++) {\r
+                               if( (i & 255) == 0 ) {\r
+                                       VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
+                                       Ofs += 512;\r
+                               }\r
+                               diskInfo->FATCache[i] = buf[i&255];\r
+                       }\r
+               }\r
+               else if(diskInfo->type == FAT32)\r
+               {\r
+                       Uint32  buf[128];\r
+                       for(i=0;i<diskInfo->ClusterCount;i++) {\r
+                               if( (i & 127) == 0 ) {\r
+                                       VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
+                                       Ofs += 512;\r
+                               }\r
+                               diskInfo->FATCache[i] = buf[i&127];\r
+                       }\r
+               }\r
+               LOG("FAT Fully Cached");\r
+       }\r
+       #endif /*CACHE_FAT*/\r
+       \r
+       diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
+       \r
+       // Initalise inode cache for filesystem\r
+       diskInfo->inodeHandle = Inode_GetHandle();\r
+       LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
+       \r
+       // == VFS Interface\r
+       node = &diskInfo->rootNode;\r
+       //node->Size = bs->files_in_root;\r
+       node->Size = -1;\r
+       node->Inode = diskInfo->rootOffset;     // 0:31 - Cluster, 32:63 - Parent Directory Cluster\r
+       node->ImplPtr = diskInfo;       // Disk info pointer\r
+       node->ImplInt = 0;      // 0:15 - Directory Index, 16: Dirty Flag, 17: Deletion Flag\r
+       \r
+       node->ReferenceCount = 1;\r
+       \r
+       node->UID = 0;  node->GID = 0;\r
+       node->NumACLs = 1;\r
+       node->ACLs = &gVFS_ACL_EveryoneRWX;\r
+       node->Flags = VFS_FFLAG_DIRECTORY;\r
+       node->CTime = node->MTime = node->ATime = now();\r
+\r
+       node->Type = &gFAT_DirType;     \r
+       \r
+       giFAT_PartCount ++;\r
+       return node;\r
+}\r
+\r
+/**\r
+ * \brief Closes a mount and marks it as free\r
+ * \param Node Mount Root\r
+ * \r
+ * \todo Remove FAT Cache\r
+ * \todo Clear LFN Cache\r
+ * \todo Check that all files are closed and flushed\r
+ */\r
+void FAT_Unmount(tVFS_Node *Node)\r
+{\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       // Close Disk Handle\r
+       VFS_Close( disk->fileHandle );\r
+       // Clear Node Cache\r
+       Inode_ClearCache(disk->inodeHandle);\r
+       // Mark as unused\r
+       disk->fileHandle = -2;\r
+       return;\r
+}\r
+\r
+/**\r
+ * \brief Converts an offset in a file into a disk address\r
+ * \param Node File (or directory) node\r
+ * \param Offset       Offset in the file\r
+ * \param Addr Return Address\r
+ * \param Cluster      Set to the current cluster (or the last one if \a Offset\r
+ *                  is past EOC) - Not touched if the node is the root\r
+ *                  directory.\r
+ * \return Zero on success, non-zero on error\r
+ */\r
+int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
+{\r
+       Uint32  cluster;\r
+       Uint64  addr;\r
+        int    skip;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       ENTER("pNode XOffset", Node, Offset);\r
+       \r
+       cluster = Node->Inode & 0xFFFFFFF;      // Cluster ID\r
+       LOG("cluster = 0x%07x", cluster);\r
+       \r
+       // Do Cluster Skip\r
+       // - Pre FAT32 had a reserved area for the root.\r
+       if( disk->type == FAT32 || cluster != disk->rootOffset )\r
+       {\r
+               skip = Offset / disk->BytesPerCluster;\r
+               LOG("skip = %i", skip);\r
+               // Skip previous clusters\r
+               for(; skip-- ; )\r
+               {\r
+                       if(Cluster)     *Cluster = cluster;\r
+                       cluster = FAT_int_GetFatValue(disk, cluster);\r
+                       // Check for end of cluster chain\r
+                       if(cluster == 0xFFFFFFFF) {     LEAVE('i', 1);  return 1;}\r
+               }\r
+               if(Cluster)     *Cluster = cluster;\r
+       }\r
+       else {\r
+               // Increment by clusters in offset\r
+               cluster += Offset / disk->BytesPerCluster;\r
+       }\r
+       \r
+       LOG("cluster = %08x", cluster);\r
+       \r
+       // Bounds Checking (Used to spot corruption)\r
+       if(cluster > disk->ClusterCount + 2)\r
+       {\r
+               Log_Warning("FAT", "Cluster ID is over cluster count (0x%x>0x%x)",\r
+                       cluster, disk->ClusterCount+2);\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       // Compute Offsets\r
+       // - Pre FAT32 cluster base (in sectors)\r
+       if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
+               addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
+               addr += cluster * disk->BytesPerCluster;\r
+       }\r
+       else {\r
+               addr = disk->firstDataSect * disk->bootsect.bps;\r
+               addr += (cluster - 2) * disk->BytesPerCluster;\r
+       }\r
+       // In-cluster offset\r
+       addr += Offset % disk->BytesPerCluster;\r
+       \r
+       LOG("addr = 0x%08x", addr);\r
+       *Addr = addr;\r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * ====================\r
+ *   FAT Manipulation\r
+ * ====================\r
+ */\r
+/**\r
+ * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
+ * \brief Fetches a value from the FAT\r
+ */\r
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
+{\r
+       Uint32  val = 0;\r
+       Uint32  ofs;\r
+       ENTER("pDisk xCluster", Disk, cluster);\r
+       Mutex_Acquire( &Disk->lFAT );\r
+       #if CACHE_FAT\r
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
+       {\r
+               val = Disk->FATCache[cluster];\r
+               if(Disk->type == FAT12 && val == EOC_FAT12)     val = -1;\r
+               if(Disk->type == FAT16 && val == EOC_FAT16)     val = -1;\r
+               if(Disk->type == FAT32 && val == EOC_FAT32)     val = -1;\r
+       }\r
+       else\r
+       {\r
+       #endif\r
+               ofs = Disk->bootsect.resvSectCount*512;\r
+               if(Disk->type == FAT12) {\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);\r
+                       val = (cluster & 1 ? val>>12 : val & 0xFFF);\r
+                       if(val == EOC_FAT12)    val = -1;\r
+               } else if(Disk->type == FAT16) {\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
+                       if(val == EOC_FAT16)    val = -1;\r
+               } else {\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
+                       if(val == EOC_FAT32)    val = -1;\r
+               }\r
+       #if CACHE_FAT\r
+       }\r
+       #endif /*CACHE_FAT*/\r
+       Mutex_Release( &Disk->lFAT );\r
+       LEAVE('x', val);\r
+       return val;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \brief Allocate a new cluster\r
+ */\r
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
+{\r
+       Uint32  ret = Previous;\r
+       #if CACHE_FAT\r
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
+       {\r
+               Uint32  eoc;\r
+               \r
+               LOCK(Disk->lFAT);\r
+               for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
+               {\r
+                       if(Disk->FATCache[ret] == 0)\r
+                               goto append;\r
+               }\r
+               for(ret = 0; ret < Previous; ret++)\r
+               {\r
+                       if(Disk->FATCache[ret] == 0)\r
+                               goto append;\r
+               }\r
+               \r
+               RELEASE(Disk->lFAT);\r
+               return 0;\r
+       \r
+       append:\r
+               switch(Disk->type)\r
+               {\r
+               case FAT12:     eoc = EOC_FAT12;        break;\r
+               case FAT16:     eoc = EOC_FAT16;        break;\r
+               case FAT32:     eoc = EOC_FAT32;        break;\r
+               default:        return 0;\r
+               }\r
+               \r
+               Disk->FATCache[ret] = eoc;\r
+               Disk->FATCache[Previous] = ret;\r
+               \r
+               RELEASE(Disk->lFAT);\r
+               return ret;\r
+       }\r
+       else\r
+       {\r
+       #endif\r
+               Uint32  val;\r
+               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
+               Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
+               return 0;\r
+               \r
+               switch(Disk->type)\r
+               {\r
+               case FAT12:\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+                       if( Previous & 1 ) {\r
+                               val &= 0xFFF000;\r
+                               val |= ret;\r
+                       }\r
+                       else {\r
+                               val &= 0xFFF;\r
+                               val |= ret<<12;\r
+                       }\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+                       \r
+                       VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
+                       if( Cluster & 1 ) {\r
+                               val &= 0xFFF000;\r
+                               val |= eoc;\r
+                       }\r
+                       else {\r
+                               val &= 0x000FFF;\r
+                               val |= eoc<<12;\r
+                       }\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
+                       break;\r
+               case FAT16:\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
+                       break;\r
+               case FAT32:\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
+                       break;\r
+               }\r
+               return ret;\r
+       #if CACHE_FAT\r
+       }\r
+       #endif\r
+}\r
+\r
+/**\r
+ * \brief Free's a cluster\r
+ * \return The original contents of the cluster\r
+ */\r
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
+{\r
+       Uint32  ret;\r
+       #if CACHE_FAT\r
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
+       {\r
+               LOCK(Disk->lFAT);\r
+               \r
+               ret = Disk->FATCache[Cluster];\r
+               Disk->FATCache[Cluster] = 0;\r
+               \r
+               RELEASE(Disk->lFAT);\r
+       }\r
+       else\r
+       {\r
+       #endif\r
+               Uint32  val;\r
+               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
+               LOCK(Disk->lFAT);\r
+               switch(Disk->type)\r
+               {\r
+               case FAT12:\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
+                       if( Cluster & 1 ) {\r
+                               ret = val & 0xFFF0000;\r
+                               val &= 0xFFF;\r
+                       }\r
+                       else {\r
+                               ret = val & 0xFFF;\r
+                               val &= 0xFFF000;\r
+                       }\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+                       break;\r
+               case FAT16:\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
+                       val = 0;\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
+                       break;\r
+               case FAT32:\r
+                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
+                       val = 0;\r
+                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
+                       break;\r
+               }\r
+               RELEASE(Disk->lFAT);\r
+       #if CACHE_FAT\r
+       }\r
+       #endif\r
+       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;\r
+       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;\r
+       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;\r
+       return ret;\r
+}\r
+#endif\r
+\r
+/*\r
+ * ====================\r
+ *      Cluster IO\r
+ * ====================\r
+ */\r
+/**\r
+ * \brief Read a cluster\r
+ * \param Disk Disk (Volume) to read from\r
+ * \param Length       Length to read\r
+ * \param Buffer       Destination for read data\r
+ */\r
+void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
+{\r
+       ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
+       VFS_ReadAt(\r
+               Disk->fileHandle,\r
+               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
+                       * Disk->bootsect.bps,\r
+               Length,\r
+               Buffer\r
+               );\r
+       LEAVE('-');\r
+}\r
+\r
+/* ====================\r
+ *       File IO\r
+ * ====================\r
+ */\r
+/**\r
+ * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
+ * \brief Reads data from a specified file\r
+ */\r
+Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+        int    preSkip, count;\r
+       Uint64  final_bytes;\r
+        int    i, cluster, pos;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       char    tmpBuf[disk->BytesPerCluster];\r
+        int    bpc = disk->BytesPerCluster;\r
+       \r
+       ENTER("pNode Xoffset Xlength pbuffer", Node, Offset, Length, Buffer);\r
+       \r
+       // Sanity Check offset\r
+       if(Offset > Node->Size) {\r
+               LOG("Seek past EOF (%i > %i)", Offset, Node->Size);\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       \r
+       // Cluster is stored in the low 32-bits of the Inode field\r
+       cluster = Node->Inode & 0xFFFFFFFF;\r
+       \r
+       // Clamp Size\r
+       if(Offset + Length > Node->Size) {\r
+               LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",\r
+                       Offset, Length, Node->Size, Node->Size - Offset);\r
+               Length = Node->Size - Offset;\r
+       }\r
+       \r
+       // Skip previous clusters\r
+       preSkip = Offset / bpc;\r
+       Offset %= bpc;\r
+       LOG("preSkip = %i, Offset = %i", preSkip, (int)Offset);\r
+       for(i = preSkip; i--; )\r
+       {\r
+               cluster = FAT_int_GetFatValue(disk, cluster);\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
+                       LEAVE('i', 0);\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       // Reading from within one cluster\r
+       if((int)Offset + (int)Length <= bpc)\r
+       {\r
+               LOG("single cluster only");\r
+               FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
+               memcpy( Buffer, (void*)( tmpBuf + Offset%bpc ), Length );\r
+               LEAVE('X', Length);\r
+               return Length;\r
+       }\r
+       \r
+       // Align read to a cluster\r
+       if( Offset > 0 )\r
+       {\r
+               pos = bpc - Offset;\r
+               FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
+               memcpy( Buffer, (void*)( tmpBuf + Offset ), pos );\r
+               LOG("pos = %i, Reading the rest of the clusters");\r
+               // Get next cluster in the chain\r
+               cluster = FAT_int_GetFatValue(disk, cluster);\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "Read past End of Cluster Chain (Align)");\r
+                       LEAVE('X', pos);\r
+                       return pos;\r
+               }\r
+       }\r
+       else\r
+               pos = 0;\r
+\r
+       // Get Count of Clusters to read\r
+//     count = DivMod64U(Length - pos, bpc, &final_bytes);\r
+       count = (Length - pos) / bpc;\r
+       final_bytes = (Length - pos) % bpc;\r
+       LOG("Offset = %i, Length = %i, count = %i, final_bytes = %i", (int)Offset, (int)Length, count, final_bytes);\r
+       \r
+       // Read the rest of the cluster data\r
+       for( ; count; count -- )\r
+       {\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "Read past End of Cluster Chain (Bulk)");\r
+                       LEAVE('X', pos);\r
+                       return pos;\r
+               }\r
+               // Read cluster\r
+               FAT_int_ReadCluster(disk, cluster, bpc, (void*)(Buffer+pos));\r
+               pos += bpc;\r
+               // Get next cluster in the chain\r
+               cluster = FAT_int_GetFatValue(disk, cluster);\r
+       }\r
+\r
+       if( final_bytes > 0 )\r
+       {\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "Read past End of Cluster Chain (Final)");\r
+                       LEAVE('X', pos);\r
+                       return pos;\r
+               }\r
+               // Read final cluster\r
+               FAT_int_ReadCluster( disk, cluster, bpc, tmpBuf );\r
+               memcpy( (void*)(Buffer+pos), tmpBuf, Length-pos );\r
+       }\r
+               \r
+       #if DEBUG\r
+       //Debug_HexDump("FAT_Read", Buffer, Length);\r
+       #endif\r
+       \r
+       LEAVE('X', Length);\r
+       return Length;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \brief Write a cluster to disk\r
+ */\r
+void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
+{\r
+       ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
+       VFS_ReadAt(\r
+               Disk->fileHandle,\r
+               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
+                       * Disk->bootsect.bps,\r
+               Disk->BytesPerCluster,\r
+               Buffer\r
+               );\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \brief Write to a file\r
+ * \param Node File Node\r
+ * \param Offset       Offset within file\r
+ * \param Length       Size of data to write\r
+ * \param Buffer       Data source\r
+ */\r
+Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       char    tmpBuf[disk->BytesPerCluster];\r
+        int    remLength = Length;\r
+       Uint32  cluster, tmpCluster;\r
+        int    bNewCluster = 0;\r
+       \r
+       if(Offset > Node->Size) return 0;\r
+       \r
+       // Seek Clusters\r
+       cluster = Node->Inode & 0xFFFFFFFF;\r
+       while( Offset > disk->BytesPerCluster )\r
+       {\r
+               cluster = FAT_int_GetFatValue( disk, cluster );\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "EOC Unexpectedly Reached");\r
+                       return 0;\r
+               }\r
+               Offset -= disk->BytesPerCluster;\r
+       }\r
+       if( Offset == disk->BytesPerCluster )\r
+       {\r
+               Uint32  tmp = FAT_int_AllocateCluster(disk, cluster);\r
+               if(!tmp)        return 0;\r
+               cluster = tmp;\r
+               Offset -= disk->BytesPerCluster;\r
+       }\r
+       \r
+       if( Offset + Length < disk->BytesPerCluster )\r
+       {\r
+               char    tmpBuf[disk->BytesPerCluster];\r
+               \r
+               // Read-Modify-Write\r
+               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+               memcpy( tmpBuf + Offset, Buffer, Length );\r
+               FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
+               \r
+               return Length;\r
+       }\r
+       \r
+       // Clean up changes within a cluster\r
+       if( Offset )\r
+       {       \r
+               // Read-Modify-Write\r
+               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+               memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
+               FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
+               \r
+               remLength -= disk->BytesPerCluster - Offset;\r
+               Buffer += disk->BytesPerCluster - Offset;\r
+               \r
+               // Get next cluster (allocating if needed)\r
+               tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
+               if(tmpCluster == -1) {\r
+                       tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
+                       if( tmpCluster == 0 ) {\r
+                               return Length - remLength;\r
+                       }\r
+               }\r
+               cluster = tmpCluster;\r
+       }\r
+       \r
+       while( remLength > disk->BytesPerCluster )\r
+       {\r
+               FAT_int_WriteCluster( disk, cluster, Buffer );\r
+               Buffer += disk->BytesPerCluster;\r
+               \r
+               // Get next cluster (allocating if needed)\r
+               tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
+               if(tmpCluster == -1) {\r
+                       bNewCluster = 1;\r
+                       tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
+                       if( tmpCluster == 0 ) {\r
+                               return Length - remLength;\r
+                       }\r
+               }\r
+               cluster = tmpCluster;\r
+       }\r
+       \r
+       // Finish off\r
+       tmpBuf = malloc( disk->BytesPerCluster );\r
+       if( bNewCluster )\r
+               memset(tmpBuf, 0, disk->BytesPerCluster);\r
+       else\r
+               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+       memcpy( tmpBuf, Buffer, remLength );\r
+       FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
+       free( tmpBuf );\r
+       \r
+       return Length;\r
+}\r
+#endif\r
+\r
+/* ====================\r
+ *  File Names & Nodes\r
+ * ====================\r
+ */\r
+/**\r
+ * \brief Converts a FAT directory entry name into a proper filename\r
+ * \param dest Destination array (must be at least 13 bytes in size)\r
+ * \param src  8.3 filename (concatenated, e.g 'FILE1   TXT')\r
+ */\r
+void FAT_int_ProperFilename(char *dest, const char *src)\r
+{\r
+        int    inpos, outpos;\r
+       \r
+       // Name\r
+       outpos = 0;\r
+       for( inpos = 0; inpos < 8; inpos++ ) {\r
+               if(src[inpos] == ' ')   break;\r
+               dest[outpos++] = src[inpos];\r
+       }\r
+       inpos = 8;\r
+       // Check for empty extensions\r
+       if(src[8] != ' ')\r
+       {\r
+               dest[outpos++] = '.';\r
+               for( ; inpos < 11; inpos++)     {\r
+                       if(src[inpos] == ' ')   break;\r
+                       dest[outpos++] = src[inpos];\r
+               }\r
+       }\r
+       dest[outpos++] = '\0';\r
+       \r
+       //LOG("dest='%s'", dest);\r
+}\r
+\r
+/**\r
+ * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
+ * \brief Converts either a LFN or a 8.3 Name into a proper name\r
+ * \param ft   Pointer to the file's entry in the parent directory\r
+ * \param LongFileName Long file name pointer\r
+ * \return Filename as a heap string\r
+ */\r
+char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
+{\r
+       char    *ret;\r
+       ENTER("pft sLongFileName", ft, LongFileName);\r
+       //Log_Debug("FAT", "FAT_int_CreateName(ft=%p, LongFileName=%p'%s')", ft, LongFileName);\r
+       #if USE_LFN\r
+       if(LongFileName && LongFileName[0] != '\0')\r
+       {       \r
+               ret = strdup(LongFileName);\r
+       }\r
+       else\r
+       {\r
+       #endif\r
+               ret = (char*) malloc(13);\r
+               if( !ret ) {\r
+                       Log_Warning("FAT", "FAT_int_CreateName: malloc(13) failed");\r
+                       return NULL;\r
+               }\r
+               FAT_int_ProperFilename(ret, ft->name);\r
+       #if USE_LFN\r
+       }\r
+       #endif\r
+       LEAVE('s', ret);\r
+       return ret;\r
+}\r
+\r
+/**\r
+ * \brief Creates a tVFS_Node structure for a given file entry\r
+ * \param Parent       Parent directory VFS node\r
+ * \param Entry        File table entry for the new node\r
+ * \param Pos  Position in the parent of the new node\r
+ */\r
+tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)\r
+{\r
+       tVFS_Node       node;\r
+       tVFS_Node       *ret;\r
+       tFAT_VolInfo    *disk = Parent->ImplPtr;\r
+       \r
+       ENTER("pParent pFT", Parent, Entry);\r
+       LOG("disk = %p", disk);\r
+       \r
+       memset(&node, 0, sizeof(tVFS_Node));\r
+       \r
+       // Set Other Data\r
+       // 0-27: Cluster, 32-59: Parent Cluster\r
+       node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);\r
+       LOG("node.Inode = %llx", node.Inode);\r
+       // Position in parent directory\r
+       node.ImplInt = Pos & 0xFFFF;\r
+       // Disk Pointer\r
+       node.ImplPtr = disk;\r
+       node.Size = Entry->size;\r
+       LOG("Entry->size = %i", Entry->size);\r
+       // root:root\r
+       node.UID = 0;   node.GID = 0;\r
+       node.NumACLs = 1;\r
+       \r
+       node.Flags = 0;\r
+       if(Entry->attrib & ATTR_DIRECTORY)      node.Flags |= VFS_FFLAG_DIRECTORY;\r
+       if(Entry->attrib & ATTR_READONLY) {\r
+               node.Flags |= VFS_FFLAG_READONLY;\r
+               node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X\r
+       }\r
+       else {\r
+               node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX\r
+       }\r
+       \r
+       // Create timestamps\r
+       node.ATime = timestamp(0,0,0,\r
+                       ((Entry->adate&0x1F) - 1),      // Days\r
+                       ((Entry->adate&0x1E0) - 1),     // Months\r
+                       1980+((Entry->adate&0xFF00)>>8) // Years\r
+                       );\r
+       \r
+       node.CTime = Entry->ctimems * 10;       // Miliseconds\r
+       node.CTime += timestamp(\r
+                       ((Entry->ctime&0x1F)<<1),       // Seconds\r
+                       ((Entry->ctime&0x3F0)>>5),      // Minutes\r
+                       ((Entry->ctime&0xF800)>>11),    // Hours\r
+                       ((Entry->cdate&0x1F)-1),                // Days\r
+                       ((Entry->cdate&0x1E0)-1),               // Months\r
+                       1980+((Entry->cdate&0xFF00)>>8) // Years\r
+                       );\r
+                       \r
+       node.MTime = timestamp(\r
+                       ((Entry->mtime&0x1F)<<1),       // Seconds\r
+                       ((Entry->mtime&0x3F0)>>5),      // Minutes\r
+                       ((Entry->mtime&0xF800)>>11),    // Hours\r
+                       ((Entry->mdate&0x1F)-1),                // Days\r
+                       ((Entry->mdate&0x1E0)-1),               // Months\r
+                       1980+((Entry->mdate&0xFF00)>>8) // Years\r
+                       );\r
+       \r
+       // Set pointers\r
+       if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
+               //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
+               node.Type = &gFAT_DirType;      \r
+               node.Size = -1;\r
+       }\r
+       else {\r
+               node.Type = &gFAT_FileType;\r
+       }\r
+       \r
+       ret = Inode_CacheNode(disk->inodeHandle, &node);\r
+       LEAVE('p', ret);\r
+       return ret;\r
+}\r
+\r
+/* \r
+ * ====================\r
+ *     Directory IO\r
+ * ====================\r
+ */\r
+\r
+/**\r
+ * \brief Reads a sector from the disk\r
+ * \param Node Directory node to read\r
+ * \param Sector       Sector number in the directory to read\r
+ * \param Buffer       Destination buffer for the read data\r
+ */\r
+int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
+{\r
+       Uint64  addr;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       ENTER("pNode iSector pEntry", Node, Sector, Buffer);\r
+       \r
+       // Parse address\r
+       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
+       {\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       LOG("addr = 0x%llx", addr);\r
+       // Read Sector\r
+       if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)\r
+       {\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \brief Writes an entry to the disk\r
+ * \todo Support expanding a directory\r
+ * \param Node Directory node\r
+ * \param ID   ID of entry to update\r
+ * \param Entry        Entry data\r
+ * \return Zero on success, non-zero on error\r
+ */\r
+int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
+{\r
+       Uint64  addr = 0;\r
+        int    tmp;\r
+       Uint32  cluster = 0;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       ENTER("pNode iID pEntry", Node, ID, Entry);\r
+       \r
+       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
+       if( tmp )\r
+       {\r
+               //TODO: Allocate a cluster\r
+               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
+                       LEAVE('i', 1);\r
+                       return 1;\r
+               }\r
+               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
+       }\r
+       \r
+\r
+       LOG("addr = 0x%llx", addr);\r
+       \r
+       // Read Sector\r
+       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);      // Read Dir Data\r
+       \r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+#endif\r
+\r
+#if USE_LFN    \r
+/**\r
+ * \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
+ * \brief Return pointer to LFN cache entry\r
+ * \param Node Directory node\r
+ * \param ID   ID of the short name\r
+ * \return Pointer to the LFN cache entry\r
+ */\r
+char *FAT_int_GetLFN(tVFS_Node *Node, int ID)\r
+{\r
+       tFAT_LFNCache   *cache;\r
+        int    i, firstFree;\r
+       \r
+       Mutex_Acquire( &Node->Lock );\r
+       \r
+       // TODO: Thread Safety (Lock things)\r
+       cache = Node->Data;\r
+       \r
+       // Create a cache if it isn't there\r
+       if(!cache) {\r
+               cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );\r
+               cache->NumEntries = 1;\r
+               cache->Entries[0].ID = ID;\r
+               cache->Entries[0].Data[0] = '\0';\r
+               Mutex_Release( &Node->Lock );\r
+               //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);\r
+               return cache->Entries[0].Data;\r
+       }\r
+       \r
+       // Scan for this entry\r
+       firstFree = -1;\r
+       for( i = 0; i < cache->NumEntries; i++ )\r
+       {\r
+               if( cache->Entries[i].ID == ID ) {\r
+                       Mutex_Release( &Node->Lock );\r
+                       //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);\r
+                       return cache->Entries[i].Data;\r
+               }\r
+               if( cache->Entries[i].ID == -1 && firstFree == -1 )\r
+                       firstFree = i;\r
+       }\r
+       \r
+       if(firstFree == -1) {\r
+               // Use `i` for temp length\r
+               i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);\r
+               Node->Data = realloc( Node->Data, i );\r
+               if( !Node->Data ) {\r
+                       Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);\r
+                       Mutex_Release( &Node->Lock );\r
+                       return NULL;\r
+               }\r
+               //Log_Debug("FAT", "Realloc (%i)\n", i);\r
+               cache = Node->Data;\r
+               i = cache->NumEntries;\r
+               cache->NumEntries ++;\r
+       }\r
+       else {\r
+               i = firstFree;\r
+       }\r
+       \r
+       // Create new entry\r
+       cache->Entries[ i ].ID = ID;\r
+       cache->Entries[ i ].Data[0] = '\0';\r
+       \r
+       Mutex_Release( &Node->Lock );\r
+       //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);\r
+       return cache->Entries[ i ].Data;\r
+}\r
+\r
+/**\r
+ * \fn void FAT_int_DelLFN(tVFS_Node *node)\r
+ * \brief Delete a LFN cache entry\r
+ * \param Node Directory node\r
+ * \param ID   File Entry ID\r
+ */\r
+void FAT_int_DelLFN(tVFS_Node *Node, int ID)\r
+{\r
+       tFAT_LFNCache   *cache = Node->Data;\r
+        int    i;\r
+       \r
+       // Fast return\r
+       if(!cache)      return;\r
+       \r
+       // Scan for a current entry\r
+       for( i = 0; i < cache->NumEntries; i++ )\r
+       {\r
+               if( cache->Entries[i].ID == ID )\r
+                       cache->Entries[i].ID = -1;\r
+       }\r
+       return ;\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
+ * \param Node Node structure of directory\r
+ * \param ID   Directory position\r
+ * \return Filename as a heap string, NULL or VFS_SKIP\r
+ */\r
+char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
+{\r
+       fat_filetable   fileinfo[16];   // sizeof(fat_filetable)=32, so 16 per sector\r
+        int    a = 0;\r
+       char    *ret;\r
+       #if USE_LFN\r
+       char    *lfn = NULL;\r
+       #endif\r
+       \r
+       ENTER("pNode iID", Node, ID);\r
+       \r
+       if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))\r
+       {\r
+               LOG("End of chain, end of dir");\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Offset in sector\r
+       a = ID % 16;\r
+\r
+       LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);\r
+       \r
+       // Check if this is the last entry\r
+       if( fileinfo[a].name[0] == '\0' ) {\r
+               Node->Size = ID;\r
+               LOG("End of list");\r
+               LEAVE('n');\r
+               return NULL;    // break\r
+       }\r
+       \r
+       // Check for empty entry\r
+       if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
+               LOG("Empty Entry");\r
+               #if 0   // Stop on empty entry?\r
+               LEAVE('n');\r
+               return NULL;    // Stop\r
+               #else\r
+               LEAVE('p', VFS_SKIP);\r
+               return VFS_SKIP;        // Skip\r
+               #endif\r
+       }\r
+       \r
+       #if USE_LFN\r
+       // Get Long File Name Cache\r
+       if(fileinfo[a].attrib == ATTR_LFN)\r
+       {\r
+               fat_longfilename        *lfnInfo;\r
+               \r
+               lfnInfo = (fat_longfilename *) &fileinfo[a];\r
+               \r
+               // Get cache for corresponding file\r
+               // > ID + Index gets the corresponding short node\r
+               lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );\r
+               \r
+               // Bit 6 indicates the start of an entry\r
+               if(lfnInfo->id & 0x40)  memset(lfn, 0, 256);\r
+               \r
+               a = ((lfnInfo->id & 0x3F) - 1) * 13;\r
+               //Log_Debug("FAT", "ID = 0x%02x, a = %i", lfnInfo->id, a);\r
+               \r
+               // Sanity Check (FAT implementations should not allow >255 character names)\r
+               if(a > 255)     return VFS_SKIP;\r
+               \r
+               // Append new bytes\r
+               lfn[a+ 0] = lfnInfo->name1[0];  lfn[a+ 1] = lfnInfo->name1[1];\r
+               lfn[a+ 2] = lfnInfo->name1[2];  lfn[a+ 3] = lfnInfo->name1[3];\r
+               lfn[a+ 4] = lfnInfo->name1[4];  \r
+               lfn[a+ 5] = lfnInfo->name2[0];  lfn[a+ 6] = lfnInfo->name2[1];\r
+               lfn[a+ 7] = lfnInfo->name2[2];  lfn[a+ 8] = lfnInfo->name2[3];\r
+               lfn[a+ 9] = lfnInfo->name2[4];  lfn[a+10] = lfnInfo->name2[5];\r
+               lfn[a+11] = lfnInfo->name3[0];  lfn[a+12] = lfnInfo->name3[1];\r
+               LOG("lfn = '%s'", lfn);\r
+               //Log_Debug("FAT", "lfn = '%s'", lfn);\r
+               LEAVE('p', VFS_SKIP);\r
+               return VFS_SKIP;\r
+       }\r
+       #endif\r
+       \r
+       // Check if it is a volume entry\r
+       if(fileinfo[a].attrib & 0x08) {\r
+               LEAVE('p', VFS_SKIP);\r
+               return VFS_SKIP;\r
+       }\r
+       // Ignore .\r
+       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {\r
+               LEAVE('p', VFS_SKIP);\r
+               return VFS_SKIP;\r
+       }\r
+       // and ..\r
+       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {\r
+               LEAVE('p', VFS_SKIP);\r
+               return VFS_SKIP;\r
+       }\r
+       \r
+       LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",\r
+               fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
+               fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
+               fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
+       \r
+       #if USE_LFN\r
+       lfn = FAT_int_GetLFN(Node, ID);\r
+       //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);\r
+       ret = FAT_int_CreateName(&fileinfo[a], lfn);\r
+       #else\r
+       ret = FAT_int_CreateName(&fileinfo[a], NULL);\r
+       #endif\r
+       \r
+       LEAVE('s', ret);\r
+       return ret;\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
+ * \brief Finds an entry in the current directory\r
+ */\r
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)\r
+{\r
+       fat_filetable   fileinfo[16];\r
+       char    tmpName[13];\r
+       #if USE_LFN\r
+       fat_longfilename        *lfnInfo;\r
+       char    lfn[256];\r
+        int    lfnPos=255, lfnId = -1;\r
+       #endif\r
+        int    i;\r
+       tVFS_Node       *tmpNode;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       Uint32  cluster;\r
+       \r
+       ENTER("pNode sname", Node, Name);       \r
+\r
+       // Fast Returns\r
+       if(!Name || Name[0] == '\0') {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       for( i = 0; ; i++ )\r
+       {\r
+               if((i & 0xF) == 0) {\r
+                       if(FAT_int_ReadDirSector(Node, i/16, fileinfo))\r
+                       {\r
+                               LEAVE('n');\r
+                               return NULL;\r
+                       }\r
+               }\r
+               \r
+               //Check if the files are free\r
+               if(fileinfo[i&0xF].name[0] == '\0')     break;  // End of List marker\r
+               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       // Free entry\r
+               \r
+               \r
+               #if USE_LFN\r
+               // Long File Name Entry\r
+               if(fileinfo[i & 0xF].attrib == ATTR_LFN)\r
+               {\r
+                       lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
+                       if(lfnInfo->id & 0x40) {\r
+                               memset(lfn, 0, 256);\r
+                               lfnPos = (lfnInfo->id & 0x3F) * 13 - 1;\r
+                       }\r
+                       // Sanity check the position so we don't overflow\r
+                       if( lfnPos < 12 )\r
+                               continue ;\r
+                       lfn[lfnPos--] = lfnInfo->name3[1];      lfn[lfnPos--] = lfnInfo->name3[0];\r
+                       lfn[lfnPos--] = lfnInfo->name2[5];      lfn[lfnPos--] = lfnInfo->name2[4];\r
+                       lfn[lfnPos--] = lfnInfo->name2[3];      lfn[lfnPos--] = lfnInfo->name2[2];\r
+                       lfn[lfnPos--] = lfnInfo->name2[1];      lfn[lfnPos--] = lfnInfo->name2[0];\r
+                       lfn[lfnPos--] = lfnInfo->name1[4];      lfn[lfnPos--] = lfnInfo->name1[3];\r
+                       lfn[lfnPos--] = lfnInfo->name1[2];      lfn[lfnPos--] = lfnInfo->name1[1];\r
+                       lfn[lfnPos--] = lfnInfo->name1[0];\r
+                       if((lfnInfo->id&0x3F) == 1)\r
+                       {\r
+                               lfnId = i+1;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       // Remove LFN if it does not apply\r
+                       if(lfnId != i)  lfn[0] = '\0';\r
+               #else\r
+               if(fileinfo[i&0xF].attrib == ATTR_LFN)  continue;\r
+               #endif\r
+                       // Get Real Filename\r
+                       FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
+                       LOG("tmpName = '%s'", tmpName);\r
+               \r
+                       // Only the long name is case sensitive, 8.3 is not\r
+                       #if USE_LFN\r
+                       if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0)\r
+                       #else\r
+                       if(strucmp(tmpName, Name) == 0)\r
+                       #endif\r
+                       {\r
+                               cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
+                               tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
+                               if(tmpNode == NULL)     // Node is not cached\r
+                               {\r
+                                       tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i);\r
+                               }\r
+                               LEAVE('p', tmpNode);\r
+                               return tmpNode;\r
+                       }\r
+               #if USE_LFN\r
+               }\r
+               #endif\r
+       }\r
+       \r
+       LEAVE('n');\r
+       return NULL;\r
+}\r
+\r
+tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)\r
+{\r
+       tFAT_VolInfo    *disk = Root->ImplPtr;\r
+        int    ents_per_sector = 512 / sizeof(fat_filetable); \r
+       fat_filetable   fileinfo[ents_per_sector];\r
+        int    sector = 0, i;\r
+       tVFS_Node       stub_node;\r
+\r
+       ENTER("pRoot XInode", Root, Inode);\r
+\r
+       stub_node.ImplPtr = disk;\r
+       stub_node.Size = -1;\r
+       stub_node.Inode = Inode >> 32;\r
+\r
+       for( i = 0; ; i ++ )\r
+       {\r
+               if( i == 0 || i == ents_per_sector )\r
+               {\r
+                       if(FAT_int_ReadDirSector(&stub_node, sector, fileinfo))\r
+                       {\r
+                               LOG("ReadDirSector failed");\r
+                               LEAVE('n');\r
+                               return NULL;\r
+                       }\r
+                       i = 0;\r
+                       sector ++;\r
+               }\r
+       \r
+               // Check for free/end of list\r
+               if(fileinfo[i].name[0] == '\0') break;  // End of List marker\r
+               if(fileinfo[i].name[0] == '\xE5')       continue;       // Free entry\r
+               \r
+               if(fileinfo[i].attrib == ATTR_LFN)      continue;\r
+\r
+               LOG("fileinfo[i].cluster = %x %04x", fileinfo[i].clusterHi, fileinfo[i].cluster);\r
+               #if DEBUG\r
+               {\r
+                       char    tmpName[13];\r
+                       FAT_int_ProperFilename(tmpName, fileinfo[i].name);\r
+                       LOG("tmpName = '%s'", tmpName);\r
+               }\r
+               #endif\r
+               \r
+       \r
+               if(fileinfo[i].cluster != (Inode & 0xFFFF))     continue;\r
+               if(fileinfo[i].clusterHi != ((Inode >> 16) & 0xFFFF))   continue;\r
+\r
+               LEAVE_RET('p', FAT_int_CreateNode(&stub_node, &fileinfo[i], sector*ents_per_sector+i));\r
+       }\r
+       LOG("sector = %i, i = %i", sector, i);\r
+       LEAVE('n');\r
+       return NULL;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
+ * \brief Create a new node\r
+ */\r
+int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
+{\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
+ * \brief Rename / Delete a file\r
+ */\r
+int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
+{\r
+       tVFS_Node       *child;\r
+       fat_filetable   ft = {0};\r
+        int    ret;\r
+       \r
+       child = FAT_FindDir(Node, OldName);\r
+       if(!child)      return ENOTFOUND;\r
+       \r
+       // Delete?\r
+       if( NewName == NULL )\r
+       {\r
+               child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close\r
+               \r
+               // Delete from the directory\r
+               ft.name[0] = '\xE9';\r
+               FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
+               \r
+               // Return success\r
+               ret = EOK;\r
+       }\r
+       // Rename\r
+       else\r
+       {\r
+               Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
+                       Node, OldName, NewName);\r
+               ret = ENOTIMPL;\r
+       }\r
+       \r
+       // Close child\r
+       child->Close( child );\r
+       return ret;\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn void FAT_CloseFile(tVFS_Node *Node)\r
+ * \brief Close an open file\r
+ */\r
+void FAT_CloseFile(tVFS_Node *Node)\r
+{\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       if(Node == NULL)        return ;\r
+       \r
+       #if SUPPORT_WRITE\r
+       // Update the node if it's dirty (don't bother if it's marked for\r
+       // deletion)\r
+       if( (Node->ImplInt & FAT_FLAG_DIRTY) && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
+       {\r
+               tFAT_VolInfo    buf[16];\r
+               tFAT_VolInfo    *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
+               \r
+               FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
+               ft->size = Node->Size;\r
+               // TODO: update adate, mtime, mdate\r
+               FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
+               \r
+               Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
+       }\r
+       #endif\r
+       \r
+       // TODO: Make this more thread safe somehow, probably by moving the\r
+       // Inode_UncacheNode higher up and saving the cluster value somewhere\r
+       if( Node->ReferenceCount == 1 )\r
+       {               \r
+               #if SUPPORT_WRITE\r
+               // Delete File\r
+               if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
+                       // Since the node is marked, we only need to remove it's data\r
+                       Uint32  cluster = Node->Inode & 0xFFFFFFFF;\r
+                       while( cluster != -1 )\r
+                               cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
+               }\r
+               #endif\r
+       }\r
+       \r
+       Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
+       return ;\r
+}\r
diff --git a/KernelLand/Modules/Filesystems/FAT/fs_fat.h b/KernelLand/Modules/Filesystems/FAT/fs_fat.h
new file mode 100644 (file)
index 0000000..6896945
--- /dev/null
@@ -0,0 +1,171 @@
+/*\r
+ * Acess2\r
+ * FAT12/16/32 Driver\r
+ * vfs/fs/fs_fat.h\r
+ */\r
+#ifndef _FS_FAT_H_\r
+#define _FS_FAT_H_\r
+\r
+// === On Disk Structures ===\r
+/**\r
+ * \struct fat_bootsect_s\r
+ * \brief Bootsector format\r
+ */\r
+struct fat_bootsect_s\r
+{\r
+       Uint8   jmp[3]; //!< Jump Instruction\r
+       char    oemname[8];     //!< OEM Name. Typically MSDOS1.1\r
+       Uint16  bps;    //!< Bytes per Sector. Assumed to be 512\r
+       Uint8   spc;            //!< Sectors per Cluster\r
+       Uint16  resvSectCount;  //!< Number of reserved sectors at beginning of volume\r
+       // +0x10\r
+       Uint8   fatCount;       //!< Number of copies of the FAT\r
+       Uint16  files_in_root;  //!< Count of files in the root directory\r
+       Uint16  totalSect16;    //!< Total sector count (FAT12/16)\r
+       Uint8   mediaDesc;      //!< Media Desctiptor\r
+       Uint16  fatSz16;        //!< FAT Size (FAT12/16)\r
+       // +0x18\r
+       Uint16  spt;    //!< Sectors per track. Ignored (Acess uses LBA)\r
+       Uint16  heads;  //!< Heads. Ignored (Acess uses LBA)\r
+       Uint32  hiddenCount;    //!< ???\r
+       Uint32  totalSect32;    //!< Total sector count (FAT32)\r
+       union {\r
+               struct {\r
+                       Uint8   drvNum; //!< Drive Number. BIOS Drive ID (E.g. 0x80)\r
+                       Uint8   resv;   //!< Reserved byte\r
+                       Uint8   bootSig;        //!< Boot Signature. ???\r
+                       Uint32  volId;  //!< Volume ID\r
+                       char    label[11];      //!< Disk Label\r
+                       char    fsType[8];      //!< FS Type. ???\r
+               } __attribute__((packed)) fat16;        //!< FAT16 Specific information\r
+               struct {\r
+                       Uint32  fatSz32;        //!< 32-Bit FAT Size\r
+                       Uint16  extFlags;       //!< Extended flags\r
+                       Uint16  fsVer;  //!< Filesystem Version\r
+                       Uint32  rootClust;      //!< Root Cluster ID\r
+                       Uint16  fsInfo; //!< FS Info. ???\r
+                       Uint16  backupBS;       //!< Backup Bootsector Sector Offset\r
+                       char    resv[12];       //!< Reserved Data\r
+                       Uint8   drvNum; //!< Drive Number\r
+                       char    resv2;  //!< Reserved Data\r
+                       Uint8   bootSig;        //!< Boot Signature. ???\r
+                       Uint32  volId;  //!< Volume ID\r
+                       char    label[11];      //!< Disk Label\r
+                       char    fsType[8];      //!< Filesystem Type. ???\r
+               } __attribute__((packed)) fat32;        //!< FAT32 Specific Information\r
+       }__attribute__((packed)) spec;  //!< Non Shared Data\r
+       char pad[512-90];       //!< Bootsector Data (Code/Boot Signature 0xAA55)\r
+} __attribute__((packed));\r
+\r
+/**\r
+ \struct fat_filetable_s\r
+ \brief Format of a 8.3 file entry on disk\r
+*/\r
+struct fat_filetable_s {\r
+       char    name[11];       //!< 8.3 Name\r
+       Uint8   attrib; //!< File Attributes.\r
+       Uint8   ntres;  //!< Reserved for NT - Set to 0\r
+       Uint8   ctimems;        //!< 10ths of a second ranging from 0-199 (2 seconds)\r
+       Uint16  ctime;  //!< Creation Time\r
+       Uint16  cdate;  //!< Creation Date\r
+       Uint16  adate;  //!< Accessed Date. No Time feild though\r
+       Uint16  clusterHi;      //!< High Cluster. 0 for FAT12 and FAT16\r
+       Uint16  mtime;  //!< Last Modified Time\r
+       Uint16  mdate;  //!< Last Modified Date\r
+       Uint16  cluster;        //!< Low Word of First cluster\r
+       Uint32  size;   //!< Size of file\r
+} __attribute__((packed));\r
+\r
+/**\r
+ * \struct fat_longfilename_s\r
+ * \brief Format of a long file name entry on disk\r
+ */\r
+struct fat_longfilename_s {\r
+       Uint8   id;     //!< ID of entry. Bit 6 is set for last entry\r
+       Uint16  name1[5];       //!< 5 characters of name\r
+       Uint8   attrib; //!< Attributes. Must be ATTR_LFN\r
+       Uint8   type;   //!< Type. ???\r
+       Uint8   checksum;       //!< Checksum\r
+       Uint16  name2[6];       //!< 6 characters of name\r
+       Uint16  firstCluster;   //!< Used for non LFN compatability. Set to 0\r
+       Uint16  name3[2];       //!< Last 2 characters of name\r
+} __attribute__((packed));\r
+\r
+/**\r
+ * \name File Attributes\r
+ * \brief Flag values for ::fat_filetable_s.attrib\r
+ * \{\r
+ */\r
+#define ATTR_READONLY  0x01    //!< Read-only file\r
+#define ATTR_HIDDEN            0x02    //!< Hidden File\r
+#define ATTR_SYSTEM            0x04    //!< System File\r
+#define ATTR_VOLUMEID  0x08    //!< Volume ID (Deprecated)\r
+#define ATTR_DIRECTORY 0x10    //!< Directory\r
+/**\r
+ * \brief File needs archiving\r
+ * \note User set flag, no significance to the FS driver\r
+ */\r
+#define ATTR_ARCHIVE   0x20\r
+/**\r
+ * \brief Meta Attribute \r
+ * \r
+ * If ::fat_filetable_s.attrib equals ATTR_LFN the file is a LFN entry\r
+ */\r
+#define        ATTR_LFN                (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID)\r
+/**\r
+ * \}\r
+ */\r
+\r
+/**\r
+ * \brief Internal IDs for FAT types\r
+ */\r
+enum eFatType\r
+{\r
+       FAT12,  //!< FAT12 Volume\r
+       FAT16,  //!< FAT16 Volume\r
+       FAT32,  //!< FAT32 Volume\r
+};\r
+\r
+/**\r
+ * \name End of Cluster marks\r
+ * \brief FAT values that indicate the end of a cluster chain in\r
+ *        different versions.\r
+ * \{\r
+ */\r
+#define        EOC_FAT12       0x0FFF  //!< FAT-12 Mark\r
+#define        EOC_FAT16       0xFFFF  //!< FAT-16 Mark\r
+#define        EOC_FAT32       0x00FFFFFF      //!< FAT-32 Mark\r
+/**\r
+ * \}\r
+ */\r
+\r
+typedef struct fat_bootsect_s fat_bootsect;\r
+typedef struct fat_filetable_s fat_filetable;\r
+typedef struct fat_longfilename_s fat_longfilename;\r
+\r
+// === Memory Structures ===\r
+/**\r
+ * \struct drv_fat_volinfo_s\r
+ * \brief Representation of a volume in memory\r
+ */\r
+struct drv_fat_volinfo_s\r
+{\r
+        int    fileHandle;     //!< File Handle\r
+        int    type;   //!< FAT Type. See eFatType\r
+       char    name[12];       //!< Volume Name (With NULL Terminator)\r
+       tMutex  lFAT;   //!< Lock to prevent double-writing to the FAT\r
+       Uint32  firstDataSect;  //!< First data sector\r
+       Uint32  rootOffset;     //!< Root Offset (clusters)\r
+       Uint32  ClusterCount;   //!< Total Cluster Count\r
+       fat_bootsect    bootsect;       //!< Boot Sector\r
+       tVFS_Node       rootNode;       //!< Root Node\r
+        int    BytesPerCluster;\r
+        int    inodeHandle;    //!< Inode Cache Handle\r
+       #if CACHE_FAT\r
+       Uint32  *FATCache;      //!< FAT Cache\r
+       #endif\r
+};\r
+\r
+typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
+\r
+#endif\r
diff --git a/KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php b/KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php
new file mode 100644 (file)
index 0000000..e7cd4f7
--- /dev/null
@@ -0,0 +1,245 @@
+<?php
+$lGenDate = date("Y-m-d H:i");
+$gOutput = <<<EOF
+/*
+ * Acess2 InitRD
+ * InitRD Data
+ * Generated $lGenDate
+ */
+#include "initrd.h"
+
+EOF;
+
+$ACESSDIR = getenv("ACESSDIR");
+$ARCH = getenv("ARCH");
+
+$gInputFile = $argv[1];
+$gOutputFile = $argv[2];
+$gOutputLDOptsFile = $argv[3];
+$gDepFile = ($argc > 4 ? $argv[4] : false);
+
+$gDependencies = array();
+
+$lines = file($argv[1]);
+
+$lDepth = 0;
+$lTree = array();
+$lStack = array( array("",array()) );
+foreach($lines as $line)
+{
+       $line = trim($line);
+       // Directory
+       if(preg_match('/^Dir\s+"([^"]+)"\s+{$/', $line, $matches))
+       {
+               $new = array($matches[1], array());
+               array_push($lStack, $new);
+               $lDepth ++;
+               continue;
+       }
+       // End of a block
+       if($line == "}")
+       {
+               $lDepth --;
+               $lStack[$lDepth][1][] = array_pop($lStack);
+               continue;
+       }
+       // File
+       if(preg_match('/^File\s+"([^"]+)"\s+"([^"]+)"$/', $line, $matches))
+       {
+               $lStack[$lDepth][1][] = array($matches[1], $matches[2]);
+               continue;
+       }
+       echo "ERROR: $line\n";
+       exit(0);
+}
+
+function hd($fp)
+{
+       //return "0x".str_pad( dechex(ord(fgetc($fp))), 8, "0", STR_PAD_LEFT );
+       $val = unpack("I", fread($fp, 4));
+       //print_r($val);        exit -1;
+       return "0x".dechex($val[1]);
+}
+
+function hd8($fp)
+{
+       return "0x".str_pad( dechex(ord(fgetc($fp))), 2, "0", STR_PAD_LEFT );
+}
+
+$inode = 0;
+$gSymFiles = array();
+function ProcessFolder($prefix, $items)
+{
+       global  $gOutput, $gDependencies;
+       global  $ACESSDIR, $ARCH;
+       global  $inode;
+       global  $gSymFiles;
+       foreach($items as $i=>$item)
+       {
+               $inode ++;
+               if(is_array($item[1]))
+               {
+                       ProcessFolder("{$prefix}_{$i}", $item[1]);
+                       
+                       $gOutput .= "tInitRD_File {$prefix}_{$i}_entries[] = {\n";
+                       foreach($item[1] as $j=>$child)
+                       {
+                               if($j)  $gOutput .= ",\n";
+                               $gOutput .= "\t{\"".addslashes($child[0])."\",&{$prefix}_{$i}_{$j}}";
+                       }
+                       $gOutput .= "\n};\n";
+                       
+                       $size = count($item[1]);
+                       $gOutput .= <<<EOF
+tVFS_Node {$prefix}_{$i} = {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Size = $size,
+       .Inode = {$inode},
+       .ImplPtr = {$prefix}_{$i}_entries,
+       .Type = &gInitRD_DirType
+};
+
+EOF;
+               }
+               else
+               {
+                       $path = $item[1];
+                       
+                       // Parse path components
+                       $path = str_replace("__BIN__", "$ACESSDIR/Usermode/Output/$ARCH", $path);
+                       $path = str_replace("__FS__", "$ACESSDIR/Usermode/Filesystem", $path);
+                       $path = str_replace("__SRC__", "$ACESSDIR", $path);
+                       echo $path,"\n";
+                       // ---
+                       
+                       $gDependencies[] = $path;
+
+                       if(!file_exists($path)) {
+                               echo "ERROR: '{$path}' does not exist\n", 
+                               exit(1);
+                       }
+                       $size = filesize($path);
+       
+/*             
+                       $_sym = $prefix."_".$i."_data";
+                       $fp = fopen($path, "rb");
+                       
+                       $gOutput .= "Uint8 $_sym[] = {\n";
+                       for( $j = 0; $j + 16 < $size; $j += 16 ) {
+                               $gOutput .= "\t";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",";
+                               $gOutput .= hd8($fp).",".hd8($fp).",\n";
+                       }
+                       $gOutput .= "\t";
+                       for( ; $j < $size; $j ++ ) {
+                               if( $j & 15 )   $gOutput .= ",";
+                               $gOutput .= hd8($fp);
+                       }
+                       fclose($fp);
+                       $gOutput .= "\n};\n";
+*/
+                       
+//*
+                       $_sym = "_binary_".str_replace(array("/","-","."), "_", $path)."_start";
+                       $gOutput .= "extern Uint8 {$_sym}[];";
+                       $gSymFiles[] = $path;
+//*/
+                       $gOutput .= <<<EOF
+tVFS_Node {$prefix}_{$i} = {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = 0,
+       .Size = $size,
+       .Inode = {$inode},
+       .ImplPtr = $_sym,
+       .Type = &gInitRD_FileType
+};
+
+EOF;
+               }
+       }
+}
+
+//print_r($lStack);
+//exit(1);
+
+ProcessFolder("gInitRD_Files", $lStack[0][1]);
+
+$gOutput .= "tInitRD_File gInitRD_Root_Files[] = {\n";
+foreach($lStack[0][1] as $j=>$child)
+{
+       if($j)  $gOutput .= ",\n";
+       $gOutput .= "\t{\"".addslashes($child[0])."\",&gInitRD_Files_{$j}}";
+}
+$gOutput .= "\n};\n";
+$nRootFiles = count($lStack[0][1]);
+$gOutput .= <<<EOF
+tVFS_Node gInitRD_RootNode = {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Size = $nRootFiles,
+       .ImplPtr = gInitRD_Root_Files,
+       .Type = &gInitRD_DirType
+};
+EOF;
+
+$gOutput .= <<<EOF
+
+tVFS_Node * const gInitRD_FileList[] = {
+&gInitRD_RootNode
+EOF;
+
+function PutNodePointers($prefix, $items)
+{
+       global $gOutput;
+       foreach($items as $i=>$item)
+       {
+               $gOutput .= ",&{$prefix}_{$i}";
+               if(is_array($item[1]))
+               {
+                       PutNodePointers("{$prefix}_{$i}", $item[1]);
+               }
+       }
+}
+
+PutNodePointers("gInitRD_Files", $lStack[0][1]);
+
+$gOutput .= <<<EOF
+};
+const int giInitRD_NumFiles = sizeof(gInitRD_FileList)/sizeof(gInitRD_FileList[0]);
+
+EOF;
+
+
+$fp = fopen($gOutputFile, "w");
+fputs($fp, $gOutput);
+fclose($fp);
+
+// - Create options call
+$fp = fopen($gOutputLDOptsFile, "w");
+fputs($fp, "--format binary\n");
+foreach($gSymFiles as $sym=>$file)
+{
+       fputs($fp, "$file\n");
+//     fputs($fp, "--defsym $sym=_binary_".$sym_filename."_start\n");
+}
+fclose($fp);
+
+if($gDepFile !== false)
+{
+       $fp = fopen($gDepFile, "w");
+       $line = $gOutputFile.":\t".implode(" ", $gDependencies);
+       fputs($fp, $line);
+       fclose($fp);
+}
+
+?>
diff --git a/KernelLand/Modules/Filesystems/InitRD/Makefile b/KernelLand/Modules/Filesystems/InitRD/Makefile
new file mode 100644 (file)
index 0000000..5aa0e65
--- /dev/null
@@ -0,0 +1,16 @@
+# InitRD Filesystem Driver
+#
+
+OBJ = main.o files.$(ARCH).o
+EXTRA = files.c
+NAME = InitRD
+EXTRA = files.$(ARCH).c files.$(ARCH).c.dep files.$(ARCH).c.ldopts
+LDFLAGS += @files.$(ARCH).c.ldopts
+
+-include ../Makefile.tpl
+
+
+files.$(ARCH).c: GenerateInitRD.php files.lst
+       ARCH=$(ARCH) ACESSDIR=$(ACESSDIR) php GenerateInitRD.php files.lst $@ [email protected] [email protected]
+
+-include files.$(ARCH).c.dep
diff --git a/KernelLand/Modules/Filesystems/InitRD/files.lst b/KernelLand/Modules/Filesystems/InitRD/files.lst
new file mode 100644 (file)
index 0000000..16d647f
--- /dev/null
@@ -0,0 +1,36 @@
+Dir "SBin" {
+       File "init" "__BIN__/SBin/init"
+       File "login" "__BIN__/SBin/login"
+}
+Dir "Bin" {
+       File "CLIShell" "__BIN__/Bin/CLIShell"
+       File "ls" "__BIN__/Bin/ls"
+       File "cat" "__BIN__/Bin/cat"
+       File "mount" "__BIN__/Bin/mount"
+       File "ifconfig" "__BIN__/Bin/ifconfig"
+       File "telnet" "__BIN__/Bin/telnet"
+       File "irc" "__BIN__/Bin/irc"
+}
+Dir "Libs" {
+       File "ld-acess.so" "__BIN__/Libs/ld-acess.so"
+       File "libld-acess.so" "__BIN__/Libs/libld-acess.so"
+       File "libc.so" "__BIN__/Libs/libc.so"
+       File "libgcc.so" "__BIN__/Libs/libgcc.so"
+       File "libreadline.so" "__BIN__/Libs/libreadline.so"
+       File "libnet.so" "__BIN__/Libs/libnet.so"
+       File "liburi.so" "__BIN__/Libs/liburi.so"
+       File "libimage_sif.so" "__BIN__/Libs/libimage_sif.so"
+       File "libaxwin3.so" "__BIN__/Libs/libaxwin3.so"
+}
+Dir "Conf" {
+       File "BootConf.cfg" "__FS__/Conf/BootConf.cfg"
+}
+Dir "Apps" {
+       Dir "AxWin" {
+               Dir "3.0" {
+                       File "AxWinWM" "__BIN__/Apps/AxWin/3.0/AxWinWM"
+                       File "AxWinUI" "__BIN__/Apps/AxWin/3.0/AxWinUI"
+                       File "AcessLogoSmall.sif" "__SRC__/Usermode/Applications/axwin3_src/AcessLogoSmall.sif"
+               }
+       }
+}
diff --git a/KernelLand/Modules/Filesystems/InitRD/initrd.h b/KernelLand/Modules/Filesystems/InitRD/initrd.h
new file mode 100644 (file)
index 0000000..479a841
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ */
+#ifndef _INITRD_H_
+#define _INITRD_H_
+
+#include <acess.h>
+#include <vfs.h>
+
+typedef struct sInitRD_File
+{
+       char    *Name;
+       tVFS_Node       *Node;
+}      tInitRD_File;
+
+
+// === Functions ===
+extern Uint64  InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer);
+extern char    *InitRD_ReadDir(tVFS_Node *Node, int ID);
+extern tVFS_Node       *InitRD_FindDir(tVFS_Node *Node, const char *Name);
+
+// === Globals ===
+tVFS_NodeType  gInitRD_DirType;
+tVFS_NodeType  gInitRD_FileType;
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/InitRD/main.c b/KernelLand/Modules/Filesystems/InitRD/main.c
new file mode 100644 (file)
index 0000000..b52ab8d
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Acess OS
+ * InitRD Driver Version 1
+ */
+#include "initrd.h"
+#include <modules.h>
+
+#define DUMP_ON_MOUNT  1
+
+// === IMPORTS ==
+extern tVFS_Node       gInitRD_RootNode;
+extern const int       giInitRD_NumFiles;
+extern tVFS_Node * const       gInitRD_FileList[];
+
+// === PROTOTYPES ===
+ int   InitRD_Install(char **Arguments);
+tVFS_Node      *InitRD_InitDevice(const char *Device, const char **Arguments);
+void   InitRD_Unmount(tVFS_Node *Node);
+tVFS_Node      *InitRD_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer);
+char   *InitRD_ReadDir(tVFS_Node *Node, int ID);
+tVFS_Node      *InitRD_FindDir(tVFS_Node *Node, const char *Name);
+void   InitRD_DumpDir(tVFS_Node *Node, int Indent);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL);
+tVFS_Driver    gInitRD_FSInfo = {
+       "initrd", 0, InitRD_InitDevice, InitRD_Unmount, InitRD_GetNodeFromINode
+       };
+tVFS_NodeType  gInitRD_DirType = {
+       .ReadDir = InitRD_ReadFile,
+       .FindDir = InitRD_FindDir
+       };
+tVFS_NodeType  gInitRD_FileType = {
+       .Read = InitRD_ReadFile
+       };
+
+/**
+ * \brief Register initrd with the kernel
+ */
+int InitRD_Install(char **Arguments)
+{
+       Log_Notice("InitRD", "Installed");
+       VFS_AddDriver( &gInitRD_FSInfo );
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Mount the InitRD
+ */
+tVFS_Node *InitRD_InitDevice(const char *Device, const char **Arguments)
+{
+       #if DUMP_ON_MOUNT
+       InitRD_DumpDir( &gInitRD_RootNode, 0 );
+       #endif
+       Log_Notice("InitRD", "Mounted (%i files)", giInitRD_NumFiles);
+       return &gInitRD_RootNode;
+}
+
+/**
+ * \brief Unmount the InitRD
+ */
+void InitRD_Unmount(tVFS_Node *Node)
+{
+}
+
+/**
+ */
+tVFS_Node *InitRD_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)
+{
+       if( Inode >= giInitRD_NumFiles )        return NULL;
+       return gInitRD_FileList[Inode];
+}
+
+/**
+ * \brief Read from a file
+ */
+Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       if(Offset > Node->Size)
+               return 0;
+       if(Offset + Length > Node->Size)
+               Length = Node->Size - Offset;
+       
+       memcpy(Buffer, Node->ImplPtr+Offset, Length);
+       
+       return Length;
+}
+
+/**
+ * \brief Read from a directory
+ */
+char *InitRD_ReadDir(tVFS_Node *Node, int ID)
+{
+       tInitRD_File    *dir = Node->ImplPtr;
+       
+       if(ID >= Node->Size)
+               return NULL;
+       
+       return strdup(dir[ID].Name);
+}
+
+/**
+ * \brief Find an element in a directory
+ */
+tVFS_Node *InitRD_FindDir(tVFS_Node *Node, const char *Name)
+{
+        int    i;
+       tInitRD_File    *dir = Node->ImplPtr;
+       
+       LOG("Name = '%s'", Name);
+       
+       for( i = 0; i < Node->Size; i++ )
+       {
+               if(strcmp(Name, dir[i].Name) == 0)
+                       return dir[i].Node;
+       }
+       
+       return NULL;
+}
+
+void InitRD_DumpDir(tVFS_Node *Node, int Indent)
+{
+        int    i;
+       char    indent[Indent+1];
+       tInitRD_File    *dir = Node->ImplPtr;
+       
+       for( i = 0; i < Indent; i++ )   indent[i] = ' ';
+       indent[i] = '\0';
+       
+       for( i = 0; i < Node->Size; i++ )
+       {
+               Log_Debug("InitRD", "%s- %p %s", indent, dir[i].Node, dir[i].Name);
+               if(dir[i].Node->Flags & VFS_FFLAG_DIRECTORY)
+                       InitRD_DumpDir(dir[i].Node, Indent+1);
+       }
+}
diff --git a/KernelLand/Modules/Filesystems/LEAN/common.h b/KernelLand/Modules/Filesystems/LEAN/common.h
new file mode 100644 (file)
index 0000000..f75b8b6
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Acess 2 LEAN Filesystem Driver
+ * By John Hodge (thePowersGang)
+ *
+ * lean.h - Filesystem Structure Definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#define EXTENTS_PER_INODE      6
+#define EXTENTS_PER_INDIRECT   38
+
+struct sLEAN_Superblock
+{
+       // TODO
+};
+
+struct sLEAN_IndirectBlock
+{
+       Uint32  Checksum;       // Block checksum
+       Uint32  Magic;  // 'INDX'
+       Uint64  SectorCount;    // Number of blocks referenced by this block
+       Uint64  Inode;  // Inode this block belongs to (in for robustness)
+       Uint64  ThisSector;     // Sector number of this block
+       Uint64  PrevIndirect;   // Backlink to the previous indirect block (or zero)
+       Uint64  NextIndirect;   // Link to the next indirect block (or zero)
+       
+       /**
+        * Number of extents stored in this block (only the last block can
+        * have this as < \a EXTENTS_PER_INDIRECT
+        */
+       Uint8   NumExtents;
+       Uint8   reserved1[3];   //!< Reserved/Padding
+       Uint32  reserved2;      //!< Reserved/Padding
+       
+       Uint64  ExtentsStarts[EXTENTS_PER_INDIRECT];
+       Uint32  ExtentsSizes[EXTENTS_PER_INDIRECT];
+}
+
+struct sLEAN_Inode
+{
+       Uint32  Checksum;       //!< Checksum of the inode
+       Uint32  Magic;  //!< Magic Value 'NODE'
+       
+       Uint8   ExtentCount;    //!< Number of extents defined in the inode structure
+       Uint8   reserved1[3];   //!< Reserved/Padding
+       
+       Uint32  IndirectCount;  //!< Number of indirect extent blocks used by the file
+       Uint32  LinkCount;      //!< Number of directory entires that refer to this inode
+       
+       Uint32  UID;    //!< Owning User
+       Uint32  GID;    //!< Owning Group
+       Uint32  Attributes;     //!< 
+       Uint64  FileSize;       //!< Size of the file data (not including inode and other bookkeeping)
+       Uint64  SectorCount;    //!< Number of sectors allocated to the file
+       Sint64  LastAccessTime; //!< Last access time
+       Sint64  StatusChangeTime;       //!< Last change of the status bits time
+       Sint64  ModifcationTime;        //!< Last modifcation time
+       Sint64  CreationTime;   //!< File creation time
+       
+       Uint64  FirstIndirect;  //!< Sector number of the first indirect block
+       Uint64  LastIndirect;   //!< Sector number of the last indirect block
+       
+       Uint64  Fork;   //!< ????
+       
+       Uint64  ExtentsStarts[EXTENTS_PER_INODE];
+       Uint32  ExtentsSizes[EXTENTS_PER_INODE];
+};
+
+enum eLEAN_InodeAttributes
+{
+       LEAN_iaXOth = 1 << 0,   LEAN_iaWOth = 1 << 1,   LEAN_iaROth = 1 << 2,
+       LEAN_iaXGrp = 1 << 3,   LEAN_iaWGrp = 1 << 4,   LEAN_iaRGrp = 1 << 5,
+       LEAN_iaXUsr = 1 << 6,   LEAN_iaWUsr = 1 << 7,   LEAN_iaRUsr = 1 << 8,
+       
+       LEAN_iaSVTX = 1 << 9,
+       LEAN_iaSGID = 1 << 10,
+       LEAN_iaSUID = 1 << 11,
+       
+       LEAN_iaHidden   = 1 << 12,
+       LEAN_iaSystem   = 1 << 13,
+       LEAN_iaArchive  = 1 << 14,      // Set on any write
+       LEAN_iaSync     = 1 << 15,
+       LEAN_iaNoAccessTime     = 1 << 16,      //!< Don't update the last accessed time
+       LEAN_iaImmutable        = 1 << 17,      //!< Don't move sectors (defragger flag)
+       LEAN_iaPrealloc = 1 << 18,      //!< Keep preallocated sectors after close
+       LEAN_iaInlineExtAttr    = 1 << 19,      //!< Reserve the first sector
+       
+       LEAN_iaFmtMask  = 7 << 29,      //!< Format mask
+       LEAN_iaFmtRegular       = 1 << 29,      //!< Regular File
+       LEAN_iaFmtDirectory     = 2 << 29,      //!< Directory
+       LEAN_iaFmtSymlink       = 3 << 29,      //!< Symlink
+       LEAN_iaFmtFork  = 4 << 29,      //!< Fork
+};
+
+struct tLEAN_ExtendedAttribute
+{
+       Uint32  Header; // 8.24 Name.Value Sizes
+};
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/LEAN/main.c b/KernelLand/Modules/Filesystems/LEAN/main.c
new file mode 100644 (file)
index 0000000..400d4f8
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Acess 2 LEAN Filesystem Driver
+ * By John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <vfs.h>
+
+// === CONSTANTS ===
+
+// === PROTOTYPES ===
+
+// === GLOBALS ===
+
+// === CODE ===
+int LEAN_Install(char **Arguments)
+{
+       return 1;
+}
diff --git a/KernelLand/Modules/Filesystems/Makefile.tpl b/KernelLand/Modules/Filesystems/Makefile.tpl
new file mode 100644 (file)
index 0000000..77dfc2c
--- /dev/null
@@ -0,0 +1,2 @@
+CATEGORY = FS
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/NFS/Makefile b/KernelLand/Modules/Filesystems/NFS/Makefile
new file mode 100644 (file)
index 0000000..0b2019f
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o
+NAME = NFS
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/NFS/common.h b/KernelLand/Modules/Filesystems/NFS/common.h
new file mode 100644 (file)
index 0000000..d73592f
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Acess2 - NFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * common.h - Common definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+typedef struct sNFS_Connection
+{
+        int    FD;
+       tIPAddr Host;
+       char    *Base;
+       tVFS_Node       Node;
+}      tNFS_Connection;
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/NFS/main.c b/KernelLand/Modules/Filesystems/NFS/main.c
new file mode 100644 (file)
index 0000000..459945f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Acess2 - NFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * main.c - Driver core
+ */
+#define DEBUG  1
+#define VERBOSE        0
+#include "common.h"
+#include <modules.h>
+
+// === PROTOTYPES ===
+ int   NFS_Install(char **Arguments);
+tVFS_Node      *NFS_InitDevice(char *Devices, char **Options);
+void   NFS_Unmount(tVFS_Node *Node);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x32 /*v0.5*/, FS_NFS, NFS_Install, NULL);
+tVFS_Driver    gNFS_FSInfo = {"nfs", 0, NFS_InitDevice, NFS_Unmount, NULL};
+
+tNFS_Connection        *gpNFS_Connections;
+
+// === CODE ===
+/**
+ * \brief Installs the NFS driver
+ */
+int NFS_Install(char **Arguments)
+{
+       VFS_AddDriver( &gNFS_FSInfo );
+       return 1;
+}
+
+/**
+ * \brief Mount a NFS share
+ */
+tVFS_Node *NFS_InitDevice(char *Device, char **Options)
+{
+       char    *path, *host;
+       tNFS_Connection *conn;
+       
+       path = strchr( Device, ':' ) + 1;
+       host = strndup( Device, (int)(path-Device)-1 );
+       
+       conn = malloc( sizeof(tNFS_Connection) );
+       
+       if( !IPTools_GetAddress(host, &conn->IP) ) {
+               free(conn);
+               return NULL;
+       }
+       free(host);
+       
+       conn->FD = IPTools_OpenUdpClient( &conn->Host );
+       if(conn->FD == -1) {
+               free(conn);
+               return NULL;
+       }
+       
+       conn->Base = strdup( path );
+       conn->RootNode.ImplPtr = conn;
+       conn->RootNode.Flags = VFS_FFLAG_DIRECTORY;
+       
+       conn->RootNode.ReadDir = NFS_ReadDir;
+       conn->RootNode.FindDir = NFS_FindDir;
+       conn->RootNode.Close = NULL;
+       
+       return &conn->RootNode;
+}
+
+void NFS_Unmount(tVFS_Node *Node)
+{
+       
+}
diff --git a/KernelLand/Modules/Filesystems/NTFS/Makefile b/KernelLand/Modules/Filesystems/NTFS/Makefile
new file mode 100644 (file)
index 0000000..22c1677
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o dir.o
+NAME = NTFS
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/NTFS/attributes.h b/KernelLand/Modules/Filesystems/NTFS/attributes.h
new file mode 100644 (file)
index 0000000..671a36e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Acess2 - NTFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * attributes.h - MFT Attribute Types
+ */
+#ifndef _ATTRIBUTES_H_
+#define _ATTRIBUTES_H_
+
+typedef struct
+{
+       Uint64  ParentDirectory;        //!< Parent directory MFT entry
+       Sint64  CreationTime;   //!< Time the file was created
+       Sint64  LastDataModTime;        //!< Last change time for the data
+       Sint64  LastMtfModTime; //!< Last change time for the MFT entry
+       Sint64  LastAccessTime; //!< Last Access Time (unreliable on most systems)
+       
+       Uint64  AllocatedSize;  //!< Allocated data size for $DATA unnamed stream
+       Uint64  DataSize;       //!< Actual size of $DATA unnamed stream
+       Uint32  Flags;  //!< File attribute files
+       
+       union {
+               struct {
+                       Uint16  PackedSize;     //!< Size of buffer needed for extended attributes
+                       Uint16  _reserved;
+               } PACKED        ExtAttrib;
+               struct {
+                       Uint32  Tag;    //!< Type of reparse point
+               } PACKED        ReparsePoint;
+       } PACKED        Type;
+       
+       Uint8   FilenameType;   //!< Filename namespace (DOS, Windows, Unix)
+       WCHAR   Filename[0];
+} PACKED       tNTFS_Attrib_Filename;
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/NTFS/common.h b/KernelLand/Modules/Filesystems/NTFS/common.h
new file mode 100644 (file)
index 0000000..598120d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Acess2 - NTFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * common.h - Common Types and Definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <acess.h>
+#include <vfs.h>
+
+typedef Uint16 WCHAR;
+
+// === STRUCTURES ===
+/**
+ * In-memory representation of an NTFS Disk
+ */
+typedef struct sNTFS_Disk
+{
+        int    FD;
+        int    CacheHandle;
+        
+        int    ClusterSize;
+       Uint64  MFTBase;
+       Uint32  MFTRecSize;
+       
+       tVFS_Node       RootNode;
+}      tNTFS_Disk;
+
+typedef struct sNTFS_BootSector
+{
+       // 0
+       Uint8   Jump[3];
+       Uint8   SystemID[8];    // = "NTFS    "
+       Uint16  BytesPerSector;
+       Uint8   SectorsPerCluster;
+       
+       // 0xE
+       Uint8   Unused[7];
+       Uint8   MediaDescriptor;
+       Uint16  Unused2;
+       Uint16  SectorsPerTrack;
+       Uint16  Heads;
+       
+       // 0x1C
+       Uint64  Unused3;
+       Uint32  Unkown; // Usually 0x00800080 (according to Linux docs)
+       
+       // 0x28
+       Uint64  TotalSectorCount;       // Size of volume in sectors
+       Uint64  MFTStart;       // Logical Cluster Number of Cluster 0 of MFT
+       Uint64  MFTMirrorStart; // Logical Cluster Number of Cluster 0 of MFT Backup
+       
+       // 0x40
+       // If either of these are -ve, the size can be obtained via
+       // SizeInBytes = 2^(-1 * Value)
+       Sint8   ClustersPerMFTRecord;
+       Uint8   Unused4[3];
+       Sint8   ClustersPerIndexRecord;
+       Uint8   Unused5[3];
+       
+       Uint64  SerialNumber;
+       
+       Uint8   Padding[512-0x50];
+       
+} PACKED       tNTFS_BootSector;
+
+/**
+ * FILE header, an entry in the MFT
+ */
+typedef struct sNTFS_FILE_Header
+{
+       Uint32  Magic;  // 'FILE'
+       Uint16  UpdateSequenceOfs;
+       Uint16  UpdateSequenceSize;     // Size in words of the UpdateSequenceArray
+       
+       Uint64  LSN;    // $LogFile Sequence Number
+       
+       Uint16  SequenceNumber;
+       Uint16  HardLinkCount;  
+       Uint16  FirstAttribOfs; // Size of header?
+       Uint16  Flags;  // 0: In Use, 1: Directory
+       
+       Uint32  RecordSize;             // Real Size of FILE Record
+       Uint32  RecordSpace;    // Allocated Size for FILE Record
+       
+       /**
+        * Base address of the MFT containing this record
+        */
+       Uint64  Reference;      // "File reference to the base FILE record" ???
+       
+       Uint16  NextAttribID;
+       union
+       {
+               // Only in XP
+               struct {
+                       Uint16  AlignTo4Byte;
+                       Uint16  RecordNumber;   // Number of this MFT Record
+                       Uint16  UpdateSequenceNumber;
+                       Uint16  UpdateSequenceArray[];
+               }       XP;
+               struct {
+                       Uint16  UpdateSequenceNumber;
+                       Uint16  UpdateSequenceArray[];
+               }       All;
+       } OSDep;        
+       
+} PACKED       tNTFS_FILE_Header;
+
+/**
+ * File Attribute, follows the FILE header
+ */
+typedef struct sNTFS_FILE_Attrib
+{
+       Uint32  Type;   // See eNTFS_FILE_Attribs
+       Uint32  Size;   // Includes header
+       
+       Uint8   ResidentFlag;   // (What does this mean?)
+       Uint8   NameLength;
+       Uint16  NameOffset;
+       Uint16  Flags;  // 0: Compressed, 14: Encrypted, 15: Sparse
+       Uint16  AttributeID;
+       
+       union
+       {
+               struct {
+                       Uint32  AttribLen;      // In words
+                       Uint16  AttribOfs;
+                       Uint8   IndexedFlag;
+                       Uint8   Padding;
+                       
+                       Uint16  Name[]; // UTF-16
+                       // Attribute Data
+               }       Resident;
+               struct {
+                       Uint64  StartingVCN;
+                       Uint64  LastVCN;
+                       Uint16  DataRunOfs;
+                       Uint16  CompressionUnitSize;
+                       Uint32  Padding;
+                       Uint64  AllocatedSize;
+                       Uint64  RealSize;
+                       Uint64  InitiatedSize;  // One assumes, ammount of actual data stored
+                       Uint16  Name[]; // UTF-16
+                       // Data Runs
+               }       NonResident;
+       };
+} PACKED       tNTFS_FILE_Attrib;
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/NTFS/dir.c b/KernelLand/Modules/Filesystems/NTFS/dir.c
new file mode 100644 (file)
index 0000000..37661e8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Acess2 - NTFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * dir.c - Directory Handling
+ */
+#include "common.h"
+#include "index.h"
+
+// === PROTOTYPES ===
+char   *NTFS_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *NTFS_FindDir(tVFS_Node *Node, const char *Name);
+Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str);
+
+// === CODE ===
+/**
+ * \brief Get the name of an indexed directory entry
+ */
+char *NTFS_ReadDir(tVFS_Node *Node, int Pos)
+{
+       return NULL;
+}
+
+/**
+ * \brief Get an entry from a directory by name
+ */
+tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tNTFS_Disk      *disk = Node->ImplPtr;
+       Uint64  inode = NTFS_int_IndexLookup(Node->Inode, "$I30", Name);
+       tVFS_Node       node;
+       
+       if(!inode)      return NULL;
+       
+       node.Inode = inode;
+       
+       return Inode_CacheNode(disk->CacheHandle, &node);
+}
+
+/**
+ * \brief Scans an index for the requested value and returns the associated ID
+ */
+Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str)
+{
+       return 0;
+}
diff --git a/KernelLand/Modules/Filesystems/NTFS/index.h b/KernelLand/Modules/Filesystems/NTFS/index.h
new file mode 100644 (file)
index 0000000..f45d897
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Acess2 - NTFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * index.h - Index Types
+ */
+#ifndef _INDEX_H_
+#define _INDEX_H_
+
+#include "attributes.h"
+
+typedef struct
+{
+       Uint32  EntryOffset;
+       Uint32  IndexLength;
+       Uint32  AllocateSize;
+       Uint8   Flags;
+       Uint8   _reserved[3];
+} PACKED       tNTFS_IndexHeader;
+
+typedef struct
+{
+       Uint32  Type;
+       Uint32  CollationRule;
+       Uint32  IndexBlockSize;
+       Uint8   ClustersPerIndexBlock;
+       Uint8   _reserved[3];
+       tNTFS_IndexHeader       Header;
+} PACKED       tNTFS_IndexRoot;
+
+typedef struct
+{
+       union {
+               struct {
+                       Uint64  File;   // MFT Index of file
+               } PACKED        Dir;
+               /**
+                * Views/Indexes
+                */
+               struct {
+                       Uint16  DataOffset;
+                       Uint16  DataLength;
+                       Uint32  _reserved;
+               } PACKED        ViewIndex;
+       } PACKED        Header;
+       
+       Uint16  Length; //!< Size of the index entry (multiple of 8 bytes)
+       Uint16  KeyLength;      //!< Size of key value
+       Uint16  Flags;  //!< Flags Bitfield
+       Uint16  _reserved;
+       
+       /**
+        * \brief Key Data
+        * \note Only valid if \a Flags does not have \a INDEX_ENTRY_END set
+        * \note In NTFS3 only \a Filename is used
+        */
+       union {
+               tNTFS_Attrib_Filename   Filename;
+               //TODO: more key types
+       } PACKED        Key;
+} PACKED       tNTFS_IndexEntry;
+
+#endif
diff --git a/KernelLand/Modules/Filesystems/NTFS/main.c b/KernelLand/Modules/Filesystems/NTFS/main.c
new file mode 100644 (file)
index 0000000..dbda06e
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Acess2 - NTFS Driver
+ * By John Hodge (thePowersGang)
+ *
+ * main.c - Driver core
+ */
+#define DEBUG  1
+#define VERBOSE        0
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+#include <modules.h>
+
+// === IMPORTS ===
+extern char    *NTFS_ReadDir(tVFS_Node *Node, int Pos);
+extern tVFS_Node       *NTFS_FindDir(tVFS_Node *Node, const char *Name);
+
+// === PROTOTYPES ===
+ int   NTFS_Install(char **Arguments);
+tVFS_Node      *NTFS_InitDevice(const char *Devices, const char **Options);
+void   NTFS_Unmount(tVFS_Node *Node);
+void   NTFS_DumpEntry(tNTFS_Disk *Disk, Uint32 Entry);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0A /*v0.1*/, FS_NTFS, NTFS_Install, NULL);
+tVFS_Driver    gNTFS_FSInfo = {"ntfs", 0, NTFS_InitDevice, NTFS_Unmount, NULL};
+tVFS_NodeType  gNTFS_DirType = {
+       .TypeName = "NTFS-File",
+       .ReadDir = NTFS_ReadDir,
+       .FindDir = NTFS_FindDir,
+       .Close = NULL
+       };
+
+tNTFS_Disk     gNTFS_Disks;
+
+// === CODE ===
+/**
+ * \brief Installs the NTFS driver
+ */
+int NTFS_Install(char **Arguments)
+{
+       VFS_AddDriver( &gNTFS_FSInfo );
+       return 0;
+}
+
+/**
+ * \brief Mount a NTFS volume
+ */
+tVFS_Node *NTFS_InitDevice(const char *Device, const char **Options)
+{
+       tNTFS_Disk      *disk;
+       tNTFS_BootSector        bs;
+       
+       disk = malloc( sizeof(tNTFS_Disk) );
+       
+       disk->FD = VFS_Open(Device, VFS_OPENFLAG_READ);
+       if(!disk->FD) {
+               free(disk);
+               return NULL;
+       }
+       
+       Log_Debug("FS_NTFS", "&bs = %p", &bs);
+       VFS_ReadAt(disk->FD, 0, 512, &bs);
+       
+       Log_Debug("FS_NTFS", "Jump = %02x%02x%02x",
+               bs.Jump[0],
+               bs.Jump[1],
+               bs.Jump[2]);
+       Log_Debug("FS_NTFS", "SystemID = %02x%02x%02x%02x%02x%02x%02x%02x (%8C)",
+               bs.SystemID[0], bs.SystemID[1], bs.SystemID[2], bs.SystemID[3],
+               bs.SystemID[4], bs.SystemID[5], bs.SystemID[6], bs.SystemID[7],
+               bs.SystemID
+               );
+       Log_Debug("FS_NTFS", "BytesPerSector = %i", bs.BytesPerSector);
+       Log_Debug("FS_NTFS", "SectorsPerCluster = %i", bs.SectorsPerCluster);
+       Log_Debug("FS_NTFS", "MediaDescriptor = 0x%x", bs.MediaDescriptor);
+       Log_Debug("FS_NTFS", "SectorsPerTrack = %i", bs.SectorsPerTrack);
+       Log_Debug("FS_NTFS", "Heads = %i", bs.Heads);
+       Log_Debug("FS_NTFS", "TotalSectorCount = 0x%llx", bs.TotalSectorCount);
+       Log_Debug("FS_NTFS", "MFTStart = 0x%llx", bs.MFTStart);
+       Log_Debug("FS_NTFS", "MFTMirrorStart = 0x%llx", bs.MFTMirrorStart);
+       Log_Debug("FS_NTFS", "ClustersPerMFTRecord = %i", bs.ClustersPerMFTRecord);
+       Log_Debug("FS_NTFS", "ClustersPerIndexRecord = %i", bs.ClustersPerIndexRecord);
+       Log_Debug("FS_NTFS", "SerialNumber = 0x%llx", bs.SerialNumber);
+       
+       disk->ClusterSize = bs.BytesPerSector * bs.SectorsPerCluster;
+       Log_Debug("NTFS", "Cluster Size = %i KiB", disk->ClusterSize/1024);
+       disk->MFTBase = bs.MFTStart;
+       Log_Debug("NTFS", "MFT Base = %i", disk->MFTBase);
+       Log_Debug("NTFS", "TotalSectorCount = 0x%x", bs.TotalSectorCount);
+       
+       if( bs.ClustersPerMFTRecord < 0 ) {
+               disk->MFTRecSize = 1 << (-bs.ClustersPerMFTRecord);
+       }
+       else {
+               disk->MFTRecSize = bs.ClustersPerMFTRecord * disk->ClusterSize;
+       }
+       
+       disk->RootNode.Inode = 5;       // MFT Ent #5 is filesystem root
+       disk->RootNode.ImplPtr = disk;
+       
+       disk->RootNode.UID = 0;
+       disk->RootNode.GID = 0;
+       
+       disk->RootNode.NumACLs = 1;
+       disk->RootNode.ACLs = &gVFS_ACL_EveryoneRX;
+       
+       disk->RootNode.Type = &gNTFS_DirType;
+
+       
+       NTFS_DumpEntry(disk, 5);
+       
+       return &disk->RootNode;
+}
+
+/**
+ * \brief Unmount an NTFS Disk
+ */
+void NTFS_Unmount(tVFS_Node *Node)
+{
+       
+}
+
+/**
+ * \brief Dumps a MFT Entry
+ */
+void NTFS_DumpEntry(tNTFS_Disk *Disk, Uint32 Entry)
+{
+       void    *buf = malloc( Disk->MFTRecSize );
+       tNTFS_FILE_Header       *hdr = buf;
+       tNTFS_FILE_Attrib       *attr;
+        int    i;
+       
+       if(!buf) {
+               Log_Warning("FS_NTFS", "malloc() fail!");
+               return ;
+       }
+       
+       VFS_ReadAt( Disk->FD,
+               Disk->MFTBase * Disk->ClusterSize + Entry * Disk->MFTRecSize,
+               Disk->MFTRecSize,
+               buf);
+       
+       Log_Debug("FS_NTFS", "MFT Entry #%i", Entry);
+       Log_Debug("FS_NTFS", "- Magic = 0x%08x (%4C)", hdr->Magic, &hdr->Magic);
+       Log_Debug("FS_NTFS", "- UpdateSequenceOfs = 0x%x", hdr->UpdateSequenceOfs);
+       Log_Debug("FS_NTFS", "- UpdateSequenceSize = 0x%x", hdr->UpdateSequenceSize);
+       Log_Debug("FS_NTFS", "- LSN = 0x%x", hdr->LSN);
+       Log_Debug("FS_NTFS", "- SequenceNumber = %i", hdr->SequenceNumber);
+       Log_Debug("FS_NTFS", "- HardLinkCount = %i", hdr->HardLinkCount);
+       Log_Debug("FS_NTFS", "- FirstAttribOfs = 0x%x", hdr->FirstAttribOfs);
+       Log_Debug("FS_NTFS", "- Flags = 0x%x", hdr->Flags);
+       Log_Debug("FS_NTFS", "- RecordSize = 0x%x", hdr->RecordSize);
+       Log_Debug("FS_NTFS", "- RecordSpace = 0x%x", hdr->RecordSpace);
+       Log_Debug("FS_NTFS", "- Reference = 0x%llx", hdr->Reference);
+       Log_Debug("FS_NTFS", "- NextAttribID = 0x%04x", hdr->NextAttribID);
+       
+       attr = (void*)( (char*)hdr + hdr->FirstAttribOfs );
+       i = 0;
+       while( (tVAddr)attr < (tVAddr)hdr + hdr->RecordSize )
+       {
+               if(attr->Type == 0xFFFFFFFF)    break;
+               Log_Debug("FS_NTFS", "- Attribute %i", i ++);
+               Log_Debug("FS_NTFS", " > Type = 0x%x", attr->Type);
+               Log_Debug("FS_NTFS", " > Size = 0x%x", attr->Size);
+               Log_Debug("FS_NTFS", " > ResidentFlag = 0x%x", attr->ResidentFlag);
+               Log_Debug("FS_NTFS", " > NameLength = %i", attr->NameLength);
+               Log_Debug("FS_NTFS", " > NameOffset = 0x%x", attr->NameOffset);
+               Log_Debug("FS_NTFS", " > Flags = 0x%x", attr->Flags);
+               Log_Debug("FS_NTFS", " > AttributeID = 0x%x", attr->AttributeID);
+               if( !attr->ResidentFlag ) {
+                       Log_Debug("FS_NTFS", " > AttribLen = 0x%x", attr->Resident.AttribLen);
+                       Log_Debug("FS_NTFS", " > AttribOfs = 0x%x", attr->Resident.AttribOfs);
+                       Log_Debug("FS_NTFS", " > IndexedFlag = 0x%x", attr->Resident.IndexedFlag);
+                       Log_Debug("FS_NTFS", " > Name = '%*C'", attr->NameLength, attr->Resident.Name);
+                       Debug_HexDump("FS_NTFS",
+                               (void*)( (tVAddr)attr + attr->Resident.AttribOfs ),
+                               attr->Resident.AttribLen
+                               );
+               }
+               else {
+                       Log_Debug("FS_NTFS", " > StartingVCN = 0x%llx", attr->NonResident.StartingVCN);
+                       Log_Debug("FS_NTFS", " > LastVCN = 0x%llx", attr->NonResident.LastVCN);
+                       Log_Debug("FS_NTFS", " > DataRunOfs = 0x%x", attr->NonResident.DataRunOfs);
+                       Log_Debug("FS_NTFS", " > CompressionUnitSize = 0x%x", attr->NonResident.CompressionUnitSize);
+                       Log_Debug("FS_NTFS", " > AllocatedSize = 0x%llx", attr->NonResident.AllocatedSize);
+                       Log_Debug("FS_NTFS", " > RealSize = 0x%llx", attr->NonResident.RealSize);
+                       Log_Debug("FS_NTFS", " > InitiatedSize = 0x%llx", attr->NonResident.InitiatedSize);
+                       Log_Debug("FS_NTFS", " > Name = '%*C'", attr->NameLength, attr->NonResident.Name);
+               }
+               
+               attr = (void*)( (tVAddr)attr + attr->Size );
+       }
+       
+       free(buf);
+}
diff --git a/KernelLand/Modules/IPStack/Makefile b/KernelLand/Modules/IPStack/Makefile
new file mode 100644 (file)
index 0000000..0838a34
--- /dev/null
@@ -0,0 +1,13 @@
+#
+#
+
+OBJ := main.o interface.o
+OBJ += link.o arp.o
+OBJ += ipv4.o icmp.o
+OBJ += ipv6.o
+OBJ += firewall.o routing.o
+OBJ += udp.o tcp.o
+NAME := IPStack
+CATEGORY := 
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/IPStack/arp.c b/KernelLand/Modules/IPStack/arp.c
new file mode 100644 (file)
index 0000000..abaea27
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Acess2 IP Stack
+ * - Address Resolution Protocol
+ * - Part of the IPv4 protocol
+ */
+#define DEBUG  0
+#include "ipstack.h"
+#include "arp.h"
+#include "link.h"
+
+#define ARPv6  0
+#define        ARP_CACHE_SIZE  64
+#define        ARP_MAX_AGE             (60*60*1000)    // 1Hr
+
+// === IMPORTS ===
+extern tInterface      *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
+#if ARPv6
+extern tInterface      *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
+#endif
+
+// === PROTOTYPES ===
+ int   ARP_Initialise();
+tMacAddr       ARP_Resolve4(tInterface *Interface, tIPv4 Address);
+void   ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer);
+
+// === GLOBALS ===
+struct sARP_Cache4 {
+       tIPv4   IP;
+       tMacAddr        MAC;
+       Sint64  LastUpdate;
+       Sint64  LastUsed;
+}      *gaARP_Cache4;
+ int   giARP_Cache4Space;
+tMutex glARP_Cache4;
+#if ARPv6
+struct sARP_Cache6 {
+       tIPv6   IP;
+       tMacAddr        MAC;
+       Sint64  LastUpdate;
+       Sint64  LastUsed;
+}      *gaARP_Cache6;
+ int   giARP_Cache6Space;
+tMutex glARP_Cache6;
+#endif
+volatile int   giARP_LastUpdateID = 0;
+
+// === CODE ===
+/**
+ * \fn int ARP_Initialise()
+ * \brief Initalise the ARP section
+ */
+int ARP_Initialise()
+{
+       gaARP_Cache4 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
+       memset( gaARP_Cache4, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
+       giARP_Cache4Space = ARP_CACHE_SIZE;
+       
+       #if ARPv6
+       gaARP_Cache6 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
+       memset( gaARP_Cache6, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
+       giARP_Cache6Space = ARP_CACHE_SIZE;
+       #endif
+       
+       Link_RegisterType(0x0806, ARP_int_GetPacket);
+       return 1;
+}
+
+/**
+ * \brief Resolves a MAC address from an IPv4 address
+ */
+tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
+{
+        int    lastID;
+        int    i;
+       struct sArpRequest4     req;
+       Sint64  timeout;
+       
+       ENTER("pInterface xAddress", Interface, Address);
+       
+       // Check for broadcast
+       if( Address.L == -1 )
+       {
+               LOG("Broadcast");
+               LEAVE('-');
+               return cMAC_BROADCAST;
+       }
+
+       // Check routing tables if not on this subnet
+       if( IPStack_CompareAddress(4, &Address, Interface->Address, Interface->SubnetBits) == 0 )
+       {
+               tRoute  *route = IPStack_FindRoute(4, Interface, &Address);
+               // If the next hop is defined, use it
+               // - 0.0.0.0 as the next hop means "no next hop / direct"
+               if( route && ((tIPv4*)route->NextHop)->L != 0 )
+               {
+                       // Recursion: see /Recursion/
+                       LOG("Recursing with %s", IPStack_PrintAddress(4, route->NextHop));
+                       LEAVE('-');
+                       return ARP_Resolve4(Interface, *(tIPv4*)route->NextHop);
+               }
+               // No route, fall though
+       }
+       else
+       {
+               Uint32  netmask;
+               // Check for broadcast
+               netmask = IPv4_Netmask(Interface->SubnetBits);
+               if( (Address.L & ~netmask) == (0xFFFFFFFF & ~netmask) )
+               {
+                       LOG("Local Broadcast");
+                       LEAVE('-');
+                       return cMAC_BROADCAST;
+               }
+       }
+       
+       // Check ARP Cache
+       Mutex_Acquire( &glARP_Cache4 );
+       for( i = 0; i < giARP_Cache4Space; i++ )
+       {
+               if(gaARP_Cache4[i].IP.L != Address.L)   continue;
+               
+               // Check if the entry needs to be refreshed
+               if( now() - gaARP_Cache4[i].LastUpdate > ARP_MAX_AGE )  break;
+               
+               Mutex_Release( &glARP_Cache4 );
+               LOG("Return %x:%x:%x:%x:%x:%x",
+                       gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1],
+                       gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3],
+                       gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]
+                       );
+               LEAVE('-');
+               return gaARP_Cache4[i].MAC;
+       }
+       Mutex_Release( &glARP_Cache4 );
+       
+       lastID = giARP_LastUpdateID;
+       
+       // Create request
+       Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
+               Address.B[0], Address.B[1], Address.B[2], Address.B[3]
+               );
+       req.HWType = htons(0x0001);     // Ethernet
+       req.Type   = htons(0x0800);
+       req.HWSize = 6;
+       req.SWSize = 4;
+       req.Request = htons(1);
+       req.SourceMac = Interface->Adapter->MacAddr;
+       req.SourceIP = *(tIPv4*)Interface->Address;
+       req.DestMac = cMAC_BROADCAST;
+       req.DestIP = Address;
+       
+       // Send Request
+       Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, sizeof(struct sArpRequest4), &req);
+       
+       timeout = now() + Interface->TimeoutDelay;
+       
+       // Wait for a reply
+       for(;;)
+       {
+               while(lastID == giARP_LastUpdateID && now() < timeout) {
+                       Threads_Yield();
+               }
+               
+               if( now() >= timeout ) {
+                       Log_Log("ARP4", "Timeout");
+                       break;  // Timeout
+               }
+               
+               lastID = giARP_LastUpdateID;
+               
+               Mutex_Acquire( &glARP_Cache4 );
+               for( i = 0; i < giARP_Cache4Space; i++ )
+               {
+                       if(gaARP_Cache4[i].IP.L != Address.L)   continue;
+                       
+                       Mutex_Release( &glARP_Cache4 );
+                       Log_Debug("ARP4", "Return %02x:%02x:%02x:%02x:%02x:%02x",
+                               gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1], 
+                               gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3], 
+                               gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]);
+                       return gaARP_Cache4[i].MAC;
+               }
+               Mutex_Release( &glARP_Cache4 );
+       }
+       {
+               tMacAddr        ret = {{0,0,0,0,0,0}};
+               return ret;
+       }
+}
+
+/**
+ * \brief Updates the ARP Cache entry for an IPv4 Address
+ */
+void ARP_UpdateCache4(tIPv4 SWAddr, tMacAddr HWAddr)
+{
+        int    i;
+        int    free = -1;
+        int    oldest = 0;
+       
+       // Find an entry for the IP address in the cache
+       Mutex_Acquire(&glARP_Cache4);
+       for( i = giARP_Cache4Space; i--; )
+       {
+               if(gaARP_Cache4[oldest].LastUpdate > gaARP_Cache4[i].LastUpdate) {
+                       oldest = i;
+               }
+               if( gaARP_Cache4[i].IP.L == SWAddr.L )  break;
+               if( gaARP_Cache4[i].LastUpdate == 0 && free == -1 )     free = i;
+       }
+       // If there was no match, we need to make one
+       if(i == -1) {
+               if(free != -1)
+                       i = free;
+               else
+                       i = oldest;
+       }
+       
+       Log_Log("ARP4", "Caching %i.%i.%i.%i (%02x:%02x:%02x:%02x:%02x:%02x) in %i",
+               SWAddr.B[0], SWAddr.B[1], SWAddr.B[2], SWAddr.B[3],
+               HWAddr.B[0], HWAddr.B[1], HWAddr.B[2], HWAddr.B[3], HWAddr.B[4], HWAddr.B[5],
+               i
+               );
+               
+       gaARP_Cache4[i].IP = SWAddr;
+       gaARP_Cache4[i].MAC = HWAddr;
+       gaARP_Cache4[i].LastUpdate = now();
+       giARP_LastUpdateID ++;
+       Mutex_Release(&glARP_Cache4);
+}
+
+#if ARPv6
+/**
+ * \brief Updates the ARP Cache entry for an IPv6 Address
+ */
+void ARP_UpdateCache6(tIPv6 SWAddr, tMacAddr HWAddr)
+{
+        int    i;
+        int    free = -1;
+        int    oldest = 0;
+       
+       // Find an entry for the MAC address in the cache
+       Mutex_Acquire(&glARP_Cache6);
+       for( i = giARP_Cache6Space; i--; )
+       {
+               if(gaARP_Cache6[oldest].LastUpdate > gaARP_Cache6[i].LastUpdate) {
+                       oldest = i;
+               }
+               if( MAC_EQU(gaARP_Cache6[i].MAC, HWAddr) )      break;
+               if( gaARP_Cache6[i].LastUpdate == 0 && free == -1 )     free = i;
+       }
+       // If there was no match, we need to make one
+       if(i == -1) {
+               if(free != -1)
+                       i = free;
+               else
+                       i = oldest;
+               gaARP_Cache6[i].MAC = HWAddr;
+       }
+       
+       gaARP_Cache6[i].IP = SWAddr;
+       gaARP_Cache6[i].LastUpdate = now();
+       giARP_LastUpdateID ++;
+       Mutex_Release(&glARP_Cache6);
+}
+#endif
+
+/**
+ * \fn void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
+ * \brief Called when an ARP packet is recieved
+ */
+void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
+{
+       tArpRequest4    *req4 = Buffer;
+       #if ARPv6
+       tArpRequest6    *req6 = Buffer;
+       #endif
+       tInterface      *iface;
+       
+       // Sanity Check Packet
+       if( Length < (int)sizeof(tArpRequest4) ) {
+               Log_Log("ARP", "Recieved undersized packet");
+               return ;
+       }
+       if( ntohs(req4->Type) != 0x0800 ) {
+               Log_Log("ARP", "Recieved a packet with a bad type (0x%x)", ntohs(req4->Type));
+               return ;
+       }
+       if( req4->HWSize != 6 ) {
+               Log_Log("ARP", "Recieved a packet with HWSize != 6 (%i)", req4->HWSize);
+               return;
+       }
+       #if ARP_DETECT_SPOOFS
+       if( !MAC_EQU(req4->SourceMac, From) ) {
+               Log_Log("ARP", "ARP spoofing detected "
+                       "(%02x%02x:%02x%02x:%02x%02x != %02x%02x:%02x%02x:%02x%02x)",
+                       req4->SourceMac.B[0], req4->SourceMac.B[1], req4->SourceMac.B[2],
+                       req4->SourceMac.B[3], req4->SourceMac.B[4], req4->SourceMac.B[5],
+                       From.B[0], From.B[1], From.B[2],
+                       From.B[3], From.B[4], From.B[5]
+                       );
+               return;
+       }
+       #endif
+       
+       switch( ntohs(req4->Request) )
+       {
+       case 1: // You want my IP?
+               // Check what type of IP it is
+               switch( req4->SWSize )
+               {
+               case 4:
+                       Log_Debug("ARP", "ARP Request IPv4 Address %i.%i.%i.%i from %i.%i.%i.%i",
+                               req4->DestIP.B[0], req4->DestIP.B[1], req4->DestIP.B[2],
+                               req4->DestIP.B[3],
+                               req4->SourceIP.B[0], req4->SourceIP.B[1],
+                               req4->SourceIP.B[2], req4->SourceIP.B[3]);
+                       Log_Debug("ARP", " from MAC %02x:%02x:%02x:%02x:%02x:%02x",
+                               req4->SourceMac.B[0], req4->SourceMac.B[1],
+                               req4->SourceMac.B[2], req4->SourceMac.B[3],
+                               req4->SourceMac.B[4], req4->SourceMac.B[5]);
+                       iface = IPv4_GetInterface(Adapter, req4->DestIP, 0);
+                       if( iface )
+                       {
+                               ARP_UpdateCache4(req4->SourceIP, req4->SourceMac);
+                               
+                               req4->DestIP = req4->SourceIP;
+                               req4->DestMac = req4->SourceMac;
+                               req4->SourceIP = *(tIPv4*)iface->Address;;
+                               req4->SourceMac = Adapter->MacAddr;
+                               req4->Request = htons(2);
+                               Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
+                                       req4->SourceMac.B[0], req4->SourceMac.B[1],
+                                       req4->SourceMac.B[2], req4->SourceMac.B[3],
+                                       req4->SourceMac.B[4], req4->SourceMac.B[5]);
+                               Link_SendPacket(Adapter, 0x0806, req4->DestMac, sizeof(tArpRequest4), req4);
+                       }
+                       break;
+               #if ARPv6
+               case 6:
+                       if( Length < (int)sizeof(tArpRequest6) ) {
+                               Log_Log("ARP", "Recieved undersized packet (IPv6)");
+                               return ;
+                       }
+                       Log_Debug("ARP", "ARP Request IPv6 Address %08x:%08x:%08x:%08x",
+                               ntohl(req6->DestIP.L[0]), ntohl(req6->DestIP.L[1]),
+                               ntohl(req6->DestIP.L[2]), ntohl(req6->DestIP.L[3])
+                               );
+                       iface = IPv6_GetInterface(Adapter, req6->DestIP, 0);
+                       if( iface )
+                       {
+                               req6->DestIP = req6->SourceIP;
+                               req6->DestMac = req6->SourceMac;
+                               req6->SourceIP = *(tIPv6*)iface->Address;
+                               req6->SourceMac = Adapter->MacAddr;
+                               req6->Request = htons(2);
+                               Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
+                                       req4->SourceMac.B[0], req4->SourceMac.B[1],
+                                       req4->SourceMac.B[2], req4->SourceMac.B[3],
+                                       req4->SourceMac.B[4], req4->SourceMac.B[5]);
+                               Link_SendPacket(Adapter, 0x0806, req6->DestMac, sizeof(tArpRequest6), req6);
+                       }
+                       break;
+               #endif
+               default:
+                       Log_Debug("ARP", "Unknown Protocol Address size (%i)", req4->SWSize);
+                       return ;
+               }
+               
+               break;
+       
+       case 2: // Ooh! A response!             
+               // Check what type of IP it is
+               switch( req4->SWSize )
+               {
+               case 4:
+                       ARP_UpdateCache4( req4->SourceIP, From );
+                       break;
+               #if ARPv6
+               case 6:
+                       if( Length < (int)sizeof(tArpRequest6) ) {
+                               Log_Debug("ARP", "Recieved undersized packet (IPv6)");
+                               return ;
+                       }
+                       ARP_UpdateCache6( req6->SourceIP, From );
+                       break;
+               #endif
+               default:
+                       Log_Debug("ARP", "Unknown Protocol Address size (%i)", req4->SWSize);
+                       return ;
+               }
+               
+               break;
+       
+       default:
+               Log_Warning("ARP", "Unknown Request ID %i", ntohs(req4->Request));
+               break;
+       }
+}
diff --git a/KernelLand/Modules/IPStack/arp.h b/KernelLand/Modules/IPStack/arp.h
new file mode 100644 (file)
index 0000000..07cdb64
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Acess2 IP Stack
+ * - Common Header
+ */
+#ifndef _ARP_H_
+#define _ARP_H_
+
+#include "ipstack.h"
+
+typedef struct sArpRequest4    tArpRequest4;
+typedef struct sArpRequest6    tArpRequest6;
+
+struct sArpRequest4 {
+       Uint16  HWType;
+       Uint16  Type;
+       Uint8   HWSize, SWSize;
+       Uint16  Request;
+       tMacAddr        SourceMac;
+       tIPv4   SourceIP;
+       tMacAddr        DestMac;
+       tIPv4   DestIP;
+} __attribute__((packed));
+
+struct sArpRequest6 {
+       Uint16  HWType;
+       Uint16  Type;
+       Uint8   HWSize, SWSize;
+       Uint16  Request;
+       tMacAddr        SourceMac;
+       tIPv6   SourceIP;
+       tMacAddr        DestMac;
+       tIPv6   DestIP;
+} __attribute__((packed));
+
+#endif
diff --git a/KernelLand/Modules/IPStack/firewall.c b/KernelLand/Modules/IPStack/firewall.c
new file mode 100644 (file)
index 0000000..b039081
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Acess2 IP Stack
+ * - Firewall Rules
+ */
+#include "ipstack.h"
+#include "firewall.h"
+
+#define MAX_ADDRTYPE   9
+
+// === IMPORTS ===
+
+// === TYPES ===
+typedef struct sKeyValue       tKeyValue;
+typedef struct sFirewallMod    tFirewallMod;
+typedef struct sModuleRule     tModuleRule;
+typedef struct sRule   tRule;
+typedef struct sChain  tChain;
+
+// === STRUCTURES ===
+struct sKeyValue
+{
+       const char      *Key;
+       const char      *Value;
+};
+
+struct sFirewallMod
+{
+       const char      *Name;
+       
+        int    (*Match)(tModuleRule *Rule, int AddrType,
+                       const void *Src, const void *Dest,
+                       Uint8 Type, Uint32 Flags,
+                       size_t Length, const void *Data);
+       
+       tModuleRule     *(*Create)(tKeyValue *Params);
+};
+
+struct sModuleRule
+{
+       tModuleRule     *Next;
+       
+       tFirewallMod    *Mod;
+       
+       char    Data[];
+};
+
+struct sRule
+{
+       tRule   *Next;
+       
+        int    PacketCount;    // Number of packets seen
+        int    ByteCount;      // Number of bytes seen (IP Payload bytes)
+       
+        int    bInvertSource;  // Boolean NOT flag on source
+       void    *Source;        // Source address bytes
+        int    SourceMask;     // Source address mask bits
+        
+        int    bInvertDest;    // Boolean NOT flag on destination
+       void    *Dest;          // Destination address bytes
+        int    DestMask;       // Destination address mask bits
+       
+       tModuleRule     *Modules;       // Modules loaded for this rule
+       
+       char    Target[];       // Target rule name
+};
+
+struct sChain
+{
+       tChain  *Next;
+       
+       tRule   *FirstRule;
+       tRule   *LastRule;
+       
+       char    Name[];
+};
+
+// === PROTOTYPES ===
+ int   IPTables_TestChain(
+       const char *RuleName,
+       const int AddressType,
+       const void *Src, const void *Dest,
+       Uint8 Type, Uint32 Flags,
+       size_t Length, const void *Data
+       );
+
+// === GLOBALS ===
+tChain *gapFirewall_Chains[MAX_ADDRTYPE+1];
+tChain gFirewall_DROP = {.Name="DROP"};
+tChain gFirewall_ACCEPT = {.Name="ACCEPT"};
+tChain gFirewall_RETURN = {.Name="RETURN"};
+
+// === CODE ===
+/**
+ * \brief Apply a rule to a packet
+ * \return -1 for no match, -2 for RETURN, eFirewallAction otherwise
+ */
+int IPTables_DoRule(
+       tRule *Rule, int AddrType,
+       const void *Src, const void *Dest,
+       Uint8 Type, Uint32 Flags,
+       size_t Length, const void *Data)
+{
+        int    rv;
+       // Check if source doesn't match
+       if( !IPStack_CompareAddress(AddrType, Src, Rule->Source, Rule->SourceMask) == !Rule->bInvertSource )
+               return -1;
+       // Check if destination doesn't match
+       if( !IPStack_CompareAddress(AddrType, Dest, Rule->Dest, Rule->DestMask) == !Rule->bInvertDest )
+               return -1;
+       
+       // TODO: Handle modules (UDP/TCP/etc)
+       tModuleRule *modrule;
+       for( modrule = Rule->Modules; modrule; modrule = modrule->Next )
+       {
+               if( !modrule->Mod->Match )      continue;
+               rv = modrule->Mod->Match(modrule, AddrType, Src, Dest, Type, Flags, Length, Data);
+               if(rv != 0)     return rv;      // No match / action
+       }
+       
+       // Update statistics
+       Rule->PacketCount ++;
+       Rule->ByteCount += Length;
+       
+       return IPTables_TestChain(Rule->Target, AddrType, Src, Dest, Type, Flags, Length, Data);
+}
+
+/**
+ * \brief Tests an IPv4 chain on a packet
+ * \return Boolean Disallow (0: Packet Allowed, 1: Drop, 2: Reject, 3: Continue, -1 no match)
+ */
+int IPTables_TestChain(
+       const char *RuleName,
+       const int AddressType,
+       const void *Src, const void *Dest,
+       Uint8 Type, Uint32 Flags,
+       size_t Length, const void *Data
+       )
+{
+        int    rv;
+       tChain  *chain;
+       tRule   *rule;
+       
+       if( AddressType >= MAX_ADDRTYPE )       return -1;      // Bad address type
+       
+       // Catch builtin targets
+       if(strcmp(RuleName, "") == 0)   return -1;      // No action
+       if(strcmp(RuleName, "ACCEPT") == 0)     return 0;       // Accept packet
+       if(strcmp(RuleName, "DROP") == 0)       return 1;       // Drop packet
+       if(strcmp(RuleName, "RETURN") == 0)     return -2;      // Return from rule
+       
+       // Find the rule
+       for( chain = gapFirewall_Chains[AddressType]; chain; chain = chain->Next )
+       {
+               if( strcmp(chain->Name, RuleName) == 0 )
+                       break;
+       }
+       if( !chain )    return -1;      // Bad rule name
+       
+       // Check the rules
+       for( rule = chain->FirstRule; rule; rule = rule->Next )
+       {
+               rv = IPTables_DoRule(rule, AddressType, Src, Dest, Type, Flags, Length, Data);
+               if( rv == -1 )
+                       continue ;
+               if( rv == -2 )  // -2 = Return from a chain/table, pretend no match
+                       return -1;
+               
+               return rv;
+       }
+       
+       
+       return 0;       // Accept all for now
+}
diff --git a/KernelLand/Modules/IPStack/firewall.h b/KernelLand/Modules/IPStack/firewall.h
new file mode 100644 (file)
index 0000000..5a62380
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ */
+#ifndef _FIREWALL_H_
+#define _FIREWALL_H_
+
+enum eFirewallActions
+{
+       FIREWALL_ACCEPT,
+       FIREWALL_DROP
+};
+
+/**
+ * \brief Tests a packet on a chain
+ */
+extern int     IPTables_TestChain(
+       const char *RuleName,
+       const int AddressType,
+       const void *Src, const void *Dest,
+       Uint8 Type, Uint32 Flags,
+       size_t Length, const void *Data
+       );
+
+#endif
diff --git a/KernelLand/Modules/IPStack/icmp.c b/KernelLand/Modules/IPStack/icmp.c
new file mode 100644 (file)
index 0000000..1603719
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Acess2 IP Stack
+ * - ICMP Handling
+ */
+#include "ipstack.h"
+#include "ipv4.h"
+#include "icmp.h"
+
+// === CONSTANTS ===
+#define PING_SLOTS     64
+
+// === PROTOTYPES ===
+void   ICMP_Initialise();
+void   ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
+
+// === GLOBALS ===
+struct {
+       tInterface      *Interface;
+        int    bArrived;
+}      gICMP_PingSlots[PING_SLOTS];
+
+// === CODE ===
+/**
+ * \fn void ICMP_Initialise()
+ * \brief Initialise the ICMP Layer
+ */
+void ICMP_Initialise()
+{
+       IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket);
+}
+
+/**
+ * \fn void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+ * \brief Handles a packet from the IP Layer
+ */
+void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+{
+       tICMPHeader     *hdr = Buffer;
+       
+       //Log_Debug("ICMPv4", "Length = %i", Length);
+       Log_Debug("ICMPv4", "hdr->Type, hdr->Code = %i, %i", hdr->Type, hdr->Code);
+       //Log_Debug("ICMPv4", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
+       Log_Debug("ICMPv4", "hdr->ID = 0x%x", ntohs(hdr->ID));
+       Log_Debug("ICMPv4", "hdr->Sequence = 0x%x", ntohs(hdr->Sequence));
+       
+       switch(hdr->Type)
+       {
+       // -- 0: Echo Reply
+       case ICMP_ECHOREPLY:
+               if(hdr->Code != 0) {
+                       Log_Warning("ICMPv4", "Code == %i for ICMP Echo Reply, should be 0", hdr->Code);
+                       return ;
+               }
+               if(hdr->ID != (Uint16)~hdr->Sequence) {
+                       Log_Warning("ICMPv4", "ID and Sequence values do not match");
+                       //return ;
+               }
+               gICMP_PingSlots[hdr->ID].bArrived = 1;
+               break;
+       
+       // -- 3: Destination Unreachable
+       case ICMP_UNREACHABLE:
+               switch(hdr->Code)
+               {
+               case 3: // Port Unreachable
+                       Log_Debug("ICMPv4", "Destination Unreachable (Port Unreachable)");
+                       break;
+               default:
+                       Log_Debug("ICMPv4", "Destination Unreachable (Code %i)", hdr->Code);
+                       break;
+               }
+//             IPv4_Unreachable( Interface, hdr->Code, htons(hdr->Length)-sizeof(tICMPHeader), hdr->Data );
+               break;
+       
+       // -- 8: Echo Request
+       case ICMP_ECHOREQ:
+               if(hdr->Code != 0) {
+                       Log_Warning("ICMPv4", "Code == %i for ICMP Echo Request, should be 0", hdr->Code);
+                       return ;
+               }
+               //Log_Debug("ICMPv4", "Replying");
+               hdr->Type = ICMP_ECHOREPLY;
+               hdr->Checksum = 0;
+               hdr->Checksum = htons( IPv4_Checksum( (Uint16*)hdr, Length/2 ) );
+               //Log_Debug("ICMPv4", "Checksum = 0x%04x", hdr->Checksum);
+               IPv4_SendPacket(Interface, *(tIPv4*)Address, 1, ntohs(hdr->Sequence), Length, hdr);
+               break;
+       default:
+               break;
+       }
+       
+}
+
+/**
+ * \brief Sends ICMP Echo and waits for the reply
+ * \note Times out after \a Interface->TimeoutDelay has elapsed
+ */
+int ICMP_Ping(tInterface *Interface, tIPv4 Addr)
+{
+       Sint64  ts;
+       Sint64  end;
+       char    buf[32] = "\x8\0\0\0\0\0\0\0Acess2 I"
+                      "P/TCP Stack 1.0\0";
+       tICMPHeader     *hdr = (void*)buf;
+        int    i;
+       
+       for(;;)
+       {
+               for(i=0;i<PING_SLOTS;i++)
+               {
+                       if(gICMP_PingSlots[i].Interface == NULL)        break;
+               }
+               if( i < PING_SLOTS )    break;
+               Threads_Yield();
+       }
+       gICMP_PingSlots[i].Interface = Interface;
+       gICMP_PingSlots[i].bArrived = 0;
+       hdr->ID = i;
+       hdr->Sequence = ~i;
+       hdr->Checksum = htons( IPv4_Checksum((Uint16*)hdr, sizeof(buf)/2) );
+       
+       ts = now();
+       
+       IPv4_SendPacket(Interface, Addr, 1, i, sizeof(buf), buf);
+       
+       end = ts + Interface->TimeoutDelay;
+       while( !gICMP_PingSlots[i].bArrived && now() < end)     Threads_Yield();
+       
+       if(now() > end)
+               return -1;
+       
+       return (int)( now() - ts );
+}
diff --git a/KernelLand/Modules/IPStack/icmp.h b/KernelLand/Modules/IPStack/icmp.h
new file mode 100644 (file)
index 0000000..8e78722
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Acess2 IP Stack
+ * - ICMP Handling
+ */
+#ifndef _ICMP_H_
+#define _ICMP_H_
+
+// === TYPEDEFS ===
+typedef struct sICMPHeader     tICMPHeader;
+
+// === STRUCTURES ===
+struct sICMPHeader
+{
+       Uint8   Type;
+       Uint8   Code;
+       Uint16  Checksum;
+       Uint16  ID;
+       Uint16  Sequence;
+       Uint8   Data[];
+};
+
+// === CONSTANTS ===
+enum eICMPTypes
+{
+       ICMP_ECHOREPLY = 0,
+       ICMP_UNREACHABLE = 3,
+       ICMP_QUENCH = 4,
+       ICMP_REDIRECT = 5,
+       ICMP_ALTADDR = 6,
+       ICMP_ECHOREQ = 8,
+       ICMP_TRACE = 30 // Information Request
+};
+
+#endif
diff --git a/KernelLand/Modules/IPStack/interface.c b/KernelLand/Modules/IPStack/interface.c
new file mode 100644 (file)
index 0000000..b0b63b9
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Acess2 IP Stack
+ * - Interface Control
+ */
+#define DEBUG  0
+#define VERSION        VER2(0,10)
+#include "ipstack.h"
+#include "link.h"
+#include <api_drv_common.h>
+#include <api_drv_network.h>
+
+// === CONSTANTS ===
+//! Default timeout value, 30 seconds
+#define DEFAULT_TIMEOUT        (30*1000)
+
+// === IMPORTS ===
+extern int     IPv4_Ping(tInterface *Iface, tIPv4 Addr);
+//extern int   IPv6_Ping(tInterface *Iface, tIPv6 Addr);
+extern tVFS_Node       gIP_RouteNode;
+
+// === PROTOTYPES ===
+char   *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
+ int   IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
+
+ int   IPStack_AddFile(tSocketFile *File);
+tInterface     *IPStack_AddInterface(const char *Device, const char *Name);
+tAdapter       *IPStack_GetAdapter(const char *Path);
+
+char   *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
+ int   IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
+
+// === GLOBALS ===
+tVFS_NodeType  gIP_InterfaceNodeType = {
+               .ReadDir = IPStack_Iface_ReadDir,
+               .FindDir = IPStack_Iface_FindDir,
+               .IOCtl = IPStack_Iface_IOCtl
+};
+//! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
+tInterface     gIP_LoopInterface = {
+       .Node = {
+               .ImplPtr = &gIP_LoopInterface,
+               .Flags = VFS_FFLAG_DIRECTORY,
+               .Size = -1,
+               .NumACLs = 1,
+               .ACLs = &gVFS_ACL_EveryoneRX,
+               .Type = &gIP_InterfaceNodeType
+       },
+       .Adapter = NULL,
+       .Type = 0
+};
+tShortSpinlock glIP_Interfaces;
+tInterface     *gIP_Interfaces = NULL;
+tInterface     *gIP_Interfaces_Last = NULL;
+
+tSocketFile    *gIP_FileTemplates;
+
+tAdapter       gIP_LoopAdapter = {
+       .DeviceLen = 8,
+       .Device = "LOOPBACK"
+       };
+tMutex glIP_Adapters;
+tAdapter       *gIP_Adapters = NULL;
+ int   giIP_NextIfaceId = 1;
+
+// === CODE ===
+
+/**
+ * \brief Read from the IP Stack's Device Directory
+ */
+char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tInterface      *iface;
+       char    *name;
+       ENTER("pNode iPos", Node, Pos);
+       
+
+       // Routing Subdir
+       if( Pos == 0 ) {
+               LEAVE('s', "routes");
+               return strdup("routes");
+       }
+       // Pseudo Interfaces
+       if( Pos == 1 ) {
+               LEAVE('s', "lo");
+               return strdup("lo");
+       }
+       Pos -= 2;
+       
+       // Traverse the list
+       for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ;
+       
+       // Did we run off the end?
+       if(!iface) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       name = malloc(4);
+       if(!name) {
+               Log_Warning("IPStack", "IPStack_Root_ReadDir - malloc error");
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Create the name
+       Pos = iface->Node.ImplInt;
+       if(Pos < 10) {
+               name[0] = '0' + Pos;
+               name[1] = '\0';
+       }
+       else if(Pos < 100) {
+               name[0] = '0' + Pos/10;
+               name[1] = '0' + Pos%10;
+               name[2] = '\0';
+       }
+       else {
+               name[0] = '0' + Pos/100;
+               name[1] = '0' + (Pos/10)%10;
+               name[2] = '0' + Pos%10;
+               name[3] = '\0';
+       }
+       
+       LEAVE('s', name);
+       // Return the pre-generated name
+       return name;
+}
+
+/**
+ * \brief Get the node of an interface
+ */
+tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name)
+{
+       #if 0
+        int    i, num;
+       #endif
+       tInterface      *iface;
+       
+       ENTER("pNode sName", Node, Name);
+       
+       // Routing subdir
+       if( strcmp(Name, "routes") == 0 ) {
+               LEAVE('p', &gIP_RouteNode);
+               return &gIP_RouteNode;
+       }
+       
+       // Loopback
+       if( strcmp(Name, "lo") == 0 ) {
+               LEAVE('p', &gIP_LoopInterface.Node);
+               return &gIP_LoopInterface.Node;
+       }
+       
+       for( iface = gIP_Interfaces; iface; iface = iface->Next )
+       {
+               if( strcmp(iface->Name, Name) == 0 )
+               {
+                       LEAVE('p', &iface->Node);
+                       return &iface->Node;
+               }
+       }
+       
+       LEAVE('p', NULL);
+       return NULL;
+}
+
+static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
+/**
+ * \brief Handles IOCtls for the IPStack root
+ */
+int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+        int    tmp;
+       ENTER("pNode iID pData", Node, ID, Data);
+       
+       switch(ID)
+       {
+       // --- Standard IOCtls (0-3) ---
+       BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Root)
+               
+       /*
+        * add_interface
+        * - Adds a new IP interface and binds it to a device
+        */
+       case 4:
+               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+               if( !CheckString( Data ) )      LEAVE_RET('i', -1);
+               LOG("New interface for '%s'", Data);
+               {
+                       char    name[4] = "";
+                       tInterface      *iface = IPStack_AddInterface(Data, name);
+                       if(iface == NULL)       LEAVE_RET('i', -1);
+                       tmp = iface->Node.ImplInt;
+               }
+               LEAVE_RET('i', tmp);
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn tInterface *IPStack_AddInterface(char *Device)
+ * \brief Adds an interface to the list
+ */
+tInterface *IPStack_AddInterface(const char *Device, const char *Name)
+{
+       tInterface      *iface;
+       tAdapter        *card;
+        int    nameLen;
+       
+       ENTER("sDevice", Device);
+       
+       card = IPStack_GetAdapter(Device);
+       if( !card ) {
+               Log_Debug("IPStack", "Unable to open card '%s'", Device);
+               LEAVE('n');
+               return NULL;    // ERR_YOURBAD
+       }
+       
+       nameLen = sprintf(NULL, "%i", giIP_NextIfaceId);
+       
+       iface = malloc(
+               sizeof(tInterface)
+               + nameLen + 1
+               + IPStack_GetAddressSize(-1)*3  // Address, Route->Network, Route->NextHop
+               );
+       if(!iface) {
+               Log_Warning("IPStack", "AddInterface - malloc() failed");
+               LEAVE('n');
+               return NULL;    // Return ERR_MYBAD
+       }
+       
+       iface->Next = NULL;
+       iface->Type = 0;        // Unset type
+       iface->Address = iface->Name + nameLen + 1;     // Address
+       iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
+       iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
+       
+       // Create Node
+       iface->Node.ImplPtr = iface;
+       iface->Node.Flags = VFS_FFLAG_DIRECTORY;
+       iface->Node.Size = -1;
+       iface->Node.NumACLs = 1;
+       iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
+       iface->Node.Type = &gIP_InterfaceNodeType;
+       
+       // Set Defaults
+       iface->TimeoutDelay = DEFAULT_TIMEOUT;
+       
+       // Get adapter handle
+       iface->Adapter = card;
+       
+       // Delay setting ImplInt until after the adapter is opened
+       // Keeps things simple
+       iface->Node.ImplInt = giIP_NextIfaceId++;
+       sprintf(iface->Name, "%i", (int)iface->Node.ImplInt);
+       
+       // Append to list
+       SHORTLOCK( &glIP_Interfaces );
+       if( gIP_Interfaces ) {
+               gIP_Interfaces_Last->Next = iface;
+               gIP_Interfaces_Last = iface;
+       }
+       else {
+               gIP_Interfaces = iface;
+               gIP_Interfaces_Last = iface;
+       }
+       SHORTREL( &glIP_Interfaces );
+
+//     gIP_DriverInfo.RootNode.Size ++;
+       
+       // Success!
+       LEAVE('p', iface);
+       return iface;
+}
+
+/**
+ * \brief Adds a file to the socket list
+ */
+int IPStack_AddFile(tSocketFile *File)
+{
+       Log_Log("IPStack", "Added file '%s'", File->Name);
+       File->Next = gIP_FileTemplates;
+       gIP_FileTemplates = File;
+       return 0;
+}
+
+// ---
+// VFS Functions
+// ---
+/**
+ * \brief Read from an interface's directory
+ */
+char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tSocketFile     *file = gIP_FileTemplates;
+       while(Pos-- && file) {
+               file = file->Next;
+       }
+       
+       if(!file)       return NULL;
+       
+       return strdup(file->Name);
+}
+
+/**
+ * \brief Gets a named node from an interface directory
+ */
+tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tSocketFile     *file = gIP_FileTemplates;
+       
+       // Get file definition
+       for(;file;file = file->Next)
+       {
+               if( strcmp(file->Name, Name) == 0 )     break;
+       }
+       if(!file)       return NULL;
+       
+       // Pass the buck!
+       return file->Init(Node->ImplPtr);
+}
+
+/**
+ * \brief Names for interface IOCtl Calls
+ */
+static const char *casIOCtls_Iface[] = {
+       DRV_IOCTLNAMES,
+       "getset_type",
+       "get_address", "set_address",
+       "getset_subnet",
+       "get_device",
+       "ping",
+       NULL
+       };
+/**
+ * \brief Handles IOCtls for the IPStack interfaces
+ */
+int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+        int    tmp, size;
+       tInterface      *iface = (tInterface*)Node->ImplPtr;
+       ENTER("pNode iID pData", Node, ID, Data);
+       
+       switch(ID)
+       {
+       // --- Standard IOCtls (0-3) ---
+       BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
+       
+       /*
+        * getset_type
+        * - Get/Set the interface type
+        */
+       case 4:
+               // Set Type?
+               if( Data )
+               {
+                       // Ok, it's set type
+                       if( Threads_GetUID() != 0 ) {
+                               LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       if( !CheckMem( Data, sizeof(int) ) ) {
+                               LOG("Invalid pointer %p", Data);
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       
+                       // Set type
+                       iface->Type = *(int*)Data;
+                       LOG("Interface type set to %i", iface->Type);
+                       size = IPStack_GetAddressSize(iface->Type);
+                       // Check it's actually valid
+                       if( iface->Type != 0 && size == 0 ) {
+                               iface->Type = 0;
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+                       
+                       // Clear address
+                       memset(iface->Address, 0, size);
+               }
+               LEAVE('i', iface->Type);
+               return iface->Type;
+       
+       /*
+        * get_address
+        * - Get the interface's address
+        */
+       case 5:
+               size = IPStack_GetAddressSize(iface->Type);
+               if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
+               memcpy( Data, iface->Address, size );
+               LEAVE('i', 1);
+               return 1;
+       
+       /*
+        * set_address
+        * - Set the interface's address
+        */
+       case 6:
+               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+               
+               size = IPStack_GetAddressSize(iface->Type);
+               if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
+               // TODO: Protect against trashing
+               LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
+               memcpy( iface->Address, Data, size );
+               LEAVE_RET('i', 1);
+       
+       /*
+        * getset_subnet
+        * - Get/Set the bits in the address subnet
+        */
+       case 7:
+               // Do we want to set the value?
+               if( Data )
+               {
+                       // Are we root? (TODO: Check Owner/Group)
+                       if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
+                       // Is the memory valid
+                       if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
+                       
+                       // Is the mask sane?
+                       if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
+                               LEAVE_RET('i', -1);
+                       LOG("Set subnet bits to %i", *(int*)Data);
+                       // Ok, set it
+                       iface->SubnetBits = *(int*)Data;
+               }
+               LEAVE_RET('i', iface->SubnetBits);
+       
+       /*
+        * get_device
+        * - Gets the name of the attached device
+        */
+       case 8:
+               if( iface->Adapter == NULL )
+                       LEAVE_RET('i', 0);
+               if( Data == NULL )
+                       LEAVE_RET('i', iface->Adapter->DeviceLen);
+               if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
+                       LEAVE_RET('i', -1);
+               strcpy( Data, iface->Adapter->Device );
+               LEAVE_RET('i', iface->Adapter->DeviceLen);
+       
+       /*
+        * ping
+        * - Send an ICMP Echo
+        */
+       case 9:
+               switch(iface->Type)
+               {
+               case 0:
+                       LEAVE_RET('i', 1);
+               
+               case 4:
+                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
+                       tmp = IPv4_Ping(iface, *(tIPv4*)Data);
+                       LEAVE_RET('i', tmp);
+                       
+               case 6:
+                       LEAVE_RET('i', 1);
+               }
+               break;
+       
+       }
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+// --- Internal ---
+/**
+ * \fn tAdapter *IPStack_GetAdapter(const char *Path)
+ * \brief Gets/opens an adapter given the path
+ */
+tAdapter *IPStack_GetAdapter(const char *Path)
+{
+       tAdapter        *dev;
+        int    tmp;
+       
+       ENTER("sPath", Path);
+       
+       // Check for loopback
+       if( strcmp(Path, "LOOPBACK") == 0 )
+       {
+               // Initialise if required
+               if( gIP_LoopAdapter.DeviceFD == 0 )
+               {
+                       dev = &gIP_LoopAdapter;
+                       
+                       dev->NRef = 1;
+                       dev->DeviceLen = 8;
+                       
+                       dev->DeviceFD = VFS_Open( "/Devices/fifo/anon", VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
+                       if( dev->DeviceFD == -1 ) {
+                               Log_Warning("IPStack", "Unable to open FIFO '/Devices/fifo/anon' for loopback");
+                               return NULL;
+                       }
+                       
+                       dev->MacAddr.B[0] = 'A';
+                       dev->MacAddr.B[1] = 'c';
+                       dev->MacAddr.B[2] = 'e';
+                       dev->MacAddr.B[3] = 's';
+                       dev->MacAddr.B[4] = 's';
+                       dev->MacAddr.B[5] = '2';
+                       
+                       // Start watcher
+                       Link_WatchDevice( dev );
+               }
+               LEAVE('p', &gIP_LoopAdapter);
+               return &gIP_LoopAdapter;
+       }
+       
+       Mutex_Acquire( &glIP_Adapters );
+       
+       // Check if this adapter is already open
+       for( dev = gIP_Adapters; dev; dev = dev->Next )
+       {
+               if( strcmp(dev->Device, Path) == 0 ) {
+                       dev->NRef ++;
+                       Mutex_Release( &glIP_Adapters );
+                       LEAVE('p', dev);
+                       return dev;
+               }
+       }
+       
+       // Ok, so let's open it
+       dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
+       if(!dev) {
+               Log_Warning("IPStack", "GetAdapter - malloc() failed");
+               Mutex_Release( &glIP_Adapters );
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Fill Structure
+       strcpy( dev->Device, Path );
+       dev->NRef = 1;
+       dev->DeviceLen = strlen(Path);
+       
+       // Open Device
+       dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
+       if( dev->DeviceFD == -1 ) {
+               free( dev );
+               Mutex_Release( &glIP_Adapters );
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Check that it is a network interface
+       tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
+       LOG("Device type = %i", tmp);
+       if( tmp != DRV_TYPE_NETWORK ) {
+               Log_Warning("IPStack", "IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
+               VFS_Close( dev->DeviceFD );
+               free( dev );
+               Mutex_Release( &glIP_Adapters );
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Get MAC Address
+       VFS_IOCtl(dev->DeviceFD, NET_IOCTL_GETMAC, &dev->MacAddr);
+       
+       // Add to list
+       dev->Next = gIP_Adapters;
+       gIP_Adapters = dev;
+       
+       Mutex_Release( &glIP_Adapters );
+       
+       // Start watcher
+       Link_WatchDevice( dev );
+       
+       LEAVE('p', dev);
+       return dev;
+}
diff --git a/KernelLand/Modules/IPStack/ipstack.h b/KernelLand/Modules/IPStack/ipstack.h
new file mode 100644 (file)
index 0000000..e51fded
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Acess2 IP Stack
+ * - Common Header
+ */
+#ifndef _IPSTACK_H_
+#define _IPSTACK_H_
+
+#include <acess.h>
+#include <vfs.h>
+
+typedef union uIPv4    tIPv4;
+typedef union uIPv6    tIPv6;
+typedef struct sMacAddr        tMacAddr;
+typedef struct sAdapter        tAdapter;
+typedef struct sInterface      tInterface;
+typedef struct sSocketFile     tSocketFile;
+
+typedef void   (*tIPCallback)(tInterface *Interface, void *Address, int Length, void *Buffer);
+
+enum eInterfaceTypes {
+       AF_NULL,
+       AF_INET4 = 4,   // tIPv4
+       AF_INET6 = 6    // tIPv6
+};
+
+union uIPv4 {
+       Uint32  L;
+       Uint8   B[4];
+} __attribute__((packed));
+
+union uIPv6 {
+       Uint16  W[8];
+       Uint32  L[4];
+       Uint8   B[16];
+} __attribute__((packed));
+
+struct sMacAddr {
+       Uint8   B[6];
+} __attribute__((packed));
+
+/**
+ * \brief Route definition structure
+ */
+typedef struct sRoute {
+       struct sRoute   *Next;
+       
+       tVFS_Node       Node;   //!< Node for route manipulation
+       
+       tInterface      *Interface;     //!< Interface for this route
+        int    AddressType;    //!< 0: Invalid, 4: IPv4, 6: IPv4
+       void    *Network;       //!< Network - Pointer to tIPv4/tIPv6/... at end of structure
+        int    SubnetBits;     //!< Number of bits in \a Network that are valid
+       void    *NextHop;       //!< Next Hop address - Pointer to tIPv4/tIPv6/... at end of structure
+        int    Metric; //!< Route priority
+}      tRoute;
+
+struct sInterface {
+       struct sInterface       *Next;  //!< Next interface in list
+       
+       tVFS_Node       Node;   //!< Node to use the interface
+       
+       tAdapter        *Adapter;       //!< Adapter the interface is associated with
+        int    TimeoutDelay;   //!< Time in miliseconds before a packet times out
+        int    Type;   //!< Interface type, see ::eInterfaceTypes
+       
+       void    *Address;       //!< IP address (stored after the Name)
+        int    SubnetBits;     //!< Number of bits that denote the address network
+       
+       tRoute  Route;  //!< Interface route
+       
+       char    Name[];
+};
+
+/**
+ * \brief Represents a network adapter
+ */
+struct sAdapter {
+       struct sAdapter *Next;
+       
+        int    DeviceFD;       //!< File descriptor of the device
+        int    NRef;   //!< Number of times it's been referenced
+       
+       tMacAddr        MacAddr;        //!< Physical address of the adapter
+        int    DeviceLen;      //!< Device name length
+       char    Device[];       //!< Device name
+};
+
+/**
+ * \brief Describes a socket file definition
+ */
+struct sSocketFile
+{
+       struct sSocketFile      *Next;
+       const char      *Name;
+       
+       tVFS_Node       *(*Init)(tInterface *Interface);
+};
+
+static const tMacAddr cMAC_BROADCAST = {{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
+static const tMacAddr cMAC_ZERO = {{0x00,0x00,0x00,0x00,0x00,0x00}};
+
+#define MAC_SET(t,v)   memcpy(&(t),&(v),sizeof(tMacAddr))
+#define IP4_SET(t,v)   (t).L = (v).L;
+#define IP6_SET(t,v)   memcpy(&(t),&(v),sizeof(tIPv6))
+
+#define MAC_EQU(a,b)   (memcmp(&(a),&(b),sizeof(tMacAddr))==0)
+#define IP4_EQU(a,b)   ((a).L==(b).L)
+#define IP6_EQU(a,b)   (memcmp(&(a),&(b),sizeof(tIPv6))==0)
+
+// === FUNCTIONS ===
+#define htonb(v)       (v)
+#define htons(v)       BigEndian16(v)
+#define htonl(v)       BigEndian32(v)
+#define ntonb(v)       (v)
+#define ntohs(v)       BigEndian16(v)
+#define ntohl(v)       BigEndian32(v)
+
+extern int     IPStack_AddFile(tSocketFile *File);
+extern int     IPStack_GetAddressSize(int AddressType);
+extern int     IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits);
+extern const char      *IPStack_PrintAddress(int AddressType, const void *Address);
+
+extern tRoute  *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
+
+#endif
diff --git a/KernelLand/Modules/IPStack/ipv4.c b/KernelLand/Modules/IPStack/ipv4.c
new file mode 100644 (file)
index 0000000..86301e9
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Acess2 IP Stack
+ * - IPv4 Protcol Handling
+ */
+#define DEBUG  1
+#include "ipstack.h"
+#include "link.h"
+#include "ipv4.h"
+#include "firewall.h"
+
+#define DEFAULT_TTL    32
+
+// === IMPORTS ===
+extern tInterface      *gIP_Interfaces;
+extern void    ICMP_Initialise();
+extern  int    ICMP_Ping(tInterface *Interface, tIPv4 Addr);
+extern tMacAddr        ARP_Resolve4(tInterface *Interface, tIPv4 Address);
+
+// === PROTOTYPES ===
+ int   IPv4_Initialise();
+ int   IPv4_RegisterCallback(int ID, tIPCallback Callback);
+void   IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
+tInterface     *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
+Uint32 IPv4_Netmask(int FixedBits);
+Uint16 IPv4_Checksum(const void *Buf, size_t Length);
+ int   IPv4_Ping(tInterface *Iface, tIPv4 Addr);
+
+// === GLOBALS ===
+tIPCallback    gaIPv4_Callbacks[256];
+
+// === CODE ===
+/**
+ * \brief Initialise the IPv4 Code
+ */
+int IPv4_Initialise()
+{
+       ICMP_Initialise();
+       Link_RegisterType(IPV4_ETHERNET_ID, IPv4_int_GetPacket);
+       return 1;
+}
+
+/**
+ * \brief Registers a callback
+ * \param ID   8-bit packet type ID
+ * \param Callback     Callback function
+ */
+int IPv4_RegisterCallback(int ID, tIPCallback Callback)
+{
+       if( ID < 0 || ID > 255 )        return 0;
+       if( gaIPv4_Callbacks[ID] )      return 0;
+       gaIPv4_Callbacks[ID] = Callback;
+       return 1;
+}
+
+/**
+ * \brief Creates and sends an IPv4 Packet
+ * \param Iface        Interface
+ * \param Address      Destination IP
+ * \param Protocol     Protocol ID
+ * \param ID   Some random ID number
+ * \param Length       Data Length
+ * \param Data Packet Data
+ * \return Boolean Success
+ */
+int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data)
+{
+       tMacAddr        to;
+        int    bufSize = sizeof(tIPv4Header) + Length;
+       char    buf[bufSize];
+       tIPv4Header     *hdr = (void*)buf;
+        int    ret;
+       
+       to = ARP_Resolve4(Iface, Address);
+       if( MAC_EQU(to, cMAC_ZERO) ) {
+               // No route to host
+               Log_Notice("IPv4", "No route to host %i.%i.%i.%i",
+                       Address.B[0], Address.B[1], Address.B[2], Address.B[3]);
+               return 0;
+       }
+       
+       // OUTPUT Firewall rule go here
+       ret = IPTables_TestChain("OUTPUT",
+               4, (tIPv4*)Iface->Address, &Address,
+               Protocol, 0,
+               Length, Data);
+       if(ret > 0) {
+               // Just drop it (with an error)
+               Log_Notice("IPv4", "Firewall dropped packet");
+               return 0;
+       }
+       
+       memcpy(&hdr->Options[0], Data, Length);
+       hdr->Version = 4;
+       hdr->HeaderLength = sizeof(tIPv4Header)/4;
+       hdr->DiffServices = 0;  // TODO: Check
+       
+       hdr->Reserved = 0;
+       hdr->DontFragment = 0;
+       hdr->MoreFragments = 0;
+       hdr->FragOffLow = 0;
+       hdr->FragOffHi = 0;
+       
+       hdr->TotalLength = htons( bufSize );
+       hdr->Identifcation = htons( ID );       // TODO: Check
+       hdr->TTL = DEFAULT_TTL;
+       hdr->Protocol = Protocol;
+       hdr->HeaderChecksum = 0;        // Will be set later
+       hdr->Source = *(tIPv4*)Iface->Address;
+       hdr->Destination = Address;
+       hdr->HeaderChecksum = htons( IPv4_Checksum(hdr, sizeof(tIPv4Header)) );
+       
+       Log_Log("IPv4", "Sending packet to %i.%i.%i.%i",
+               Address.B[0], Address.B[1], Address.B[2], Address.B[3]);
+       Link_SendPacket(Iface->Adapter, IPV4_ETHERNET_ID, to, bufSize, buf);
+       return 1;
+}
+
+/**
+ * \fn void IPv4_int_GetPacket(tInterface *Adapter, tMacAddr From, int Length, void *Buffer)
+ * \brief Process an IPv4 Packet
+ */
+void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
+{
+       tIPv4Header     *hdr = Buffer;
+       tInterface      *iface;
+       Uint8   *data;
+        int    dataLength;
+        int    ret;
+       
+       if(Length < sizeof(tIPv4Header))        return;
+       
+       #if 0
+       //Log_Log("IPv4", "Version = %i", hdr->Version);
+       //Log_Log("IPv4", "HeaderLength = %i", hdr->HeaderLength);
+       //Log_Log("IPv4", "DiffServices = %i", hdr->DiffServices);
+       Log_Debug("IPv4", "TotalLength = %i", ntohs(hdr->TotalLength) );
+       //Log_Log("IPv4", "Identifcation = %i", ntohs(hdr->Identifcation) );
+       //Log_Log("IPv4", "TTL = %i", hdr->TTL );
+       Log_Debug("IPv4", "Protocol = %i", hdr->Protocol );
+       //Log_Log("IPv4", "HeaderChecksum = 0x%x", ntohs(hdr->HeaderChecksum) );
+       Log_Debug("IPv4", "Source = %i.%i.%i.%i",
+               hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3] );
+       Log_Debug("IPv4", "Destination = %i.%i.%i.%i",
+               hdr->Destination.B[0], hdr->Destination.B[1],
+               hdr->Destination.B[2], hdr->Destination.B[3] );
+       #endif  
+
+       // Check that the version IS IPv4
+       if(hdr->Version != 4) {
+               Log_Log("IPv4", "hdr->Version(%i) != 4", hdr->Version);
+               return;
+       }
+       
+       // Check Header checksum
+       {
+               Uint16  hdrVal, compVal;
+               hdrVal = ntohs(hdr->HeaderChecksum);
+               hdr->HeaderChecksum = 0;
+               compVal = IPv4_Checksum(hdr, hdr->HeaderLength * 4);
+               if(hdrVal != compVal) {
+                       Log_Log("IPv4", "Header checksum fails (%04x != %04x)", hdrVal, compVal);
+                       return ;
+               }
+               hdr->HeaderChecksum = hdrVal;
+       }
+       
+       // Check Packet length
+       if( ntohs(hdr->TotalLength) > Length) {
+               Log_Log("IPv4", "hdr->TotalLength(%i) > Length(%i)", ntohs(hdr->TotalLength), Length);
+               return;
+       }
+       
+       // TODO: Handle packet fragmentation
+       
+       
+       Log_Debug("IPv4", " From %i.%i.%i.%i to %i.%i.%i.%i",
+               hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3],
+               hdr->Destination.B[0], hdr->Destination.B[1], hdr->Destination.B[2], hdr->Destination.B[3]
+               );
+       
+       // Get Data and Data Length
+       dataLength = ntohs(hdr->TotalLength) - sizeof(tIPv4Header);
+       data = &hdr->Options[0];
+       
+       // Get Interface (allowing broadcasts)
+       iface = IPv4_GetInterface(Adapter, hdr->Destination, 1);
+       
+       // Firewall rules
+       if( iface ) {
+               // Incoming Packets
+               ret = IPTables_TestChain("INPUT",
+                       4, &hdr->Source, &hdr->Destination,
+                       hdr->Protocol, 0,
+                       dataLength, data
+                       );
+       }
+       else {
+               // Routed packets
+               ret = IPTables_TestChain("FORWARD",
+                       4, &hdr->Source, &hdr->Destination,
+                       hdr->Protocol, 0,
+                       dataLength, data
+                       );
+       }
+       switch(ret)
+       {
+       // 0 - Allow
+       case 0: break;
+       // 1 - Silent Drop
+       case 1:
+               Log_Debug("IPv4", "Silently dropping packet");
+               return ;
+       case -1:
+               // Bad rule
+               break ;
+       // Unknown, silent drop
+       default:
+               Log_Warning("IPv4", "Unknown firewall rule");
+               return ;
+       }
+       
+       // Routing
+       if(!iface)
+       {
+               tMacAddr        to;
+               tRoute  *rt;
+               
+               Log_Debug("IPv4", "Route the packet");
+               // Drop the packet if the TTL is zero
+               if( hdr->TTL == 0 ) {
+                       Log_Warning("IPv4", "TODO: Send ICMP-Timeout when TTL exceeded");
+                       return ;
+               }
+               
+               hdr->TTL --;
+               
+               rt = IPStack_FindRoute(4, NULL, &hdr->Destination);     // Get the route (gets the interface)
+               if( !rt || !rt->Interface )
+                       return ;
+               to = ARP_Resolve4(rt->Interface, hdr->Destination);     // Resolve address
+               if( MAC_EQU(to, cMAC_ZERO) )
+                       return ;
+               
+               // Send packet
+               Log_Log("IPv4", "Forwarding packet to %i.%i.%i.%i (via %i.%i.%i.%i)",
+                       hdr->Destination.B[0], hdr->Destination.B[1],
+                       hdr->Destination.B[2], hdr->Destination.B[3],
+                       ((tIPv4*)rt->NextHop)->B[0], ((tIPv4*)rt->NextHop)->B[1],
+                       ((tIPv4*)rt->NextHop)->B[2], ((tIPv4*)rt->NextHop)->B[3]);
+               Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer);
+               
+               
+               return ;
+       }
+       
+       // Send it on
+       if( !gaIPv4_Callbacks[hdr->Protocol] ) {
+               Log_Log("IPv4", "Unknown Protocol %i", hdr->Protocol);
+               return ;
+       }
+       
+       gaIPv4_Callbacks[hdr->Protocol]( iface, &hdr->Source, dataLength, data );
+}
+
+/**
+ * \fn tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address)
+ * \brief Searches an adapter for a matching address
+ * \param Adapter      Incoming Adapter
+ * \param Address      Destination Address
+ * \param Broadcast    Allow broadcast packets
+ */
+tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
+{
+       tInterface      *iface = NULL;
+       Uint32  netmask;
+       Uint32  addr, this;
+
+       ENTER("pAdapter xAddress bBroadcast", Adapter, Address, Broadcast);     
+
+       addr = ntohl( Address.L );
+       LOG("addr = 0x%x", addr);
+       
+       for( iface = gIP_Interfaces; iface; iface = iface->Next)
+       {
+               if( iface->Adapter != Adapter ) continue;
+               if( iface->Type != 4 )  continue;
+               if( IP4_EQU(Address, *(tIPv4*)iface->Address) ) {
+                       LOG("Exact match");
+                       LEAVE('p', iface);
+                       return iface;
+               }
+               
+               if( !Broadcast )        continue;
+               
+               // Check for broadcast
+               this = ntohl( ((tIPv4*)iface->Address)->L );
+               netmask = IPv4_Netmask(iface->SubnetBits);
+               LOG("iface addr = 0x%x, netmask = 0x%x (bits = %i)", this, netmask, iface->SubnetBits);
+
+               if( (addr & netmask) == (this & netmask) && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
+               {
+                       LOG("Broadcast match");
+                       LEAVE('p', iface);
+                       return iface;
+               }
+       }
+       LEAVE('n');
+       return NULL;
+}
+
+/**
+ * \brief Convert a network prefix to a netmask
+ * \param FixedBits    Netmask size (/n)
+ * 
+ * For example /24 will become 255.255.255.0 (0xFFFFFF00)
+ */
+Uint32 IPv4_Netmask(int FixedBits)
+{
+       Uint32  ret = 0xFFFFFFFF;
+       if( FixedBits == 0 )
+               return 0;
+       if( FixedBits < 32 )
+       {
+               ret >>= (32-FixedBits);
+               ret <<= (32-FixedBits);
+       }
+       // Returns a native endian netmask
+       return ret;
+}
+
+/**
+ * \brief Calculate the IPv4 Checksum
+ * \param Buf  Input buffer
+ * \param Size Size of input
+ * 
+ * One's complement sum of all 16-bit words (bitwise inverted)
+ */
+Uint16 IPv4_Checksum(const void *Buf, size_t Length)
+{
+       const Uint16    *words = Buf;
+       Uint32  sum = 0;
+        int    i;
+       
+       // Sum all whole words
+       for(i = 0; i < Length/2; i++ )
+       {
+               sum += ntohs(words[i]);
+       }
+       if( Length & 1 )
+               sum += ntohs( words[i] & 0xFF );
+       
+       // Apply one's complement
+       while (sum >> 16)
+               sum = (sum & 0xFFFF) + (sum >> 16);
+       
+       return ~sum;
+}
+
+/**
+ * \brief Sends an ICMP Echo and waits for a reply
+ * \param IFace        Interface
+ * \param Addr Destination address
+ */
+int IPv4_Ping(tInterface *IFace, tIPv4 Addr)
+{
+       return ICMP_Ping(IFace, Addr);
+}
diff --git a/KernelLand/Modules/IPStack/ipv4.h b/KernelLand/Modules/IPStack/ipv4.h
new file mode 100644 (file)
index 0000000..2c3e1ca
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Acess2 IP Stack
+ * - IPv4 Definitions
+ */
+#ifndef _IPV4_H_
+#define _IPV4_H_
+
+#include "ipstack.h"
+
+typedef struct sIPv4Header     tIPv4Header;
+
+struct sIPv4Header
+{
+       struct {
+               // Spec says Version is first, but stupid bit ordering
+               unsigned HeaderLength:  4;      // in 4-byte chunks
+               unsigned Version:       4;      // = 4
+       } __attribute__((packed));
+       Uint8   DiffServices;   // Differentiated Services
+       Uint16  TotalLength;
+       Uint16  Identifcation;
+       
+       struct {
+               unsigned Reserved:      1;
+               unsigned DontFragment:  1;
+               unsigned MoreFragments: 1;
+               unsigned FragOffLow:    5;
+       } __attribute__((packed));
+       Uint8   FragOffHi;      // Number of 8-byte blocks from the original start
+       
+       Uint8   TTL;    // Max number of hops, effectively
+       Uint8   Protocol;
+       Uint16  HeaderChecksum; // One's Complement Sum of the entire header must equal zero
+       
+       tIPv4   Source;
+       tIPv4   Destination;
+       
+       Uint8   Options[];
+} __attribute__((packed));
+
+#define IP4PROT_ICMP   1
+#define IP4PROT_TCP    6
+#define IP4PROT_UDP    17
+
+#define IPV4_ETHERNET_ID       0x0800
+
+// === FUNCTIONS ===
+extern int     IPv4_RegisterCallback(int ID, tIPCallback Callback);
+extern Uint16  IPv4_Checksum(const void *Buf, size_t Length);
+extern int     IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data);
+
+#endif
diff --git a/KernelLand/Modules/IPStack/ipv6.c b/KernelLand/Modules/IPStack/ipv6.c
new file mode 100644 (file)
index 0000000..7cb8e0a
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Acess2 IP Stack
+ * - IPv6 Protcol Handling
+ */
+#include "ipstack.h"
+#include "link.h"
+#include "ipv6.h"
+#include "firewall.h"
+
+// === IMPORTS ===
+extern tInterface      *gIP_Interfaces;
+extern Uint32  IPv4_Netmask(int FixedBits);
+
+// === PROTOTYPES ===
+ int   IPv6_Initialise();
+ int   IPv6_RegisterCallback(int ID, tIPCallback Callback);
+void   IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
+tInterface     *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
+
+// === GLOBALS ===
+tIPCallback    gaIPv6_Callbacks[256];
+
+// === CODE ===
+/**
+ * \brief Initialise the IPv6 handling code
+ */
+int IPv6_Initialise()
+{
+       Link_RegisterType(IPV6_ETHERNET_ID, IPv6_int_GetPacket);
+       return 1;
+}
+
+/**
+ * \brief Registers a callback
+ * \param ID   8-bit packet type ID
+ * \param Callback     Callback function
+ */
+int IPv6_RegisterCallback(int ID, tIPCallback Callback)
+{
+       if( ID < 0 || ID > 255 )        return 0;
+       if( gaIPv6_Callbacks[ID] )      return 0;
+       gaIPv6_Callbacks[ID] = Callback;
+       return 1;
+}
+
+/**
+ * \brief Creates and sends an IPv6 Packet
+ * \param Iface        Interface
+ * \param Destination  Destination IP
+ * \param Protocol     Protocol ID
+ * \param Length       Data Length
+ * \param Data Packet Data
+ * \return Boolean Success
+ */
+int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data)
+{
+       return 0;
+}
+
+/**
+ * \fn void IPv6_int_GetPacket(tInterface *Interface, tMacAddr From, int Length, void *Buffer)
+ * \brief Process an IPv6 Packet
+ * \param Interface    Input interface
+ * \param From Source MAC address
+ * \param Length       Packet length
+ * \param Buffer       Packet data
+ */
+void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
+{
+       tInterface      *iface;
+       tIPv6Header     *hdr = Buffer;
+        int    ret, dataLength;
+       char    *dataPtr;
+       Uint8   nextHeader;
+       
+       if(Length < sizeof(tIPv6Header))        return;
+       
+       hdr->Head = ntohl(hdr->Head);
+       
+       //if( ((hdr->Head >> (20+8)) & 0xF) != 6 )
+       if( hdr->Version != 6 )
+               return;
+       
+       #if 1
+       Log_Debug("IPv6", "hdr = {");
+       Log_Debug("IPv6", " .Version       = %i", hdr->Version );
+       Log_Debug("IPv6", " .TrafficClass  = %i", hdr->TrafficClass );
+       Log_Debug("IPv6", " .FlowLabel     = %i", hdr->FlowLabel );
+       Log_Debug("IPv6", " .PayloadLength = 0x%04x", ntohs(hdr->PayloadLength) );
+       Log_Debug("IPv6", " .NextHeader    = 0x%02x", hdr->NextHeader );
+       Log_Debug("IPv6", " .HopLimit      = 0x%02x", hdr->HopLimit );
+       Log_Debug("IPv6", " .Source        = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Source );
+       Log_Debug("IPv6", " .Destination   = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Destination );
+       Log_Debug("IPv6", "}");
+       #endif
+       
+       // No checksum in IPv6
+       
+       // Check Packet length
+       if( ntohs(hdr->PayloadLength)+sizeof(tIPv6Header) > Length) {
+               Log_Log("IPv6", "hdr->PayloadLength(%i) > Length(%i)", ntohs(hdr->PayloadLength), Length);
+               return;
+       }
+       
+       // Process Options
+       nextHeader = hdr->NextHeader;
+       dataPtr = hdr->Data;
+       dataLength = hdr->PayloadLength;
+       for( ;; )
+       {
+               struct {
+                       Uint8   NextHeader;
+                       Uint8   Length; // In 8-byte chunks, with 0 being 8 bytes long
+                       Uint8   Data[];
+               }       *optionHdr;
+               optionHdr = (void*)dataPtr;
+               // Hop-by-hop options
+               if(nextHeader == 0)
+               {
+                       // TODO: Parse the options (actually, RFC2460 doesn't specify any)
+               }
+               // Routing Options
+               else if(nextHeader == 43)
+               {
+                       // TODO: Routing Header options
+               }
+               else
+               {
+                       break;  // Unknown, pass on
+               }
+               nextHeader = optionHdr->NextHeader;
+               dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long)
+       }
+       
+       // Get Interface (allowing broadcasts)
+       iface = IPv6_GetInterface(Adapter, hdr->Destination, 1);
+       
+       // Firewall rules
+       if( iface ) {
+               // Incoming Packets
+               ret = IPTables_TestChain("INPUT",
+                       6, &hdr->Source, &hdr->Destination,
+                       hdr->NextHeader, 0,
+                       hdr->PayloadLength, hdr->Data
+                       );
+       }
+       else {
+               // Routed packets
+               ret = IPTables_TestChain("FORWARD",
+                       6, &hdr->Source, &hdr->Destination,
+                       hdr->NextHeader, 0,
+                       hdr->PayloadLength, hdr->Data
+                       );
+       }
+       
+       switch(ret)
+       {
+       // 0 - Allow
+       case 0: break;
+       // 1 - Silent Drop
+       case 1:
+               Log_Debug("IPv6", "Silently dropping packet");
+               return ;
+       // Unknown, silent drop
+       default:
+               return ;
+       }
+       
+       // Routing
+       if(!iface)
+       {
+               #if 0
+               tMacAddr        to;
+               tRoute  *rt;
+               
+               Log_Debug("IPv6", "Route the packet");
+               // Drop the packet if the TTL is zero
+               if( hdr->HopLimit == 0 ) {
+                       Log_Warning("IPv6", "TODO: Sent ICMP-Timeout when TTL exceeded");
+                       return ;
+               }
+               
+               hdr->HopLimit --;
+               
+               rt = IPStack_FindRoute(6, NULL, &hdr->Destination);     // Get the route (gets the interface)
+               to = ICMP6_ResolveHWAddr(rt->Interface, hdr->Destination);      // Resolve address
+               
+               // Send packet
+               Log_Log("IPv6", "Forwarding packet");
+               Link_SendPacket(rt->Interface->Adapter, IPV6_ETHERNET_ID, to, Length, Buffer);
+               #endif
+               
+               return ;
+       }
+       
+       // Send it on
+       if( !gaIPv6_Callbacks[hdr->NextHeader] ) {
+               Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader);
+               return ;
+       }
+       
+       gaIPv6_Callbacks[hdr->NextHeader]( iface, &hdr->Source, hdr->PayloadLength, hdr->Data );
+}
+
+/**
+ * \fn tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address)
+ * \brief Searches an adapter for a matching address
+ * \param Adapter      Source adapter
+ * \param Address      Destination Address
+ * \param Broadcast    Allow broadcast?
+ */
+tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
+{
+        int    i, j;
+       tInterface      *iface = NULL;
+       Uint32  netmask;
+       
+       for( iface = gIP_Interfaces; iface; iface = iface->Next)
+       {
+               tIPv6   *thisAddr;
+               
+               // Check for this adapter
+               if( iface->Adapter != Adapter ) continue;
+               
+               // Skip non-IPv6 Interfaces
+               if( iface->Type != 6 )  continue;
+               
+               thisAddr = (tIPv6*)iface->Address;
+               // If the address is a perfect match, return this interface
+               if( IP6_EQU(Address, *thisAddr) )       return iface;
+               
+               // Check if we want to match broadcast addresses
+               if( !Broadcast )        continue;
+               
+               // Check for broadcast
+               // - Check first DWORDs
+               if( iface->SubnetBits > 32 && Address.L[0] != thisAddr->L[0] )
+                       continue;
+               if( iface->SubnetBits > 64 && Address.L[1] != thisAddr->L[1] )
+                       continue;
+               if( iface->SubnetBits > 96 && Address.L[2] != thisAddr->L[2] )
+                       continue;
+               
+               // Check final DWORD
+               j = iface->SubnetBits / 32;
+               i = iface->SubnetBits % 32;
+               netmask = IPv4_Netmask( iface->SubnetBits % 32 );
+               
+               // Check the last bit of the netmask
+               if( (Address.L[j] >> i) != (thisAddr->L[j] >> i) )      continue;
+               
+               // Check that the host portion is one
+               if( (Address.L[j] & ~netmask) != (0xFFFFFFFF & ~netmask) )      continue;
+               if( j >= 2 && Address.L[3] != 0xFFFFFFFF)       continue;
+               if( j >= 1 && Address.L[2] != 0xFFFFFFFF)       continue;
+               if( j >= 0 && Address.L[1] != 0xFFFFFFFF)       continue;
+               
+               return iface;
+       }
+       return NULL;
+}
diff --git a/KernelLand/Modules/IPStack/ipv6.h b/KernelLand/Modules/IPStack/ipv6.h
new file mode 100644 (file)
index 0000000..d2e4f28
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Acess2 IP Stack
+ * - IPv6 Definitions
+ */
+#ifndef _IPV6_H_
+#define _IPV6_H_
+
+#include "ipstack.h"
+
+typedef struct sIPv6Header     tIPv6Header;
+
+struct sIPv6Header
+{
+       #if 0
+       // High 4: Version
+       // Next 8: Traffic Class
+       // Low 20: Flow Label
+       Uint32  Head;
+       #else
+       union {
+               Uint32  Head;   // Allow a ntohl to happen
+               struct {
+                       unsigned Version:       4;
+                       unsigned TrafficClass:  8;
+                       unsigned FlowLabel:     20;
+               } PACKED;
+       } PACKED;
+       #endif
+       Uint16  PayloadLength;
+       Uint8   NextHeader;     // Type of payload data
+       Uint8   HopLimit;
+       tIPv6   Source;
+       tIPv6   Destination;
+       char    Data[];
+};
+
+#define IPV6_ETHERNET_ID       0x86DD
+
+extern int     IPv6_RegisterCallback(int ID, tIPCallback Callback);
+extern int     IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data);
+
+#endif
diff --git a/KernelLand/Modules/IPStack/link.c b/KernelLand/Modules/IPStack/link.c
new file mode 100644 (file)
index 0000000..8bca51f
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Acess2 IP Stack
+ * - Link/Media Layer Interface
+ */
+#include "ipstack.h"
+#include "link.h"
+
+// === CONSTANTS ===
+#define        MAX_PACKET_SIZE 2048
+
+// === PROTOTYPES ===
+void   Link_RegisterType(Uint16 Type, tPacketCallback Callback);
+void   Link_InitCRC();
+Uint32 Link_CalculateCRC(void *Data, int Length);
+void   Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer);
+void   Link_WatchDevice(tAdapter *Adapter);
+
+// === GLOBALS ===
+ int   giRegisteredTypes = 0;
+ int   giRegisteredTypeSpace = 0;
+struct {
+       Uint16  Type;
+       tPacketCallback Callback;
+}      *gaRegisteredTypes;
+ int   gbLink_CRCTableGenerated = 0;
+Uint32 gaiLink_CRCTable[256];
+
+// === CODE ===
+/**
+ * \fn void Link_RegisterType(Uint16 Type, tPacketCallback Callback)
+ * \brief Registers a callback for a specific packet type
+ * 
+ * \todo Make thread safe (place a mutex on the list)
+ */
+void Link_RegisterType(Uint16 Type, tPacketCallback Callback)
+{
+        int    i;
+       void    *tmp;
+       
+       for( i = giRegisteredTypes; i -- ; )
+       {
+               if(gaRegisteredTypes[i].Type == Type) {
+                       Log_Warning("Net Link", "Attempt to register 0x%x twice", Type);
+                       return ;
+               }
+               // Ooh! Free slot!
+               if(gaRegisteredTypes[i].Callback == NULL)       break;
+       }
+       
+       if(i == -1)
+       {
+               giRegisteredTypeSpace += 5;
+               tmp = realloc(gaRegisteredTypes, giRegisteredTypeSpace*sizeof(*gaRegisteredTypes));
+               if(!tmp) {
+                       Log_Warning("Net Link",
+                               "Out of heap space! (Attempted to allocate %i)",
+                               giRegisteredTypeSpace*sizeof(*gaRegisteredTypes)
+                               );
+                       return ;
+               }
+               gaRegisteredTypes = tmp;
+               i = giRegisteredTypes;
+               giRegisteredTypes ++;
+       }
+       
+       gaRegisteredTypes[i].Callback = Callback;
+       gaRegisteredTypes[i].Type = Type;
+}
+
+/**
+ * \fn void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer)
+ * \brief Formats and sends a packet on the specified interface
+ */
+void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer)
+{
+        int    bufSize = sizeof(tEthernetHeader) + ((Length+3)&~3) + 4;
+       Uint8   buf[bufSize];   // dynamic stack arrays ftw!
+       tEthernetHeader *hdr = (void*)buf;
+       
+       Log_Log("Net Link", "Sending %i bytes to %02x:%02x:%02x:%02x:%02x:%02x (Type 0x%x)",
+               Length, To.B[0], To.B[1], To.B[2], To.B[3], To.B[4], To.B[5], Type);
+       
+       hdr->Dest = To;
+       hdr->Src = Adapter->MacAddr;
+       hdr->Type = htons(Type);
+       
+       memcpy(hdr->Data, Buffer, Length);
+       
+       *(Uint32*) &hdr->Data[bufSize-4] = 0;
+       *(Uint32*) &hdr->Data[bufSize-4] = htonl( Link_CalculateCRC(buf, bufSize) );
+       
+       VFS_Write(Adapter->DeviceFD, bufSize, buf);
+}
+
+void Link_WorkerThread(void *Ptr)
+{
+       tAdapter        *Adapter = Ptr;
+       
+       Threads_SetName(Adapter->Device);
+       Log_Log("Net Link", "Thread %i watching '%s'", Threads_GetTID(), Adapter->Device);
+
+       // Child Thread
+       while(Adapter->DeviceFD != -1)
+       {
+               Uint8   buf[MAX_PACKET_SIZE];
+               tEthernetHeader *hdr = (void*)buf;
+                int    ret, i;
+               Uint32  checksum;
+               
+               // Wait for a packet (Read on a network device is blocking)
+               //Log_Debug("NET", "Waiting on adapter FD#0x%x", Adapter->DeviceFD);
+               ret = VFS_Read(Adapter->DeviceFD, MAX_PACKET_SIZE, buf);
+               if(ret == -1)   break;
+               
+               if(ret < sizeof(tEthernetHeader)) {
+                       Log_Log("Net Link", "Recieved an undersized packet (%i < %i)",
+                               ret, sizeof(tEthernetHeader));
+                       continue;
+               }
+               
+               Log_Log("Net Link",
+                       "Packet from %02x:%02x:%02x:%02x:%02x:%02x"
+                       " to %02x:%02x:%02x:%02x:%02x:%02x (Type=%04x)",
+                       hdr->Src.B[0], hdr->Src.B[1], hdr->Src.B[2],
+                       hdr->Src.B[3], hdr->Src.B[4], hdr->Src.B[5],
+                       hdr->Dest.B[0], hdr->Dest.B[1], hdr->Dest.B[2],
+                       hdr->Dest.B[3], hdr->Dest.B[4], hdr->Dest.B[5],
+                       ntohs(hdr->Type)
+                       );
+               checksum = *(Uint32*)&hdr->Data[ret-sizeof(tEthernetHeader)-4];
+               //Log_Log("NET", "Checksum 0x%08x", checksum);
+               // TODO: Check checksum
+               
+               // Check if there is a registered callback for this packet type
+               for( i = giRegisteredTypes; i--; )
+               {
+                       if(gaRegisteredTypes[i].Type == ntohs(hdr->Type))       break;
+               }
+               // No? Ignore it
+               if( i == -1 ) {
+                       Log_Log("Net Link", "Unregistered type 0x%x", ntohs(hdr->Type));
+                       continue;
+               }
+               
+               // Call the callback
+               gaRegisteredTypes[i].Callback(
+                       Adapter,
+                       hdr->Src,
+                       ret - sizeof(tEthernetHeader),
+                       hdr->Data
+                       );
+       }
+       
+       Log_Log("Net Link", "Watcher terminated (file closed)");
+       
+       Threads_Exit(0, 0);
+}
+
+/**
+ * \fn void Link_WatchDevice(tAdapter *Adapter)
+ * \brief Spawns a worker thread to watch the specified adapter
+ */
+void Link_WatchDevice(tAdapter *Adapter)
+{
+        int    tid;
+
+       if( !gbLink_CRCTableGenerated )
+               Link_InitCRC();
+       
+       tid = Proc_SpawnWorker(Link_WorkerThread, Adapter);     // Create a new worker thread
+       
+       if(tid < 0) {
+               Log_Warning("Net Link", "Unable to create watcher thread for '%s'", Adapter->Device);
+               return ;
+       }
+       
+       Log_Log("Net Link", "Watching '%s' using tid %i", Adapter->Device, tid);
+}
+
+// From http://www.cl.cam.ac.uk/research/srg/bluebook/21/crc/node6.html
+#define        QUOTIENT        0x04c11db7
+void Link_InitCRC(void)
+{
+     int       i, j;
+    Uint32     crc;
+
+    for (i = 0; i < 256; i++)
+    {
+        crc = i << 24;
+        for (j = 0; j < 8; j++)
+        {
+            if (crc & 0x80000000)
+                crc = (crc << 1) ^ QUOTIENT;
+            else
+                crc = crc << 1;
+        }
+        gaiLink_CRCTable[i] = crc;
+    }
+       
+       gbLink_CRCTableGenerated = 1;
+}
+
+Uint32 Link_CalculateCRC(void *Data, int Length)
+{
+       // x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
+       Uint32  result;
+     int       i;
+       Uint32  *data = Data;
+    
+    if(Length < 4)     return 0;
+
+    result = *data++ << 24;
+    result |= *data++ << 16;
+    result |= *data++ << 8;
+    result |= *data++;
+    result = ~ result;
+    Length -= 4;
+    
+    for( i = 0; i < Length; i++ )
+    {
+        result = (result << 8 | *data++) ^ gaiLink_CRCTable[result >> 24];
+    }
+    
+    return ~result;
+}
diff --git a/KernelLand/Modules/IPStack/link.h b/KernelLand/Modules/IPStack/link.h
new file mode 100644 (file)
index 0000000..d96008d
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Acess2 IP Stack
+ * - Link/Media Layer Header
+ */
+#ifndef _LINK_H_
+#define _LINK_H_
+
+// === EXTERNAL ===
+typedef void (*tPacketCallback)(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
+
+extern void    Link_RegisterType(Uint16 Type, tPacketCallback Callback);
+extern void    Link_SendPacket(tAdapter *Interface, Uint16 Type, tMacAddr To, int Length, void *Buffer);
+extern void    Link_WatchDevice(tAdapter *Adapter);
+
+// === INTERNAL ===
+typedef struct sEthernetHeader tEthernetHeader;
+typedef struct sEthernetFooter tEthernetFooter;
+struct sEthernetHeader {
+       tMacAddr        Dest;
+       tMacAddr        Src;
+       Uint16  Type;
+       Uint8   Data[];
+};
+
+struct sEthernetFooter {
+       //Uint32        CRC;
+};
+
+#endif
diff --git a/KernelLand/Modules/IPStack/main.c b/KernelLand/Modules/IPStack/main.c
new file mode 100644 (file)
index 0000000..d5d1ebc
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Acess2 IP Stack
+ * - Stack Initialisation
+ */
+#define DEBUG  0
+#define VERSION        VER2(0,10)
+#include "ipstack.h"
+#include "link.h"
+#include <modules.h>
+#include <fs_devfs.h>
+
+// === IMPORTS ===
+extern int     ARP_Initialise();
+extern void    UDP_Initialise();
+extern void    TCP_Initialise();
+extern int     IPv4_Initialise();
+extern int     IPv6_Initialise();
+
+extern tAdapter        *IPStack_GetAdapter(const char *Path);
+extern char    *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
+extern tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
+extern int     IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
+extern tInterface      gIP_LoopInterface;
+extern tInterface      *IPStack_AddInterface(const char *Device, const char *Name);
+extern tRoute  *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
+
+// === PROTOTYPES ===
+ int   IPStack_Install(char **Arguments);
+ int   IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
+tVFS_NodeType  gIP_RootNodeType = {
+       .ReadDir = IPStack_Root_ReadDir,
+       .FindDir = IPStack_Root_FindDir,
+       .IOCtl = IPStack_Root_IOCtl
+};
+tDevFS_Driver  gIP_DriverInfo = {
+       NULL, "ip",
+       {
+       .Size = -1,     // Number of interfaces
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Type = &gIP_RootNodeType
+       }
+};
+
+// === CODE ===
+/**
+ * \fn int IPStack_Install(char **Arguments)
+ * \brief Intialise the relevant parts of the stack and register with DevFS
+ */
+int IPStack_Install(char **Arguments)
+{
+        int    i = 0;
+       
+       // Layer 3 - Network Layer Protocols
+       ARP_Initialise();
+       IPv4_Initialise();
+       IPv6_Initialise();
+       // Layer 4 - Transport Layer Protocols
+       TCP_Initialise();
+       UDP_Initialise();
+       
+       if(Arguments)
+       {
+               // Parse module arguments
+               for( i = 0; Arguments[i]; i++ )
+               {
+                       // TODO:
+                       // Define interfaces by <Device>:<Type>:<HexStreamAddress>:<Bits>
+                       // Where:
+                       // - <Device> is the device path (E.g. /Devices/ne2k/0)
+                       // - <Type> is a number (e.g. 4) or symbol (e.g. AF_INET4)
+                       // - <HexStreamAddress> is a condensed hexadecimal stream (in big endian)
+                       //      (E.g. 0A000201 for 10.0.2.1 IPv4)
+                       // - <Bits> is the number of subnet bits (E.g. 24 for an IPv4 Class C)
+                       // Example: /Devices/ne2k/0:4:0A00020A:24
+                       //  would define an interface with the address 10.0.2.10/24
+                       if( Arguments[i][0] == '/' ) {
+                               // Define Interface
+                               char    *dev, *type, *addr, *bits;
+                               
+                               // Read definition
+                               dev = Arguments[i];
+                               type = strchr(dev, ':');
+                               if( !type ) {
+                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
+                                       continue;
+                               }
+                               *type = '\0';   type ++;
+                               
+                               addr = strchr(type, ':');
+                               if( !addr ) {
+                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
+                                       continue;
+                               }
+                               *addr = '\0';   addr ++;
+                               
+                               bits = strchr(addr, ':');
+                               if( !bits ) {
+                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
+                                       continue;
+                               }
+                               *bits = '\0';   bits ++;
+                               
+                               // Define interface
+                               {
+                                        int    iType = atoi(type);
+                                        int    size = IPStack_GetAddressSize(iType);
+                                       Uint8   addrData[size];
+                                        int    iBits = atoi(bits);
+                                       
+                                       UnHex(addrData, size, addr);
+                                       
+                                       tInterface      *iface = IPStack_AddInterface(dev, "");
+                                       if( !iface ) {
+                                               Log_Warning("IPStack", "Unable to add interface on '%s'", dev);
+                                               continue ;
+                                       }
+                                       iface->Type = iType;
+                                       memcpy(iface->Address, addrData, size);
+                                       iface->SubnetBits = iBits;
+                                       
+                                       // Route for addrData/iBits, no next hop, default metric
+                                       IPStack_AddRoute(iface->Name, iface->Address, iBits, NULL, 0);
+
+                                       Log_Notice("IPStack", "Boot interface %s/%i on %s",
+                                               IPStack_PrintAddress(iType, addrData), iBits,
+                                               dev);
+                               }
+                               
+                               continue;
+                       }
+                       
+                       // I could also define routes using <Interface>:<HexStreamNetwork>:<Bits>[:<HexStreamGateway>]
+                       // Example: 1:00000000:0:0A000201
+                       if( '0' <= Arguments[i][0] && Arguments[i][0] <= '9' )
+                       {
+                               // Define Interface
+                               char    *ifaceName, *network, *bits, *gateway;
+                               
+                               // Read definition
+                               ifaceName = Arguments[i];
+                               
+                               network = strchr(ifaceName, ':');
+                               if( !network ) {
+                                       Log_Warning("IPStack", "<iface>:<HexStreamNetwork>:<Bits>:<HexStreamGateway>");
+                                       continue;
+                               }
+                               *network = '\0';        network ++;
+                               
+                               bits = strchr(network, ':');
+                               if( !bits ) {
+                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
+                                       continue;
+                               }
+                               *bits = '\0';   bits ++;
+                               
+                               gateway = strchr(bits, ':');
+                               if( gateway ) {
+                                       *gateway = '\0';        gateway ++;
+                               }
+                               
+                               // Define route
+                               {
+                                       tVFS_Node       *node = IPStack_Root_FindDir(NULL, ifaceName);
+                                       if( !node ) {
+                                               Log_Warning("IPStack", "Unknown interface '%s' in arg %i", ifaceName, i);
+                                               continue ;
+                                       }
+                                       tInterface      *iface = node->ImplPtr;
+                                       
+                                        int    size = IPStack_GetAddressSize(iface->Type);
+                                       Uint8   netData[size];
+                                       Uint8   gwData[size];
+                                        int    iBits = atoi(bits);
+                                       
+                                       UnHex(netData, size, network);
+                                       if( gateway )
+                                               UnHex(gwData, size, gateway);
+                                       else
+                                               memset(gwData, 0, size);
+                                       
+                                       IPStack_AddRoute(ifaceName, netData, iBits, gwData, 30);
+                               }
+                               
+                               continue;
+                       }
+               }
+       }
+       
+       // Initialise loopback interface
+       gIP_LoopInterface.Adapter = IPStack_GetAdapter("LOOPBACK");
+       
+       DevFS_AddDevice( &gIP_DriverInfo );
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Gets the size (in bytes) of a specified form of address
+ */
+int IPStack_GetAddressSize(int AddressType)
+{
+       switch(AddressType)
+       {
+       case -1:        // -1 = maximum
+               return sizeof(tIPv6);
+       
+       case AF_NULL:
+               return 0;
+       
+       case AF_INET4:
+               return sizeof(tIPv4);
+       case AF_INET6:
+               return sizeof(tIPv6);
+               
+       default:
+               return 0;
+       }
+}
+
+/**
+ * \brief Compare two IP Addresses masked by CheckBits
+ */
+int IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits)
+{
+        int    size = IPStack_GetAddressSize(AddressType);
+       Uint8   mask;
+       const Uint8     *addr1 = Address1, *addr2 = Address2;
+       
+       // Sanity check size
+       if( CheckBits < 0 )     CheckBits = size*8;
+       if( CheckBits > size*8 )        CheckBits = size*8;
+       
+       if( CheckBits == 0 )    return 1;       // /0 matches anything
+       
+       // Check first bits/8 bytes
+       if( memcmp(Address1, Address2, CheckBits/8) != 0 )      return 0;
+       
+       // Check if the mask is a multiple of 8
+       if( CheckBits % 8 == 0 )        return 1;
+       
+       // Check last bits
+       mask = 0xFF << (8 - (CheckBits % 8));
+       if( (addr1[CheckBits/8] & mask) == (addr2[CheckBits/8] & mask) )
+               return 1;
+       
+       return 0;
+}
+
+const char *IPStack_PrintAddress(int AddressType, const void *Address)
+{
+       switch( AddressType )
+       {
+       case 4: {
+               static char     ret[4*3+3+1];
+               const Uint8     *addr = Address;
+               sprintf(ret, "%i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
+               return ret;
+               }
+       
+       case 6: {       // TODO: address compression
+               static char     ret[8*4+7+1];
+               const Uint16    *addr = Address;
+               sprintf(ret, "%x:%x:%x:%x:%x:%x:%x:%x",
+                       ntohs(addr[0]), ntohs(addr[1]), ntohs(addr[2]), ntohs(addr[3]),
+                       ntohs(addr[4]), ntohs(addr[5]), ntohs(addr[6]), ntohs(addr[7])
+                       );
+               return ret;
+               }
+       
+       default:
+               return "";
+       }
+}
diff --git a/KernelLand/Modules/IPStack/routing.c b/KernelLand/Modules/IPStack/routing.c
new file mode 100644 (file)
index 0000000..7173d1f
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ * Acess2 IP Stack
+ * - Routing Tables
+ */
+#define DEBUG  0
+#define VERSION        VER2(0,10)
+#include <acess.h>
+#include <api_drv_common.h>
+#include "ipstack.h"
+#include "link.h"
+
+#define        DEFAUTL_METRIC  30
+
+// === IMPORTS ===
+extern tInterface      *gIP_Interfaces;
+extern tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename);
+
+// === PROTOTYPES ===
+// - Routes directory
+char   *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
+ int   IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
+ int   _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
+ int   IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
+// - Route Management
+tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric);
+tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
+tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
+// - Individual Routes
+ int   IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data);
+
+// === GLOBALS ===
+ int   giIP_NextRouteId = 1;
+tRoute *gIP_Routes;
+tRoute *gIP_RoutesEnd;
+tVFS_NodeType  gIP_RouteNodeType = {
+       .IOCtl = IPStack_Route_IOCtl
+};
+tVFS_NodeType  gIP_RouteDirNodeType = {
+       .ReadDir = IPStack_RouteDir_ReadDir,
+       .FindDir = IPStack_RouteDir_FindDir,
+       .MkNod = IPStack_RouteDir_MkNod,
+       .Relink = IPStack_RouteDir_Relink,
+       .IOCtl = IPStack_RouteDir_IOCtl
+};
+tVFS_Node      gIP_RouteNode = {
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Size = -1,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Type = &gIP_RouteDirNodeType
+};
+
+// === CODE ===
+/**
+ * \brief ReadDir for the /Devices/ip/routes/ directory
+ */
+char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tRoute  *rt;
+       
+       for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
+       if( !rt )       return NULL;
+       
+       {
+                int    addrlen = IPStack_GetAddressSize(rt->AddressType);
+                int    len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
+               char    buf[len+1];
+                int    ofs;
+               ofs = sprintf(buf, "%i:", rt->AddressType);
+               ofs += Hex(buf+ofs, addrlen, rt->Network);
+               sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
+               return strdup(buf);
+       }
+}
+
+/**
+ * \brief FindDir for the /Devices/ip/routes/ directory
+ */
+tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
+{
+       // Interpret the name as <type>:<addr>, returning the interface for
+       // needed to access that address.
+       //   E.g. '@4:0A02000A' - 10.2.0.10
+       // Hm... It could do with a way to have a better address type representation
+       if( Name[0] == '@' )
+       {
+               tRoute  *rt;
+                int    ofs = 1;
+                int    type;
+               
+               ofs += ParseInt(Name+ofs, &type);
+                int    addrSize = IPStack_GetAddressSize(type);
+               Uint8   addrData[addrSize];
+
+               // Separator
+               if( Name[ofs] != ':' )  return NULL;
+               ofs ++;
+
+               // Error if the size is invalid
+               if( strlen(Name+ofs) != addrSize*2 )
+                       return NULL;
+               
+               // Parse the address
+               // - Error if the address data is not fully hex
+               if( UnHex(addrData, addrSize, Name + ofs) != addrSize )
+                       return NULL;
+               
+               // Find the route
+               rt = IPStack_FindRoute(type, NULL, addrData);
+               if(!rt) return NULL;
+       
+               if( rt->Interface )
+               {       
+                       // Return the interface node
+                       // - Sure it's hijacking it from inteface.c's area, but it's
+                       //   simpler this way
+                       return &rt->Interface->Node;
+               }
+               else
+               {
+                       return NULL;
+               }
+       }
+       else if( Name[0] == '#' )
+       {
+               int num, ofs = 1;
+               
+               ofs = ParseInt(Name+ofs, &num);
+               if( ofs == 1 )  return NULL;
+               if( Name[ofs] != '\0' ) return NULL;
+               if( num < 0)    return NULL;            
+
+               for( tRoute *rt = gIP_Routes; rt; rt = rt->Next )
+               {
+                       if( rt->Node.Inode > num )      return NULL;
+                       if( rt->Node.Inode == num )     return &rt->Node;
+               }
+               return NULL;
+       }
+       else
+       {
+                int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
+               if( type <= 0 ) return NULL;
+
+                int    addrSize = IPStack_GetAddressSize(type);
+               Uint8   addrData[addrSize];
+                int    subnet_bits, metric;
+               
+               _Route_ParseRouteName(Name, addrData, &subnet_bits, &metric);
+
+               tRoute *rt = _Route_FindExactRoute(type, addrData, subnet_bits, metric);
+               if(rt)  return &rt->Node;
+               return NULL;
+       }
+}
+
+/**
+ * \brief Create a new route node
+ */
+int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+       if( Flags )     return -EINVAL; 
+       if( Threads_GetUID() != 0 )     return -EACCES;
+
+        int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
+       if( type <= 0 ) return -EINVAL;
+
+        int    size = IPStack_GetAddressSize(type);
+       Uint8   addrdata[size]; 
+        int    subnet, metric;
+
+       _Route_ParseRouteName(Name, addrdata, &subnet, &metric);
+
+       // Check for duplicates
+       if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
+               return -EEXIST;
+
+       IPStack_Route_Create(type, addrdata, subnet, metric);
+
+       return 0;
+}
+
+/**
+ * \brief Rename / Delete a route
+ */
+int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+{
+       tRoute  *rt;
+       
+       if( Threads_GetUID() != 0 )     return -EACCES;
+
+       // Get the original route entry
+       {
+                int    type = _Route_ParseRouteName(OldName, NULL, NULL, NULL);
+               if(type <= 0)   return -EINVAL;
+               Uint8   addr[IPStack_GetAddressSize(type)];
+                int    subnet, metric;
+               _Route_ParseRouteName(OldName, addr, &subnet, &metric);
+               
+               rt = _Route_FindExactRoute(type, addr, subnet, metric);
+       }       
+
+       if( NewName == NULL )
+       {
+               // Delete the route
+               tRoute  *prev = NULL;
+               for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
+               
+               if(prev)
+                       prev->Next = rt->Next;
+               else
+                       gIP_Routes = rt->Next;
+               free(rt);
+       }
+       else
+       {
+               // Change the route
+                int    type = _Route_ParseRouteName(NewName, NULL, NULL, NULL);
+               if(type <= 0)   return -EINVAL;
+               Uint8   addr[IPStack_GetAddressSize(type)];
+                int    subnet, metric;
+               _Route_ParseRouteName(NewName, addr, &subnet, &metric);
+       
+               return -ENOTIMPL;       
+       }
+       return 0;
+}
+
+tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric)
+{
+       for(tRoute *rt = gIP_Routes; rt; rt = rt->Next)
+       {
+               if( rt->AddressType != Type )   continue;
+               if( rt->Metric != Metric )      continue;
+               if( rt->SubnetBits != Subnet )  continue;
+               if( IPStack_CompareAddress(Type, rt->Network, Network, -1) == 0 )
+                       continue ;
+               return rt;
+       }
+       return NULL;
+}
+
+int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric)
+{
+        int    type, addrlen;
+        int    ofs = 0, ilen;
+       
+       ENTER("sName pAddr pSubnetBits pMetric", Name, Addr, SubnetBits, Metric);
+
+       ilen = ParseInt(Name, &type);
+       if(ilen == 0) {
+               LOG("Type failed to parse");
+               LEAVE_RET('i', -1);
+       }
+       ofs += ilen;
+       
+       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
+       ofs ++;
+
+       addrlen = IPStack_GetAddressSize(type);
+       if( Addr )
+       {
+               if( UnHex(Addr, addrlen, Name + ofs) != addrlen )
+                       return -1;
+       }
+       ofs += addrlen*2;
+       
+       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
+       ofs ++;
+
+       ilen = ParseInt(Name+ofs, SubnetBits);
+       if(ilen == 0) {
+               LOG("Subnet failed to parse");
+               LEAVE_RET('i', -1);
+       }
+       ofs += ilen;
+       
+       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
+       ofs ++;
+
+       ilen = ParseInt(Name+ofs, Metric);
+       if(ilen == 0) {
+               LOG("Metric failed to parse");
+               LEAVE_RET('i', -1);
+       }
+       ofs += ilen;
+       
+       if(Name[ofs] != '\0')   LEAVE_RET('i', -1);
+
+       LEAVE('i', type);
+       return type;
+}
+
+/**
+ * \brief Names for the route list IOCtl Calls
+ */
+static const char *casIOCtls_RouteDir[] = {
+       DRV_IOCTLNAMES,
+       "locate_route", // Find the best route for an address - struct {int Type, char Address[]} *
+       NULL
+       };
+
+/**
+ * \brief IOCtl for /Devices/ip/routes/
+ */
+int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tRoute  *rt;
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       // --- Standard IOCtls (0-3) ---
+       BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir)
+       
+       case 4: // Locate Route
+               {
+                       struct {
+                                int    Type;
+                               Uint8   Addr[];
+                       }       *data = Data;
+                       
+                       if( !CheckMem(Data, sizeof(int)) )
+                               LEAVE_RET('i', -1);
+                       if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) )
+                               LEAVE_RET('i', -1);
+                       
+                       Log_Debug("IPStack", "Route_RouteDir_IOCtl - FindRoute %i, %s",
+                               data->Type, IPStack_PrintAddress(data->Type, data->Addr) );
+                       rt = IPStack_FindRoute(data->Type, NULL, data->Addr);
+                       
+                       if( !rt )
+                               LEAVE_RET('i', 0);
+                       
+                       LEAVE('i', rt->Node.Inode);
+                       return rt->Node.Inode;
+               }
+               break;
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \brief Create a new route entry
+ * \param InterfaceName        Name of the interface using this route
+ */
+tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric)
+{
+       tRoute  *rt;
+        int    size;
+       
+       // Get the size of the specified address type
+       size = IPStack_GetAddressSize(AddrType);
+       if( size == 0 ) {
+               return NULL;
+       }
+       
+       // Allocate space
+       rt = calloc(1, sizeof(tRoute) + size*2 );
+       
+       // Set up node
+       rt->Node.ImplPtr = rt;
+       rt->Node.Inode = giIP_NextRouteId ++;
+       rt->Node.Size = 0;
+       rt->Node.NumACLs = 1,
+       rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
+       rt->Node.Type = &gIP_RouteNodeType;
+       
+       // Set up state
+       rt->AddressType = AddrType;
+       rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
+       rt->SubnetBits = SubnetBits;
+       rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
+       rt->Interface = NULL;
+       rt->Metric = Metric;
+       memcpy(rt->Network, Network, size);
+       memset(rt->NextHop, 0, size);
+       
+       // Clear non-fixed bits
+       {
+               Uint8   *data = rt->Network;
+                int    i;
+               i = SubnetBits / 8;
+               if( SubnetBits % 8 ) {
+                       data[i] &= ~((1 << (8 - SubnetBits % 8)) - 1);
+                       i ++;
+               }
+               memset(data + i, 0, size - i);
+       }       
+
+
+       // Add to list
+       if( gIP_RoutesEnd ) {
+               gIP_RoutesEnd->Next = rt;
+               gIP_RoutesEnd = rt;
+       }
+       else {
+               gIP_Routes = gIP_RoutesEnd = rt;
+       }
+       
+//     Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
+       
+       return rt;
+}
+
+/**
+ * \brief Add and fill a route
+ */
+tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
+{
+       tInterface      *iface;
+       tRoute  *rt;
+        int    addrSize;
+       
+       {
+               tVFS_Node       *tmp;
+               tmp = IPStack_Root_FindDir(NULL, Interface);
+               if(!tmp)        return NULL;
+               iface = tmp->ImplPtr;
+               if(tmp->Type->Close)    tmp->Type->Close(tmp);
+       }
+
+       rt = IPStack_Route_Create(iface->Type, Network, SubnetBits, Metric);
+       if( !rt )       return NULL;
+       
+       addrSize = IPStack_GetAddressSize(iface->Type);
+       rt->Interface = iface;
+       
+       if( NextHop )
+               memcpy(rt->NextHop, NextHop, addrSize);
+       
+       return rt;
+}
+
+/**
+ */
+tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
+{
+       tRoute  *rt;
+       tRoute  *best = NULL;
+       tInterface      *iface;
+        int    addrSize;
+       
+       ENTER("iAddressType pInterface sAddress",
+               AddressType, Interface, IPStack_PrintAddress(AddressType, Address));
+       
+       if( Interface && AddressType != Interface->Type ) {
+               LOG("Interface->Type (%i) != AddressType", Interface->Type);
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Get address size
+       addrSize = IPStack_GetAddressSize(AddressType);
+       
+       // Check against explicit routes
+       for( rt = gIP_Routes; rt; rt = rt->Next )
+       {
+               // Check interface
+               if( Interface && rt->Interface != Interface )   continue;
+               // Check address type
+               if( rt->AddressType != AddressType )    continue;
+               
+               LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits);
+               
+               // Check if the address matches
+               if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
+                       continue;
+               
+               if( best ) {
+                       // More direct routes are preferred
+                       if( best->SubnetBits > rt->SubnetBits ) {
+                               LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
+                               continue;
+                       }
+                       // If equally direct, choose the best metric
+                       if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
+                               LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
+                               continue;
+                       }
+               }
+               
+               best = rt;
+       }
+       
+       // Check against implicit routes
+       if( !best && !Interface )
+       {
+               for( iface = gIP_Interfaces; iface; iface = iface->Next )
+               {
+                       if( Interface && iface != Interface )   continue;
+                       if( iface->Type != AddressType )        continue;
+                       
+                       
+                       // Check if the address matches
+                       if( !IPStack_CompareAddress(AddressType, iface->Address, Address, iface->SubnetBits) )
+                               continue;
+                       
+                       if( best ) {
+                               // More direct routes are preferred
+                               if( best->SubnetBits > rt->SubnetBits ) {
+                                       LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
+                                       continue;
+                               }
+                               // If equally direct, choose the best metric
+                               if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
+                                       LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
+                                       continue;
+                               }
+                       }
+                       
+                       rt = &iface->Route;
+                       memcpy(rt->Network, iface->Address, addrSize);
+                       memset(rt->NextHop, 0, addrSize);
+                       rt->Metric = DEFAUTL_METRIC;
+                       rt->SubnetBits = iface->SubnetBits;
+                       
+                       best = rt;
+               }
+       }
+       if( !best && Interface )
+       {
+               rt = &Interface->Route;
+               // Make sure route is up to date
+               memcpy(rt->Network, Interface->Address, addrSize);
+               memset(rt->NextHop, 0, addrSize);
+               rt->Metric = DEFAUTL_METRIC;
+               rt->SubnetBits = Interface->SubnetBits;
+               
+               if( IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
+               {
+                       best = rt;
+               }
+       }
+       
+       LEAVE('p', best);
+       return best;
+}
+
+/**
+ * \brief Names for route IOCtl Calls
+ */
+static const char *casIOCtls_Route[] = {
+       DRV_IOCTLNAMES,
+       "get_nexthop",  // Get next hop - (void *Data), returns boolean success
+       "set_nexthop",  // Set next hop - (void *Data), returns boolean success
+       "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
+       "set_interface",        // Set interface - (const char *Name)
+       NULL
+       };
+
+/**
+ * \brief IOCtl for /Devices/ip/routes/#
+ */
+int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tRoute  *rt = Node->ImplPtr;
+        int    addrSize = IPStack_GetAddressSize(rt->AddressType);
+       
+       switch(ID)
+       {
+       // --- Standard IOCtls (0-3) ---
+       BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route)
+       
+       // Get Next Hop
+       case 4:
+               if( !CheckMem(Data, addrSize) ) return -1;
+               memcpy(Data, rt->NextHop, addrSize);
+               return 1;
+       // Set Next Hop
+       case 5:
+               if( Threads_GetUID() != 0 )     return -1;
+               if( !CheckMem(Data, addrSize) ) return -1;
+               memcpy(rt->NextHop, Data, addrSize);
+               return 1;
+
+       // Get interface name
+       case 6:
+               if( !rt->Interface ) {
+                       if(Data && !CheckMem(Data, 1) )
+                               return -1;
+                       if(Data)
+                               *(char*)Data = 0;
+                       return 0;
+               }
+               if( Data ) {
+                       if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
+                               return -1;
+                       strcpy(Data, rt->Interface->Name);
+               }
+               return strlen(rt->Interface->Name);
+       // Set interface name
+       case 7:
+               if( Threads_GetUID() != 0 )
+                       return -1;
+               if( !CheckString(Data) )
+                       return -1;
+               else
+               {
+                       tInterface      *iface;
+                       tVFS_Node       *tmp;
+                       tmp = IPStack_Root_FindDir(NULL, Data);
+                       if(!tmp)
+                               return -1;
+                       iface = tmp->ImplPtr;
+                       if(tmp->Type->Close)    tmp->Type->Close(tmp);
+                       
+                       if( iface->Type != rt->AddressType )
+                               return -1;
+
+                       // TODO: Other checks?          
+       
+                       rt->Interface = iface;
+               }
+               return 0;
+
+       default:
+               return -1;
+       }
+}
diff --git a/KernelLand/Modules/IPStack/sctp.c b/KernelLand/Modules/IPStack/sctp.c
new file mode 100644 (file)
index 0000000..d130933
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * Acess2 IP Stack
+ * - SCTP (Stream Control Transmission Protocol) Handling
+ */
+#include "ipstack.h"
+#include <api_drv_common.h>
+#include "sctp.h"
+
+#define SCTP_ALLOC_BASE        0xC000
+
+// === PROTOTYPES ===
+void   SCTP_Initialise();
+void   SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
+void   SCTP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
+void   SCTP_SendPacket(tSCTPChannel *Channel, void *Data, size_t Length);
+// --- Listening Server
+tVFS_Node      *SCTP_Server_Init(tInterface *Interface);
+char   *SCTP_Server_ReadDir(tVFS_Node *Node, int ID);
+tVFS_Node      *SCTP_Server_FindDir(tVFS_Node *Node, const char *Name);
+ int   SCTP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
+void   SCTP_Server_Close(tVFS_Node *Node);
+// --- Client Channels
+tVFS_Node      *SCTP_Channel_Init(tInterface *Interface);
+Uint64 SCTP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 SCTP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   SCTP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
+void   SCTP_Channel_Close(tVFS_Node *Node);
+// --- Helpers
+Uint16 SCTP_int_AllocatePort();
+ int   SCTP_int_MarkPortAsUsed(Uint16 Port);
+void   SCTP_int_FreePort(Uint16 Port);
+
+// === GLOBALS ===
+tMutex glSCTP_Servers;
+tSCTPServer    *gpSCTP_Servers;
+
+tMutex glSCTP_Channels;
+tSCTPChannel   *gpSCTP_Channels;
+
+tMutex glSCTP_Ports;
+Uint32 gSCTP_Ports[0x10000/32];
+
+tSocketFile    gSCTP_ServerFile = {NULL, "sctps", SCTP_Server_Init};
+tSocketFile    gSCTP_ClientFile = {NULL, "sctpc", SCTP_Channel_Init};
+
+// === CODE ===
+/**
+ * \fn void TCP_Initialise()
+ * \brief Initialise the TCP Layer
+ */
+void SCTP_Initialise()
+{
+       IPStack_AddFile(&gSCTP_ServerFile);
+       IPStack_AddFile(&gSCTP_ClientFile);
+       //IPv4_RegisterCallback(IP4PROT_SCTP, SCTP_GetPacket, SCTP_Unreachable);
+       IPv4_RegisterCallback(IP4PROT_SCTP, SCTP_GetPacket);
+}
+
+/**
+ * \brief Scan a list of tSCTPChannels and find process the first match
+ * \return 0 if no match was found, -1 on error and 1 if a match was found
+ */
+int SCTP_int_ScanList(tSCTPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
+{
+       tSCTPHeader     *hdr = Buffer;
+       tSCTPChannel    *chan;
+       tSCTPPacket     *pack;
+        int    len;
+       
+       for(chan = List;
+               chan;
+               chan = chan->Next)
+       {
+               if(chan->Interface != Interface)        continue;
+               if(chan->LocalPort != ntohs(hdr->DestPort))     continue;
+               if(chan->RemotePort != ntohs(hdr->SourcePort))  continue;
+               
+               if(Interface->Type == 4) {
+                       if(!IP4_EQU(chan->RemoteAddr.v4, *(tIPv4*)Address))     continue;
+               }
+               else if(Interface->Type == 6) {
+                       if(!IP6_EQU(chan->RemoteAddr.v6, *(tIPv6*)Address))     continue;
+               }
+               else {
+                       Log_Warning("SCTP", "Address type %i unknown", Interface->Type);
+                       Mutex_Release(&glSCTP_Channels);
+                       return -1;
+               }
+               
+               Log_Log("SCTP", "Recieved packet for %p", chan);
+               // Create the cached packet
+               len = ntohs(hdr->Length);
+               pack = malloc(sizeof(tSCTPPacket) + len);
+               pack->Next = NULL;
+               pack->Length = len;
+               memcpy(pack->Data, hdr->Data, len);
+               
+               // Add the packet to the channel's queue
+               SHORTLOCK(&chan->lQueue);
+               if(chan->Queue)
+                       chan->QueueEnd->Next = pack;
+               else
+                       chan->QueueEnd = chan->Queue = pack;
+               SHORTREL(&chan->lQueue);
+               Mutex_Release(&glSCTP_Channels);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * \fn void SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+ * \brief Handles a packet from the IP Layer
+ */
+void SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+{
+       tSCTPHeader     *hdr = Buffer;
+       tSCTPServer     *srv;
+        int    ret;
+       
+       Log_Log("SCTP", "hdr->SourcePort = %i", ntohs(hdr->SourcePort));
+       Log_Log("SCTP", "hdr->DestPort = %i", ntohs(hdr->DestPort));
+       Log_Log("SCTP", "hdr->VerifcationTag = %i", ntohs(hdr->VerifcationTag));
+       Log_Log("SCTP", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
+       
+       // Check registered connections
+       Mutex_Acquire(&glSCTP_Channels);
+       ret = SCTP_int_ScanList(gpSCTP_Channels, Interface, Address, Length, Buffer);
+       Mutex_Release(&glSCTP_Channels);
+       if(ret != 0)    return ;
+       
+       
+       // TODO: Server/Listener
+       Mutex_Acquire(&glSCTP_Servers);
+       for(srv = gpSCTP_Servers;
+               srv;
+               srv = srv->Next)
+       {
+               if(srv->Interface != Interface) continue;
+               if(srv->ListenPort != ntohs(hdr->DestPort))     continue;
+               ret = SCTP_int_ScanList(srv->Channels, Interface, Address, Length, Buffer);
+               if(ret != 0)    break;
+               
+               // Add connection
+               Log_Warning("SCTP", "TODO - Add channel on connection");
+               //TODO
+       }
+       Mutex_Release(&glSCTP_Servers);
+       
+}
+
+/**
+ * \brief Handle an ICMP Unrechable Error
+ */
+void SCTP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
+{
+       
+}
+
+/**
+ * \brief Send a packet
+ * \param Channel      Channel to send the packet from
+ * \param Data Packet data
+ * \param Length       Length in bytes of packet data
+ */
+void SCTP_SendPacket(tSCTPChannel *Channel, void *Data, size_t Length)
+{
+       tSCTPHeader     *hdr;
+       
+       switch(Channel->Interface->Type)
+       {
+       case 4:
+               // Create the packet
+               hdr = malloc(sizeof(tSCTPHeader)+Length);
+               hdr->SourcePort = htons( Channel->LocalPort );
+               hdr->DestPort = htons( Channel->RemotePort );
+               hdr->Length = htons( sizeof(tSCTPHeader) + Length );
+               hdr->Checksum = 0;      // Checksum can be zero on IPv4
+               memcpy(hdr->Data, Data, Length);
+               // Pass on the the IPv4 Layer
+               IPv4_SendPacket(Channel->Interface, Channel->RemoteAddr.v4, IP4PROT_SCTP, 0, sizeof(tSCTPHeader)+Length, hdr);
+               // Free allocated packet
+               free(hdr);
+               break;
+       }
+}
+
+// --- Listening Server
+tVFS_Node *SCTP_Server_Init(tInterface *Interface)
+{
+       tSCTPServer     *new;
+       new = calloc( sizeof(tSCTPServer), 1 );
+       if(!new)        return NULL;
+       
+       new->Node.ImplPtr = new;
+       new->Node.Flags = VFS_FFLAG_DIRECTORY;
+       new->Node.NumACLs = 1;
+       new->Node.ACLs = &gVFS_ACL_EveryoneRX;
+       new->Node.ReadDir = SCTP_Server_ReadDir;
+       new->Node.FindDir = SCTP_Server_FindDir;
+       new->Node.IOCtl = SCTP_Server_IOCtl;
+       new->Node.Close = SCTP_Server_Close;
+       
+       Mutex_Acquire(&glSCTP_Servers);
+       new->Next = gpSCTP_Servers;
+       gpSCTP_Servers = new;
+       Mutex_Release(&glSCTP_Servers);
+       
+       return &new->Node;
+}
+
+/**
+ * \brief Wait for a connection and return its ID in a string
+ */
+char *SCTP_Server_ReadDir(tVFS_Node *Node, int ID)
+{
+       tSCTPServer     *srv = Node->ImplPtr;
+       tSCTPChannel    *chan;
+       char    *ret;
+       
+       if( srv->ListenPort == 0 )      return NULL;
+       
+       // Lock (so another thread can't collide with us here) and wait for a connection
+       Mutex_Acquire( &srv->Lock );
+       while( srv->NewChannels == NULL )       Threads_Yield();
+       // Pop the connection off the new list
+       chan = srv->NewChannels;
+       srv->NewChannels = chan->Next;
+       // Release the lock
+       Mutex_Release( &srv->Lock );
+       
+       // Create the ID string and return it
+       ret = malloc(11+1);
+       sprintf(ret, "%i", chan->Node.ImplInt);
+       
+       return ret;
+}
+
+/**
+ * \brief Take a string and find the channel
+ */
+tVFS_Node *SCTP_Server_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tSCTPServer     *srv = Node->ImplPtr;
+       tSCTPChannel    *chan;
+        int    id = atoi(Name);
+       
+       for(chan = srv->Channels;
+               chan;
+               chan = chan->Next)
+       {
+               if( chan->Node.ImplInt < id )   continue;
+               if( chan->Node.ImplInt > id )   break;  // Go sorted lists!
+               
+               return &chan->Node;
+       }
+       
+       return NULL;
+}
+
+/**
+ * \brief Names for server IOCtl Calls
+ */
+static const char *casIOCtls_Server[] = {
+       DRV_IOCTLNAMES,
+       "getset_listenport",
+       NULL
+       };
+/**
+ * \brief Channel IOCtls
+ */
+int SCTP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tSCTPServer     *srv = Node->ImplPtr;
+       
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_MISC, "SCTP Server", 0x100, casIOCtls_Server);
+       
+       case 4: // getset_localport (returns bool success)
+               if(!Data)       LEAVE_RET('i', srv->ListenPort);
+               if(!CheckMem( Data, sizeof(Uint16) ) ) {
+                       LOG("Invalid pointer %p", Data);
+                       LEAVE_RET('i', -1);
+               }
+               // Set port
+               srv->ListenPort = *(Uint16*)Data;
+               // Permissions check (Ports lower than 1024 are root-only)
+               if(srv->ListenPort != 0 && srv->ListenPort < 1024) {
+                       if( Threads_GetUID() != 0 ) {
+                               LOG("Attempt by non-superuser to listen on port %i", srv->ListenPort);
+                               srv->ListenPort = 0;
+                               LEAVE_RET('i', -1);
+                       }
+               }
+               // Allocate a random port if requested
+               if( srv->ListenPort == 0 )
+                       srv->ListenPort = SCTP_int_AllocatePort();
+               else
+               {
+                       // Else, mark the requested port as used
+                       if( SCTP_int_MarkPortAsUsed(srv->ListenPort) == 0 ) {
+                               LOG("Port %i us currently in use", srv->ListenPort);
+                               srv->ListenPort = 0;
+                               LEAVE_RET('i', -1);
+                       }
+                       LEAVE_RET('i', 1);
+               }
+               LEAVE_RET('i', 1);
+       
+       default:
+               LEAVE_RET('i', -1);
+       }
+       LEAVE_RET('i', 0);
+}
+
+void SCTP_Server_Close(tVFS_Node *Node)
+{
+       tSCTPServer     *srv = Node->ImplPtr;
+       tSCTPServer     *prev;
+       tSCTPChannel    *chan;
+       tSCTPPacket     *tmp;
+       
+       
+       // Remove from the main list first
+       Mutex_Acquire(&glSCTP_Servers);
+       if(gpSCTP_Servers == srv)
+               gpSCTP_Servers = gpSCTP_Servers->Next;
+       else
+       {
+               for(prev = gpSCTP_Servers;
+                       prev->Next && prev->Next != srv;
+                       prev = prev->Next);
+               if(!prev->Next)
+                       Log_Warning("SCTP", "Bookeeping Fail, server %p is not in main list", srv);
+               else
+                       prev->Next = prev->Next->Next;
+       }
+       Mutex_Release(&glSCTP_Servers);
+       
+       
+       Mutex_Acquire(&srv->Lock);
+       for(chan = srv->Channels;
+               chan;
+               chan = chan->Next)
+       {
+               // Clear Queue
+               SHORTLOCK(&chan->lQueue);
+               while(chan->Queue)
+               {
+                       tmp = chan->Queue;
+                       chan->Queue = tmp->Next;
+                       free(tmp);
+               }
+               SHORTREL(&chan->lQueue);
+               
+               // Free channel structure
+               free(chan);
+       }
+       Mutex_Release(&srv->Lock);
+       
+       free(srv);
+}
+
+// --- Client Channels
+tVFS_Node *SCTP_Channel_Init(tInterface *Interface)
+{
+       tSCTPChannel    *new;
+       new = calloc( sizeof(tSCTPChannel), 1 );
+       new->Interface = Interface;
+       new->Node.ImplPtr = new;
+       new->Node.NumACLs = 1;
+       new->Node.ACLs = &gVFS_ACL_EveryoneRW;
+       new->Node.Read = SCTP_Channel_Read;
+       new->Node.Write = SCTP_Channel_Write;
+       new->Node.IOCtl = SCTP_Channel_IOCtl;
+       new->Node.Close = SCTP_Channel_Close;
+       
+       Mutex_Acquire(&glSCTP_Channels);
+       new->Next = gpSCTP_Channels;
+       gpSCTP_Channels = new;
+       Mutex_Release(&glSCTP_Channels);
+       
+       return &new->Node;
+}
+
+/**
+ * \brief Read from the channel file (wait for a packet)
+ */
+Uint64 SCTP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tSCTPChannel    *chan = Node->ImplPtr;
+       tSCTPPacket     *pack;
+       
+       if(chan->LocalPort == 0)        return 0;
+       if(chan->RemotePort == 0)       return 0;
+       
+       while(chan->Queue == NULL)      Threads_Yield();
+       
+       for(;;)
+       {
+               SHORTLOCK(&chan->lQueue);
+               if(chan->Queue == NULL) {
+                       SHORTREL(&chan->lQueue);
+                       continue;
+               }
+               pack = chan->Queue;
+               chan->Queue = pack->Next;
+               if(!chan->Queue)        chan->QueueEnd = NULL;
+               SHORTREL(&chan->lQueue);
+               break;
+       }
+       
+       // Clip length to packet length
+       if(Length > pack->Length)       Length = pack->Length;
+       // Copy packet data from cache
+       memcpy(Buffer, pack->Data, Length);
+       // Free cached packet
+       free(pack);     
+       
+       return Length;
+}
+
+/**
+ * \brief Write to the channel file (send a packet)
+ */
+Uint64 SCTP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tSCTPChannel    *chan = Node->ImplPtr;
+       if(chan->RemotePort == 0)       return 0;
+       
+       SCTP_SendPacket(chan, Buffer, (size_t)Length);
+       
+       return 0;
+}
+
+/**
+ * \brief Names for channel IOCtl Calls
+ */
+static const char *casIOCtls_Channel[] = {
+       DRV_IOCTLNAMES,
+       "getset_localport",
+       "getset_remoteport",
+       "set_remoteaddr",
+       NULL
+       };
+/**
+ * \brief Channel IOCtls
+ */
+int SCTP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tSCTPChannel    *chan = Node->ImplPtr;
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_MISC, "SCTP Channel", 0x100, casIOCtls_Channel);
+       
+       case 4: // getset_localport (returns bool success)
+               if(!Data)       LEAVE_RET('i', chan->LocalPort);
+               if(!CheckMem( Data, sizeof(Uint16) ) ) {
+                       LOG("Invalid pointer %p", Data);
+                       LEAVE_RET('i', -1);
+               }
+               // Set port
+               chan->LocalPort = *(Uint16*)Data;
+               // Permissions check (Ports lower than 1024 are root-only)
+               if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
+                       if( Threads_GetUID() != 0 ) {
+                               LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
+                               chan->LocalPort = 0;
+                               LEAVE_RET('i', -1);
+                       }
+               }
+               // Allocate a random port if requested
+               if( chan->LocalPort == 0 )
+                       chan->LocalPort = SCTP_int_AllocatePort();
+               else
+               {
+                       // Else, mark the requested port as used
+                       if( SCTP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
+                               LOG("Port %i us currently in use", chan->LocalPort);
+                               chan->LocalPort = 0;
+                               LEAVE_RET('i', 0);
+                       }
+                       LEAVE_RET('i', 1);
+               }
+               LEAVE_RET('i', 1);
+       
+       case 5: // getset_remoteport (returns bool success)
+               if(!Data)       LEAVE_RET('i', chan->RemotePort);
+               if(!CheckMem( Data, sizeof(Uint16) ) ) {
+                       LOG("Invalid pointer %p", Data);
+                       LEAVE_RET('i', -1);
+               }
+               chan->RemotePort = *(Uint16*)Data;
+               return 1;
+       
+       case 6: // set_remoteaddr (returns bool success)
+               switch(chan->Interface->Type)
+               {
+               case 4:
+                       if(!CheckMem(Data, sizeof(tIPv4))) {
+                               LOG("Invalid pointer %p", Data);
+                               LEAVE_RET('i', -1);
+                       }
+                       chan->RemoteAddr.v4 = *(tIPv4*)Data;
+                       break;
+               }
+               break;
+       }
+       LEAVE_RET('i', 0);
+}
+
+/**
+ * \brief Close and destroy an open channel
+ */
+void SCTP_Channel_Close(tVFS_Node *Node)
+{
+       tSCTPChannel    *chan = Node->ImplPtr;
+       tSCTPChannel    *prev;
+       
+       // Remove from the main list first
+       Mutex_Acquire(&glSCTP_Channels);
+       if(gpSCTP_Channels == chan)
+               gpSCTP_Channels = gpSCTP_Channels->Next;
+       else
+       {
+               for(prev = gpSCTP_Channels;
+                       prev->Next && prev->Next != chan;
+                       prev = prev->Next);
+               if(!prev->Next)
+                       Log_Warning("SCTP", "Bookeeping Fail, channel %p is not in main list", chan);
+               else
+                       prev->Next = prev->Next->Next;
+       }
+       Mutex_Release(&glSCTP_Channels);
+       
+       // Clear Queue
+       SHORTLOCK(&chan->lQueue);
+       while(chan->Queue)
+       {
+               tSCTPPacket     *tmp;
+               tmp = chan->Queue;
+               chan->Queue = tmp->Next;
+               free(tmp);
+       }
+       SHORTREL(&chan->lQueue);
+       
+       // Free channel structure
+       free(chan);
+}
+
+/**
+ * \return Port Number on success, or zero on failure
+ */
+Uint16 SCTP_int_AllocatePort()
+{
+        int    i;
+       Mutex_Acquire(&glSCTP_Ports);
+       // Fast Search
+       for( i = SCTP_ALLOC_BASE; i < 0x10000; i += 32 )
+               if( gSCTP_Ports[i/32] != 0xFFFFFFFF )
+                       break;
+       if(i == 0x10000)        return 0;
+       for( ;; i++ )
+       {
+               if( !(gSCTP_Ports[i/32] & (1 << (i%32))) )
+                       return i;
+       }
+       Mutex_Release(&glSCTP_Ports);
+}
+
+/**
+ * \brief Allocate a specific port
+ * \return Boolean Success
+ */
+int SCTP_int_MarkPortAsUsed(Uint16 Port)
+{
+       Mutex_Acquire(&glSCTP_Ports);
+       if( gSCTP_Ports[Port/32] & (1 << (Port%32)) ) {
+               return 0;
+               Mutex_Release(&glSCTP_Ports);
+       }
+       gSCTP_Ports[Port/32] |= 1 << (Port%32);
+       Mutex_Release(&glSCTP_Ports);
+       return 1;
+}
+
+/**
+ * \brief Free an allocated port
+ */
+void SCTP_int_FreePort(Uint16 Port)
+{
+       Mutex_Acquire(&glSCTP_Ports);
+       gSCTP_Ports[Port/32] &= ~(1 << (Port%32));
+       Mutex_Release(&glSCTP_Ports);
+}
diff --git a/KernelLand/Modules/IPStack/tcp.c b/KernelLand/Modules/IPStack/tcp.c
new file mode 100644 (file)
index 0000000..e9c3de9
--- /dev/null
@@ -0,0 +1,1373 @@
+/*
+ * Acess2 IP Stack
+ * - TCP Handling
+ */
+#define DEBUG  1
+#include "ipstack.h"
+#include "ipv4.h"
+#include "ipv6.h"
+#include "tcp.h"
+
+#define USE_SELECT     1
+#define HEXDUMP_INCOMING       0
+#define HEXDUMP_OUTGOING       0
+#define        CACHE_FUTURE_PACKETS_IN_BYTES   1       // Use a ring buffer to cache out of order packets
+
+#define TCP_MIN_DYNPORT        0xC000
+#define TCP_MAX_HALFOPEN       1024    // Should be enough
+
+#define TCP_MAX_PACKET_SIZE    1024
+#define TCP_WINDOW_SIZE        0x2000
+#define TCP_RECIEVE_BUFFER_SIZE        0x4000
+
+// === PROTOTYPES ===
+void   TCP_Initialise(void);
+void   TCP_StartConnection(tTCPConnection *Conn);
+void   TCP_SendPacket(tTCPConnection *Conn, size_t Length, tTCPHeader *Data);
+void   TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
+void   TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length);
+int    TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length);
+void   TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection);
+Uint16 TCP_GetUnusedPort();
+ int   TCP_AllocatePort(Uint16 Port);
+ int   TCP_DeallocatePort(Uint16 Port);
+// --- Server
+tVFS_Node      *TCP_Server_Init(tInterface *Interface);
+char   *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *TCP_Server_FindDir(tVFS_Node *Node, const char *Name);
+ int   TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
+void   TCP_Server_Close(tVFS_Node *Node);
+// --- Client
+tVFS_Node      *TCP_Client_Init(tInterface *Interface);
+Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+ int   TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
+void   TCP_Client_Close(tVFS_Node *Node);
+// --- Helpers
+ int   WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue);
+
+// === TEMPLATES ===
+tSocketFile    gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
+tSocketFile    gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
+tVFS_NodeType  gTCP_ServerNodeType = {
+       .TypeName = "TCP Server",
+       .ReadDir = TCP_Server_ReadDir,
+       .FindDir = TCP_Server_FindDir,
+       .IOCtl   = TCP_Server_IOCtl,
+       .Close   = TCP_Server_Close
+       };
+tVFS_NodeType  gTCP_ClientNodeType = {
+       .TypeName = "TCP Client/Connection",
+       .Read  = TCP_Client_Read,
+       .Write = TCP_Client_Write,
+       .IOCtl = TCP_Client_IOCtl,
+       .Close = TCP_Client_Close
+       };
+
+// === GLOBALS ===
+ int   giTCP_NumHalfopen = 0;
+tShortSpinlock glTCP_Listeners;
+tTCPListener   *gTCP_Listeners;
+tShortSpinlock glTCP_OutbountCons;
+tTCPConnection *gTCP_OutbountCons;
+Uint32 gaTCP_PortBitmap[0x800];
+ int   giTCP_NextOutPort = TCP_MIN_DYNPORT;
+
+// === CODE ===
+/**
+ * \brief Initialise the TCP Layer
+ * 
+ * Registers the client and server files and the GetPacket callback
+ */
+void TCP_Initialise(void)
+{
+       giTCP_NextOutPort += rand()%32;
+       IPStack_AddFile(&gTCP_ServerFile);
+       IPStack_AddFile(&gTCP_ClientFile);
+       IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
+       IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
+}
+
+/**
+ * \brief Sends a packet from the specified connection, calculating the checksums
+ * \param Conn Connection
+ * \param Length       Length of data
+ * \param Data Packet data (cast as a TCP Header)
+ */
+void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data )
+{
+       Uint16  checksum[2];
+       
+       Data->Checksum = 0;
+       checksum[1] = htons( ~IPv4_Checksum( (void*)Data, Length ) );   // Partial checksum
+       if(Length & 1)
+               ((Uint8*)Data)[Length] = 0;
+       
+       // TODO: Fragment packet
+       
+       switch( Conn->Interface->Type )
+       {
+       case 4:
+               // Append IPv4 Pseudo Header
+               {
+                       Uint32  buf[3];
+                       buf[0] = ((tIPv4*)Conn->Interface->Address)->L;
+                       buf[1] = Conn->RemoteIP.v4.L;
+                       buf[2] = (htons(Length)<<16) | (6<<8) | 0;
+                       checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) );        // Partial checksum
+               }
+               Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two
+               IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, Length, Data);
+               break;
+               
+       case 6:
+               // Append IPv6 Pseudo Header
+               {
+                       Uint32  buf[4+4+1+1];
+                       memcpy(buf, Conn->Interface->Address, 16);
+                       memcpy(&buf[4], &Conn->RemoteIP, 16);
+                       buf[8] = htonl(Length);
+                       buf[9] = htonl(6);
+                       checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) );        // Partial checksum
+               }
+               Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two
+               IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data);
+               break;
+       }
+}
+
+/**
+ * \brief Handles a packet from the IP Layer
+ * \param Interface    Interface the packet arrived from
+ * \param Address      Pointer to the addres structure
+ * \param Length       Size of packet in bytes
+ * \param Buffer       Packet data
+ */
+void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+{
+       tTCPHeader      *hdr = Buffer;
+       tTCPListener    *srv;
+       tTCPConnection  *conn;
+
+       Log_Log("TCP", "TCP_GetPacket: <Local>:%i from [%s]:%i, Flags= %s%s%s%s%s%s%s%s",
+               ntohs(hdr->DestPort),
+               IPStack_PrintAddress(Interface->Type, Address),
+               ntohs(hdr->SourcePort),
+               (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "",
+               (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "",
+               (hdr->Flags & TCP_FLAG_URG) ? "URG " : "",
+               (hdr->Flags & TCP_FLAG_ACK) ? "ACK " : "",
+               (hdr->Flags & TCP_FLAG_PSH) ? "PSH " : "",
+               (hdr->Flags & TCP_FLAG_RST) ? "RST " : "",
+               (hdr->Flags & TCP_FLAG_SYN) ? "SYN " : "",
+               (hdr->Flags & TCP_FLAG_FIN) ? "FIN " : ""
+               );
+
+       if( Length > (hdr->DataOffset >> 4)*4 )
+       {
+               Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
+#if HEXDUMP_INCOMING
+               Debug_HexDump(
+                       "TCP_GetPacket: Packet Data = ",
+                       (Uint8*)hdr + (hdr->DataOffset >> 4)*4,
+                       Length - (hdr->DataOffset >> 4)*4
+                       );
+#endif
+       }
+
+       // Check Servers
+       {
+               for( srv = gTCP_Listeners; srv; srv = srv->Next )
+               {
+                       // Check if the server is active
+                       if(srv->Port == 0)      continue;
+                       // Check the interface
+                       if(srv->Interface && srv->Interface != Interface)       continue;
+                       // Check the destination port
+                       if(srv->Port != htons(hdr->DestPort))   continue;
+                       
+                       Log_Log("TCP", "TCP_GetPacket: Matches server %p", srv);
+                       // Is this in an established connection?
+                       for( conn = srv->Connections; conn; conn = conn->Next )
+                       {
+                               // Check that it is coming in on the same interface
+                               if(conn->Interface != Interface)        continue;
+
+                               // Check Source Port
+                               Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)",
+                                       conn->RemotePort, ntohs(hdr->SourcePort));
+                               if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
+
+                               // Check Source IP
+                               Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)",
+                                       IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP));
+                               Log_Debug("TCP", "                == Address(%s)",
+                                       IPStack_PrintAddress(conn->Interface->Type, Address));
+                               if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
+                                       continue ;
+
+                               Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn);
+                               // We have a response!
+                               TCP_INT_HandleConnectionPacket(conn, hdr, Length);
+
+                               return;
+                       }
+
+                       Log_Log("TCP", "TCP_GetPacket: Opening Connection");
+                       // Open a new connection (well, check that it's a SYN)
+                       if(hdr->Flags != TCP_FLAG_SYN) {
+                               Log_Log("TCP", "TCP_GetPacket: Packet is not a SYN");
+                               return ;
+                       }
+                       
+                       // TODO: Check for halfopen max
+                       
+                       conn = calloc(1, sizeof(tTCPConnection));
+                       conn->State = TCP_ST_SYN_RCVD;
+                       conn->LocalPort = srv->Port;
+                       conn->RemotePort = ntohs(hdr->SourcePort);
+                       conn->Interface = Interface;
+                       
+                       switch(Interface->Type)
+                       {
+                       case 4: conn->RemoteIP.v4 = *(tIPv4*)Address;   break;
+                       case 6: conn->RemoteIP.v6 = *(tIPv6*)Address;   break;
+                       }
+                       
+                       conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
+                       
+                       conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1;
+                       conn->NextSequenceSend = rand();
+                       
+                       // Create node
+                       conn->Node.NumACLs = 1;
+                       conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
+                       conn->Node.ImplPtr = conn;
+                       conn->Node.ImplInt = srv->NextID ++;
+                       conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end?
+                       
+                       // Hmm... Theoretically, this lock will never have to wait,
+                       // as the interface is locked to the watching thread, and this
+                       // runs in the watching thread. But, it's a good idea to have
+                       // it, just in case
+                       // Oh, wait, there is a case where a wildcard can be used
+                       // (srv->Interface == NULL) so having the lock is a good idea
+                       SHORTLOCK(&srv->lConnections);
+                       if( !srv->Connections )
+                               srv->Connections = conn;
+                       else
+                               srv->ConnectionsTail->Next = conn;
+                       srv->ConnectionsTail = conn;
+                       if(!srv->NewConnections)
+                               srv->NewConnections = conn;
+                       VFS_MarkAvaliable( &srv->Node, 1 );
+                       SHORTREL(&srv->lConnections);
+
+                       // Send the SYN ACK
+                       hdr->Flags |= TCP_FLAG_ACK;
+                       hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv);
+                       hdr->SequenceNumber = htonl(conn->NextSequenceSend);
+                       hdr->DestPort = hdr->SourcePort;
+                       hdr->SourcePort = htons(srv->Port);
+                       hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4;
+                       TCP_SendPacket( conn, sizeof(tTCPHeader), hdr );
+                       conn->NextSequenceSend ++;
+                       return ;
+               }
+       }
+
+
+       // Check Open Connections
+       {
+               for( conn = gTCP_OutbountCons; conn; conn = conn->Next )
+               {
+                       // Check that it is coming in on the same interface
+                       if(conn->Interface != Interface)        continue;
+
+                       // Check Source Port
+                       if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
+
+                       // Check Source IP
+                       if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
+                               continue;
+                       if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
+                               continue;
+
+                       TCP_INT_HandleConnectionPacket(conn, hdr, Length);
+                       return ;
+               }
+       }
+       
+       Log_Log("TCP", "TCP_GetPacket: No Match");
+}
+
+/**
+ * \brief Handles a packet sent to a specific connection
+ * \param Connection   TCP Connection pointer
+ * \param Header       TCP Packet pointer
+ * \param Length       Length of the packet
+ */
+void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length)
+{
+        int    dataLen;
+       Uint32  sequence_num;
+       
+       // Silently drop once finished
+       // TODO: Check if this needs to be here
+       if( Connection->State == TCP_ST_FINISHED ) {
+               Log_Log("TCP", "Packet ignored - connection finnished");
+               return ;
+       }
+       
+       // Syncronise sequence values
+       if(Header->Flags & TCP_FLAG_SYN) {
+               // TODO: What if the packet also has data?
+               Connection->NextSequenceRcv = ntohl(Header->SequenceNumber);
+       }
+       
+       // Ackowledge a sent packet
+       if(Header->Flags & TCP_FLAG_ACK) {
+               // TODO: Process an ACKed Packet
+               Log_Log("TCP", "Conn %p, Sent packet 0x%x ACKed", Connection, Header->AcknowlegementNumber);
+       }
+       
+       // Get length of data
+       dataLen = Length - (Header->DataOffset>>4)*4;
+       Log_Log("TCP", "HandleConnectionPacket - dataLen = %i", dataLen);
+       
+       // 
+       // State Machine
+       //
+       switch( Connection->State )
+       {
+       // Pre-init connection?
+       case TCP_ST_CLOSED:
+               Log_Log("TCP", "Packets to a closed connection?!");
+               break;
+       
+       // --- Init States ---
+       // SYN sent, expecting SYN-ACK Connection Opening
+       case TCP_ST_SYN_SENT:
+               if( Header->Flags & TCP_FLAG_SYN )
+               {
+                       Connection->NextSequenceRcv ++;
+                       Header->DestPort = Header->SourcePort;
+                       Header->SourcePort = htons(Connection->LocalPort);
+                       Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
+                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
+                       Header->Flags = TCP_FLAG_ACK;
+                       Header->DataOffset = (sizeof(tTCPHeader)/4) << 4;
+                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+                       
+                       if( Header->Flags & TCP_FLAG_ACK )
+                       {       
+                               Log_Log("TCP", "ACKing SYN-ACK");
+                               Connection->State = TCP_ST_OPEN;
+                       }
+                       else
+                       {
+                               Log_Log("TCP", "ACKing SYN");
+                               Connection->State = TCP_ST_SYN_RCVD;
+                       }
+               }
+               break;
+       
+       // SYN-ACK sent, expecting ACK
+       case TCP_ST_SYN_RCVD:
+               if( Header->Flags & TCP_FLAG_ACK )
+               {
+                       // TODO: Handle max half-open limit
+                       Connection->State = TCP_ST_OPEN;
+                       Log_Log("TCP", "Connection fully opened");
+               }
+               break;
+               
+       // --- Established State ---
+       case TCP_ST_OPEN:
+               // - Handle State changes
+               //
+               if( Header->Flags & TCP_FLAG_FIN ) {
+                       Log_Log("TCP", "Conn %p closed, recieved FIN", Connection);
+                       VFS_MarkError(&Connection->Node, 1);
+                       Connection->State = TCP_ST_CLOSE_WAIT;
+//                     Header->Flags &= ~TCP_FLAG_FIN;
+                       // CLOSE WAIT requires the client to close (or does it?)
+                       #if 0
+                       
+                       #endif
+               }
+       
+               // Check for an empty packet
+               if(dataLen == 0) {
+                       if( Header->Flags == TCP_FLAG_ACK )
+                       {
+                               Log_Log("TCP", "ACK only packet");
+                               return ;
+                       }
+                       Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte)
+                       Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
+                       Header->DestPort = Header->SourcePort;
+                       Header->SourcePort = htons(Connection->LocalPort);
+                       Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
+                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+                       Header->Flags |= TCP_FLAG_ACK;
+                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+                       return ;
+               }
+               
+               // NOTES:
+               // Flags
+               //    PSH - Has Data?
+               // /NOTES
+               
+               sequence_num = ntohl(Header->SequenceNumber);
+               
+               Log_Log("TCP", "0x%08x <= 0x%08x < 0x%08x",
+                       Connection->NextSequenceRcv,
+                       ntohl(Header->SequenceNumber),
+                       Connection->NextSequenceRcv + TCP_WINDOW_SIZE
+                       );
+               
+               // Is this packet the next expected packet?
+               if( sequence_num == Connection->NextSequenceRcv )
+               {
+                        int    rv;
+                       // Ooh, Goodie! Add it to the recieved list
+                       rv = TCP_INT_AppendRecieved(Connection,
+                               (Uint8*)Header + (Header->DataOffset>>4)*4,
+                               dataLen
+                               );
+                       if(rv != 0) {
+                               break;
+                       }
+                       Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen);
+                       Connection->NextSequenceRcv += dataLen;
+                       
+                       // TODO: This should be moved out of the watcher thread,
+                       // so that a single lost packet on one connection doesn't cause
+                       // all connections on the interface to lag.
+                       // - Meh, no real issue, as the cache shouldn't be that large
+                       TCP_INT_UpdateRecievedFromFuture(Connection);
+               
+                       // ACK Packet
+                       Header->DestPort = Header->SourcePort;
+                       Header->SourcePort = htons(Connection->LocalPort);
+                       Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
+                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
+                       Header->Flags &= TCP_FLAG_SYN;  // Eliminate all flags save for SYN
+                       Header->Flags |= TCP_FLAG_ACK;  // Add ACK
+                       Log_Log("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv);
+                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+                       //Connection->NextSequenceSend ++;
+               }
+               // Check if the packet is in window
+               else if( WrapBetween(Connection->NextSequenceRcv, sequence_num,
+                               Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) )
+               {
+                       Uint8   *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4;
+                       #if CACHE_FUTURE_PACKETS_IN_BYTES
+                       Uint32  index;
+                        int    i;
+                       
+                       index = sequence_num % TCP_WINDOW_SIZE;
+                       for( i = 0; i < dataLen; i ++ )
+                       {
+                               Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8);
+                               Connection->FuturePacketData[index] = dataptr[i];
+                               // Do a wrap increment
+                               index ++;
+                               if(index == TCP_WINDOW_SIZE)    index = 0;
+                       }
+                       #else
+                       tTCPStoredPacket        *pkt, *tmp, *prev = NULL;
+                       
+                       // Allocate and fill cached packet
+                       pkt = malloc( sizeof(tTCPStoredPacket) + dataLen );
+                       pkt->Next = NULL;
+                       pkt->Sequence = ntohl(Header->SequenceNumber);
+                       pkt->Length = dataLen;
+                       memcpy(pkt->Data, dataptr, dataLen);
+                       
+                       Log_Log("TCP", "We missed a packet, caching",
+                               pkt->Sequence, Connection->NextSequenceRcv);
+                       
+                       // No? Well, let's cache it and look at it later
+                       SHORTLOCK( &Connection->lFuturePackets );
+                       for(tmp = Connection->FuturePackets;
+                               tmp;
+                               prev = tmp, tmp = tmp->Next)
+                       {
+                               if(tmp->Sequence >= pkt->Sequence)      break;
+                       }
+                       
+                       // Add if before first, or sequences don't match 
+                       if( !tmp || tmp->Sequence != pkt->Sequence )
+                       {
+                               if(prev)
+                                       prev->Next = pkt;
+                               else
+                                       Connection->FuturePackets = pkt;
+                               pkt->Next = tmp;
+                       }
+                       // Replace if larger
+                       else if(pkt->Length > tmp->Length)
+                       {
+                               if(prev)
+                                       prev->Next = pkt;
+                               pkt->Next = tmp->Next;
+                               free(tmp);
+                       }
+                       else
+                       {
+                               free(pkt);      // TODO: Find some way to remove this
+                       }
+                       SHORTREL( &Connection->lFuturePackets );
+                       #endif
+               }
+               // Badly out of sequence packet
+               else
+               {
+                       Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped",
+                               sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE);
+                       // TODO: Spec says we should send an empty ACK with the current state
+               }
+               break;
+       
+       // --- Remote close states
+       case TCP_ST_CLOSE_WAIT:
+               
+               // Ignore everything, CLOSE_WAIT is terminated by the client
+               Log_Debug("TCP", "CLOSE WAIT - Ignoring packets");
+               
+               break;
+       
+       // LAST-ACK - Waiting for the ACK of FIN (from CLOSE WAIT)
+       case TCP_ST_LAST_ACK:
+               if( Header->Flags & TCP_FLAG_ACK )
+               {
+                       Connection->State = TCP_ST_FINISHED;    // Connection completed
+                       Log_Log("TCP", "LAST-ACK to CLOSED - Connection remote closed");
+                       // TODO: Destrory the TCB
+               }
+               break;
+       
+       // --- Local close States
+       case TCP_ST_FIN_WAIT1:
+               if( Header->Flags & TCP_FLAG_FIN )
+               {
+                       Connection->State = TCP_ST_CLOSING;
+                       Log_Debug("TCP", "Conn %p closed, sent FIN and recieved FIN", Connection);
+                       VFS_MarkError(&Connection->Node, 1);
+                       
+                       // ACK Packet
+                       Header->DestPort = Header->SourcePort;
+                       Header->SourcePort = htons(Connection->LocalPort);
+                       Header->AcknowlegementNumber = Header->SequenceNumber;
+                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
+                       Header->Flags = TCP_FLAG_ACK;
+                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+                       break ;
+               }
+               
+               // TODO: Make sure that the packet is actually ACKing the FIN
+               if( Header->Flags & TCP_FLAG_ACK )
+               {
+                       Connection->State = TCP_ST_FIN_WAIT2;
+                       Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection);
+                       VFS_MarkError(&Connection->Node, 1);
+                       return ;
+               }
+               break;
+       
+       case TCP_ST_FIN_WAIT2:
+               if( Header->Flags & TCP_FLAG_FIN )
+               {
+                       Connection->State = TCP_ST_TIME_WAIT;
+                       Log_Debug("TCP", "FIN sent and recieved, ACKing and going into TIME WAIT %p FINWAIT-2 -> TIME WAIT", Connection);
+                       // Send ACK
+                       Header->DestPort = Header->SourcePort;
+                       Header->SourcePort = htons(Connection->LocalPort);
+                       Header->AcknowlegementNumber = Header->SequenceNumber;
+                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
+                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
+                       Header->Flags = TCP_FLAG_ACK;
+                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+               }
+               break;
+       
+       case TCP_ST_CLOSING:
+               // TODO: Make sure that the packet is actually ACKing the FIN
+               if( Header->Flags & TCP_FLAG_ACK )
+               {
+                       Connection->State = TCP_ST_TIME_WAIT;
+                       Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection);
+                       VFS_MarkError(&Connection->Node, 1);
+                       return ;
+               }
+               break;
+       
+       // --- Closed (or near closed) states) ---
+       case TCP_ST_TIME_WAIT:
+               Log_Log("TCP", "Packets on Time-Wait, ignored");
+               break;
+       
+       case TCP_ST_FINISHED:
+               Log_Log("TCP", "Packets when CLOSED, ignoring");
+               break;
+       
+       //default:
+       //      Log_Warning("TCP", "Unhandled TCP state %i", Connection->State);
+       //      break;
+       }
+       
+}
+
+/**
+ * \brief Appends a packet to the recieved list
+ * \param Connection   Connection structure
+ * \param Data Packet contents
+ * \param Length       Length of \a Data
+ */
+int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length)
+{
+       Mutex_Acquire( &Connection->lRecievedPackets );
+
+       if(Connection->RecievedBuffer->Length + Length > Connection->RecievedBuffer->Space )
+       {
+               VFS_MarkAvaliable(&Connection->Node, 1);
+               Log_Error("TCP", "Buffer filled, packet dropped (:%i) - %i + %i > %i",
+                       Connection->LocalPort, Connection->RecievedBuffer->Length, Length,
+                       Connection->RecievedBuffer->Space
+                       );
+               Mutex_Release( &Connection->lRecievedPackets );
+               return 1;
+       }
+       
+       RingBuffer_Write( Connection->RecievedBuffer, Data, Length );
+
+       VFS_MarkAvaliable(&Connection->Node, 1);
+       
+       Mutex_Release( &Connection->lRecievedPackets );
+       return 0;
+}
+
+/**
+ * \brief Updates the connections recieved list from the future list
+ * \param Connection   Connection structure
+ * 
+ * Updates the recieved packets list with packets from the future (out 
+ * of order) packets list that are now able to be added in direct
+ * sequence.
+ */
+void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
+{
+       #if CACHE_FUTURE_PACKETS_IN_BYTES
+        int    i, length = 0;
+       Uint32  index;
+       
+       // Calculate length of contiguous bytes
+       length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
+       index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
+       for( i = 0; i < length; i ++ )
+       {
+               if( Connection->FuturePacketValidBytes[i / 8] == 0xFF ) {
+                       i += 7; index += 7;
+                       continue;
+               }
+               else if( !(Connection->FuturePacketValidBytes[i / 8] & (1 << (i%8))) )
+                       break;
+               
+               index ++;
+               if(index > TCP_WINDOW_SIZE)
+                       index -= TCP_WINDOW_SIZE;
+       }
+       length = i;
+       
+       index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
+       
+       // Write data to to the ring buffer
+       if( TCP_WINDOW_SIZE - index > length )
+       {
+               // Simple case
+               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length );
+       }
+       else
+       {
+                int    endLen = TCP_WINDOW_SIZE - index;
+               // 2-part case
+               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, endLen );
+               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - length );
+       }
+       
+       // Mark (now saved) bytes as invalid
+       // - Align index
+       while(index % 8 && length)
+       {
+               Connection->FuturePacketData[index] = 0;
+               Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
+               index ++;
+               if(index > TCP_WINDOW_SIZE)
+                       index -= TCP_WINDOW_SIZE;
+               length --;
+       }
+       while( length > 7 )
+       {
+               Connection->FuturePacketData[index] = 0;
+               Connection->FuturePacketValidBytes[index/8] = 0;
+               length -= 8;
+               index += 8;
+               if(index > TCP_WINDOW_SIZE)
+                       index -= TCP_WINDOW_SIZE;
+       }
+       while(length)
+       {
+               Connection->FuturePacketData[index] = 0;
+               Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
+               index ++;
+               if(index > TCP_WINDOW_SIZE)
+                       index -= TCP_WINDOW_SIZE;
+               length --;
+       }
+       
+       #else
+       tTCPStoredPacket        *pkt;
+       for(;;)
+       {
+               SHORTLOCK( &Connection->lFuturePackets );
+               
+               // Clear out duplicates from cache
+               // - If a packet has just been recieved, and it is expected, then
+               //   (since NextSequenceRcv = rcvd->Sequence + rcvd->Length) all
+               //   packets in cache that are smaller than the next expected
+               //   are now defunct.
+               pkt = Connection->FuturePackets;
+               while(pkt && pkt->Sequence < Connection->NextSequenceRcv)
+               {
+                       tTCPStoredPacket        *next = pkt->Next;
+                       free(pkt);
+                       pkt = next;
+               }
+               
+               // If there's no packets left in cache, stop looking
+               if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) {
+                       SHORTREL( &Connection->lFuturePackets );
+                       return;
+               }
+               
+               // Delete packet from future list
+               Connection->FuturePackets = pkt->Next;
+               
+               // Release list
+               SHORTREL( &Connection->lFuturePackets );
+               
+               // Looks like we found one
+               TCP_INT_AppendRecieved(Connection, pkt);
+               Connection->NextSequenceRcv += pkt->Length;
+               free(pkt);
+       }
+       #endif
+}
+
+/**
+ * \fn Uint16 TCP_GetUnusedPort()
+ * \brief Gets an unused port and allocates it
+ */
+Uint16 TCP_GetUnusedPort()
+{
+       Uint16  ret;
+
+       // Get Next outbound port
+       ret = giTCP_NextOutPort++;
+       while( gaTCP_PortBitmap[ret/32] & (1UL << (ret%32)) )
+       {
+               ret ++;
+               giTCP_NextOutPort++;
+               if(giTCP_NextOutPort == 0x10000) {
+                       ret = giTCP_NextOutPort = TCP_MIN_DYNPORT;
+               }
+       }
+
+       // Mark the new port as used
+       gaTCP_PortBitmap[ret/32] |= 1 << (ret%32);
+
+       return ret;
+}
+
+/**
+ * \fn int TCP_AllocatePort(Uint16 Port)
+ * \brief Marks a port as used
+ */
+int TCP_AllocatePort(Uint16 Port)
+{
+       // Check if the port has already been allocated
+       if( gaTCP_PortBitmap[Port/32] & (1 << (Port%32)) )
+               return 0;
+
+       // Allocate
+       gaTCP_PortBitmap[Port/32] |= 1 << (Port%32);
+
+       return 1;
+}
+
+/**
+ * \fn int TCP_DeallocatePort(Uint16 Port)
+ * \brief Marks a port as unused
+ */
+int TCP_DeallocatePort(Uint16 Port)
+{
+       // Check if the port has already been allocated
+       if( !(gaTCP_PortBitmap[Port/32] & (1 << (Port%32))) )
+               return 0;
+
+       // Allocate
+       gaTCP_PortBitmap[Port/32] &= ~(1 << (Port%32));
+
+       return 1;
+}
+
+// --- Server
+tVFS_Node *TCP_Server_Init(tInterface *Interface)
+{
+       tTCPListener    *srv;
+       
+       srv = calloc( 1, sizeof(tTCPListener) );
+
+       if( srv == NULL ) {
+               Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
+               return NULL;
+       }
+
+       srv->Interface = Interface;
+       srv->Port = 0;
+       srv->NextID = 0;
+       srv->Connections = NULL;
+       srv->ConnectionsTail = NULL;
+       srv->NewConnections = NULL;
+       srv->Next = NULL;
+       srv->Node.Flags = VFS_FFLAG_DIRECTORY;
+       srv->Node.Size = -1;
+       srv->Node.ImplPtr = srv;
+       srv->Node.NumACLs = 1;
+       srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
+       srv->Node.Type = &gTCP_ServerNodeType;
+
+       SHORTLOCK(&glTCP_Listeners);
+       srv->Next = gTCP_Listeners;
+       gTCP_Listeners = srv;
+       SHORTREL(&glTCP_Listeners);
+
+       return &srv->Node;
+}
+
+/**
+ * \brief Wait for a new connection and return the connection ID
+ * \note Blocks until a new connection is made
+ * \param Node Server node
+ * \param Pos  Position (ignored)
+ */
+char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tTCPListener    *srv = Node->ImplPtr;
+       tTCPConnection  *conn;
+       char    *ret;
+       
+       ENTER("pNode iPos", Node, Pos);
+
+       Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID());
+       for(;;)
+       {
+               SHORTLOCK( &srv->lConnections );
+               if( srv->NewConnections != NULL )       break;
+               SHORTREL( &srv->lConnections );
+               Threads_Yield();        // TODO: Sleep until poked
+       }
+       
+
+       // Increment the new list (the current connection is still on the 
+       // normal list)
+       conn = srv->NewConnections;
+       srv->NewConnections = conn->Next;
+
+       if( srv->NewConnections == NULL )
+               VFS_MarkAvaliable( Node, 0 );
+       
+       SHORTREL( &srv->lConnections );
+       
+       LOG("conn = %p", conn);
+       LOG("srv->Connections = %p", srv->Connections);
+       LOG("srv->NewConnections = %p", srv->NewConnections);
+       LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail);
+
+       ret = malloc(9);
+       itoa(ret, conn->Node.ImplInt, 16, 8, '0');
+       Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret);
+       LEAVE('s', ret);
+       return ret;
+}
+
+/**
+ * \brief Gets a client connection node
+ * \param Node Server node
+ * \param Name Hexadecimal ID of the node
+ */
+tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tTCPConnection  *conn;
+       tTCPListener    *srv = Node->ImplPtr;
+       char    tmp[9];
+        int    id = atoi(Name);
+       
+       ENTER("pNode sName", Node, Name);
+
+       // Check for a non-empty name
+       if( Name[0] ) 
+       {       
+               // Sanity Check
+               itoa(tmp, id, 16, 8, '0');
+               if(strcmp(tmp, Name) != 0) {
+                       LOG("'%s' != '%s' (%08x)", Name, tmp, id);
+                       LEAVE('n');
+                       return NULL;
+               }
+               
+               Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
+               Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
+               Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
+               
+               // Search
+               SHORTLOCK( &srv->lConnections );
+               for(conn = srv->Connections;
+                       conn;
+                       conn = conn->Next)
+               {
+                       LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
+                       if(conn->Node.ImplInt == id)    break;
+               }
+               SHORTREL( &srv->lConnections );
+
+               // If not found, ret NULL
+               if(!conn) {
+                       LOG("Connection %i not found", id);
+                       LEAVE('n');
+                       return NULL;
+               }
+       }
+       // Empty Name - Check for a new connection and if it's there, open it
+       else
+       {
+               SHORTLOCK( &srv->lConnections );
+               conn = srv->NewConnections;
+               if( conn != NULL )
+                       srv->NewConnections = conn->Next;
+               VFS_MarkAvaliable( Node, srv->NewConnections != NULL );
+               SHORTREL( &srv->lConnections );
+               if( !conn ) {
+                       LOG("No new connections");
+                       LEAVE('n');
+                       return NULL;
+               }
+       }
+               
+       // Return node
+       LEAVE('p', &conn->Node);
+       return &conn->Node;
+}
+
+/**
+ * \brief Handle IOCtl calls
+ */
+int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tTCPListener    *srv = Node->ImplPtr;
+
+       switch(ID)
+       {
+       case 4: // Get/Set Port
+               if(!Data)       // Get Port
+                       return srv->Port;
+
+               if(srv->Port)   // Wait, you can't CHANGE the port
+                       return -1;
+
+               if(!CheckMem(Data, sizeof(Uint16)))     // Sanity check
+                       return -1;
+
+               // Permissions check
+               if(Threads_GetUID() != 0
+               && *(Uint16*)Data != 0
+               && *(Uint16*)Data < 1024)
+                       return -1;
+
+               // TODO: Check if a port is in use
+
+               // Set Port
+               srv->Port = *(Uint16*)Data;
+               if(srv->Port == 0)      // Allocate a random port
+                       srv->Port = TCP_GetUnusedPort();
+               else    // Else, mark this as used
+                       TCP_AllocatePort(srv->Port);
+               
+               Log_Log("TCP", "Server %p listening on port %i", srv, srv->Port);
+               
+               return srv->Port;
+       }
+       return 0;
+}
+
+void TCP_Server_Close(tVFS_Node *Node)
+{
+       free(Node->ImplPtr);
+}
+
+// --- Client
+/**
+ * \brief Create a client node
+ */
+tVFS_Node *TCP_Client_Init(tInterface *Interface)
+{
+       tTCPConnection  *conn = calloc( sizeof(tTCPConnection) + TCP_WINDOW_SIZE + TCP_WINDOW_SIZE/8, 1 );
+
+       conn->State = TCP_ST_CLOSED;
+       conn->Interface = Interface;
+       conn->LocalPort = -1;
+       conn->RemotePort = -1;
+
+       conn->Node.ImplPtr = conn;
+       conn->Node.NumACLs = 1;
+       conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
+       conn->Node.Type = &gTCP_ClientNodeType;
+
+       conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
+       #if 0
+       conn->SentBuffer = RingBuffer_Create( TCP_SEND_BUFFER_SIZE );
+       Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name);
+       #endif
+       
+       #if CACHE_FUTURE_PACKETS_IN_BYTES
+       // Future recieved data (ahead of the expected sequence number)
+       conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection);
+       conn->FuturePacketValidBytes = conn->FuturePacketData + TCP_WINDOW_SIZE;
+       #endif
+
+       SHORTLOCK(&glTCP_OutbountCons);
+       conn->Next = gTCP_OutbountCons;
+       gTCP_OutbountCons = conn;
+       SHORTREL(&glTCP_OutbountCons);
+
+       return &conn->Node;
+}
+
+/**
+ * \brief Wait for a packet and return it
+ * \note If \a Length is smaller than the size of the packet, the rest
+ *       of the packet's data will be discarded.
+ */
+Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tTCPConnection  *conn = Node->ImplPtr;
+       size_t  len;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       LOG("conn = %p {State:%i}", conn, conn->State);
+       
+       // Check if connection is estabilishing
+       // - TODO: Sleep instead (maybe using VFS_SelectNode to wait for the
+       //   data to be availiable
+       while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
+               Threads_Yield();
+       
+       // If the conneciton is not open, then clean out the recieved buffer
+       if( conn->State != TCP_ST_OPEN )
+       {
+               Mutex_Acquire( &conn->lRecievedPackets );
+               len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
+               Mutex_Release( &conn->lRecievedPackets );
+               
+               if( len == 0 ) {
+                       VFS_MarkAvaliable(Node, 0);
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               
+               LEAVE('i', len);
+               return len;
+       }
+       
+       // Wait
+       VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, NULL, "TCP_Client_Read");
+       
+       // Lock list and read as much as possible (up to `Length`)
+       Mutex_Acquire( &conn->lRecievedPackets );
+       len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
+       
+       if( len == 0 || conn->RecievedBuffer->Length == 0 ) {
+               LOG("Marking as none avaliable (len = %i)", len);
+               VFS_MarkAvaliable(Node, 0);
+       }
+               
+       // Release the lock (we don't need it any more)
+       Mutex_Release( &conn->lRecievedPackets );
+
+       LEAVE('i', len);
+       return len;
+}
+
+/**
+ * \brief Send a data packet on a connection
+ */
+void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const void *Data)
+{
+       char    buf[sizeof(tTCPHeader)+Length];
+       tTCPHeader      *packet = (void*)buf;
+       
+       packet->SourcePort = htons(Connection->LocalPort);
+       packet->DestPort = htons(Connection->RemotePort);
+       packet->DataOffset = (sizeof(tTCPHeader)/4)*16;
+       packet->WindowSize = htons(TCP_WINDOW_SIZE);
+       
+       packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
+       packet->SequenceNumber = htonl(Connection->NextSequenceSend);
+       packet->Flags = TCP_FLAG_PSH|TCP_FLAG_ACK;      // Hey, ACK if you can!
+       
+       memcpy(packet->Options, Data, Length);
+       
+       Log_Debug("TCP", "Send sequence 0x%08x", Connection->NextSequenceSend);
+#if HEXDUMP_OUTGOING
+       Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length);
+#endif
+       
+       TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet );
+       
+       Connection->NextSequenceSend += Length;
+}
+
+/**
+ * \brief Send some bytes on a connection
+ */
+Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tTCPConnection  *conn = Node->ImplPtr;
+       size_t  rem = Length;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+//     #if DEBUG
+//     Debug_HexDump("TCP_Client_Write: Buffer = ",
+//             Buffer, Length);
+//     #endif
+       
+       // Check if connection is open
+       while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
+               Threads_Yield();
+       
+       if( conn->State != TCP_ST_OPEN ) {
+               VFS_MarkError(Node, 1);
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       do
+       {
+                int    len = (rem < TCP_MAX_PACKET_SIZE) ? rem : TCP_MAX_PACKET_SIZE;
+               
+               #if 0
+               // Wait for space in the buffer
+               Semaphore_Signal( &Connection->SentBufferSpace, len );
+               
+               // Save data to buffer (and update the length read by the ammount written)
+               len = RingBuffer_Write( &Connection->SentBuffer, Buffer, len);
+               #endif
+               
+               // Send packet
+               TCP_INT_SendDataPacket(conn, len, Buffer);
+               
+               Buffer += len;
+               rem -= len;
+       } while( rem > 0 );
+       
+       LEAVE('i', Length);
+       return Length;
+}
+
+/**
+ * \brief Open a connection to another host using TCP
+ * \param Conn Connection structure
+ */
+void TCP_StartConnection(tTCPConnection *Conn)
+{
+       tTCPHeader      hdr = {0};
+
+       Conn->State = TCP_ST_SYN_SENT;
+
+       hdr.SourcePort = htons(Conn->LocalPort);
+       hdr.DestPort = htons(Conn->RemotePort);
+       Conn->NextSequenceSend = rand();
+       hdr.SequenceNumber = htonl(Conn->NextSequenceSend);
+       hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4;
+       hdr.Flags = TCP_FLAG_SYN;
+       hdr.WindowSize = htons(TCP_WINDOW_SIZE);        // Max
+       hdr.Checksum = 0;       // TODO
+       
+       TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr );
+       
+       Conn->NextSequenceSend ++;
+       Conn->State = TCP_ST_SYN_SENT;
+
+       return ;
+}
+
+/**
+ * \brief Control a client socket
+ */
+int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tTCPConnection  *conn = Node->ImplPtr;
+       
+       ENTER("pNode iID pData", Node, ID, Data);
+
+       switch(ID)
+       {
+       case 4: // Get/Set local port
+               if(!Data)
+                       LEAVE_RET('i', conn->LocalPort);
+               if(conn->State != TCP_ST_CLOSED)
+                       LEAVE_RET('i', -1);
+               if(!CheckMem(Data, sizeof(Uint16)))
+                       LEAVE_RET('i', -1);
+
+               if(Threads_GetUID() != 0 && *(Uint16*)Data < 1024)
+                       LEAVE_RET('i', -1);
+
+               conn->LocalPort = *(Uint16*)Data;
+               LEAVE_RET('i', conn->LocalPort);
+
+       case 5: // Get/Set remote port
+               if(!Data)       LEAVE_RET('i', conn->RemotePort);
+               if(conn->State != TCP_ST_CLOSED)        LEAVE_RET('i', -1);
+               if(!CheckMem(Data, sizeof(Uint16)))     LEAVE_RET('i', -1);
+               conn->RemotePort = *(Uint16*)Data;
+               LEAVE_RET('i', conn->RemotePort);
+
+       case 6: // Set Remote IP
+               if( conn->State != TCP_ST_CLOSED )
+                       LEAVE_RET('i', -1);
+               if( conn->Interface->Type == 4 )
+               {
+                       if(!CheckMem(Data, sizeof(tIPv4)))      LEAVE_RET('i', -1);
+                       conn->RemoteIP.v4 = *(tIPv4*)Data;
+               }
+               else if( conn->Interface->Type == 6 )
+               {
+                       if(!CheckMem(Data, sizeof(tIPv6)))      LEAVE_RET('i', -1);
+                       conn->RemoteIP.v6 = *(tIPv6*)Data;
+               }
+               LEAVE_RET('i', 0);
+
+       case 7: // Connect
+               if(conn->LocalPort == 0xFFFF)
+                       conn->LocalPort = TCP_GetUnusedPort();
+               if(conn->RemotePort == -1)
+                       LEAVE_RET('i', 0);
+
+               {
+                       tTime   timeout_end = now() + conn->Interface->TimeoutDelay;
+       
+                       TCP_StartConnection(conn);
+                       // TODO: Wait for connection to open
+                       while( conn->State == TCP_ST_SYN_SENT && timeout_end > now() ) {
+                               Threads_Yield();
+                       }
+                       if( conn->State == TCP_ST_SYN_SENT )
+                               LEAVE_RET('i', 0);
+               }
+
+               LEAVE_RET('i', 1);
+       
+       // Get recieve buffer length
+       case 8:
+               LEAVE_RET('i', conn->RecievedBuffer->Length);
+       }
+
+       return 0;
+}
+
+void TCP_Client_Close(tVFS_Node *Node)
+{
+       tTCPConnection  *conn = Node->ImplPtr;
+       tTCPHeader      packet;
+       
+       ENTER("pNode", Node);
+       
+       if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_OPEN )
+       {
+               packet.SourcePort = htons(conn->LocalPort);
+               packet.DestPort = htons(conn->RemotePort);
+               packet.DataOffset = (sizeof(tTCPHeader)/4)*16;
+               packet.WindowSize = TCP_WINDOW_SIZE;
+               
+               packet.AcknowlegementNumber = 0;
+               packet.SequenceNumber = htonl(conn->NextSequenceSend);
+               packet.Flags = TCP_FLAG_FIN;
+               
+               TCP_SendPacket( conn, sizeof(tTCPHeader), &packet );
+       }
+       
+       switch( conn->State )
+       {
+       case TCP_ST_CLOSE_WAIT:
+               conn->State = TCP_ST_LAST_ACK;
+               break;
+       case TCP_ST_OPEN:
+               conn->State = TCP_ST_FIN_WAIT1;
+               while( conn->State == TCP_ST_FIN_WAIT1 )        Threads_Yield();
+               break;
+       default:
+               Log_Warning("TCP", "Unhandled connection state in TCP_Client_Close");
+               break;
+       }
+       
+       free(conn);
+       
+       LEAVE('-');
+}
+
+/**
+ * \brief Checks if a value is between two others (after taking into account wrapping)
+ */
+int WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue)
+{
+       if( MaxValue < 0xFFFFFFFF )
+       {
+               Lower %= MaxValue + 1;
+               Value %= MaxValue + 1;
+               Higher %= MaxValue + 1;
+       }
+       
+       // Simple Case, no wrap ?
+       //       Lower Value Higher
+       // | ... + ... + ... + ... |
+
+       if( Lower < Higher ) {
+               return Lower < Value && Value < Higher;
+       }
+       // Higher has wrapped below lower
+       
+       // Value > Lower ?
+       //       Higher Lower Value
+       // | ... +  ... + ... + ... |
+       if( Value > Lower ) {
+               return 1;
+       }
+       
+       // Value < Higher ?
+       //       Value Higher Lower
+       // | ... + ... +  ... + ... |
+       if( Value < Higher ) {
+               return 1;
+       }
+       
+       return 0;
+}
diff --git a/KernelLand/Modules/IPStack/tcp.h b/KernelLand/Modules/IPStack/tcp.h
new file mode 100644 (file)
index 0000000..6aa404f
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Acess2 IP Stack
+ * - TCP Definitions
+ */
+#ifndef _TCP_H_
+#define _TCP_H_
+
+#include "ipstack.h"
+#include <adt.h>       // tRingBuffer
+
+typedef struct sTCPHeader      tTCPHeader;
+typedef struct sTCPListener    tTCPListener;
+typedef struct sTCPStoredPacket        tTCPStoredPacket;
+typedef struct sTCPConnection  tTCPConnection;
+
+struct sTCPHeader
+{
+       Uint16  SourcePort;
+       Uint16  DestPort;
+       Uint32  SequenceNumber;
+       Uint32  AcknowlegementNumber;
+       #if 0
+       struct {        // Lowest to highest
+               unsigned Reserved:      4;
+               unsigned DataOffset: 4; // Size of the header in 32-bit words
+       } __attribute__ ((packed));
+       #else
+       Uint8   DataOffset;
+       #endif
+       #if 0
+       struct {        // Lowest to Highest
+               unsigned FIN:   1;      // Last packet
+               unsigned SYN:   1;      // Synchronise Sequence Numbers
+               unsigned RST:   1;      // Reset Connection
+               unsigned PSH:   1;      // Push Function
+               unsigned ACK:   1;      // Acknowlegement field is significant
+               unsigned URG:   1;      // Urgent pointer is significant
+               unsigned ECE:   1;      // ECN-Echo
+               unsigned CWR:   1;      // Congestion Window Reduced
+       } __attribute__ ((packed)) Flags;
+       #else
+       Uint8   Flags;
+       #endif
+       Uint16  WindowSize;
+       
+       Uint16  Checksum;
+       Uint16  UrgentPointer;
+       
+       Uint8   Options[];
+} __attribute__ ((packed));
+
+enum eTCPFlags
+{
+       TCP_FLAG_FIN    = 0x01,
+       TCP_FLAG_SYN    = 0x02,
+       TCP_FLAG_RST    = 0x04,
+       TCP_FLAG_PSH    = 0x08,
+       TCP_FLAG_ACK    = 0x10,
+       TCP_FLAG_URG    = 0x20,
+       TCP_FLAG_ECE    = 0x40,
+       TCP_FLAG_CWR    = 0x80
+};
+
+struct sTCPListener
+{
+       struct sTCPListener     *Next;  //!< Next server in the list
+       Uint16  Port;           //!< Listening port (0 disables the server)
+       tInterface      *Interface;     //!< Listening Interface
+       tVFS_Node       Node;   //!< Server Directory node
+        int    NextID;         //!< Name of the next connection
+       tShortSpinlock  lConnections;   //!< Spinlock for connections
+       tTCPConnection  *Connections;   //!< Connections (linked list)
+       tTCPConnection  *volatile NewConnections;
+       tTCPConnection  *ConnectionsTail;
+};
+
+struct sTCPStoredPacket
+{
+       struct sTCPStoredPacket *Next;
+       size_t  Length;
+       Uint32  Sequence;
+       Uint8   Data[];
+};
+
+enum eTCPConnectionState
+{
+       TCP_ST_CLOSED,          // 0 - Connection invalid
+       
+       TCP_ST_SYN_SENT,        // 1 - SYN sent by local, waiting for SYN-ACK
+       TCP_ST_SYN_RCVD,        // 2 - SYN recieved, SYN-ACK sent
+       
+       TCP_ST_OPEN,            // 3 - Connection open
+       
+       // Local Close
+       TCP_ST_FIN_WAIT1,       // 4 - FIN sent, waiting for reply (ACK or FIN)
+       TCP_ST_FIN_WAIT2,       // 5 - sent FIN acked, waiting for FIN from peer
+       TCP_ST_CLOSING,         // 6 - Waiting for ACK of FIN (FIN sent and recieved)
+       TCP_ST_TIME_WAIT,       // 7 - Waiting for timeout after local close
+       // Remote close
+       TCP_ST_CLOSE_WAIT,      // 8 - FIN recieved, waiting for user to close (error set, wait for node close)
+       TCP_ST_LAST_ACK,        // 9 - FIN sent and recieved, waiting for ACK
+       TCP_ST_FINISHED         // 10 - Essentially closed, all packets are invalid
+};
+
+struct sTCPConnection
+{
+       struct sTCPConnection   *Next;
+       enum eTCPConnectionState        State;  //!< Connection state (see ::eTCPConnectionState)
+       Uint16  LocalPort;      //!< Local port
+       Uint16  RemotePort;     //!< Remote port
+       tInterface      *Interface;     //!< Listening Interface
+       tVFS_Node       Node;   //!< Node
+       
+       Uint32  NextSequenceSend;       //!< Next sequence value for outbound packets
+       Uint32  NextSequenceRcv;        //!< Next expected sequence value for inbound
+       
+       #if 0
+       /**
+        * \brief Non-ACKed packets
+        * \note Ring buffer
+        * \{
+        */
+       tMutex  lNonACKedPackets;
+       tTCPStoredPacket        *SentPackets;   //!< Non-acknowleged packets
+       /**
+        * \}
+        */
+       #endif
+       
+       /**
+        * \brief Unread Packets
+        * \note Ring buffer
+        * \{
+        */
+       tMutex  lRecievedPackets;
+       tRingBuffer     *RecievedBuffer;
+       /**
+        * \}
+        */
+       
+       /**
+        * \brief Out of sequence packets
+        * \note Sorted list to improve times
+        * \todo Convert this to a ring buffer and a bitmap of valid bytes
+        * \{
+        */
+       #if CACHE_FUTURE_PACKETS_OR_BYTES == bytes
+       Uint32  HighestSequenceRcvd;    //!< Highest sequence number (within window) recieved
+       Uint8   *FuturePacketData;      //!< Future packet data (indexed by sequence number)
+       Uint8   *FuturePacketValidBytes;        //!< Valid byte bitmap (WINDOW_SIZE/8 bytes)
+       #else
+       tShortSpinlock  lFuturePackets; //!< Future packets spinlock
+       tTCPStoredPacket        *FuturePackets; //!< Out of sequence packets
+       #endif
+       /**
+        * \}
+        */
+       
+       union {
+               tIPv4   v4;
+               tIPv6   v6;
+       } RemoteIP;     //!< Remote IP Address
+       // Type is determined by LocalInterface->Type
+};
+
+#endif
diff --git a/KernelLand/Modules/IPStack/udp.c b/KernelLand/Modules/IPStack/udp.c
new file mode 100644 (file)
index 0000000..cbdcd56
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Acess2 IP Stack
+ * - UDP Handling
+ */
+#include "ipstack.h"
+#include <api_drv_common.h>
+#include "udp.h"
+
+#define UDP_ALLOC_BASE 0xC000
+
+// === PROTOTYPES ===
+void   UDP_Initialise();
+void   UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
+void   UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
+void   UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length);
+// --- Client Channels
+tVFS_Node      *UDP_Channel_Init(tInterface *Interface);
+Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+ int   UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
+void   UDP_Channel_Close(tVFS_Node *Node);
+// --- Helpers
+Uint16 UDP_int_AllocatePort();
+ int   UDP_int_MarkPortAsUsed(Uint16 Port);
+void   UDP_int_FreePort(Uint16 Port);
+
+// === GLOBALS ===
+tVFS_NodeType  gUDP_NodeType = {
+       .Read = UDP_Channel_Read,
+       .Write = UDP_Channel_Write,
+       .IOCtl = UDP_Channel_IOCtl,
+       .Close = UDP_Channel_Close
+};
+tMutex glUDP_Channels;
+tUDPChannel    *gpUDP_Channels;
+
+tMutex glUDP_Ports;
+Uint32 gUDP_Ports[0x10000/32];
+
+tSocketFile    gUDP_SocketFile = {NULL, "udp", UDP_Channel_Init};
+
+// === CODE ===
+/**
+ * \fn void TCP_Initialise()
+ * \brief Initialise the TCP Layer
+ */
+void UDP_Initialise()
+{
+       IPStack_AddFile(&gUDP_SocketFile);
+       //IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_Unreachable);
+       IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket);
+}
+
+/**
+ * \brief Scan a list of tUDPChannels and find process the first match
+ * \return 0 if no match was found, -1 on error and 1 if a match was found
+ */
+int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
+{
+       tUDPHeader      *hdr = Buffer;
+       tUDPChannel     *chan;
+       tUDPPacket      *pack;
+        int    len;
+       
+       for(chan = List;
+               chan;
+               chan = chan->Next)
+       {
+               // Match local endpoint
+               if(chan->Interface && chan->Interface != Interface)     continue;
+               if(chan->LocalPort != ntohs(hdr->DestPort))     continue;
+               
+               // Check for remote port restriction
+               if(chan->Remote.Port && chan->Remote.Port != ntohs(hdr->SourcePort))
+                       continue;
+               // Check for remote address restriction
+               if(chan->RemoteMask)
+               {
+                       if(chan->Remote.AddrType != Interface->Type)
+                               continue;
+                       if(!IPStack_CompareAddress(Interface->Type, Address,
+                               &chan->Remote.Addr, chan->RemoteMask)
+                               )
+                               continue;
+               }
+               
+               Log_Log("UDP", "Recieved packet for %p", chan);
+               // Create the cached packet
+               len = ntohs(hdr->Length);
+               pack = malloc(sizeof(tUDPPacket) + len);
+               pack->Next = NULL;
+               memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type));
+               pack->Remote.Port = ntohs(hdr->SourcePort);
+               pack->Remote.AddrType = Interface->Type;
+               pack->Length = len;
+               memcpy(pack->Data, hdr->Data, len);
+               
+               // Add the packet to the channel's queue
+               SHORTLOCK(&chan->lQueue);
+               if(chan->Queue)
+                       chan->QueueEnd->Next = pack;
+               else
+                       chan->QueueEnd = chan->Queue = pack;
+               SHORTREL(&chan->lQueue);
+               VFS_MarkAvaliable(&chan->Node, 1);
+               Mutex_Release(&glUDP_Channels);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+ * \brief Handles a packet from the IP Layer
+ */
+void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
+{
+       tUDPHeader      *hdr = Buffer;
+       
+       Log_Debug("UDP", "hdr->SourcePort = %i", ntohs(hdr->SourcePort));
+       Log_Debug("UDP", "hdr->DestPort = %i", ntohs(hdr->DestPort));
+       Log_Debug("UDP", "hdr->Length = %i", ntohs(hdr->Length));
+       Log_Debug("UDP", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
+       
+       // Check registered connections
+       Mutex_Acquire(&glUDP_Channels);
+       UDP_int_ScanList(gpUDP_Channels, Interface, Address, Length, Buffer);
+       Mutex_Release(&glUDP_Channels);
+}
+
+/**
+ * \brief Handle an ICMP Unrechable Error
+ */
+void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
+{
+       
+}
+
+/**
+ * \brief Send a packet
+ * \param Channel      Channel to send the packet from
+ * \param Data Packet data
+ * \param Length       Length in bytes of packet data
+ */
+void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length)
+{
+       tUDPHeader      *hdr;
+
+       if(Channel->Interface && Channel->Interface->Type != AddrType)  return ;
+       
+       switch(AddrType)
+       {
+       case 4:
+               // Create the packet
+               hdr = malloc(sizeof(tUDPHeader)+Length);
+               hdr->SourcePort = htons( Channel->LocalPort );
+               hdr->DestPort = htons( Port );
+               hdr->Length = htons( sizeof(tUDPHeader) + Length );
+               hdr->Checksum = 0;      // Checksum can be zero on IPv4
+               memcpy(hdr->Data, Data, Length);
+               // Pass on the the IPv4 Layer
+               // TODO: What if Channel->Interface is NULL here?
+               IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, sizeof(tUDPHeader)+Length, hdr);
+               // Free allocated packet
+               free(hdr);
+               break;
+       }
+}
+
+// --- Client Channels
+tVFS_Node *UDP_Channel_Init(tInterface *Interface)
+{
+       tUDPChannel     *new;
+       new = calloc( sizeof(tUDPChannel), 1 );
+       new->Interface = Interface;
+       new->Node.ImplPtr = new;
+       new->Node.NumACLs = 1;
+       new->Node.ACLs = &gVFS_ACL_EveryoneRW;
+       new->Node.Type = &gUDP_NodeType;
+       
+       Mutex_Acquire(&glUDP_Channels);
+       new->Next = gpUDP_Channels;
+       gpUDP_Channels = new;
+       Mutex_Release(&glUDP_Channels);
+       
+       return &new->Node;
+}
+
+/**
+ * \brief Read from the channel file (wait for a packet)
+ */
+Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tUDPChannel     *chan = Node->ImplPtr;
+       tUDPPacket      *pack;
+       tUDPEndpoint    *ep;
+        int    ofs, addrlen;
+       
+       if(chan->LocalPort == 0) {
+               Log_Notice("UDP", "Channel %p sent with no local port", chan);
+               return 0;
+       }
+       
+       while(chan->Queue == NULL)      Threads_Yield();
+       
+       for(;;)
+       {
+               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "UDP_Channel_Read");
+               SHORTLOCK(&chan->lQueue);
+               if(chan->Queue == NULL) {
+                       SHORTREL(&chan->lQueue);
+                       continue;
+               }
+               pack = chan->Queue;
+               chan->Queue = pack->Next;
+               if(!chan->Queue) {
+                       chan->QueueEnd = NULL;
+                       VFS_MarkAvaliable(Node, 0);     // Nothing left
+               }
+               SHORTREL(&chan->lQueue);
+               break;
+       }
+
+       // Check that the header fits
+       addrlen = IPStack_GetAddressSize(pack->Remote.AddrType);
+       ep = Buffer;
+       ofs = 4 + addrlen;
+       if(Length < ofs) {
+               free(pack);
+               Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs);
+               return 0;
+       }
+       
+       // Fill header
+       ep->Port = pack->Remote.Port;
+       ep->AddrType = pack->Remote.AddrType;
+       memcpy(&ep->Addr, &pack->Remote.Addr, addrlen);
+       
+       // Copy packet data
+       if(Length > ofs + pack->Length) Length = ofs + pack->Length;
+       memcpy((char*)Buffer + ofs, pack->Data, Length - ofs);
+
+       // Free cached packet
+       free(pack);
+       
+       return Length;
+}
+
+/**
+ * \brief Write to the channel file (send a packet)
+ */
+Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tUDPChannel     *chan = Node->ImplPtr;
+       const tUDPEndpoint      *ep;
+       const void      *data;
+        int    ofs;
+       if(chan->LocalPort == 0)        return 0;
+       
+       ep = Buffer;    
+       ofs = 2 + 2 + IPStack_GetAddressSize( ep->AddrType );
+
+       data = (const char *)Buffer + ofs;
+
+       UDP_SendPacketTo(chan, ep->AddrType, &ep->Addr, ep->Port, data, (size_t)Length - ofs);
+       
+       return 0;
+}
+
+/**
+ * \brief Names for channel IOCtl Calls
+ */
+static const char *casIOCtls_Channel[] = {
+       DRV_IOCTLNAMES,
+       "getset_localport",
+       "getset_remoteport",
+       "getset_remotemask",
+       "set_remoteaddr",
+       NULL
+       };
+/**
+ * \brief Channel IOCtls
+ */
+int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tUDPChannel     *chan = Node->ImplPtr;
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_MISC, "UDP Channel", 0x100, casIOCtls_Channel);
+       
+       case 4: // getset_localport (returns bool success)
+               if(!Data)       LEAVE_RET('i', chan->LocalPort);
+               if(!CheckMem( Data, sizeof(Uint16) ) ) {
+                       LOG("Invalid pointer %p", Data);
+                       LEAVE_RET('i', -1);
+               }
+               // Set port
+               chan->LocalPort = *(Uint16*)Data;
+               // Permissions check (Ports lower than 1024 are root-only)
+               if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
+                       if( Threads_GetUID() != 0 ) {
+                               LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
+                               chan->LocalPort = 0;
+                               LEAVE_RET('i', -1);
+                       }
+               }
+               // Allocate a random port if requested
+               if( chan->LocalPort == 0 )
+                       chan->LocalPort = UDP_int_AllocatePort();
+               else
+               {
+                       // Else, mark the requested port as used
+                       if( UDP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
+                               LOG("Port %i us currently in use", chan->LocalPort);
+                               chan->LocalPort = 0;
+                               LEAVE_RET('i', 0);
+                       }
+                       LEAVE_RET('i', 1);
+               }
+               LEAVE_RET('i', 1);
+       
+       case 5: // getset_remoteport (returns bool success)
+               if(!Data)       LEAVE_RET('i', chan->Remote.Port);
+               if(!CheckMem( Data, sizeof(Uint16) ) ) {
+                       LOG("Invalid pointer %p", Data);
+                       LEAVE_RET('i', -1);
+               }
+               chan->Remote.Port = *(Uint16*)Data;
+               return 1;
+       
+       case 6: // getset_remotemask (returns bool success)
+               if(!Data)       LEAVE_RET('i', chan->RemoteMask);
+               if(!CheckMem(Data, sizeof(int)))        LEAVE_RET('i', -1);
+               if( !chan->Interface ) {
+                       LOG("Can't set remote mask on NULL interface");
+                       LEAVE_RET('i', -1);
+               }
+               if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) )
+                       LEAVE_RET('i', -1);
+               chan->RemoteMask = *(int*)Data;
+               return 1;       
+
+       case 7: // set_remoteaddr (returns bool success)
+               if( !chan->Interface ) {
+                       LOG("Can't set remote address on NULL interface");
+                       LEAVE_RET('i', -1);
+               }
+               if(!CheckMem(Data, IPStack_GetAddressSize(chan->Interface->Type))) {
+                       LOG("Invalid pointer");
+                       LEAVE_RET('i', -1);
+               }
+               memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type));
+               return 0;
+       }
+       LEAVE_RET('i', 0);
+}
+
+/**
+ * \brief Close and destroy an open channel
+ */
+void UDP_Channel_Close(tVFS_Node *Node)
+{
+       tUDPChannel     *chan = Node->ImplPtr;
+       tUDPChannel     *prev;
+       
+       // Remove from the main list first
+       Mutex_Acquire(&glUDP_Channels);
+       if(gpUDP_Channels == chan)
+               gpUDP_Channels = gpUDP_Channels->Next;
+       else
+       {
+               for(prev = gpUDP_Channels;
+                       prev->Next && prev->Next != chan;
+                       prev = prev->Next);
+               if(!prev->Next)
+                       Log_Warning("UDP", "Bookeeping Fail, channel %p is not in main list", chan);
+               else
+                       prev->Next = prev->Next->Next;
+       }
+       Mutex_Release(&glUDP_Channels);
+       
+       // Clear Queue
+       SHORTLOCK(&chan->lQueue);
+       while(chan->Queue)
+       {
+               tUDPPacket      *tmp;
+               tmp = chan->Queue;
+               chan->Queue = tmp->Next;
+               free(tmp);
+       }
+       SHORTREL(&chan->lQueue);
+       
+       // Free channel structure
+       free(chan);
+}
+
+/**
+ * \return Port Number on success, or zero on failure
+ */
+Uint16 UDP_int_AllocatePort()
+{
+        int    i;
+       Mutex_Acquire(&glUDP_Ports);
+       // Fast Search
+       for( i = UDP_ALLOC_BASE; i < 0x10000; i += 32 )
+               if( gUDP_Ports[i/32] != 0xFFFFFFFF )
+                       break;
+       if(i == 0x10000)        return 0;
+       for( ;; i++ )
+       {
+               if( !(gUDP_Ports[i/32] & (1 << (i%32))) )
+                       return i;
+       }
+       Mutex_Release(&glUDP_Ports);
+}
+
+/**
+ * \brief Allocate a specific port
+ * \return Boolean Success
+ */
+int UDP_int_MarkPortAsUsed(Uint16 Port)
+{
+       Mutex_Acquire(&glUDP_Ports);
+       if( gUDP_Ports[Port/32] & (1 << (Port%32)) ) {
+               return 0;
+               Mutex_Release(&glUDP_Ports);
+       }
+       gUDP_Ports[Port/32] |= 1 << (Port%32);
+       Mutex_Release(&glUDP_Ports);
+       return 1;
+}
+
+/**
+ * \brief Free an allocated port
+ */
+void UDP_int_FreePort(Uint16 Port)
+{
+       Mutex_Acquire(&glUDP_Ports);
+       gUDP_Ports[Port/32] &= ~(1 << (Port%32));
+       Mutex_Release(&glUDP_Ports);
+}
diff --git a/KernelLand/Modules/IPStack/udp.h b/KernelLand/Modules/IPStack/udp.h
new file mode 100644 (file)
index 0000000..3914789
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Acess2 IP Stack
+ * - UDP Definitions
+ */
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#include "ipstack.h"
+#include "ipv4.h"
+
+typedef struct sUDPHeader      tUDPHeader;
+typedef struct sUDPEndpoint    tUDPEndpoint;
+typedef struct sUDPPacket      tUDPPacket;
+typedef struct sUDPChannel     tUDPChannel;
+
+struct sUDPHeader
+{
+       Uint16  SourcePort;
+       Uint16  DestPort;
+       Uint16  Length;
+       Uint16  Checksum;
+       Uint8   Data[];
+};
+
+struct sUDPEndpoint
+{
+       Uint16  Port;
+       Uint16  AddrType;
+       union {
+               tIPv4   v4;
+               tIPv6   v6;
+       }       Addr;
+};
+
+struct sUDPPacket
+{
+       struct sUDPPacket       *Next;
+       tUDPEndpoint    Remote;
+       size_t  Length;
+       Uint8   Data[];
+};
+
+struct sUDPChannel
+{
+       struct sUDPChannel      *Next;
+       tInterface      *Interface;
+       Uint16  LocalPort;
+
+       tUDPEndpoint    Remote; // Only accept packets form this address/port pair
+        int    RemoteMask;     // Mask on the address
+       
+       tVFS_Node       Node;
+       tShortSpinlock  lQueue;
+       tUDPPacket      * volatile Queue;
+       tUDPPacket      *QueueEnd;
+};
+
+#endif
+
diff --git a/KernelLand/Modules/Input/Makefile.tpl b/KernelLand/Modules/Input/Makefile.tpl
new file mode 100644 (file)
index 0000000..c36c928
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = Input
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/Input/PS2KbMouse/8042.c b/KernelLand/Modules/Input/PS2KbMouse/8042.c
new file mode 100644 (file)
index 0000000..e11bc74
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Acess2
+ * - By thePowersGang (John Hodge)
+ *
+ * 8042 (or comaptible) Driver
+ */
+#include <acess.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+void   KBC8042_Init(void);
+void   KBC8042_KeyboardHandler(int IRQ, void *Ptr);
+void   KBC8042_MouseHandler(int IRQ, void *Ptr);
+void   KBC8042_EnableMouse(void);
+static inline void     KBC8042_SendDataAlt(Uint8 data);
+static inline void     KBC8042_SendData(Uint8 data);
+static inline Uint8    KBC8042_ReadData(void);
+static void    KBC8042_SendMouseCommand(Uint8 cmd);
+
+// === CODE ===
+void KBC8042_Init(void)
+{
+       IRQ_AddHandler(1, KBC8042_KeyboardHandler, NULL);
+       IRQ_AddHandler(12, KBC8042_MouseHandler, NULL); // Set IRQ
+       
+       {
+               Uint8   temp;
+               // Attempt to get around a strange bug in Bochs/Qemu by toggling
+               // the controller on and off
+               temp = inb(0x61);
+               outb(0x61, temp | 0x80);
+               outb(0x61, temp & 0x7F);
+               inb(0x60);      // Clear keyboard buffer
+       }
+}
+
+void KBC8042_KeyboardHandler(int IRQ, void *Ptr)
+{
+       Uint8   scancode;
+
+//     Log("KBC8042_KeyboardHandler: (IRQ=%i, Ptr=%p)", IRQ, Ptr);
+
+       scancode = inb(0x60);
+       KB_HandleScancode( scancode );
+}
+
+void KBC8042_MouseHandler(int IRQ, void *Ptr)
+{
+       PS2Mouse_HandleInterrupt( inb(0x60) );
+}
+
+void KBC8042_SetLEDs(Uint8 leds)
+{
+       while( inb(0x64) & 2 ); // Wait for bit 2 to unset
+       outb(0x60, 0xED);       // Send update command
+
+       while( inb(0x64) & 2 ); // Wait for bit 2 to unset
+       outb(0x60, leds);
+}
+
+void KBC8042_EnableMouse(void)
+{
+       Uint8   status;
+       Log_Log("8042", "Enabling Mouse...");
+       
+       // Enable AUX PS/2
+       KBC8042_SendDataAlt(0xA8);
+       
+       // Enable AUX PS/2 (Compaq Status Byte)
+       KBC8042_SendDataAlt(0x20);      // Send Command
+       status = KBC8042_ReadData();    // Get Status
+       status &= ~0x20;        // Clear "Disable Mouse Clock"
+       status |= 0x02;         // Set IRQ12 Enable
+       KBC8042_SendDataAlt(0x60);      // Send Command
+       KBC8042_SendData(status);       // Set Status
+       
+       //mouseSendCommand(0xF6);       // Set Default Settings
+       KBC8042_SendMouseCommand(0xF4); // Enable Packets
+}
+
+static inline void KBC8042_SendDataAlt(Uint8 data)
+{
+       int timeout=100000;
+       while( timeout-- && inb(0x64) & 2 );    // Wait for Flag to clear
+       outb(0x64, data);       // Send Command
+}
+static inline void KBC8042_SendData(Uint8 data)
+{
+       int timeout=100000;
+       while( timeout-- && inb(0x64) & 2 );    // Wait for Flag to clear
+       outb(0x60, data);       // Send Command
+}
+static inline Uint8 KBC8042_ReadData(void)
+{
+       int timeout=100000;
+       while( timeout-- && (inb(0x64) & 1) == 0);      // Wait for Flag to set
+       return inb(0x60);
+}
+static inline void KBC8042_SendMouseCommand(Uint8 cmd)
+{
+       KBC8042_SendDataAlt(0xD4);
+       KBC8042_SendData(cmd);
+}
+
diff --git a/KernelLand/Modules/Input/PS2KbMouse/Makefile b/KernelLand/Modules/Input/PS2KbMouse/Makefile
new file mode 100644 (file)
index 0000000..306e2b4
--- /dev/null
@@ -0,0 +1,8 @@
+#
+#
+
+OBJ = main.o kb.o ps2mouse.o
+OBJ += 8042.o pl050.o
+NAME = PS2KbMouse
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Input/PS2KbMouse/common.h b/KernelLand/Modules/Input/PS2KbMouse/common.h
new file mode 100644 (file)
index 0000000..7cbffe9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Acess2
+ * 
+ * PS2 Keyboard/Mouse Driver
+ *
+ * common.h
+ * - Shared definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+extern int     KB_Install(char **Arguments);
+extern int     PS2Mouse_Install(char **Arguments);
+
+extern void    KBC8042_Init(void);
+extern void    KBC8042_EnableMouse(void);
+
+extern void    PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ);
+extern void    PL050_EnableMouse(void);
+
+extern void    KB_HandleScancode(Uint8 scancode);
+extern void    PS2Mouse_HandleInterrupt(Uint8 InputByte);
+
+extern void    (*gpMouse_EnableFcn)(void);
+
+#endif
diff --git a/KernelLand/Modules/Input/PS2KbMouse/kb.c b/KernelLand/Modules/Input/PS2KbMouse/kb.c
new file mode 100644 (file)
index 0000000..a121b61
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Acess2
+ * PS2 Keyboard Driver
+ */
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <api_drv_common.h>
+#include <api_drv_keyboard.h>
+#include "kb_kbdus.h"
+
+// === CONSTANTS ===
+#define        KB_BUFFER_SIZE  1024
+#define        USE_KERNEL_MAGIC        1
+
+// === IMPORTS ===
+extern void    Threads_ToggleTrace(int TID);
+extern void    Threads_Dump(void);
+extern void    Heap_Stats(void);
+
+// === PROTOTYPES ===
+ int   KB_Install(char **Arguments);
+void   KB_HandleScancode(Uint8 scancode);
+void   KB_UpdateLEDs(void);
+ int   KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === GLOBALS ===
+tVFS_NodeType  gKB_NodeType = {
+       .IOCtl = KB_IOCtl
+};
+tDevFS_Driver  gKB_DevInfo = {
+       NULL, "PS2Keyboard",
+       { .Type = &gKB_NodeType }
+};
+tKeybardCallback       gKB_Callback = NULL;
+Uint32 **gpKB_Map = gpKBDUS;
+Uint8  gbaKB_States[3][256];
+ int   gbKB_ShiftState = 0;
+ int   gbKB_CapsState = 0;
+ int   gbKB_KeyUp = 0;
+ int   giKB_KeyLayer = 0;
+#if USE_KERNEL_MAGIC
+ int   gbKB_MagicState = 0;
+ int   giKB_MagicAddress = 0;
+ int   giKB_MagicAddressPos = 0;
+#endif
+
+// === CODE ===
+/**
+ * \brief Install the keyboard driver
+ */
+int KB_Install(char **Arguments)
+{
+       DevFS_AddDevice( &gKB_DevInfo );
+       //Log("KB_Install: Installed");
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Called on a keyboard IRQ
+ * \param IRQNum       IRQ number (unused)
+ */
+void KB_HandleScancode(Uint8 scancode)
+{
+       Uint32  ch;
+        int    bCaseSwitch = (gbKB_ShiftState != 0) != (gbKB_CapsState != 0);
+
+       //Log_Debug("Keyboard", "scancode = %02x", scancode);
+
+       // Ignore ACKs
+       if(scancode == 0xFA) {
+               // Oh man! This is anarchic (I'm leaving it here to represent
+               // the mess that Acess once was)
+               //kb_lastChar = KB_ACK;
+               return;
+       }
+
+       // Layer +1
+       if(scancode == 0xE0) {
+               giKB_KeyLayer = 1;
+               return;
+       }
+       // Layer +2
+       if(scancode == 0xE1) {
+               giKB_KeyLayer = 2;
+               return;
+       }
+
+       #if KB_ALT_SCANCODES
+       if(scancode == 0xF0)
+       {
+               gbKB_KeyUp = 1;
+               return;
+       }
+       #else
+       if(scancode & 0x80)
+       {
+               scancode &= 0x7F;
+               gbKB_KeyUp = 1;
+       }
+       #endif
+       
+       if( gKB_Callback )
+               gKB_Callback( (giKB_KeyLayer << 8) | scancode | KEY_ACTION_RAWSYM );
+
+       // Translate
+       ch = gpKB_Map[giKB_KeyLayer*2+bCaseSwitch][scancode];
+       // - Unknown characters in the shift layer fall through to lower
+       if(bCaseSwitch && ch == 0)
+               ch = gpKB_Map[giKB_KeyLayer*2][scancode];
+       // Check for unknown key
+       if(!ch)
+       {
+               if(!gbKB_KeyUp)
+                       Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
+//             return ;
+               // Can pass through to ensure each raw message has a up/down with it
+       }
+
+       // Key Up?
+       if (gbKB_KeyUp)
+       {
+               gbKB_KeyUp = 0;
+               gbaKB_States[giKB_KeyLayer][scancode] = 0;      // Unset key state flag
+
+               #if USE_KERNEL_MAGIC
+               if(ch == KEY_LCTRL)     gbKB_MagicState &= ~1;
+               if(ch == KEY_LALT)      gbKB_MagicState &= ~2;
+               #endif
+
+               if(ch == KEY_LSHIFT)    gbKB_ShiftState &= ~1;
+               if(ch == KEY_RSHIFT)    gbKB_ShiftState &= ~2;
+
+               // Call callback
+               if(gKB_Callback)        gKB_Callback( ch | KEY_ACTION_RELEASE );
+
+               // Reset Layer
+               giKB_KeyLayer = 0;
+               return;
+       }
+
+       // Refire?
+       if( gbaKB_States[giKB_KeyLayer][scancode] == 1 )
+       {
+               if(gKB_Callback)        gKB_Callback(ch | KEY_ACTION_REFIRE);
+               giKB_KeyLayer = 0;
+               return ;
+       }
+
+       // Set the bit relating to the key
+       gbaKB_States[giKB_KeyLayer][scancode] = 1;
+       // Set shift key bits
+       if(ch == KEY_LSHIFT)    gbKB_ShiftState |= 1;
+       if(ch == KEY_RSHIFT)    gbKB_ShiftState |= 2;
+
+       // Check for Caps Lock
+       if(ch == KEY_CAPSLOCK) {
+               gbKB_CapsState = !gbKB_CapsState;
+               KB_UpdateLEDs();
+       }
+
+       // --- Check for Kernel Magic Combos
+       #if USE_KERNEL_MAGIC
+       if(ch == KEY_LCTRL) {
+               gbKB_MagicState |= 1;
+               //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
+       }
+       if(ch == KEY_LALT) {
+               gbKB_MagicState |= 2;
+               //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
+       }
+       if(gbKB_MagicState == 3)
+       {
+               switch(ch)
+               {
+               case '0':       case '1':       case '2':       case '3':
+               case '4':       case '5':       case '6':       case '7':
+               case '8':       case '9':       case 'a':       case 'b':
+               case 'c':       case 'd':       case 'e':       case 'f':
+                       {
+                       char    str[4] = {'0', 'x', ch, 0};
+                       if(giKB_MagicAddressPos == BITS/4)      return;
+                       giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
+                       giKB_MagicAddressPos ++;
+                       }
+                       return;
+               
+               // Instruction Tracing
+               case 't':
+                       Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
+                       Threads_ToggleTrace( giKB_MagicAddress );
+                       giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
+                       return;
+               
+               // Thread List Dump
+               case 'p':       Threads_Dump(); return;
+               // Heap Statistics
+               case 'h':       Heap_Stats();   return;
+               // Dump Structure
+               case 's':       return;
+               }
+       }
+       #endif
+
+       if(gKB_Callback)
+               gKB_Callback(ch | KEY_ACTION_PRESS);
+
+       // Reset Layer
+       giKB_KeyLayer = 0;
+}
+
+/**
+ * \fn void KB_UpdateLEDs(void)
+ * \brief Updates the status of the keyboard LEDs
+ */
+void KB_UpdateLEDs(void)
+{
+       Uint8   leds;
+
+       leds = (gbKB_CapsState ? 4 : 0);
+
+       // TODO: Update LEDS
+       Log_Warning("Keyboard", "TODO: Update LEDs");
+}
+
+static const char      *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
+
+/**
+ * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Calls an IOCtl Command
+ */
+int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       switch(Id)
+       {
+       BASE_IOCTLS(DRV_TYPE_KEYBOARD, "KB", 0x100, csaIOCTL_NAMES);
+       
+       // Sets the Keyboard Callback
+       case KB_IOCTL_SETCALLBACK:
+               // Sanity Check
+               if((Uint)Data < KERNEL_BASE)    return 0;
+               // Can only be set once
+               if(gKB_Callback != NULL)        return 0;
+               // Set Callback
+               gKB_Callback = Data;
+               return 1;
+
+       default:
+               return 0;
+       }
+}
diff --git a/KernelLand/Modules/Input/PS2KbMouse/kb_kbdus.h b/KernelLand/Modules/Input/PS2KbMouse/kb_kbdus.h
new file mode 100644 (file)
index 0000000..5df3257
--- /dev/null
@@ -0,0 +1,61 @@
+\r
+#ifndef _KBDUS_H\r
+#define _KBDUS_H\r
+\r
+// - Base (NO PREFIX)\r
+Uint32 gpKBDUS1[256] = {\r
+       0,\r
+       KEY_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',      // 0x01 - 0x0e\r
+       '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', // 0x0f - 0x1c\r
+       KEY_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'',       // 0x1d - 0x28\r
+       '`', KEY_LSHIFT,'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT,     // 0x29 - 0x3e\r
+       KEY_KPSTAR,\r
+       KEY_LALT, ' ', KEY_CAPSLOCK,\r
+       KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,\r
+       KEY_NUMLOCK, KEY_SCROLLLOCK,\r
+       KEY_KPHOME, KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS,\r
+       KEY_KPLEFT, KEY_KP5, KEY_KPRIGHT, KEY_KPPLUS,\r
+       KEY_KPEND, KEY_KPDOWN, KEY_KPPGDN,\r
+       KEY_KPINS, KEY_KPDEL,\r
+       0, 0, 0, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0,\r
+/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+};\r
+// Shift Key pressed\r
+Uint32 gpKBDUS1s[256] = {\r
+       0,\r
+       KEY_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',      // 0x01 - 0x0e\r
+       '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', // 0x0f - 0x1c\r
+       KEY_LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':','"',        // 0x1d - 0x28\r
+       '~', KEY_LSHIFT,'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', KEY_RSHIFT,      // 0x29 - 0x3e\r
+       0\r
+       };\r
+// - 0xE0 Prefixed\r
+Uint32 gpKBDUS2[256] = {\r
+//     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\r
+/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-F\r
+/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_KPENTER, KEY_RCTRL, 0, 0,\r
+/*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*30*/ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, 0, KEY_RALT, 0, 0, 0, 0, 0, 0, 0,\r
+/*40*/ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, KEY_UP, KEY_PGUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END,\r
+/*50*/ KEY_DOWN, KEY_PGDOWN, KEY_INS, KEY_DEL, 0, 0, 0, 0, 0, 0, 0, KEY_LWIN, KEY_RWIN, KEY_MENU, 0, 0,\r
+/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+};\r
+// - 0xE1 Prefixed\r
+Uint32 gpKBDUS3[256] = {\r
+//     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\r
+/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-F\r
+/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PAUSE, 0, 0,\r
+/*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
+};\r
+\r
+\r
+Uint32 *gpKBDUS[6] = { gpKBDUS1, gpKBDUS1s, gpKBDUS2, gpKBDUS2, gpKBDUS3, gpKBDUS3 };\r
+\r
+#endif\r
diff --git a/KernelLand/Modules/Input/PS2KbMouse/main.c b/KernelLand/Modules/Input/PS2KbMouse/main.c
new file mode 100644 (file)
index 0000000..c5ad4e8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Acess2
+ *
+ * PS/2 Keboard / Mouse Driver
+ */
+#include <acess.h>
+#include <modules.h>
+#include "common.h"
+
+// === IMPORTS ===
+// TODO: Allow runtime/compile-time switching
+//       Maybe PCI will have it?
+// Integrator-CP
+#if 0
+#define KEYBOARD_IRQ   3
+#define KEYBOARD_BASE  0x18000000
+#define MOUSE_IRQ      4
+#define MOUSE_BASE     0x19000000
+#endif
+// Realview
+#if 1
+#define KEYBOARD_IRQ   20
+#define KEYBOARD_BASE  0x10006000
+#define MOUSE_IRQ      21
+#define MOUSE_BASE     0x10007000
+#endif
+
+// === PROTOTYPES ===
+ int   PS2_Install(char **Arguments);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0100, Input_PS2KbMouse, PS2_Install, NULL, NULL);   // Shuts the makefile up
+MODULE_DEFINE(0, 0x0100, PS2Keyboard, KB_Install, NULL, "Input_PS2KbMouse", NULL);
+MODULE_DEFINE(0, 0x0100, PS2Mouse, PS2Mouse_Install, NULL, "Input_PS2KbMouse", NULL);
+
+// === CODE ===
+int PS2_Install(char **Arguments)
+{
+       #if ARCHDIR_is_x86 || ARCHDIR_is_x86_64
+       KBC8042_Init();
+       gpMouse_EnableFcn = KBC8042_EnableMouse;
+       #elif ARCHDIR_is_armv7
+       PL050_Init(KEYBOARD_BASE, KEYBOARD_IRQ, MOUSE_BASE, MOUSE_IRQ);
+       gpMouse_EnableFcn = PL050_EnableMouse;
+       #endif
+
+       return MODULE_ERR_OK;
+}
diff --git a/KernelLand/Modules/Input/PS2KbMouse/pl050.c b/KernelLand/Modules/Input/PS2KbMouse/pl050.c
new file mode 100644 (file)
index 0000000..839c0bd
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Acess2
+ * - By thePowersGang (John Hodge)
+ *
+ * PL050 (or comaptible) Driver
+ */
+#define DEBUG  1
+
+#include <acess.h>
+#include "common.h"
+
+// === CONSTANTS ===
+#define PL050_TXBUSY   0x20
+
+// === PROTOTYPES ===
+void   PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ);
+void   PL050_KeyboardHandler(int IRQ, void *Ptr);
+void   PL050_MouseHandler(int IRQ, void *Ptr);
+void   PL050_EnableMouse(void);
+static inline void     PL050_WriteMouseData(Uint8 data);
+static inline void     PL050_WriteKeyboardData(Uint8 data);
+static inline Uint8    PL050_ReadMouseData(void);
+static inline Uint8    PL050_ReadKeyboardData(void);
+
+// === GLOBALS ===
+Uint32 *gpPL050_KeyboardBase;
+Uint32 *gpPL050_MouseBase;
+
+// === CODE ===
+void PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ)
+{
+       if( KeyboardBase ) {
+               LOG("KeyboardBase = 0x%x", KeyboardBase);
+               gpPL050_KeyboardBase = (void*)MM_MapHWPages(KeyboardBase, 1);
+               LOG("gpPL050_KeyboardBase = %p", gpPL050_KeyboardBase);
+               IRQ_AddHandler(KeyboardIRQ, PL050_KeyboardHandler, NULL);
+
+               gpPL050_KeyboardBase[0] = 0x10;
+       }
+       if( MouseBase ) {
+               gpPL050_MouseBase = (void*)MM_MapHWPages(MouseBase, 1);
+               IRQ_AddHandler(MouseIRQ, PL050_MouseHandler, NULL);
+
+               gpPL050_MouseBase[0] = 0x10;
+       }
+}
+
+void PL050_KeyboardHandler(int IRQ, void *Ptr)
+{
+       Uint8   scancode;
+
+       scancode = PL050_ReadKeyboardData();
+       KB_HandleScancode( scancode );
+}
+
+void PL050_MouseHandler(int IRQ, void *Ptr)
+{
+       PS2Mouse_HandleInterrupt( PL050_ReadMouseData() );
+}
+
+void PL050_SetLEDs(Uint8 leds)
+{
+       PL050_WriteKeyboardData(0xED);
+       PL050_WriteKeyboardData(leds);
+}
+
+void PL050_EnableMouse(void)
+{
+       Log_Log("PL050", "Enabling Mouse...");
+       
+       //PL050_WriteMouseData(0xD4);
+       //PL050_WriteMouseData(0xF6);   // Set Default Settings
+       PL050_WriteMouseData(0xD4);
+       PL050_WriteMouseData(0xF4);     // Enable Packets
+       LOG("Done");
+}
+
+static inline void PL050_WriteMouseData(Uint8 Data)
+{
+        int    timeout = 10000;
+
+       if( !gpPL050_MouseBase ) {
+               Log_Error("PL050", "Mouse disabled (gpPL050_MouseBase = NULL)");
+               return ;
+       }
+
+       ENTER("xData", Data);
+
+       while( --timeout && (gpPL050_MouseBase[1] & PL050_TXBUSY) );
+       if(timeout)
+               gpPL050_MouseBase[2] = Data;
+       else
+               Log_Error("PL050", "Write to mouse timed out");
+       LEAVE('-');
+}
+
+static inline Uint8 PL050_ReadMouseData(void)
+{
+       if( !gpPL050_MouseBase ) {
+               Log_Error("PL050", "Mouse disabled (gpPL050_MouseBase = NULL)");
+               return 0;
+       }
+       return gpPL050_MouseBase[2];
+}
+static inline void PL050_WriteKeyboardData(Uint8 Data)
+{
+        int    timeout = 10000;
+
+       if( !gpPL050_KeyboardBase ) {
+               Log_Error("PL050", "Keyboard disabled (gpPL050_KeyboardBase = NULL)");
+               return ;
+       }
+
+       while( --timeout && gpPL050_KeyboardBase[1] & PL050_TXBUSY );
+       if(timeout)
+               gpPL050_KeyboardBase[2] = Data;
+       else
+               Log_Error("PL050", "Write to keyboard timed out");
+}
+static inline Uint8 PL050_ReadKeyboardData(void)
+{
+       if( !gpPL050_KeyboardBase ) {
+               Log_Error("PL050", "Keyboard disabled (gpPL050_KeyboardBase = NULL)");
+               return 0;
+       }
+
+       return gpPL050_KeyboardBase[2];
+}
+
diff --git a/KernelLand/Modules/Input/PS2KbMouse/ps2mouse.c b/KernelLand/Modules/Input/PS2KbMouse/ps2mouse.c
new file mode 100644 (file)
index 0000000..44be3b7
--- /dev/null
@@ -0,0 +1,206 @@
+/*\r
+ * Acess2 Mouse Driver\r
+ */\r
+#define DEBUG  0\r
+#include <acess.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <api_drv_common.h>\r
+#include <api_drv_joystick.h>\r
+#include "common.h"\r
+\r
+// == CONSTANTS ==\r
+#define NUM_AXIES      2       // X+Y\r
+#define NUM_BUTTONS    5       // Left, Right, Scroll Click, Scroll Up, Scroll Down\r
+\r
+// == PROTOTYPES ==\r
+// - Internal -\r
+ int   PS2Mouse_Install(char **Arguments);\r
+void   PS2Mouse_HandleInterrupt(Uint8 InputByte);\r
+// - Filesystem -\r
+Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+int    PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+\r
+// == GLOBALS ==\r
+void   (*gpMouse_EnableFcn)(void);\r
+// - Settings\r
+ int   giMouse_Sensitivity = 1;\r
+ int   giMouse_MaxX = 640, giMouse_MaxY = 480;\r
+// - File Data\r
+Uint8  gMouse_FileData[sizeof(tJoystick_FileHeader) + NUM_AXIES*sizeof(tJoystick_Axis) + NUM_BUTTONS];\r
+tJoystick_FileHeader   *gMouse_FileHeader = (void *)gMouse_FileData;\r
+tJoystick_Axis *gMouse_Axies;\r
+Uint8  *gMouse_Buttons;\r
+tJoystick_Callback     gMouse_Callback;\r
+ int   gMouse_CallbackArg;\r
+ int   giMouse_AxisLimits[2];\r
+// - Internal State\r
+ int   giMouse_Cycle = 0;      // IRQ Position\r
+Uint8  gaMouse_Bytes[4] = {0,0,0,0};\r
+// - Driver definition\r
+tVFS_NodeType  gMouse_NodeType = {\r
+       .Read = PS2Mouse_Read,\r
+       .IOCtl = PS2Mouse_IOCtl\r
+};\r
+tDevFS_Driver  gMouse_DriverStruct = {\r
+       NULL, "PS2Mouse",\r
+       {\r
+       .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
+       .Type = &gMouse_NodeType\r
+       }\r
+};\r
+\r
+// == CODE ==\r
+int PS2Mouse_Install(char **Arguments)\r
+{\r
+       \r
+\r
+       // Set up variables\r
+       gMouse_Axies = (void*)&gMouse_FileData[4];\r
+       gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];\r
+\r
+       gMouse_FileHeader->NAxies = 2;  gMouse_FileHeader->NButtons = 3;\r
+       gMouse_Axies[0].MinValue = -10; gMouse_Axies[0].MaxValue = 10;\r
+       gMouse_Axies[1].MinValue = -10; gMouse_Axies[1].MaxValue = 10;\r
+       \r
+       // Initialise Mouse Controller\r
+       giMouse_Cycle = 0;      // Set Current Cycle position\r
+       gpMouse_EnableFcn();\r
+       \r
+       DevFS_AddDevice(&gMouse_DriverStruct);\r
+       \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/* Handle Mouse Interrupt\r
+ */\r
+void PS2Mouse_HandleInterrupt(Uint8 InputByte)\r
+{\r
+       Uint8   flags;\r
+        int    d[2], d_accel[2];\r
+        int    i;\r
+       \r
+       // Gather mouse data\r
+       gaMouse_Bytes[giMouse_Cycle] = InputByte;\r
+       LOG("gaMouse_Bytes[%i] = 0x%02x", gMouse_Axies[0].MaxValue);\r
+       // - If bit 3 of the first byte is not set, it's not a valid packet?\r
+       if(giMouse_Cycle == 0 && !(gaMouse_Bytes[0] & 0x08) )\r
+               return ;\r
+       giMouse_Cycle++;\r
+       if(giMouse_Cycle < 3)\r
+               return ;\r
+\r
+       giMouse_Cycle = 0;\r
+\r
+       // Actual Processing (once we have all bytes)   \r
+       flags = gaMouse_Bytes[0];\r
+\r
+       LOG("flags = 0x%x", flags);\r
+       \r
+       // Check for X/Y Overflow\r
+       if(flags & 0xC0)        return;\r
+               \r
+       // Calculate dX and dY\r
+       d[0] = gaMouse_Bytes[1];        if(flags & 0x10) d[0] = -(256-d[0]);    // x\r
+       d[1] = gaMouse_Bytes[2];        if(flags & 0x20) d[1] = -(256-d[1]);    // y\r
+       d[1] = -d[1];   // Y is negated\r
+       LOG("RAW dx=%i, dy=%i\n", d[0], d[1]);\r
+       // Apply scaling\r
+       // TODO: Apply a form of curve to the mouse movement (dx*log(dx), dx^k?)\r
+       // TODO: Independent sensitivities?\r
+       // TODO: Disable acceleration via a flag?\r
+       d_accel[0] = d[0]*giMouse_Sensitivity;\r
+       d_accel[1] = d[1]*giMouse_Sensitivity;\r
+       \r
+       // Set Buttons (Primary)\r
+       for( i = 0; i < 3; i ++ )\r
+       {\r
+               Uint8   newVal = (flags & (1 << i)) ? 0xFF : 0;\r
+               if(newVal != gMouse_Buttons[i]) {\r
+                       if( gMouse_Callback )\r
+                               gMouse_Callback(gMouse_CallbackArg, 0, i, newVal - gMouse_Buttons[i]);\r
+                       gMouse_Buttons[i] = newVal;\r
+               }\r
+       }\r
+       \r
+       // Update X and Y Positions\r
+       for( i = 0; i < 2; i ++ )\r
+       {\r
+               Sint16  newCursor = 0;\r
+               if( giMouse_AxisLimits[i] )\r
+                       newCursor = MIN( MAX(0, gMouse_Axies[i].CursorPos + d_accel[i]), giMouse_AxisLimits[i] );;\r
+               \r
+               if( gMouse_Callback )\r
+               {\r
+                       if(giMouse_AxisLimits[i] && gMouse_Axies[i].CursorPos != newCursor)\r
+                               gMouse_Callback(gMouse_CallbackArg, 1, i, newCursor - gMouse_Axies[i].CursorPos);\r
+                       if(!giMouse_AxisLimits[i] && gMouse_Axies[i].CurValue != d_accel[i])\r
+                               gMouse_Callback(gMouse_CallbackArg, 1, i, d_accel[i] - gMouse_Axies[i].CurValue);\r
+               }\r
+               \r
+               gMouse_Axies[i].CurValue = d_accel[i];\r
+               gMouse_Axies[i].CursorPos = newCursor;\r
+       }\r
+\r
+//     Log("Mouse at %ix%i", gMouse_Axies[0].CursorPos, gMouse_Axies[1].CursorPos);\r
+               \r
+       VFS_MarkAvaliable(&gMouse_DriverStruct.RootNode, 1);\r
+}\r
+\r
+/* Read mouse state (coordinates)\r
+ */\r
+Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+       if(Offset > sizeof(gMouse_FileData))    return 0;\r
+       if(Length > sizeof(gMouse_FileData))    Length = sizeof(gMouse_FileData);\r
+       if(Offset + Length > sizeof(gMouse_FileData))   Length = sizeof(gMouse_FileData) - Offset;\r
+\r
+       memcpy(Buffer, &gMouse_FileData[Offset], Length);\r
+       \r
+       VFS_MarkAvaliable(Node, 0);\r
+       return Length;\r
+}\r
+\r
+static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};\r
+/* Handle messages to the device\r
+ */\r
+int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+       tJoystick_NumValue      *info = Data;\r
+\r
+       switch(ID)\r
+       {\r
+       BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);\r
+\r
+       case JOY_IOCTL_SETCALLBACK:     // TODO: Implement\r
+               return -1;\r
+       \r
+       case JOY_IOCTL_SETCALLBACKARG:  // TODO: Implement\r
+               return -1;\r
+       \r
+       case JOY_IOCTL_GETSETAXISLIMIT:\r
+               if(!info)       return 0;\r
+               if(info->Num < 0 || info->Num >= 2)     return 0;\r
+               if(info->Value != -1)\r
+                       giMouse_AxisLimits[info->Num] = info->Value;\r
+               return giMouse_AxisLimits[info->Num];\r
+       \r
+       case JOY_IOCTL_GETSETAXISPOSITION:\r
+               if(!info)       return 0;\r
+               if(info->Num < 0 || info->Num >= 2)     return 0;\r
+               if(info->Value != -1)\r
+                       gMouse_Axies[info->Num].CursorPos = info->Value;\r
+               return gMouse_Axies[info->Num].CursorPos;\r
+\r
+       case JOY_IOCTL_GETSETAXISFLAGS:\r
+               return -1;\r
+       \r
+       case JOY_IOCTL_GETSETBUTTONFLAGS:\r
+               return -1;\r
+\r
+       default:\r
+               return 0;\r
+       }\r
+}\r
+\r
diff --git a/KernelLand/Modules/Interfaces/EDI/Makefile b/KernelLand/Modules/Interfaces/EDI/Makefile
new file mode 100644 (file)
index 0000000..a93a8b7
--- /dev/null
@@ -0,0 +1,10 @@
+# 
+# EDI - Extensible Driver Interface
+# 
+# Acess Interface
+
+
+OBJ = main.o edi.o
+NAME = EDI
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/acess-edi.h b/KernelLand/Modules/Interfaces/EDI/edi/acess-edi.h
new file mode 100644 (file)
index 0000000..4071388
--- /dev/null
@@ -0,0 +1,41 @@
+/*! \file acess-edi.h
+ * \brief Acess Specific EDI Objects
+ * 
+ * Contains documentation and information for
+ * - Timers
+ */
+
+/* Copyright (c)  2006  John Hodge
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#ifndef ACESS_EDI_H
+#define ACESS_EDI_H
+
+#include "edi_objects.h"
+
+/// \brief Name of Acess EDI Time Class
+#define        ACESS_TIMER_CLASS       "ACESSEDI-TIMER"
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t ACESSEDI-TIMER.init_timer(uint32_t Delay, void (*Callback)(int), int Arg);
+ *
+ * Takes a timer pointer and intialises the timer object to fire after \a Delay ms
+ * When the timer fires, \a Callback is called with \a Arg passed to it.
+ */
+EDI_DEFVAR int32_t (*init_timer)(object_pointer port_object, uint32_t Delay, void (*fcn)(int), int arg);
+
+/*! \brief void ACESSEDI-TIMER.disable_timer();
+ * 
+ * Disables the timer and prevents it from firing
+ * After this has been called, the timer can then be initialised again.
+ */
+EDI_DEFVAR void (*disable_timer)(object_pointer port_object);
+
+
+#endif // defined(IMPLEMENTING_EDI)
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi.h b/KernelLand/Modules/Interfaces/EDI/edi/edi.h
new file mode 100644 (file)
index 0000000..273f7a3
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef EDI_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_H
+/*! \file edi.h
+ * \brief The unitive EDI header to include others, start EDI, and stop EDI.
+ *
+ * Data structures and algorithms this header represents:
+ *     DATA STRUCTURE: CLASS QUOTAS - The runtime and the driver have the right to set a quota on how many objects of a given class
+ * owned by that party the other may construct.  These quotas are kept internally by the driver or runtime, are optional and are
+ * exposed to the other party via the quota() function (for quotas of runtime-owned classes) and the k_quota() function pointer given
+ * to the runtime by the driver.
+ *
+ *     ALGORITHMS: INITIALIZATION AND SHUTDOWN - On initialization of the runtime's EDI environment for this driver it calls the
+ * driver's driver_init() routine (which must match driver_init_t) to initialize the driver with a list of EDI objects the runtime
+ * thinks the driver should run with.  The driver then initializes.  This can include calling edi_negotiate_resources() to try and
+ * obtain more or different objects.  Eventually driver_init() returns an edi_initialization_t structure containing its quota
+ * function and the list of classes belonging to the driver which the runtime can construct.  Either the driver or the runtime can
+ * shut down EDI by calling edi_shutdown(), which in turn calls the driver's driver_finish() routine.  On shutdown all objects, of
+ * classes belonging to both the runtime and driver, are destroyed. */
+
+#include "edi_objects.h"
+#include "edi_dma_streams.h"
+#include "edi_pthreads.h"
+#include "edi_port_io.h"
+#include "edi_memory_mapping.h"
+#include "edi_devices.h"
+#include "edi_interrupts.h"
+
+/*! \brief A pointer to a function the runtime can call if it fails to construct one of the driver's classes to find out what the
+ * runtime's quota is for that class.
+ *
+ * A pointer to a function which takes an edi_string_t as a parameter and returns in int32_t.  This function follows the same
+ * semantics as the quota() function, returning the number of objects of the given class that can be constructed, -1 for infinity or
+ * -2 for an erroneous class name.  It is used to tell the runtime the location of such a function in the driver so that the runtime
+ * can check quotas on driver-owned classes. */
+typedef int32_t (*k_quota_t)(edi_string_t resource_class);
+/*!\struct edi_initialization_t
+ * \brief Structure containing driver classes available to the runtime and the driver's quota function after the driver has initialized. 
+ *
+ * Structure containing driver classes available to runtime, the driver's quota function and the driver's name provided to the runtime
+ * after the driver has initialized.  driver_bus, vendor_id, and device_id are all optional fields which coders should consider
+ * supplementary information.  Kernels can require these fields if they so please, but doing so for devices which don't run on a Vendor
+ * ID/Product ID supporting bus is rather unwise. */
+typedef struct {
+       /*!\brief The number of driver classes in the driver_classes array. */
+       int32_t num_driver_classes;
+       /*!\brief An array of declarations of driver classes available to the runtime. 
+        *
+        * This array should not necessarily contain the entire list of EDI classes implemented by the driver.  Instead, it should
+        * contain a list of those classes which the driver has correctly initialized itself to provide instances of with full
+        * functionality. */
+       edi_class_declaration_t *driver_classes;
+       /*!\brief The driver's quota function. */
+       k_quota_t k_quota;
+       /*!\brief The driver's name. */
+       edi_string_t driver_name;
+       /*!\brief The bus of the device this driver wants to drive, if applicable.
+        *
+        * The driver does not have to supply this field, and can also supply "MULTIPLE BUSES" here to indicate that it drives devices
+        * on multiple buses. */
+       edi_string_t driver_bus;
+       /*!\brief The driver's vendor ID, if applicable.
+        *
+        * The driver does not need to supply this field, and should supply -1 to indicate that it does not wish to. */
+       int16_t vendor_id;
+       /*!\brief The driver's device ID, if applicable.
+        *
+        * The driver does not need to supply this field, but can supply it along with vendor_id.  If either vendor_id or this field are
+        * set to -1 the runtime should consider this field not supplied. */
+       int16_t driver_id;
+} edi_initialization_t;        
+/*!\brief A pointer to a driver's initialization function.
+ *
+ * The protocol for the driver's initialization function.  The runtime gives the driver a set of EDI objects representing the
+ * resources it thinks the driver should run with.  This function returns an edi_initialization_t structure containing declarations
+ * of the EDI classes the driver can make available to the runtime after initialization.  If any member of that structure contains 0
+ * or NULL, it is considered invalid and the runtime should destroy the driver without calling its driver_finish() routine. */
+typedef edi_initialization_t (*driver_init_t)(int32_t num_resources,edi_object_metadata_t *resources);
+/*!\brief Requests more resources from the runtime.  Can be called during driver initialization.
+ *
+ * Called to negotiate with the runtime for the right to create further EDI objects/obtain further resources owned by the runtime.
+ * When the driver calls this routine, the runtime decides whether to grant more resources.  If yes, this call returns true, and the
+ * driver can proceed to try and create the objects it desires, in addition to destroying EDI objects it doesn't want.  Otherwise,
+ * it returns false.
+ * The driver must deal with whatever value this routine returns. */
+bool edi_negotiate_resources();
+
+/*! \brief Returns the driver's quota of objects for a given runtime-owned class. 
+ *
+ * This function takes an edi_string_t with the name of a runtime-owned class in it and returns the number of objects of that class
+ * which drivers can construct, -1 for infinity, or -2 for an erroneous class name. */
+int32_t quota(edi_string_t resource_class);
+/*! \brief Sends a string to the operating systems debug output or logging facilities. */
+void edi_debug_write(uint32_t debug_string_length, char *debug_string);
+/*! \brief This call destroys all objects and shuts down the entire EDI environment of the driver. 
+ *
+ * This function shuts down EDI as described in INITIALIZATION AND SHUTDOWN above.  All objects are destroyed, EDI functions can no
+ * longer be successfully called, etc.  This function only succeeds when EDI has already been initialized, so it returns -1 when EDI
+ * hasn't been, 1 on success, or 0 for all other errors. */
+int32_t shutdown_edi(void);
+
+/*!\brief A pointer to the driver's finishing/shutdown function.
+ *
+ * The protocol for the driver's shutting down.  This function should do anything the driver wants done before it dies. */
+typedef void (*driver_finish_t)();
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_devices.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_devices.h
new file mode 100644 (file)
index 0000000..245e01f
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef EDI_DEVICES_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+/* Edited by thePowersGang (John Hodge) June 2009
+ * - Add #ifdef EDI_MAIN_FILE
+ */
+
+#define EDI_DEVICES_H
+
+/*! \file edi_devices.h
+ * \brief Declaration and description of simple classes for implementation by EDI drivers to represent hardware devices.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ *     DATA STRUCTURE AND ALGORITHM: BASIC DEVICES - There are two functions, select() for waiting on devices and ioctl() for
+ * controlling them, common to many POSIX devices.  Implementations of EDI-CHARACTER-DEVICE or EDI-BLOCK-DEVICE may implement either of
+ * these or both, and users of such objects much query for the methods to see if they're supported.  Obviously, runtime or driver
+ * developers don't *need* to support these.
+ *
+ *     DATA STRUCTURE AND ALGORITHM: CHARACTER DEVICES - The class EDI-CHARACTER-DEVICE provides a very basic interface to character
+ * devices, which read and write streams of characters.  As such, this class only provides read() and write().  The calls attempt a
+ * likeness to POSIX.
+ *
+ *     DATA STRUCTURE AND ALGORITHM: BLOCK DEVICES - The class EDI-BLOCK-DEVICE provides a very basic interface to block devices, which
+ * can read(), write() and seek() to blocks of a specific size in an array of blocks with a specific size.  Its declarations and
+ * semantics should behave like those of most POSIX operating systems.
+ *
+ * Note that EDI runtimes should not implement these classes.  Their declarations are provided for drivers to implement. */
+
+#include "edi_objects.h"
+
+/* Methods common to all EDI device classes specified in this header. */
+
+/*!\brief EAGAIN returned by functions for block and character devices.
+ *
+ * Means that the amount of data the device has ready is less than count. */
+#define EAGAIN -1
+/*!\brief EBADOBJ returned by functions for block and character devices.
+ *
+ * Means that the object passed as the method's this point was not a valid object of the needed class. */
+#define EBADOBJ -2
+/*!\brief EINVAL returned by functions for block and character devices.
+ *
+ * Means that the method got passed invalid parameters. */
+#ifdef EINVAL
+# undef EINVAL
+#endif
+#define EINVAL -3
+
+/*!\brief select() type to wait until device is writable. */
+#define EDI_SELECT_WRITABLE 0
+/*!\brief select() type to wait until device is readable. */
+#define EDI_SELECT_READABLE 1
+
+/*!\brief Argument to seek().  Sets the block offset (ie: the "current block" index) to the given whence value. */
+#define EDI_SEEK_SET 0
+/*!\brief Argument to seek().  Sets the block offset (ie: the "current block" index) to its current value + whence. */
+#define EDI_SEEK_CURRENT 1
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI's basic select() function. */
+edi_variable_declaration_t select_arguments[2] = {{"pointer void","device",1},
+                                                {"unsigned int32_t","select_type",1}};
+/*!\brief Declaration of EDI's basic select() function. 
+ *
+ * Contrary to the POSIX version, this select() puts its error codes in its return value. */
+edi_function_declaration_t select_declaration = {"int32_t","edi_device_select",0,2,select_arguments,NULL};
+#else
+extern edi_function_declaration_t select_declaration;  // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI's basic ioctl() function. */
+edi_variable_declaration_t ioctl_arguments[3] = {{"pointer void","device",1},{"int32_t","request",1},{"pointer void","argp",1}};
+/*!\brief Declaration of EDI's basic ioctl() function. 
+ *
+ * Contrary to the POSIX version, this ioctl() puts its error codes in its return value. */
+edi_function_declaration_t ioctl_declaration = {"int32_t","edi_device_ioctl",0,3,ioctl_arguments,NULL};
+#else
+extern edi_class_declaration_t ioctl_declaration;      // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Declaration of the arguments EDI-CHARACTER-DEVICE's read() and write() methods. */
+edi_variable_declaration_t chardev_read_write_arguments[3] = {{"pointer void","chardev",1},
+                                                             {"pointer void","buffer",1},
+                                                             {"unsigned int32_t","char_count",1}};
+/*!\brief Declarations of the methods of EDI-CHARACTER-DEVICE, read() and write().
+ *
+ * The code pointers of these function declarations are all given as NULL.  Driver developers implementing EDI-CHARACTER-DEVICE should
+ * fill in these entries with pointers to their own functions. */
+EDI_DEFVAR edi_function_declaration_t chardev_methods[2]= {{"int32_t","edi_chardev_read",0,3,chardev_read_write_arguments,NULL},
+                                               {"int32_t","edi_chardev_write",0,3,chardev_read_write_arguments,NULL}};
+/*!\brief Declaration of the EDI-CHARACTER-DEVICE class.
+ *
+ * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
+ * before passing the filled-in structure to the EDI runtime. */
+EDI_DEFVAR edi_class_declaration_t chardev_class = {"EDI-CHARACTER-DEVICE",0,2,chardev_methods,NULL,NULL,NULL};
+#else
+extern edi_class_declaration_t chardev_class;  // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI-BLOCK-DEVICE's read() and write() methods. */
+edi_variable_declaration_t blockdev_read_write_arguments[3] = {{"pointer void","blockdev",1},
+                                                              {"pointer void","buffer",1},
+                                                              {"unsigned int32_t","blocks",1}};
+/*!\brief Arguments to EDI-BLOCK-DEVICE's seek() method. */
+edi_variable_declaration_t blockdev_seek_arguments[3] = {{"pointer void","blockdev",1},
+                                                        {"int32_t","offset",1},
+                                                        {"int32_t","whence",1}};
+/*!\brief Declaration of the methods of EDI-BLOCK-DEVICE, read(), write(), seek(), and get_block_size(). 
+ *
+ * The code pointers of these function declarations are all given as NULL.  Driver developers implementing EDI-BLOCK-DEVICE should fill
+ * these entries in with pointers to their own functions. */
+edi_function_declaration_t blockdev_methods[4] = {{"int32_t","edi_blockdev_read",0,3,blockdev_read_write_arguments,NULL},
+                                                 {"int32_t","edi_blockdev_write",0,3,blockdev_read_write_arguments,NULL},
+                                                 {"int32_t","edi_blockdev_seek",0,3,blockdev_seek_arguments,NULL},
+                                                 {"unsigned int32_t","edi_blockdev_get_block_size",0,0,NULL,NULL}};
+/*!\brief Declaration of the EDI-BLOCK-DEVICE class.
+ *
+ * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
+ * before passing the filled-in structure to the EDI runtime. */
+edi_class_declaration_t blockdev_class = {"EDI-BLOCK-DEVICE",0,4,blockdev_methods,NULL,NULL,NULL};
+#else
+extern edi_class_declaration_t blockdev_class; // Declare for non main files
+#endif
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_dma_streams.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_dma_streams.h
new file mode 100644 (file)
index 0000000..8ab80cc
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef EDI_DMA_STREAMS_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_DMA_STREAMS_H
+
+/*! \file edi_dma_streams.h 
+ * \brief EDI's stream subclass for handling Direct Memory Access hardware.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ *     DATA STRUCTURE: DMA STREAMS - DMA streams are objects of the class EDI-STREAM-DMA used to pass data between a buffer of
+ * memory and the computer's DMA hardware.  It is the responsibility of the object to allocate memory for its stream memory buffer
+ * which can be used with DMA hardware and to program the DMA hardware for transmissions.  DMA streams can be bidirectional if the
+ * correct DMA mode is used. */
+
+#include "edi_objects.h"
+
+#define DMA_STREAM_CLASS       "EDI-STREAM-DMA"
+
+/*! \brief The name of the EDI DMA stream class.
+ *
+ * An edi_string_t with the class name "EDI-STREAM-DMA" in it. */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t dma_stream_class = DMA_STREAM_CLASS;
+#else
+extern const edi_string_t dma_stream_class;
+#endif
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t EDI-STREAM-DMA.init_dma_stream(unsigned int32_t channel,unsigned int32_t mode,unsigned int32_t buffer_pages);
+ *
+ * Pointer to the init_dma_stream() method of class EDI-STREAM-DMA, which initializes a DMA stream with a DMA channel, DMA mode, and
+ * the number of DMA-accessible memory pages to keep as a buffer.  It will only work once per stream object.  It's possible return
+ * values are 1 for sucess, -1 for invalid DMA channel, -2 for invalid DMA mode, -3 for inability to allocate enough buffer pages and
+ * 0 for all other errors. */
+EDI_DEFVAR  int32_t (*init_dma_stream)(object_pointer stream, uint32_t channel, uint32_t mode, uint32_t buffer_pages);
+/*! \brief int32_t EDI-STREAM-DMA.transmit(data_pointer *anchor,unsigned int32 num_bytes,bool sending);
+ *
+ * Pointer to the dma_stream_transmit() method of class EDI-STREAM-DMA, which transmits the given number of bytes of data through
+ * the DMA stream to/from the given anchor (either source or destination), in the given direction.  It returns 1 on success, -1 on
+ * an uninitialized or invalid DMA stream object, -2 when the anchor was NULL or otherwise invalid, -3 if the DMA stream can't
+ * transmit in the given direction, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*dma_stream_transmit)(object_pointer stream, data_pointer anchor, uint32_t num_bytes, bool sending);
+#endif
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_interrupts.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_interrupts.h
new file mode 100644 (file)
index 0000000..ef2ffc9
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef EDI_INTERRUPTS_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_INTERRUPTS_H
+
+/*! \file edi_interrupts.h
+ * \brief Declaration and description of EDI's interrupt handling class.
+ *
+ * Data structures and algorithms this header represents:
+ *     DATA STRUCTURE AND ALGORITHM: INTERRUPT OBJECTS - The class EDI-INTERRUPT encapsulates the handling of machine interrupts.
+ * It is initialized with an interrupt number to handle and a handler routine to call when that interrupt occurs.  Only a couple of
+ * guarantees are made to the driver regarding the runtime's implementation of interrupt handling: 1) That the driver's handler is
+ * called for every time the interrupt associated with a valid and initialized interrupt object occurs, in the order of the
+ * occurences, 2) That the runtime handle the architecture-specific (general to the entire machine, not just this device)
+ * end-of-interrupt code when the driver is called without first returning from the machine interrupt.  Note that the runtime hands
+ * out interrupt numbers at its own discretion and policy. */
+
+#include "edi_objects.h"
+
+/*! \brief Macro constant containing the name of the interrupt class
+ */
+#define INTERRUPTS_CLASS       "EDI-INTERRUPT"
+/*! \brief The name of EDI's interrupt-handling class.
+ *
+ * An edi_string_t holding the name of the runtime-implemented interrupt object class.  It's value is "EDI-INTERRUPT". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t interrupts_class = INTERRUPTS_CLASS;
+#else
+extern const edi_string_t interrupts_class;
+#endif
+
+/*! \brief A pointer to an interrupt handling function.
+ *
+ * A pointer to a function called to handle interrupts.  Its unsigned int32_t parameter is the interrupt number that is being
+ * handled. */
+typedef void (*interrupt_handler_t)(uint32_t interrupt_number);
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief Initializes an interrupt object with an interrupt number and a pointer to a handler function.
+ *
+ * A pointer to the init_interrupt() method of class EDI-INTERRUPT.  This method initializes a newly-created interrupt object with an
+ * interrupt number and a pointer to the driver's handler of type interrupt_handler_t.  It can only be called once per object, and
+ * returns 1 on success, fails with -1 when the interrupt number is invalid or unacceptable to the runtime, fails with -2 when the
+ * pointer to the driver's interrupt handler is invalid, and fails with -3 for all other errors. */
+EDI_DEFVAR int32_t (*init_interrupt)(object_pointer interrupt, uint32_t interrupt_number, interrupt_handler_t handler);
+/*! \brief Get this interrupt object's interrupt number. */
+EDI_DEFVAR uint32_t (*interrupt_get_irq)(object_pointer interrupt);
+/*! \brief Set a new handler for this interrupt object. */
+EDI_DEFVAR void (*interrupt_set_handler)(object_pointer interrupt, interrupt_handler_t handler);
+/*! \brief Return from this interrupt, letting the runtime run any necessary End-Of-Interrupt code.
+ *
+ * A pointer to the interrupt_return() method of class EDI-INTERRUPT.  This method returns from the interrupt designated by the
+ * calling interrupt object.  If there is a machine-wide end-of-interrupt procedure and the driver was called during the handling of
+ * the machine interrupt (as opposed to delaying the handling and letting the runtime EOI), the runtime runs it during this method.
+ * This method has no return value, since once it's called control leaves the calling thread. */
+EDI_DEFVAR void (*interrupt_return)(object_pointer interrupt);
+#endif
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_memory_mapping.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_memory_mapping.h
new file mode 100644 (file)
index 0000000..ba8dff3
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef EDI_MEMORY_MAPPING_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_MEMORY_MAPPING_H
+
+/*! \file edi_memory_mapping.h
+ * \brief Declaration and description of EDI's class for mapping physical pages into the driver's address space.
+ *
+ * Data structures and algorithms this header represents:
+ *     ALGORITHM: MEMORY MAPPINGS - Memory mapping objects of the class EDI-MEMORY-MAPPING are used to give virtual (driver-visible)
+ * addresses to sections of physical memory.  These can either be memory mappings belonging to hardware devices or plain RAM which
+ * the driver wants page-aligned.  A memory mapping object is initialized with the physical address for the memory mapping and the
+ * number of pages the mapping takes up, or simply the desired length of the a physically contiguous buffer in pages.  The class's
+ * two methods map the section of memory into and out of the driver's virtual address space. */
+
+#include "edi_objects.h"
+
+/*! \brief The name of EDI's memory mapping class.
+ *
+ * An edi_string_t with the name of the memory mapping class, "EDI-MEMORY-MAPPING". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t memory_mapping_class = "EDI-MEMORY-MAPPING";
+#else
+extern const edi_string_t memory_mapping_class;
+#endif
+
+/*! \brief Flag representing Strong Uncacheable caching method. */
+#define CACHING_STRONG_UNCACHEABLE 0
+/*! \brief Flag representing Uncacheable caching method. */
+#define CACHING_UNCACHEABLE 1
+/*! \brief Flag representing Write combining caching method. */
+#define CACHING_WRITE_COMBINING 2
+/*! \brief Flag representing Write Through caching method. */
+#define CACHING_WRITE_THROUGH 3
+/*! \brief Flag representing Write Back caching method. */
+#define CACHING_WRITE_BACK 3
+/*! \brief Flag representing Write Protected caching method. */
+#define CACHING_WRITE_PROTECTED 3
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief Initialize an EDI-MEMORY-MAPPING object with a physical address range.
+ *
+ * This method takes the start_physical_address of a memory mapping and the number of pages in that mapping and uses these arguments
+ * to initialize an EDI-MEMORY-MAPPING object.  It can only be called once per object.  It returns 1 when successful, -1 when an
+ * invalid physical address is given (one that the runtime knows is neither a physical memory mapping belonging to a device nor
+ * normal RAM), -2 when the number of pages requested is bad (for the same reasons as the starting address can be bad), and 0 for
+ * all other errors. 
+ *
+ * Note that this method can't be invoked on an object which has already initialized via init_memory_mapping_with_pages(). */
+EDI_DEFVAR int32_t (*init_memory_mapping_with_address)(object_pointer mapping, data_pointer start_physical_address, uint32_t pages);
+/*! \brief Initialize an EDI-MEMORY-MAPPING object by requesting a number of new physical pages.
+ *
+ * This method takes a desired number of physical pages for a memory mapping, and uses that number to initialize an
+ * EDI-MEMORY-MAPPING object by creating a buffer of contiguous physical pages.  It can only be called once per object.  It returns
+ * 1 when successful, -1 when the request for pages cannot be fulfilled, and 0 for all other errors.
+ *
+ * Note that this method cannot be called if init_memory_mapping_with_address() has already been used on the given object. */
+EDI_DEFVAR int32_t (*init_memory_mapping_with_pages)(object_pointer mapping, uint32_t pages);
+/*! \brief Map the memory-mapping into this driver's visible address space.
+ *
+ * This asks the runtime to map a given memory mapping into the driver's virtual address space.  Its parameter is the address of a
+ * data_pointer to place the virtual address of the mapping into.  This method returns 1 on success, -1 on an invalid argument, -2
+ * for an uninitialized object, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*map_in_mapping)(object_pointer mapping, data_pointer *address_mapped_to);
+/*! \brief Unmap the memory mapping from this driver's visible address space.
+ *
+ * This method tries to map the given memory mapping out of the driver's virtual address space.  It returns 1 for success, -1
+ * for an uninitialized memory mapping object, -2 if the mapping isn't mapped into the driver's address space already, and 0
+ * for all other errors. */
+EDI_DEFVAR int32_t (*map_out_mapping)(object_pointer mapping);
+
+/*! \brief Set the caching flags for a memory mapping. */
+EDI_DEFVAR void (*mapping_set_caching_method)(object_pointer mapping, uint32_t caching_method);
+/*! \brief Get the current caching method for a memory mapping. */
+EDI_DEFVAR uint32_t (*mapping_get_caching_method)(object_pointer mapping);
+/*! \brief Flush write-combining buffers on CPU to make sure changes to memory mapping actually get written.  Only applies to a Write Combining caching method (I think.).*/
+EDI_DEFVAR void (*flush_write_combining_mapping)(object_pointer mapping);
+#endif
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_objects.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_objects.h
new file mode 100644 (file)
index 0000000..0e47951
--- /dev/null
@@ -0,0 +1,257 @@
+#ifndef EDI_OBJECTS_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_OBJECTS_H
+
+/*! \file edi_objects.h
+ * \brief The header file for basic EDI types and the object system.
+ *
+ * This file contains declarations of EDI's primitive data types, as well as structures and functions for with the object system.
+ * It represents these data structures and algorithms:
+ * 
+ *     DATA STRUCTURE: THE CLASS LIST - EDI implementing runtime's must keep an internal list of classes implemented by the runtime
+ *     and separate lists of classes implemented by each driver.  Whoever implements a class is said to "own" that class.  The
+ *     internal format of this list is up to the runtime coders, but it must be possible to recreate the original list of
+ *     edi_class_declaration structures the driver declared to the runtime from it.  This list is declared to the runtime in an
+ *     initialization function in the header edi.h.  The object_class member of an edi_object_metadata structure must point to that
+ *     object's class's entry in this list.
+ *     
+ *     ALGORITHM AND DATA STRUCTURE: CLASSES AND INHERITANCE - Classes are described using edi_class_declaration_t structures and
+ *     follow very simple rules.  All data is private and EDI provides no way to access instance data, so there are no member
+ *     variable declarations.  However, if the data isn't memory-protected (for example, driver data on the driver heap) EDI allows
+ *     the possibility of pointer access to data, since runtime and driver coders could make use of that behavior.  Classes may have
+ *     one ancestor by declaring so in their class declaration structure, and if child methods are different then parent methods
+ *     the children always override their parents.  An EDI runtime must also be able to check the existence and ownership of a given
+ *     class given its name in an edi_string_t.
+ *     
+ *     ALGORITHM: OBJECT CREATION AND DESTRUCTION - An EDI runtime should be able to call the constructor of a named class, put the
+ *     resulting object_pointer into an edi_object_metadata_t and return that structure.  The runtime should also be able to call an
+ *     object's class's destructor when given a pointer to a valid edi_metadata_t for an already-existing object.  Data equivalent
+ *     to an edi_object_metadata_t should also be tracked by the runtime for every object in existence in case of sudden EDI shutdown
+ *     (see edi.h).
+ *
+ *     ALGORITHM: RUNTIME TYPE INFORMATION - When passed the data_pointer member of an edi_object_metadata_t to a valid object, an
+ *     EDI runtime must be able to return an edi_string_t containing the name of that object's class and to return function_pointers
+ *     to methods when the required information to find the correct method is given by calling a class's method getting function.*/
+
+/* If the EDI headers are linked with the standard C library, they use its type definitions.  Otherwise, equivalent definitions are
+ * made.*/
+#if __STDC_VERSION__ == 199901L
+# include <stdbool.h>
+# include <stdint.h>
+#else
+# ifndef NULL
+#  define      NULL    ((void*)0)
+# endif
+typedef unsigned char bool;
+# define true 1
+# define false 0
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef long long int64_t;
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long  uint32_t;
+typedef unsigned long long     uint64_t;
+#endif
+
+/*! \brief Define a variable in the header
+ */
+#ifdef EDI_MAIN_FILE
+# define EDI_DEFVAR
+#else
+# define EDI_DEFVAR    extern
+#endif
+
+/*! \brief A pointer to the in-memory instance of an object.
+ *
+ * This type is sized just like a general C pointer type (whatever*) for the target architecture.  It's passed as a first parameter
+ * to all methods, thus allowing EDI classes to be implemented as C++ classes and providing some protection from confusing objects
+ * with normal pointers.  Equivalent to a C++ this pointer or an Object Pascal Self argument. */
+typedef void *object_pointer;
+/*! \brief A basic pointer type pointing to arbitrary data in an arbitrary location. */
+typedef void *data_pointer;
+/*! \brief A basic function pointer type.
+ *
+ * A pointer to a piece of code which can be called and return to its caller, used to distinguish between pointers to code and
+ * pointers to data.  Its size is hardware-dependent. */
+typedef void (*function_pointer)(void);
+/*! \brief The length of an EDI string without its null character. */
+#define EDI_STRING_LENGTH 31
+/*! \brief A type representing a 31-character long string with a terminating NULL character at the end.  All of EDI uses this type
+ * for strings.
+ *
+ * A null-terminated string type which stores characters in int8s.  It allows for 31 characters in each string, with the final
+ * character being the NULL terminator.  Functions which use this type must check that its final character is NULL, a string which
+ * doesn't not have this property is invalid and insecure.  I (the author of EDI) know and understand that this form of a string
+ * suffers from C programmer's disease, but I can't use anything else without either making string use far buggier or dragging
+ * everyone onto a better language than C.  */
+typedef int8_t edi_string_t[0x20];
+/*! \brief A type representing a pointer form of #edi_string_t suitable for function returns
+ */
+typedef int8_t *edi_string_ptr_t;
+
+/*! \var EDI_BASE_TYPES
+ * \brief A constant array of edi_string_t's holding every available EDI primitive type. */
+/*! \var EDI_TYPE_MODIFIERS
+ * \brief A constant array of edi_string_t's holding available modifiers for EDI primitive types. */
+#ifdef IMPLEMENTING_EDI
+ const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg","edi_string_t"};
+ const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
+#else
+ //extern const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg", "edi_string_t"};
+ //extern const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
+ extern const edi_string_t EDI_BASE_TYPES[9];
+ extern const edi_string_t EDI_TYPE_MODIFIERS[2];
+#endif
+
+/*! \struct edi_object_metadata_t
+ * \brief A packed structure holding all data to identify an object to the EDI object system. */
+typedef struct {
+       /*! \brief Points to the instance data of the object represented by this structure.
+        *
+        * An object_pointer to the object this structure refers to.  The this pointer, so to speak. */
+       object_pointer object;
+       /*! \brief Points the internal record kept by the runtime describing the object's class.
+        *
+        * Points to wherever the runtime has stored the class data this object was built from.  The class data doesn't need to be
+        * readable to the driver, and so this pointer can point to an arbitrary runtime-reachable location. */
+       data_pointer object_class;
+} edi_object_metadata_t;
+
+/*! \struct edi_variable_declaration_t
+ * \brief The data structure used to describe a variable declaration to the EDI object system.
+ *
+ * The data structure used to describe a variable declaration to the EDI object system.  The context of the declaration depends on
+ * where the data structure appears, ie: alone, in a class declaration, in a parameter list, etc. */
+typedef struct {
+       /*! \brief The type of the declared variable. 
+        *
+        * The type of the variable, which must be a valid EDI primitive type as specified in the constant EDI_BASE_TYPES and
+        * possibly modified by a modifier specified in the constant EDI_TYPE_MODIFIERS. */
+       edi_string_t type;
+       /*! \brief The name of the declared variable. */
+       edi_string_t name;
+       /*! \brief Number of array entries if this variable is an array declaration. 
+        *
+        * An int32_t specifying the number of variables of 'type' in the array 'name'.  For a single variable this value should
+        * simply be set to 1, for values greater than 1 a packed array of contiguous variables is being declared, and a value of 0
+        * is invalid. */
+       int32_t array_length;
+} edi_variable_declaration_t;
+
+/*! \struct edi_function_declaration_t
+ * \brief The data structure used to declare a function to the EDI object system. */
+typedef struct {
+       /*! \brief The return type of the function.  The same type rules which govern variable definitions apply here. */
+       edi_string_t return_type;
+       /*! \brief The name of the declared function. */
+       edi_string_t name;
+       /*! \brief The version number of the function, used to tell different implementations of the same function apart. */
+       uint32_t version;
+       /*! \brief The number of arguments passed to the function.
+        *
+        * The number of entries in the member arguments that the object system should care about.  Caring about less misses
+        * parameters to functions, caring about more results in buffer overflows. */
+       uint32_t num_arguments;
+       /*! \brief An array of the declared function's arguments.
+        *
+        * A pointer to an array num_arguments long containing edi_variable_declaration_t's for each argument to the declared
+        * function.*/
+       edi_variable_declaration_t *arguments;
+       /*!\brief A pointer to the declared function's code in memory. */
+       function_pointer code;
+} edi_function_declaration_t;
+
+/*! \brief A pointer to a function for constructing instances of a class.
+ *
+ * A pointer to a function which takes no parameters and returns an object_pointer pointing to the newly made instance of a class.
+ * It is the constructor's responsibility to allocate memory for the new object.  Each EDI class needs one of these. */
+typedef object_pointer (*edi_constructor_t)(void);
+/*! \brief A pointer to a function for destroying instances of a class.
+ *
+ * A pointer to a function which takes an object_pointer as a parameter and returns void.  This is the destructor counterpart to a
+ * class's edi_constructor_t, it destroys the object pointed to by its parameter and frees the object's memory.  Every class must
+ * have one */
+typedef void (*edi_destructor_t)(object_pointer);
+
+/*! \brief Information the driver must give the runtime about its classes so EDI can construct them and call their methods.
+ *
+ * A structure used to declare a class to an EDI runtime so instances of it can be constructed by the EDI object system. */
+typedef struct {
+       /*! \brief The name of the class declared by the structure. */
+       edi_string_t name;
+       /*! \brief The version of the class.  This number is used to tell identically named but differently
+        * implemented classes apart.*/
+       uint32_t version;
+       /*! \brief The number of methods in the 'methods' function declaration array. */
+       uint32_t num_methods;
+       /*! \brief An array of edi_function_declaration_t declaring the methods of this class. */
+       edi_function_declaration_t *methods;
+       /*! \brief Allocates the memory for a new object of the declared class and constructs the object.  Absolutely required.*/
+       edi_constructor_t constructor;
+       /*! \brief Destroys the given object of the declared class and frees its memory. Absolutely required. */
+       edi_destructor_t destructor;
+       /*! \brief A pointer to another EDI class declaration structure specifying the declared class's parent class. 
+        *
+        * Points to a parent class declared in another class declaration.  It can be NULL to mean this class has no parent. */
+       struct edi_class_declaration_t *parent;
+} edi_class_declaration_t;
+
+/*! \brief Checks the existence of the named class.
+ *
+ * This checks for the existence on THE CLASS LIST of the class named by its edi_string_t parameter and returns a signed int32_t.  If
+ * the class isn't found (ie: it doesn't exist as far as EDI is concerned) -1 is returned, if the class is owned by the driver
+ * (implemented by the driver and declared to the runtime by the driver) 0, and if the class is owned by the runtime (implemented by
+ * the runtime) 1. */
+int32_t check_class_existence(edi_string_t class_name);
+/*! \brief Constructs an object of the named class and returns its object_pointer and a data_pointer to its class data.
+ *
+ * Given a valid class name in an edi_string_t this function constructs the specified class and returns an edi_metadata_t describing
+ * the new object as detailed in OBJECT CREATION AND DESTRUCTION.  If the construction fails it returns a structure full of NULL
+ * pointers. */
+edi_object_metadata_t construct_object(edi_string_t class_name);
+/*! \brief Destroys the given object using its class data.
+ *
+ * As specified in OBJECT CREATION AND DESTRUCTION this function should destroy an object when given its valid edi_metadata_t.  The
+ * destruction is accomplished by calling the class's destructor. */
+void destroy_object(edi_object_metadata_t object);
+/*! \brief Obtains a function pointer to a named method of a given class. 
+ *
+ * When given a valid data_pointer object_class from an edi_object_metadata_t and an edi_string_t representing the name of the
+ * desired method retrieves a function_pointer to the method's machine code in memory.  If the desired method isn't found, NULL is
+ * returned. */
+function_pointer get_method_by_name(data_pointer object_class,edi_string_t method_name);
+/*! \brief Obtains a function pointer to a method given by a declaration of the given class if the class's method matches the
+ * declaration. 
+ *
+ * Works just like get_method_by_name(), but by giving an edi_function_declaration_t for the desired method instead of just its name.
+ * Performs detailed checking against THE CLASS LIST to make sure that the method returned exactly matches the declaration passed
+ * in. */
+function_pointer get_method_by_declaration(data_pointer object_class,edi_function_declaration_t declaration);
+
+/* Runtime typing information. */
+/*! \brief Returns the name of the class specified by a pointer to class data. 
+ *
+ * Given the data_pointer to an object's class data as stored in an edi_object_metadata_t retrieves the name of the object's class
+ * and returns it in an edi_string_t. */
+edi_string_ptr_t get_object_class(data_pointer object_class);
+/*! \brief Returns the name of a class's parent class.
+ *
+ * When given an edi_string_t with a class name in it, returns another edi_string_t containing the name of the class's parent, or an
+ * empty string. */
+edi_string_ptr_t get_class_parent(edi_string_t some_class);
+/*! \brief Returns the internal class data of a named class (if it exists) or NULL.
+ *
+ * When given an edi_string_t with a valid class name in it, returns a pointer to the runtime's internal class data for that class.
+ * Otherwise, it returns NULL. */
+data_pointer get_internal_class(edi_string_t some_class);
+
+#endif 
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_port_io.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_port_io.h
new file mode 100644 (file)
index 0000000..a2a1773
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef EDI_PORT_IO_H
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+/* Modified by thePowersGang (John Hodge)
+ * - Surround variable definitions with an #ifdef IMPLEMENTING_EDI
+ */
+
+#define EDI_PORT_IO_H
+
+/*! \file edi_port_io.h
+ * \brief Declaration and description of EDI's port I/O class.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ *     DATA STRUCTURE AND ALGORITHM: PORT I/O OBJECTS - A class named "EDI-IO-PORT" is defined as an encapsulation of the port I/O
+ * used on some machine architectures.  Each object of this class represents a single I/O port which can be read from and written to
+ * in various sizes.  Each port can be held by one object only at a time. */
+
+#include "edi_objects.h"
+
+/*! \brief Macro to create methods for reading from ports.
+ *
+ * This macro creates four similar methods, differing in the size of the type they read from the I/O port held by the object.  Their
+ * parameter is a pointer to the output type, which is filled with the value read from the I/O port.  They return 1 for success, -1
+ * for an uninitialized I/O port object, and 0 for other errors. */
+#define port_read_method(type,name) int32_t (*name)(object_pointer port_object, type *out)
+/*! \brief Macro to create methods for writing to ports.
+ *
+ * This macro creates four more similar methods, differing in the size of the type they write to the I/O port held by the object.
+ * Their parameter is the value to write to the port.  They return 1 for success, -1 for an uninitialized I/O port object and 0 for
+ * other errors. */
+#define port_write_method(type,name) int32_t (*name)(object_pointer port_object, type in)
+
+/*! \brief Name of EDI I/O port class. (Constant)
+ *
+ * A CPP constant with the value of #io_port_class */
+#define        IO_PORT_CLASS   "EDI-IO-PORT"
+/*! \brief Name of EDI I/O port class.
+ *
+ * An edi_string_t containing the class name "EDI-IO-PORT". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t io_port_class = IO_PORT_CLASS;
+#else
+extern const edi_string_t io_port_class;
+#endif
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t EDI-IO-PORT.init_io_port(unsigned int16_t port);
+ *
+ * This method takes an unsigned int16_t representing a particular I/O port and initializes the invoked EDI-IO-PORT object with it.
+ * The method returns 1 if successful, -1 if the I/O port could not be obtained for the object, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*init_io_port)(object_pointer port_object, uint16_t port);
+/*! \brief Get the port number from a port object. */
+EDI_DEFVAR uint16_t (*get_port_number)(object_pointer port);
+/*! \brief Method created by port_read_method() in order to read bytes (int8s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_byte_io_port)(object_pointer port_object, int8_t *out);
+/*! \brief Method created by port_read_method() in order to read words (int16s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_word_io_port)(object_pointer port_object, int16_t *out);
+/*! \brief Method created by port_read_method() in order to read longwords (int32s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_long_io_port)(object_pointer port_object, int32_t *out);
+/*! \brief Method created by port_read_method() in order to read long longwords (int64s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_longlong_io_port)(object_pointer port_object,int64_t *out);
+/*! \brief Method of EDI-IO-PORT to read long strings of data from I/O ports.
+ *
+ * Reads arbitrarily long strings of data from the given I/O port.  Returns 1 for success, -1 for an uninitialized port object, -2
+ * for a bad pointer to the destination buffer, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*read_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *out);
+/*! \brief Method created by port_write_method() in order to write bytes (int8s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_byte_io_port)(object_pointer port_object, int8_t in);
+/*! \brief Method created by port_write_method() in order to write words (int16s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_word_io_port)(object_pointer port_object, int16_t in);
+/*! \brief Method created by port_write_method() in order to write longwords (int32s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_long_io_port)(object_pointer port_object, int32_t in);
+/*! \brief Method created by port_write_method() in order to write long longwords (int64s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_longlong_io_port)(object_pointer port_object, int64_t in);
+/*! \brief Method of EDI-IO-PORT to write long strings of data to I/O ports.
+ *
+ * Writes arbitrarily long strings of data to the given I/O port.  Returns 1 for success, -1 for an uninitialized port object, -2
+ * for a bad pointer to the source buffer, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*write_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *in);
+
+#endif // defined(IMPLEMENTING_EDI)
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/edi_pthreads.h b/KernelLand/Modules/Interfaces/EDI/edi/edi_pthreads.h
new file mode 100644 (file)
index 0000000..c21fa75
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef EDI_PTHREADS
+
+/* Copyright (c)  2006  Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts.  A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_PTHREADS
+/*!\file edi_pthreads.h
+ * \brief A basic subset of POSIX Threads functionality, providing threading and thread synchronization.
+ *
+ * A very basic POSIX Threads interface.  Note that pthreads are not a class, because none of these calls really gels with
+ * object-oriented programming.  Also, if drivers aren't processes or threads under the implementing operating system a small
+ * threading system must be implemented in-runtime just to multiplex the pthreads of EDI drivers.  Sorry about that.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ *     ALGORITHM AND DATA STRUCTURE: POSIX Threading - The runtime must provide enough of a POSIX threading interface to implement
+ * the calls described here.  The actual multithreading must be performed by the runtime, and the runtime can implement that
+ * multithreading however it likes as long as the given POSIX Threads subset works.  There is, however, a caveat: since the runtime
+ * calls the driver like it would a library, the driver must perceive all calls made to it by the runtime as running under one thread.
+ * From this thread the driver can create others.  Such behavior is a quirk of EDI, and does not come from the POSIX standard.
+ * However, it is necessary to provide the driver with a thread for its own main codepaths.  For further details on a given POSIX
+ * Threading routine, consult its Unix manual page. */
+
+#include "edi_objects.h"
+
+/* Placeholder type definitions.  Users of the PThreads interface only ever need to define pointers to these types. */
+/*!\brief Opaque POSIX Threading thread attribute type. */
+typedef void pthread_attr_t;
+/*!\brief Opaque POSIX Threading mutex (mutual exclusion semaphore) type. */
+typedef void pthread_mutex_t;
+/*!\brief Opaque POSIX Threading mutex attribute type. */
+typedef void pthread_mutex_attr_t;
+
+/*!\struct sched_param
+ * \brief POSIX Threading scheduler parameters for a thread. */
+typedef struct {
+       /*!\brief The priority of the thread. */
+       int32_t sched_priority;
+} sched_param;
+
+/*!\brief POSIX Threading thread identifier. */
+typedef uint32_t pthread_t;
+/*!\brief POSIX Threading thread function type.
+ *
+ * A function pointer to a thread function, with the required signature of a thread function.  A thread function takes one untyped
+ * pointer as an argument and returns an untyped pointer.  Such a function is a thread's main routine: it's started with the thread,
+ * and the thread exits if it returns. */
+typedef void *(*pthread_function_t)(void*);
+
+/*!\brief Insufficient resources. */
+#define EAGAIN -1
+/*!\brief Invalid parameter. */
+#define EINVAL -2
+/*!\brief Permission denied. */
+#define EPERM -3
+/*!\brief Operation not supported. */
+#define ENOTSUP -4
+/*!\brief Priority scheduling for POSIX/multiple schedulers is not implemented. */
+#define ENOSYS -5
+/*!\brief Out of memory. */
+#define ENOMEM -6
+/*!\brief Deadlock.  Crap. */
+#define EDEADLK -7
+/*!\brief Busy.  Mutex already locked. */
+#define EBUSY -8
+
+/*!\brief Scheduling policy for regular, non-realtime scheduling.  The default. */
+#define SCHED_OTHER 0
+/*!\brief Real-time, first-in first-out scheduling policy.  Requires special (superuser, where such a thing exists) permissions. */
+#define SCHED_FIFO 1
+/*!\brief Real-time, round-robin scheduling policy.  Requires special (superuser, where such a thing exists) permissions. */
+#define SCHED_RR 0
+
+/*!\brief Creates a new thread with the given attributes, thread function and arguments, giving back the thread ID of the new
+ * thread.
+ *
+ * pthread_create() creates a new thread of control that executes concurrently with the calling thread.  The new thread applies the
+ * function start_routine, passing it arg as its argument.  The attr argument specifies thread attributes to apply to the new thread;
+ * it can also be NULL for the default thread attributes (joinable with default scheduling policy).  On success this function returns
+ * 0 and places the identifier of the new thread into thread_id.  On an error, pthread_create() can return EAGAIN if insufficient
+ * runtime resources are available to create the requested thread, EINVAL a value specified by attributes is invalid, or EPERM if the
+ * caller doesn't have permissions to set the given attributes.
+ *
+ * For further information: man 3 pthread_create */
+int32_t pthread_create(pthread_t *thread_id, const pthread_attr_t *attributes, pthread_function_t thread_function, void *arguments);
+/*!\brief Terminates the execution of the calling thread.  The thread's exit code with by status, and this routine never returns. */
+void pthread_exit(void *status);
+/*!\brief Returns the thread identifier of the calling thread. */
+pthread_t pthread_self();
+/*!\brief Compares two thread identifiers.
+ *
+ * Determines of the given two thread identifiers refer to the same thread.  If so, returns non-zero.  Otherwise, 0 is returned. */
+int32_t pthread_equal(pthread_t thread1, pthread_t thread2);
+/*!\brief Used by the calling thread to relinquish use of the processor.  The thread then waits in the run queue to be scheduled
+ * again. */
+void pthread_yield();
+
+/*!\brief Gets the scheduling policy of the given attributes.
+ *
+ * Places the scheduling policy for attributes into policy.  Returns 0 on success, EINVAL if attributes was invalid, and ENOSYS if
+ * priority scheduling/multiple scheduler support is not implemented. */
+int32_t pthread_attr_getschedpolicy(const pthread_attr_t *attributes, int32_t *policy);
+/*!\brief Sets the scheduling policy of the given attributes.
+ *
+ * Requests a switch of scheduling policy to policy for the given attributes.  Can return 0 for success, EINVAL if the given policy
+ * is not one of SCHED_OTHER, SCHED_FIFO or SCHED_RR or ENOTSUP if policy is either SCHED_FIFO or SCHED_RR and the driver is not
+ * running with correct privileges. */
+int32_t pthread_attr_setschedpolicy(pthread_attr_t *attributes, int32_t policy);
+
+/*!\brief Gets the scheduling paramaters (priority) from the given attributes.
+ *
+ * On success, stores scheduling parameters in param from attributes, and returns 0.  Otherwise, returns non-zero error code, such
+ * as EINVAL if the attributes object is invalid. */
+int32_t pthread_attr_getschedparam(const pthread_attr_t *attributes, sched_param *param);
+/*!\brief Sets the scheduling parameters (priority) of the given attributes.
+ *
+ * Requests that the runtime set the scheduling parameters (priority) of attributes from param. Returns 0 for success, EINVAL for an
+ * invalid attributes object, ENOSYS when multiple schedulers/priority scheduling is not implemented, and ENOTSUP when the value of
+ * param isn't supported/allowed. */
+int32_t pthread_attr_setschedparam(pthread_attr_t *attributes, const sched_param *param);
+
+/*!\brief The thread obtains its scheduling properties explicitly from its attributes structure. */
+#define PTHREAD_EXPLICIT_SCHED 1
+/*!\brief The thread inherits its scheduling properties from its parent thread. */
+#define PTHREAD_INHERIT_SCHED 0
+
+/*!\brief Returns the inheritsched attribute of the given attributes.
+ *
+ * On success, returns 0 and places the inheritsched attribute from attributes into inherit.  This attribute specifies where the
+ * thread's scheduling properites shall come from, and can be set to PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED.  On failure it
+ * returns EINVAL if attributes was invalid or ENOSYS if multiple schedulers/priority scheduling isn't implemented. */
+int32_t pthread_attr_getinheritsched(const pthread_attr_t *attributes, int32_t *inherit);
+/*!\brief Sets the inheritsched attribute of the given attributes.
+ *
+ * On success, places inherit into the inheritsched attribute of attributes and returns 0.  inherit must either contain
+ * PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED.  On failure, this routine returns EINVAL if attributes is invalid, ENOSYS when
+ * multiple schedulers/priority scheduling isn't implemented, and ENOSUP if the inheritsched attribute isn't supported. */
+int32_t pthread_attr_setinheritsched(pthread_attr_t *attributes, int32_t inherit);
+
+/*!\brief Creates a new POSIX Threads mutex, which will initially be unlocked.
+ *
+ * Creates a new mutex with the given attributes.  If attributes is NULL, the default attributes will be used.  The mutex starts out
+ * unlocked.  On success, the new mutex resides in the mutex structure pointed to by mutex, and this routine routines 0.  On failure,
+ * it returns EAGAIN if the system lacked sufficient non-memory resources to initialize the mutex, EBUSY if the given mutex is
+ * already initialized and in use, EINVAL if either parameter is invalid, and ENOMEM if the system lacks the memory for a new
+ * mutex.  Note: All EDI mutexes are created with the default attributes, and are of type PTHREAD_MUTEX_ERRORCHECK.  This means
+ * undefined behavior can never result from an badly placed function call. */
+int32_t pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *attributes);
+/*!\brief Locks the given mutex.
+ *
+ * Locks the given mutex.  If the mutex is already locked, blocks the calling thread until it can acquire the lock.  When this
+ * routine returns successfully, it will return 0 and the calling thread will own the lock of the mutex.  If the call fails, it can
+ * return EINVAL when mutex is invalid or EDEADLK if the calling thread already owns the mutex. */
+int32_t pthread_mutex_lock(pthread_mutex_t *mutex);
+/*!\brief Unlocks the given mutex.
+ *
+ * Unlocks the given mutex, returning 0 on success.  On failure, it can return EINVAL when mutex is invalid or EPERM when the
+ * calling thread doesn't own the mutex. */
+int32_t pthread_mutex_unlock(pthread_mutex_t *mutex);
+/*!\brief Tries to lock the given mutex, returning immediately even if the mutex is already locked.
+ *
+ * Attempts to lock the given mutex, but returns immediately if it can't acquire a lock.  Returns 0 when it has acquired a lock,
+ * EBUSY if the mutex is already locked, or EINVAL if mutex is invalid. */
+int32_t pthread_mutex_trylock(pthread_mutex_t *mutex);
+/*!\brief Destroys the given mutex, or at least the internal structure of it. 
+ *
+ * Deletes the given mutex, making mutex invalid until it should be initialized by pthread_mutex_init().  Returns 0 on success,
+ * EINVAL when mutex is invalid, or EBUSY when mutex is locked or referenced by another thread. */
+int32_t pthread_mutex_destroy (pthread_mutex_t *mutex);
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi/helpers.h b/KernelLand/Modules/Interfaces/EDI/edi/helpers.h
new file mode 100644 (file)
index 0000000..d7bc138
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef HELPERS_H
+
+#define HELPERS_H
+
+#include <edi.h>
+
+// Locally Defined
+bool edi_string_equal(edi_string_t x,edi_string_t y);
+bool descends_from(data_pointer object_class,edi_string_t desired_class);
+data_pointer get_actual_class(edi_string_t ancestor,int32_t num_objects,edi_object_metadata_t *objects);
+
+// Local Copy/set
+void *memcpyd(void *dest, void *src, unsigned int count);
+
+// Implementation Defined Common functions
+void *memcpy(void *dest, void *src, unsigned int count);
+void *memmove(void *dest, void *src, unsigned int count);
+void *realloc(void *ptr, unsigned int size);
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/EDI/edi_int.inc.c b/KernelLand/Modules/Interfaces/EDI/edi_int.inc.c
new file mode 100644 (file)
index 0000000..0ab3359
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * AcessOS EDI Interface
+ * - IRQ Class
+ * 
+ * By John Hodge (thePowersGang)
+ * 
+ * This file has been released into the public domain.
+ * You are free to use it as you wish.
+ */
+#include "edi/edi.h"
+
+// === TYPES ===
+typedef struct {
+       uint16_t        State;  // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
+       uint16_t        Num;
+       interrupt_handler_t     Handler;
+} tEdiIRQ;
+
+// === PROTOTYPES ===
+void EDI_Int_IRQ_Handler(tRegs *Regs);
+
+// === GLOBALS ===
+tEdiIRQ        gEdi_IRQObjects[16];
+
+// === FUNCTIONS ===
+/**
+ * \fn object_pointer Edi_Int_IRQ_Construct(void)
+ * \brief Creates a new IRQ Object
+ * \return     Pointer to object
+ */
+object_pointer Edi_Int_IRQ_Construct(void)
+{
+        int    i;
+       // Search for a free irq
+       for( i = 0; i < 16; i ++ )
+       {
+               if(gEdi_IRQObjects[i].State)    continue;
+               gEdi_IRQObjects[i].State = 1;
+               gEdi_IRQObjects[i].Num = 0;
+               gEdi_IRQObjects[i].Handler = NULL;
+               return &gEdi_IRQObjects[i];
+       }
+       return NULL;
+}
+
+/**
+ * \fn void Edi_Int_IRQ_Destruct(object_pointer Object)
+ * \brief Destruct an IRQ Object
+ * \param Object       Object to destroy
+ */
+void Edi_Int_IRQ_Destruct(object_pointer Object)
+{
+       tEdiIRQ *obj;
+       
+       VALIDATE_PTR(Object,);
+       obj = GET_DATA(Object);
+       
+       if( !obj->State )       return;
+       
+       if( obj->Handler )
+               irq_uninstall_handler( obj->Num );
+       
+       if( obj->State & 0x8000 ) {     // If in heap, free
+               free(Object);
+       } else {        // Otherwise, mark as unallocated
+               obj->State = 0;
+       }
+}
+
+/**
+ * \fn int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
+ * \brief Initialises an IRQ
+ * \param Object       Object Pointer (this)
+ * \param Num  IRQ Number to use
+ * \param Handler      Callback for IRQ
+ */
+int32_t        Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
+{
+       tEdiIRQ *obj;
+       
+       //LogF("Edi_Int_IRQ_InitInt: (Object=0x%x, Num=%i, Handler=0x%x)\n", Object, Num, Handler);
+       
+       VALIDATE_PTR(Object,0);
+       obj = GET_DATA(Object);
+       
+       if( !obj->State )       return 0;
+       
+       if(Num > 15)    return 0;
+       
+       // Install the IRQ if a handler is passed
+       if(Handler) {
+               if( !irq_install_handler(Num, Edi_Int_IRQ_Handler) )
+                       return 0;
+               obj->Handler = Handler;
+       }
+       
+       obj->Num = Num;
+       obj->State &= ~0x3FFF;
+       obj->State |= 2;        // Set initialised flag
+       return 1;
+}
+
+/**
+ * \fn uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
+ * \brief Returns the irq number associated with the object
+ * \param Object       IRQ Object to get number from
+ * \return IRQ Number
+ */
+uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
+{
+       tEdiIRQ *obj;
+       
+       VALIDATE_PTR(Object,0);
+       obj = GET_DATA(Object);
+       
+       if( !obj->State )       return 0;
+       return obj->Num;
+}
+
+/**
+ * \fn void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
+ * \brief Set the IRQ handler for an IRQ object
+ * \param Object       IRQ Object to alter
+ * \param Handler      Function to use as handler
+ */
+void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
+{
+       tEdiIRQ *obj;
+       
+       // Get Data Pointer
+       VALIDATE_PTR(Object,);
+       obj = GET_DATA(Object);
+       
+       // Sanity Check arguments
+       if( !obj->State )       return ;
+       
+       // Only register the mediator if it is not already
+       if( Handler && !obj->Handler )
+               if( !irq_install_handler(obj->Num, Edi_Int_IRQ_Handler) )
+                       return ;
+       obj->Handler = Handler;
+}
+
+/**
+ * \fn void EDI_Int_IRQ_Return(object_pointer Object)
+ * \brief Return from interrupt
+ * \param Object       IRQ Object
+ * \note Due to the structure of acess interrupts, this is a dummy
+ */
+void EDI_Int_IRQ_Return(object_pointer Object)
+{
+}
+
+/**
+ * \fn void Edi_Int_IRQ_Handler(struct regs *Regs)
+ * \brief EDI IRQ Handler - Calls the handler 
+ * \param Regs Register state at IRQ call
+ */
+void Edi_Int_IRQ_Handler(struct regs *Regs)
+{
+        int    i;
+       for( i = 0; i < 16; i ++ )
+       {
+               if(!gEdi_IRQObjects[i].State)   continue;       // Unused, Skip
+               if(gEdi_IRQObjects[i].Num != Regs->int_no)      continue;       // Another IRQ, Skip
+               if(!gEdi_IRQObjects[i].Handler) continue;       // No Handler, Skip
+               gEdi_IRQObjects[i].Handler( Regs->int_no );     // Call Handler
+               return;
+       }
+}
+
+
+// === CLASS DECLARATION ===
+static edi_function_declaration_t      scEdi_Int_Functions_IRQ[] = {
+               {"int32_t", "init_interrupt", 1, 3, NULL, //scEdi_Int_Variables_IO[0],
+                       (function_pointer)Edi_Int_IRQ_InitInt
+                       },
+               {"uint32_t", "interrupt_get_irq", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
+                       (function_pointer)Edi_Int_IRQ_GetInt
+                       },
+               {"void", "interrupt_set_handler", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
+                       (function_pointer)Edi_Int_IRQ_GetInt
+                       },
+               {"void", "interrupt_return", 1, 1, NULL, //scEdi_Int_Variables_IO[3],
+                       (function_pointer)Edi_Int_IRQ_GetInt
+                       }
+       };
+static edi_class_declaration_t scEdi_Int_Class_IRQ = 
+       {
+               INTERRUPTS_CLASS, 1, 12,
+               scEdi_Int_Functions_IRQ,
+               Edi_Int_IRQ_Construct,
+               Edi_Int_IRQ_Destruct,
+               NULL
+       };
diff --git a/KernelLand/Modules/Interfaces/EDI/edi_io.inc.c b/KernelLand/Modules/Interfaces/EDI/edi_io.inc.c
new file mode 100644 (file)
index 0000000..8a6ef22
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * AcessOS EDI Interface
+ * - IO Port Class
+ * 
+ * By John Hodge (thePowersGang)
+ * 
+ * This file has been released into the public domain.
+ * You are free to use it as you wish.
+ */
+#include "edi/edi.h"
+
+// === TYPES ===
+typedef struct {
+       uint16_t        State;  // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
+       uint16_t        Num;
+} tEdiPort;
+
+// === GLOBALS ===
+#define        NUM_PREALLOC_PORTS      128
+tEdiPort       gEdi_PortObjects[NUM_PREALLOC_PORTS];
+
+// === FUNCTIONS ===
+/**
+ * \fn object_pointer Edi_Int_IO_Construct(void)
+ * \brief Creates a new IO Port Object
+ * \return     Pointer to object
+ */
+object_pointer Edi_Int_IO_Construct(void)
+{
+       tEdiPort        *ret;
+        int    i;
+       // Search for a free preallocated port
+       for( i = 0; i < NUM_PREALLOC_PORTS; i ++ )
+       {
+               if(gEdi_PortObjects[i].State)   continue;
+               gEdi_PortObjects[i].State = 1;
+               gEdi_PortObjects[i].Num = 0;
+               return &gEdi_PortObjects[i];
+       }
+       // Else, use heap space
+       ret = malloc( sizeof(tEdiPort) );
+       ret->State = 0x8001;
+       ret->Num = 0;
+       return ret;
+}
+
+/**
+ * \fn void Edi_Int_IO_Destruct(object_pointer Object)
+ * \brief Destruct an IO Port Object
+ * \param Object       Object to destroy
+ */
+void Edi_Int_IO_Destruct(object_pointer Object)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object,);
+       obj = GET_DATA(Object);
+       
+       if(obj->State & 0x8000) {       // If in heap, free
+               free(Object);
+       } else {        // Otherwise, mark as unallocated
+               obj->State = 0;
+       }
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
+ * \brief Initialises an IO Port
+ * \param Object       Object Pointer (this)
+ * \param Port Port Number to use
+ */
+int32_t        Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       
+       if( !obj->State )       return 0;
+       obj->Num = Port;
+       obj->State &= ~0x3FFF;
+       obj->State |= 2;        // Set initialised flag
+       return 1;
+}
+
+/**
+ * \fn uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
+ * \brief Returns the port number associated with the object
+ * \param Object       Port Object to get number from
+ * \return Port Number
+ */
+uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       // Check if valid
+       if( !obj->State )       return 0;
+       // Return Port No
+       return obj->Num;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
+ * \brief Read a byte from an IO port
+ * \param Object       Port Object
+ * \param out  Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "inb %%dx, %%al" : "=a" (*out) : "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
+ * \brief Read a word from an IO port
+ * \param Object       Port Object
+ * \param out  Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
+{
+       
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "inw %%dx, %%ax" : "=a" (*out) : "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
+ * \brief Read a double word from an IO port
+ * \param Object       Port Object
+ * \param out  Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
+{
+       
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out) : "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
+ * \brief Read a quad word from an IO port
+ * \param Object       Port Object
+ * \param out  Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
+{
+       uint32_t        *out32 = (uint32_t*)out;
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out32) : "d" ( obj->Num ) );
+       __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*(out32+1)) : "d" ( obj->Num+4 ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
+ * \brief Read a byte from an IO port
+ * \param Object       Port Object
+ * \param Length       Number of bytes to read
+ * \param out  Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "rep insb" : : "c" (Length), "D" (out), "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
+ * \brief Write a byte from an IO port
+ * \param Object       Port Object
+ * \param in   Data to write
+ */
+int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "outb %%al, %%dx" : : "a" (in), "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
+ * \brief Write a word from an IO port
+ * \param Object       Port Object
+ * \param in   Data to write
+ */
+int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "outw %%ax, %%dx" : : "a" (in), "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
+ * \brief Write a double word from an IO port
+ * \param Object       Port Object
+ * \param in   Data to write
+ */
+int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (in), "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
+ * \brief Write a quad word from an IO port
+ * \param Object       Port Object
+ * \param in   Data to write
+ */
+int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
+{
+       uint32_t        *in32 = (uint32_t*)&in;
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*in32), "d" ( obj->Num ) );
+       __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*(in32+1)), "d" ( obj->Num+4 ) );
+       
+       return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
+ * \brief Read a byte from an IO port
+ * \param Object       Port Object
+ * \param Length       Number of bytes to write
+ * \param in   Pointer to of data to write
+ */
+int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
+{
+       tEdiPort        *obj;
+       // Get Data Pointer
+       VALIDATE_PTR(Object, 0);
+       obj = GET_DATA(Object);
+       if( !obj->State )       return 0;
+       if( obj->State & 1 )    return -1;      // Unintialised
+       
+       __asm__ __volatile__ ( "rep outsb" : : "c" (Length), "D" (in), "d" ( obj->Num ) );
+       
+       return 1;
+}
+
+// === CLASS DECLARATION ===
+/*static edi_variable_declaration_t    *scEdi_Int_Variables_IO[] = {
+       {
+               {"pointer", "port_object", 0},
+               {"uint16_t", "port", 0}
+       },
+       {
+               {"pointer", "port_object", 0}
+       },
+       {
+               {"pointer", "port_object", 0},
+               {"pointer int8_t", "out", 0}
+       }
+};*/
+static edi_function_declaration_t      scEdi_Int_Functions_IO[] = {
+               {"int32_t", "init_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[0],
+                       (function_pointer)Edi_Int_IO_InitPort
+                       },
+               {"uint16_t", "get_port_number", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
+                       (function_pointer)Edi_Int_IO_GetPortNum
+                       },
+               {"int32_t", "read_byte_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
+                       (function_pointer)Edi_Int_IO_ReadByte
+                       },
+               {"int32_t", "read_word_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"pointer int16_t", "out", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_ReadWord
+                       },
+               {"int32_t", "read_long_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"pointer int32_t", "out", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_ReadDWord
+                       },
+               {"int32_t", "read_longlong_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"pointer int64_t", "out", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_ReadQWord
+                       },
+               {"int32_t", "read_string_io_port", 1, 3, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"int32_T", "data_length", 0},
+                               {"pointer int64_t", "out", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_ReadString
+                       },
+                       
+               {"int32_t", "write_byte_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"int8_t", "in", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_WriteByte},
+               {"int32_t", "write_word_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"int16_t", "in", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_WriteWord},
+               {"int32_t", "write_long_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"int32_t", "in", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_WriteDWord},
+               {"int32_t", "write_longlong_io_port", 1, 2, NULL/*{
+                               {"pointer", "port_object", 0},
+                               {"int64_t", "in", 0}
+                       }*/,
+                       (function_pointer)Edi_Int_IO_WriteQWord}
+       };
+static edi_class_declaration_t scEdi_Int_Class_IO = 
+       {
+               IO_PORT_CLASS, 1, 12,
+               scEdi_Int_Functions_IO,
+               Edi_Int_IO_Construct,
+               Edi_Int_IO_Destruct,
+               NULL
+       };
diff --git a/KernelLand/Modules/Interfaces/EDI/main.c b/KernelLand/Modules/Interfaces/EDI/main.c
new file mode 100644 (file)
index 0000000..c3d0272
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * Acess2 EDI Layer
+ */
+#define DEBUG  0
+#define VERSION        ((0<<8)|1)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#define        IMPLEMENTING_EDI        1
+#include "edi/edi.h"
+
+#define        VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0)
+#define        GET_DATA(_ptr)  (Object)
+
+#include "edi_io.inc.c"
+#include "edi_int.inc.c"
+
+// === STRUCTURES ===
+typedef struct sAcessEdiDriver {
+       struct sAcessEdiDriver  *Next;
+       tDevFS_Driver   Driver;
+        int    FileCount;
+       struct {
+               char    *Name;
+               tVFS_Node       Node;
+       }       *Files;
+       edi_object_metadata_t   *Objects;
+       edi_initialization_t    Init;
+       driver_finish_t Finish;
+} tAcessEdiDriver;
+
+// === PROTOTYPES ===
+ int   EDI_Install(char **Arguments);
+ int   EDI_DetectDriver(void *Base);
+ int   EDI_LoadDriver(void *Base);
+vfs_node *EDI_FS_ReadDir(vfs_node *Node, int Pos);
+vfs_node *EDI_FS_FindDir(vfs_node *Node, char *Name);
+ int   EDI_FS_CharRead(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   EDI_FS_CharWrite(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   EDI_FS_IOCtl(vfs_node *Node, int Id, void *Data);
+data_pointer EDI_GetInternalClass(edi_string_t ClassName);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL);
+tModuleLoader  gEDI_Loader = {
+       NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL
+};
+tSpinlock      glEDI_Drivers;
+tAcessEdiDriver        *gEdi_Drivers = NULL;
+edi_class_declaration_t        *gcEdi_IntClasses[] = {
+       &scEdi_Int_Class_IO, &scEdi_Int_Class_IRQ
+};
+#define        NUM_INT_CLASSES (sizeof(gcEdi_IntClasses)/sizeof(gcEdi_IntClasses[0]))
+char *csCharNumbers[] = {"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"};
+char *csBlockNumbers[] = {"blk0", "blk1", "blk2", "blk3", "blk4", "blk5", "blk6", "blk7", "blk8", "blk9"};
+
+// === CODE ===
+/**
+ * \fn int EDI_Install(char **Arguments)
+ * \brief Stub intialisation routine
+ */
+int EDI_Install(char **Arguments)
+{
+       Module_RegisterLoader( &gEDI_Loader );
+       return 1;
+}
+
+/**
+ * \brief Detects if a driver should be loaded by the EDI subsystem
+ */
+int EDI_DetectDriver(void *Base)
+{
+       if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 )
+               return 0;
+       
+       return 1;
+}
+
+/**
+ * \fn int Edi_LoadDriver(void *Base)
+ * \brief Load an EDI Driver from a loaded binary
+ * \param Base Binary Handle
+ * \return 0 on success, non zero on error
+ */
+int EDI_LoadDriver(void *Base)
+{
+       driver_init_t   init;
+       driver_finish_t finish;
+       tAcessEdiDriver *info;
+        int    i, j;
+        int    devfsId;
+       edi_class_declaration_t *classes;
+
+       ENTER("pBase", Base);
+       
+       // Get Functions
+       if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init)
+       ||      !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) )
+       {
+               Warning("[EDI  ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base);
+               Binary_Unload(Base);
+               return 0;
+       }
+       
+       // Allocate Driver Information
+       info = malloc( sizeof(tAcessEdiDriver) );
+       info->Finish = finish;
+       
+       // Initialise Driver
+       info->Init = init( 0, NULL );   // TODO: Implement Resources
+       
+       LOG("info->Init.driver_name = '%s'", info->Init.driver_name);
+       LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes);
+       
+       // Count mappable classes
+       classes = info->Init.driver_classes;
+       info->FileCount = 0;
+       info->Objects = NULL;
+       for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ )
+       {
+               if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 )
+               {
+                       data_pointer    *obj;
+                       // Initialise Object Instances
+                       for( ; (obj = classes[i].constructor()); j++ ) {
+                               LOG("%i - Constructed '%s'", j, classes[i].name);
+                               info->FileCount ++;
+                               info->Objects = realloc(info->Objects, sizeof(*info->Objects)*info->FileCount);
+                               info->Objects[j].object = obj;
+                               info->Objects[j].object_class = &classes[i];
+                       }
+               }
+               else
+                       LOG("%i - %s", i, classes[i].name);
+       }
+       
+       if(info->FileCount)
+       {
+                int    iNumChar = 0;
+               // Create VFS Nodes
+               info->Files = malloc( info->FileCount * sizeof(*info->Files) );
+               memset(info->Files, 0, info->FileCount * sizeof(*info->Files));
+               j = 0;
+               for( j = 0; j < info->FileCount; j++ )
+               {
+                       classes = info->Objects[j].object_class;
+                       if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 )
+                       {
+                               LOG("%i - %s", j, csCharNumbers[iNumChar]);
+                               info->Files[j].Name = csCharNumbers[iNumChar];
+                               info->Files[j].Node.NumACLs = 1;
+                               info->Files[j].Node.ACLs = &gVFS_ACL_EveryoneRW;
+                               info->Files[j].Node.ImplPtr = &info->Objects[j];
+                               info->Files[j].Node.Read = EDI_FS_CharRead;
+                               info->Files[j].Node.Write = EDI_FS_CharWrite;
+                               info->Files[j].Node.IOCtl = EDI_FS_IOCtl;
+                               info->Files[j].Node.CTime =
+                                       info->Files[j].Node.MTime =
+                                       info->Files[j].Node.ATime = now();
+                               
+                               iNumChar ++;
+                               continue;
+                       }
+               }
+               
+               // Create DevFS Driver
+               info->Driver.ioctl = EDI_FS_IOCtl;
+               memsetda(&info->Driver.rootNode, 0, sizeof(vfs_node) / 4);
+               info->Driver.Name = info->Init.driver_name;
+               info->Driver.RootNode.Flags = VFS_FFLAG_DIRECTORY;
+               info->Driver.RootNode.NumACLs = 1;
+               info->Driver.RootNode.ACLs = &gVFS_ACL_EveryoneRX;
+               info->Driver.RootNode.Length = info->FileCount;
+               info->Driver.RootNode.ImplPtr = info;
+               info->Driver.RootNode.ReadDir = EDI_FS_ReadDir;
+               info->Driver.RootNode.FindDir = EDI_FS_FindDir;
+               info->Driver.RootNode.IOCtl = EDI_FS_IOCtl;
+               
+               // Register
+               devfsId = dev_addDevice( &info->Driver );
+               if(devfsId == -1) {
+                       free(info->Files);      // Free Files
+                       info->Finish(); // Clean up driver
+                       free(info);             // Free info structure
+                       Binary_Unload(iDriverBase);     // Unload library
+                       return -3;      // Return error
+               }
+       }
+       
+       // Append to loaded list;
+       LOCK(&glEDI_Drivers);
+       info->Next = gEDI_Drivers;
+       gEDI_Drivers = info;
+       RELEASE(&glEDI_Drivers);
+       
+       LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path);
+       LEAVE('i', 1);
+       return 1;
+}
+
+// --- Filesystem Interaction ---
+/**
+ * \brief Read from a drivers class list
+ * \param Node Driver's Root Node
+ * \param Pos  Index of file to get
+ */
+char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos)
+{
+       tAcessEdiDriver *info;
+       
+       // Sanity Check
+       if(!Node)       return NULL;
+       
+       // Get Information Structure
+       info = (void *) Node->ImplPtr;
+       if(!info)       return NULL;
+       
+       // Check Position
+       if(Pos < 0)     return NULL;
+       if(Pos >= info->FileCount)      return NULL;
+       
+       return strdup( info->Files[Pos].Name );
+}
+
+/**
+ * \fn tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Find a named file in a driver
+ * \param Node Driver's Root Node
+ * \param Name Name of file to find
+ */
+tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
+{
+       tAcessEdiDriver *info;
+        int    i;
+       
+       // Sanity Check
+       if(!Node)       return NULL;
+       if(!Name)       return NULL;
+       
+       // Get Information Structure
+       info = (void *) Node->ImplPtr;
+       if(!info)       return NULL;
+       
+       for( i = 0; i < info->FileCount; i++ )
+       {
+               if(strcmp(info->Files[i].name, Name) == 0)
+                       return &info->Files[i].Node;
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from an EDI Character Device
+ * \param Node File Node
+ * \param Offset       Offset into file (ignored)
+ * \param Length       Number of characters to read
+ * \param Buffer       Destination for data
+ * \return     Number of characters read
+ */
+Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       edi_object_metadata_t   *meta;
+       edi_class_declaration_t *class;
+       
+       // Sanity Check
+       if(!Node || !Buffer)    return 0;
+       if(Length <= 0) return 0;
+       // Get Object Metadata
+       meta = (void *) Node->ImplPtr;
+       if(!meta)       return 0;
+       
+       // Get Class
+       class = meta->object_class;
+       if(!class)      return 0;
+       
+       // Read from object
+       if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length ))
+               return Length;
+
+       return 0;
+}
+
+/**
+ * \fn Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to an EDI Character Device
+ * \param Node File Node
+ * \param Offset       Offset into file (ignored)
+ * \param Length       Number of characters to write
+ * \param Buffer       Source for data
+ * \return     Number of characters written
+ */
+Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       edi_object_metadata_t   *meta;
+       edi_class_declaration_t *class;
+       
+       // Sanity Check
+       if(!Node || !Buffer)    return 0;
+       if(Length <= 0) return 0;
+       // Get Object Metadata
+       meta = (void *) Node->ImplPtr;
+       if(!meta)       return 0;
+       
+       // Get Class
+       class = meta->object_class;
+       if(!class)      return 0;
+       
+       // Write to object
+       if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length ))
+               return Length;
+
+       return 0;
+}
+
+/**
+ * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Perfom an IOCtl call on the object
+ */
+int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       return 0;
+}
+
+// --- EDI Functions ---
+/**
+ * \fn data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
+ * \brief Gets the structure of a driver defined class
+ * \param ClassName    Name of class to find
+ * \return Class definition or NULL
+ */
+data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
+{
+        int    i;
+       tAcessEdiDriver *drv;
+       edi_class_declaration_t *classes;
+       
+       for(drv = gEdi_Drivers;
+               drv;
+               drv = drv->Next )
+       {
+               classes = drv->Init.driver_classes;
+               for( i = 0; i < drv->Init.num_driver_classes; i++ )
+               {
+                       if( strncmp(classes[i].name, ClassName, 32) == 0 )
+                               return &classes[i];
+               }
+       }
+       return NULL;
+}
+
+/**
+ * \fn int32_t EDI_CheckClassExistence(edi_string_t ClassName)
+ * \brief Checks if a class exists
+ * \param ClassName    Name of class
+ * \return 1 if the class exists, -1 otherwise
+ */
+int32_t EDI_CheckClassExistence(edi_string_t ClassName)
+{
+       //LogF("check_class_existence: (ClassName='%s')\n", ClassName);
+       if(EDI_GetInternalClass(ClassName))
+               return 1;
+               
+       if(EDI_GetDefinedClass(ClassName))      // Driver Defined
+               return 1;
+       
+       return -1;
+}
+
+/**
+ * \fn edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
+ * \brief Construct an instance of an class (an object)
+ * \param ClassName    Name of the class to construct
+ */
+edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
+{
+       edi_object_metadata_t   ret = {0, 0};
+       edi_class_declaration_t *class;
+       
+       //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName);
+       
+       // Get class definition
+       if( !(class = EDI_GetInternalClass(ClassName)) )        // Internal
+               if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined
+                       return ret;             // Return ERROR
+       
+       // Initialise
+       ret.object = class->constructor();
+       if( !ret.object )
+               return ret;     // Return ERROR
+       
+       // Set declaration pointer
+       ret.object_class = class;
+       
+       //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class);
+       return ret;
+}
+
+/**
+ * \fn void EDI_DestroyObject(edi_object_metadata_t Object)
+ * \brief Destroy an instance of a class
+ * \param Object       Object to destroy
+ */
+void EDI_DestroyObject(edi_object_metadata_t Object)
+{
+       if( !Object.object )    return;
+       if( !Object.object_class )      return;
+       
+       ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object );
+}
+
+/**
+ * \fn function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
+ * \brief Get a method of a class by it's name
+ * \param ObjectClass  Pointer to a ::edi_object_metadata_t of the object
+ * \param MethodName   Name of the desired method
+ * \return Function address or NULL
+ */
+function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
+{
+       edi_class_declaration_t *dec = ObjectClass;
+        int    i;
+       
+       //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName);
+       
+       if(!ObjectClass)        return NULL;
+       
+       for(i = 0; i < dec->num_methods; i++)
+       {
+               if(strncmp(MethodName, dec->methods[i].name, 32) == 0)
+                       return dec->methods[i].code;
+       }
+       return NULL;
+}
+
+#if 0
+function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration);
+#endif
+
+/**
+ * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
+ * \brief Get the parent of the named class
+ * \todo Implement
+ */
+edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
+{
+       WarningEx("EDI", "`get_class_parent` is unimplemented");
+       return NULL;
+}
+
+/**
+ * \fn data_pointer EDI_GetInternalClass(edi_string_t ClassName)
+ * \brief Get a builtin class
+ * \param ClassName    Name of class to find
+ * \return Pointer to the ::edi_class_declaration_t of the class
+ */
+data_pointer EDI_GetInternalClass(edi_string_t ClassName)
+{
+        int    i;
+       //LogF("get_internal_class: (ClassName='%s')\n", ClassName);
+       for( i = 0; i < NUM_INT_CLASSES; i++ )
+       {
+               if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) {
+                       return gcEdi_IntClasses[i];
+               }
+       }
+       //LogF("get_internal_class: RETURN NULL\n");
+       return NULL;
+}
+
+/**
+ * \fn edi_string_ptr_t EDI_GetObjectClass(data_pointer Object)
+ * \brief Get the name of the object of \a Object
+ * \param Object       Object to get name of
+ * \return Pointer to the class name
+ */
+edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass)
+{
+       edi_object_metadata_t   *Metadata = ObjectClass;
+       // Sanity Check
+       if(!ObjectClass)        return NULL;
+       if(!(edi_class_declaration_t*) Metadata->object_class)  return NULL;
+       
+       // Return Class Name
+       return ((edi_class_declaration_t*) Metadata->object_class)->name;
+}
+
+// === EXPORTS ===
+EXPORTAS(EDI_CheckClassExistence, check_class_existence);
+EXPORTAS(EDI_ConstructObject, construct_object);
+EXPORTAS(EDI_DestroyObject, destroy_object);
+EXPORTAS(EDI_GetMethodByName, get_method_by_name);
+EXPORTAS(EDI_GetClassParent, get_class_parent);
+EXPORTAS(EDI_GetInternalClass, get_internal_class);
+EXPORTAS(EDI_GetObjectClass, get_object_class);
diff --git a/KernelLand/Modules/Interfaces/Makefile.tpl b/KernelLand/Modules/Interfaces/Makefile.tpl
new file mode 100644 (file)
index 0000000..80c6d4d
--- /dev/null
@@ -0,0 +1 @@
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/Interfaces/UDI/Makefile b/KernelLand/Modules/Interfaces/UDI/Makefile
new file mode 100644 (file)
index 0000000..4c199f1
--- /dev/null
@@ -0,0 +1,10 @@
+#
+#
+
+CPPFLAGS = -I./include
+OBJ  = main.o logging.o strmem.o imc.o mem.o buf.o cb.o
+OBJ += meta_mgmt.o meta_gio.o
+OBJ += physio.o physio/meta_bus.o physio/meta_intr.o
+NAME = UDI
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Interfaces/UDI/Notes.txt b/KernelLand/Modules/Interfaces/UDI/Notes.txt
new file mode 100644 (file)
index 0000000..1e2e9d4
--- /dev/null
@@ -0,0 +1,36 @@
+
+<Love4Boobies> logical volume metalanguage - for file system drivers to use, network protocol 
+               metalanguage and audio support
+<Love4Boobies> madeofstaples expressed his interest in reviewing the OpenUSBDI specification to update 
+               it for USB 3.0
+
+
+=== Initialisation ===
+udi_init_t
+ > udi_init_info
+ > This is the only defined symbol in a UDI driver
+
+udi_primary_init_t
+- UDI_MAX_SCRATCH
+- UDI_OP_LONG_EXEC
+
+udi_secondary_init_t
+
+udi_ops_init_t
+
+udi_cb_init_t
+
+udi_cb_select_t
+
+udi_gcb_init_t
+
+udi_init_context_t
+
+udi_limits_t
+- UDI_MIN_ALLOC_LIMIT
+- UDI_MIN_TRACE_LOG_LIMIT
+- UDI_MIN_INSTANCE_ATTR_LIMIT
+
+udi_chan_context_t
+
+udi_child_chan_context_t
diff --git a/KernelLand/Modules/Interfaces/UDI/buf.c b/KernelLand/Modules/Interfaces/UDI/buf.c
new file mode 100644 (file)
index 0000000..5327cc8
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * \file buf.c
+ * \author John Hodge (thePowersGang)
+ * 
+ * Buffer Manipulation
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === EXPORTS ===
+EXPORT(udi_buf_copy);
+EXPORT(udi_buf_write);
+EXPORT(udi_buf_read);
+EXPORT(udi_buf_free);
+
+// === CODE ===
+void udi_buf_copy(
+       udi_buf_copy_call_t *callback,
+       udi_cb_t        *gcb,
+       udi_buf_t       *src_buf,
+       udi_size_t      src_off,
+       udi_size_t      src_len,
+       udi_buf_t       *dst_buf,
+       udi_size_t      dst_off,
+       udi_size_t      dst_len,
+       udi_buf_path_t path_handle
+       )
+{
+       UNIMPLEMENTED();
+}
+
+/**
+ * \brief Write to a buffer
+ * \param callback     Function to call once the write has completed
+ * \param gcb  Control Block
+ * \param src_mem      Source Data
+ * \param src_len      Length of source data
+ * \param dst_buf      Destination buffer
+ * \param dst_off      Destination offset in the buffer
+ * \param dst_len      Length of destination area (What the?, Redundant
+ *                     Department of redundacny department)
+ * \param path_handle  ???
+ */
+void udi_buf_write(
+       udi_buf_write_call_t *callback,
+       udi_cb_t        *gcb,
+       const void      *src_mem,
+       udi_size_t      src_len,
+       udi_buf_t       *dst_buf,
+       udi_size_t      dst_off,
+       udi_size_t      dst_len,
+       udi_buf_path_t path_handle
+       )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_buf_read(
+       udi_buf_t       *src_buf,
+       udi_size_t      src_off,
+       udi_size_t      src_len,
+       void    *dst_mem )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_buf_free(udi_buf_t *buf)
+{
+       UNIMPLEMENTED();
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/cb.c b/KernelLand/Modules/Interfaces/UDI/cb.c
new file mode 100644 (file)
index 0000000..b615dfe
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * \file cb.c
+ * \author John Hodge (thePowersGang)
+ * \brief Control block code
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === CODE ===
+void udi_cb_alloc (
+       udi_cb_alloc_call_t     *callback,      //!< Function to be called when the CB is allocated
+       udi_cb_t        *gcb,   //!< Parent Control Block
+       udi_index_t     cb_idx,
+       udi_channel_t   default_channel
+       )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_cb_alloc_dynamic(
+       udi_cb_alloc_call_t     *callback,
+       udi_cb_t        *gcb,
+       udi_index_t     cb_idx,
+       udi_channel_t   default_channel,
+       udi_size_t      inline_size,
+       udi_layout_t    *inline_layout
+       )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_cb_alloc_batch(
+       udi_cb_alloc_batch_call_t       *callback,      //!< 
+       udi_cb_t        *gcb,   //!< 
+       udi_index_t     cb_idx,
+       udi_index_t     count,
+       udi_boolean_t   with_buf,
+       udi_size_t      buf_size,
+       udi_buf_path_t  path_handle
+       )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_cb_free(udi_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_cancel(udi_cancel_call_t *callback, udi_cb_t *gcb)
+{
+       UNIMPLEMENTED();
+}
+
+// === EXPORTS ===
+EXPORT(udi_cb_alloc);
+EXPORT(udi_cb_alloc_dynamic);
+EXPORT(udi_cb_alloc_batch);
+EXPORT(udi_cb_free);
+EXPORT(udi_cancel);
diff --git a/KernelLand/Modules/Interfaces/UDI/imc.c b/KernelLand/Modules/Interfaces/UDI/imc.c
new file mode 100644 (file)
index 0000000..cd15e07
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * \file imc.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === EXPORTS ===
+EXPORT(udi_channel_anchor);
+EXPORT(udi_channel_spawn);
+EXPORT(udi_channel_set_context);
+EXPORT(udi_channel_op_abort);
+EXPORT(udi_channel_close);
+EXPORT(udi_channel_event_ind);
+EXPORT(udi_channel_event_complete);
+
+// === CODE ===
+/**
+ */
+void udi_channel_anchor(
+       udi_channel_anchor_call_t *callback, udi_cb_t *gcb,
+       udi_channel_t channel, udi_index_t ops_idx, void *channel_context
+       )
+{
+       Warning("%s Unimplemented", __func__);
+}
+
+/**
+ */
+extern void udi_channel_spawn(
+       udi_channel_spawn_call_t *callback, udi_cb_t *gcb,
+       udi_channel_t channel, udi_index_t spawn_idx,
+       udi_index_t ops_idx, void *channel_context
+       )
+{
+       Warning("%s Unimplemented", __func__);
+}
+
+/**
+ * 
+ */
+void udi_channel_set_context(
+       udi_channel_t target_channel, void *channel_context
+       )
+{
+       Warning("%s Unimplemented", __func__);
+}
+
+void udi_channel_op_abort(
+       udi_channel_t target_channel, udi_cb_t *orig_cb
+       )
+{
+       Warning("%s Unimplemented", __func__);
+}
+
+void udi_channel_close(udi_channel_t channel)
+{
+       Warning("%s Unimplemented", __func__);
+}
+
+void udi_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       udi_channel_event_complete(cb, UDI_OK);
+}
+
+void udi_channel_event_complete(udi_channel_event_cb_t *cb, udi_status_t status)
+{
+       Warning("%s Unimplemented", __func__);
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/include/physio/meta_bus.h b/KernelLand/Modules/Interfaces/UDI/include/physio/meta_bus.h
new file mode 100644 (file)
index 0000000..7b88ece
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * \file physio/meta_bus.h
+ */
+#ifndef _PHYSIO_META_BUS_H_
+#define _PHYSIO_META_BUS_H_
+
+#include <udi.h>
+#include <udi_physio.h>
+
+typedef const struct udi_bus_device_ops_s      udi_bus_device_ops_t;
+typedef const struct udi_bus_bridge_ops_s      udi_bus_bridge_ops_t;
+typedef struct udi_bus_bind_cb_s       udi_bus_bind_cb_t;
+typedef void   udi_bus_unbind_req_op_t(udi_bus_bind_cb_t *cb);
+typedef void   udi_bus_unbind_ack_op_t(udi_bus_bind_cb_t *cb);
+typedef void   udi_bus_bind_req_op_t(udi_bus_bind_cb_t *cb);
+typedef void   udi_bus_bind_ack_op_t(
+       udi_bus_bind_cb_t       *cb,
+       udi_dma_constraints_t   dma_constraints,
+       udi_ubit8_t     preferred_endianness,
+       udi_status_t    status
+       );
+
+
+struct udi_bus_device_ops_s
+{
+       udi_channel_event_ind_op_t      *channel_event_ind_op;
+       udi_bus_bind_ack_op_t   *bus_bind_ack_op;
+       udi_bus_unbind_ack_op_t *bus_unbind_ack_op;
+       udi_intr_attach_ack_op_t        *intr_attach_ack_op;
+       udi_intr_detach_ack_op_t        *intr_detach_ack_op;
+};
+/* Bus Device Ops Vector Number */
+#define UDI_BUS_DEVICE_OPS_NUM            1
+
+struct udi_bus_bridge_ops_s
+{
+     udi_channel_event_ind_op_t        *channel_event_ind_op;
+     udi_bus_bind_req_op_t     *bus_bind_req_op;
+     udi_bus_unbind_req_op_t   *bus_unbind_req_op;
+     udi_intr_attach_req_op_t  *intr_attach_req_op;
+     udi_intr_detach_req_op_t  *intr_detach_req_op;
+};
+/* Bus Bridge Ops Vector Number */
+#define UDI_BUS_BRIDGE_OPS_NUM
+
+struct udi_bus_bind_cb_s
+{
+     udi_cb_t gcb;
+};
+/* Bus Bind Control Block Group Number */
+#define UDI_BUS_BIND_CB_NUM              1
+
+
+extern void udi_bus_bind_req(udi_bus_bind_cb_t *cb);
+
+extern void udi_bus_bind_ack(
+       udi_bus_bind_cb_t       *cb,
+       udi_dma_constraints_t   dma_constraints,
+       udi_ubit8_t     preferred_endianness,
+       udi_status_t    status
+       );
+/* Values for preferred_endianness */
+#define UDI_DMA_BIG_ENDIAN                (1U<<5)
+#define UDI_DMA_LITTLE_ENDIAN             (1U<<6)
+#define UDI_DMA_ANY_ENDIAN                (1U<<0)
+
+extern void udi_bus_unbind_req(udi_bus_bind_cb_t *cb);
+extern void udi_bus_unbind_ack(udi_bus_bind_cb_t *cb);
+
+
+
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/physio/meta_intr.h b/KernelLand/Modules/Interfaces/UDI/include/physio/meta_intr.h
new file mode 100644 (file)
index 0000000..d5dd394
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * \file physio/meta_intr.h
+ */
+#ifndef _PHYSIO_META_INTR_H_
+#define _PHYSIO_META_INTR_H_
+
+#include <udi.h>
+#include <udi_physio.h>
+#include "pio.h"
+
+typedef struct udi_intr_attach_cb_s    udi_intr_attach_cb_t;
+typedef void   udi_intr_attach_req_op_t(udi_intr_attach_cb_t *intr_attach_cb);
+typedef void   udi_intr_attach_ack_op_t(
+       udi_intr_attach_cb_t *intr_attach_cb,
+       udi_status_t status
+       );
+typedef struct udi_intr_detach_cb_s    udi_intr_detach_cb_t;
+typedef void   udi_intr_detach_req_op_t(udi_intr_detach_cb_t *intr_detach_cb);
+typedef void   udi_intr_detach_ack_op_t(udi_intr_detach_cb_t *intr_detach_cb);
+typedef const struct udi_intr_handler_ops_s    udi_intr_handler_ops_t;
+typedef const struct udi_intr_dispatcher_ops_s udi_intr_dispatcher_ops_t;
+typedef struct udi_intr_event_cb_s     udi_intr_event_cb_t;
+typedef void   udi_intr_event_ind_op_t(udi_intr_event_cb_t *intr_event_cb, udi_ubit8_t flags);
+typedef void   udi_intr_event_rdy_op_t(udi_intr_event_cb_t *intr_event_cb);
+
+
+struct udi_intr_attach_cb_s
+{
+       udi_cb_t        gcb;
+       udi_index_t     interrupt_idx;
+       udi_ubit8_t     min_event_pend;
+       udi_pio_handle_t        preprocessing_handle;
+};
+/* Bridge Attach Control Block Group Number */
+#define UDI_BUS_INTR_ATTACH_CB_NUM        2
+
+struct udi_intr_detach_cb_s
+{
+       udi_cb_t        gcb;
+       udi_index_t     interrupt_idx;
+};
+/* Bridge Detach Control Block Group Number */
+#define UDI_BUS_INTR_DETACH_CB_NUM       3
+
+struct udi_intr_handler_ops_s
+{
+       udi_channel_event_ind_op_t      *channel_event_ind_op;
+       udi_intr_event_ind_op_t *intr_event_ind_op;
+};
+/* Interrupt Handler Ops Vector Number */
+#define UDI_BUS_INTR_HANDLER_OPS_NUM      3
+
+struct udi_intr_dispatcher_ops_s
+{
+       udi_channel_event_ind_op_t      *channel_event_ind_op;
+       udi_intr_event_rdy_op_t *intr_event_rdy_op;
+};
+/* Interrupt Dispatcher Ops Vector Number */
+#define UDI_BUS_INTR_DISPATCH_OPS_NUM     4
+
+struct udi_intr_event_cb_s
+{
+       udi_cb_t        gcb;
+       udi_buf_t       *event_buf;
+       udi_ubit16_t    intr_result;
+};
+/* Flag values for interrupt handling */
+#define UDI_INTR_UNCLAIMED               (1U<<0)
+#define UDI_INTR_NO_EVENT                (1U<<1)
+/* Bus Interrupt Event Control Block Group Number */
+#define UDI_BUS_INTR_EVENT_CB_NUM        4
+
+
+
+extern void udi_intr_attach_req(udi_intr_attach_cb_t *intr_attach_cb);
+extern void udi_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status);
+extern void udi_intr_attach_ack_unused(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status);
+
+extern void udi_intr_detach_req(udi_intr_detach_cb_t *intr_detach_cb);
+extern void udi_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb);
+extern void udi_intr_detach_ack_unused(udi_intr_detach_cb_t *intr_detach_cb);
+
+
+extern void udi_intr_event_ind(udi_intr_event_cb_t *intr_event_cb, udi_ubit8_t flags);
+/**
+ * \brief Values for ::udi_intr_event_ind \a flags
+ * \{
+ */
+#define UDI_INTR_MASKING_NOT_REQUIRED    (1U<<0)
+#define UDI_INTR_OVERRUN_OCCURRED        (1U<<1)
+#define UDI_INTR_PREPROCESSED            (1U<<2)
+/**
+ * \}
+ */
+
+extern void udi_intr_event_rdy(udi_intr_event_cb_t *intr_event_cb);
+
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/physio/pio.h b/KernelLand/Modules/Interfaces/UDI/include/physio/pio.h
new file mode 100644 (file)
index 0000000..1ce305f
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * \file physio/pio.h
+ */
+#ifndef _PHYSIO_PIO_H_
+#define _PHYSIO_PIO_H_
+
+#include <udi.h>
+#include <udi_physio.h>
+
+
+typedef _udi_handle_t  udi_pio_handle_t;
+/* Null handle value for udi_pio_handle_t */
+#define UDI_NULL_PIO_HANDLE    _NULL_HANDLE
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi.h b/KernelLand/Modules/Interfaces/UDI/include/udi.h
new file mode 100644 (file)
index 0000000..53953c0
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * \file udi.h
+ */
+#ifndef _UDI_H_
+#define _UDI_H_
+
+// Use the core acess file to use the specific size types (plus va_arg)
+#include <acess.h>
+
+#include "udi/arch/x86.h"
+
+/**
+ * \name Values and Flags for udi_status_t
+ * \{
+ */
+#define UDI_STATUS_CODE_MASK           0x0000FFFF
+#define UDI_STAT_META_SPECIFIC         0x00008000
+#define UDI_SPECIFIC_STATUS_MASK       0x00007FFF
+#define UDI_CORRELATE_OFFSET           16
+#define UDI_CORRELATE_MASK                     0xFFFF0000
+/* Common Status Values */
+#define UDI_OK                                         0
+#define UDI_STAT_NOT_SUPPORTED         1
+#define UDI_STAT_NOT_UNDERSTOOD                2
+#define UDI_STAT_INVALID_STATE         3
+#define UDI_STAT_MISTAKEN_IDENTITY     4
+#define UDI_STAT_ABORTED                       5
+#define UDI_STAT_TIMEOUT                       6
+#define UDI_STAT_BUSY                          7
+#define UDI_STAT_RESOURCE_UNAVAIL      8
+#define UDI_STAT_HW_PROBLEM                    9
+#define UDI_STAT_NOT_RESPONDING                10
+#define UDI_STAT_DATA_UNDERRUN         11
+#define UDI_STAT_DATA_OVERRUN          12
+#define UDI_STAT_DATA_ERROR                    13
+#define UDI_STAT_PARENT_DRV_ERROR      14
+#define UDI_STAT_CANNOT_BIND           15
+#define UDI_STAT_CANNOT_BIND_EXCL      16
+#define UDI_STAT_TOO_MANY_PARENTS      17
+#define UDI_STAT_BAD_PARENT_TYPE       18
+#define UDI_STAT_TERMINATED                    19
+#define UDI_STAT_ATTR_MISMATCH         20
+/**
+ * \}
+ */
+
+/**
+ * \name Data Layout Specifiers
+ * \{
+ */
+typedef const udi_ubit8_t      udi_layout_t;
+/* Specific-Length Layout Type Codes */
+#define UDI_DL_UBIT8_T                   1
+#define UDI_DL_SBIT8_T                   2
+#define UDI_DL_UBIT16_T                  3
+#define UDI_DL_SBIT16_T                  4
+#define UDI_DL_UBIT32_T                  5
+#define UDI_DL_SBIT32_T                  6
+#define UDI_DL_BOOLEAN_T                 7
+#define UDI_DL_STATUS_T                  8
+/* Abstract Element Layout Type Codes */
+#define UDI_DL_INDEX_T                   20
+/* Opaque Handle Element Layout Type Codes */
+#define UDI_DL_CHANNEL_T                 30
+#define UDI_DL_ORIGIN_T                  32
+/* Indirect Element Layout Type Codes */
+#define UDI_DL_BUF                       40
+#define UDI_DL_CB                        41
+#define UDI_DL_INLINE_UNTYPED            42
+#define UDI_DL_INLINE_DRIVER_TYPED       43
+#define UDI_DL_MOVABLE_UNTYPED           44
+/* Nested Element Layout Type Codes */
+#define UDI_DL_INLINE_TYPED              50
+#define UDI_DL_MOVABLE_TYPED             51
+#define UDI_DL_ARRAY                     52
+#define UDI_DL_END                       0
+/**
+ * \}
+ */
+
+
+// === INCLUDE SUB-SECTIONS ===
+#include "udi/cb.h"    // Control Blocks
+#include "udi/log.h"   // Logging
+#include "udi/attr.h"  // Attributes
+#include "udi/strmem.h"        // String/Memory
+#include "udi/buf.h"   // Buffers
+#include "udi/mem.h"   // Memory Management
+#include "udi/imc.h"   // Inter-module Communication
+#include "udi/meta_mgmt.h"     // Management Metalanguage
+#include "udi/meta_gio.h"      // General IO Metalanguage
+#include "udi/init.h"  // Init
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/arch/x86.h b/KernelLand/Modules/Interfaces/UDI/include/udi/arch/x86.h
new file mode 100644 (file)
index 0000000..9c505d3
--- /dev/null
@@ -0,0 +1,67 @@
+
+#ifndef _UDI_ARCH_x86_H_
+#define _UDI_ARCH_x86_H_
+
+typedef Sint8  udi_sbit8_t;    /* signed 8-bit: -2^7..2^7-1 */
+typedef Sint16 udi_sbit16_t;   /* signed 16-bit: -2^15..2^15-1 */
+typedef Sint32 udi_sbit32_t;   /* signed 32-bit: -2^31..2^31-1 */
+typedef Uint8  udi_ubit8_t;    /* unsigned 8-bit: 0..28-1 */
+typedef Uint16 udi_ubit16_t;   /* unsigned 16-bit: 0..216-1 */
+typedef Uint32 udi_ubit32_t;   /* unsigned 32-bit: 0..232-1 */
+
+typedef udi_ubit8_t    udi_boolean_t;  /* 0=False; 1..28-1=True */
+#define FALSE  0
+#define TRUE   1
+
+typedef size_t udi_size_t;     /* buffer size */
+typedef size_t udi_index_t;    /* zero-based index type */
+
+typedef void   *_udi_handle_t;
+#define        _NULL_HANDLE    NULL
+
+/* Channel Handle */
+typedef _udi_handle_t  *udi_channel_t;
+#define UDI_NULL_CHANNEL       _NULL_HANDLE
+
+/**
+ * \brief Buffer Path
+ */
+typedef _udi_handle_t  udi_buf_path_t;
+#define UDI_NULL_BUF_PATH      _NULL_HANDLE
+
+typedef _udi_handle_t  udi_origin_t;
+#define UDI_NULL_ORIGIN        _NULL_HANDLE
+
+typedef Sint64 udi_timestamp_t;
+
+#define UDI_HANDLE_IS_NULL(handle, handle_type)        (handle == NULL)
+#define UDI_HANDLE_ID(handle, handle_type)     ((Uint32)handle)
+
+/**
+ * \name va_arg wrapper
+ * \{
+ */
+#define UDI_VA_ARG(pvar, type, va_code)        va_arg(pvar,type)
+#define UDI_VA_UBIT8_T
+#define UDI_VA_SBIT8_T
+#define UDI_VA_UBIT16_T
+#define UDI_VA_SBIT16_T
+#define UDI_VA_UBIT32_T
+#define UDI_VA_SBIT32_T
+#define UDI_VA_BOOLEAN_T
+#define UDI_VA_INDEX_T
+#define UDI_VA_SIZE_T
+#define UDI_VA_STATUS_T
+#define UDI_VA_CHANNEL_T
+#define UDI_VA_ORIGIN_T
+#define UDI_VA_POINTER
+/**
+ * \}
+ */
+
+/**
+ * \brief Status Type
+ */
+typedef udi_ubit32_t   udi_status_t;
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/attr.h b/KernelLand/Modules/Interfaces/UDI/include/udi/attr.h
new file mode 100644 (file)
index 0000000..a63ce8a
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * \file udi_attr.h
+ */
+#ifndef _UDI_ATTR_H_
+#define _UDI_ATTR_H_
+
+typedef struct udi_instance_attr_list_s        udi_instance_attr_list_t;
+typedef udi_ubit8_t    udi_instance_attr_type_t;
+
+/* Instance attribute limits */
+#define UDI_MAX_ATTR_NAMELEN   32
+#define UDI_MAX_ATTR_SIZE              64
+
+/**
+ * \brief Instance Attribute
+ */
+struct udi_instance_attr_list_s
+{
+     char      attr_name[UDI_MAX_ATTR_NAMELEN];
+     udi_ubit8_t       attr_value[UDI_MAX_ATTR_SIZE];
+     udi_ubit8_t       attr_length;
+     udi_instance_attr_type_t  attr_type;
+};
+
+
+/**
+ * \brief Instance Attribute Types
+ * \see ::udi_instance_attr_type_t
+ */
+enum
+{
+       UDI_ATTR_NONE,
+       UDI_ATTR_STRING,
+       UDI_ATTR_ARRAY8,
+       UDI_ATTR_UBIT32,
+       UDI_ATTR_BOOLEAN,
+       UDI_ATTR_FILE
+};
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/buf.h b/KernelLand/Modules/Interfaces/UDI/include/udi/buf.h
new file mode 100644 (file)
index 0000000..fa2428b
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * \file udi_buf.h
+ */
+#ifndef _UDI_BUF_H_
+#define _UDI_BUF_H_
+
+
+typedef struct udi_buf_s       udi_buf_t;
+typedef struct udi_xfer_constraints_s  udi_xfer_constraints_t;
+typedef void udi_buf_copy_call_t(udi_cb_t *gcb, udi_buf_t *new_dst_buf);
+typedef void udi_buf_write_call_t(udi_cb_t *gcb, udi_buf_t *new_dst_buf);
+
+/**
+ * \brief Describes a buffer
+ * \note Semi-Opaque
+ */
+struct udi_buf_s
+{
+       udi_size_t      buf_size;
+       Uint8   Data[]; //!< ENVIRONMENT ONLY
+};
+
+/**
+ * \brief 
+ */
+struct udi_xfer_constraints_s
+{
+       udi_ubit32_t    udi_xfer_max;
+       udi_ubit32_t    udi_xfer_typical;
+       udi_ubit32_t    udi_xfer_granularity;
+       udi_boolean_t   udi_xfer_one_piece;
+       udi_boolean_t   udi_xfer_exact_size;
+       udi_boolean_t   udi_xfer_no_reorder;
+};
+
+// --- MACROS ---
+/**
+ * \brief Allocates a buffer
+ */
+#define UDI_BUF_ALLOC(callback, gcb, init_data, size, path_handle) \
+       udi_buf_write(callback, gcb, init_data, size, NULL, 0, 0, path_handle)
+
+/**
+ * \brief Inserts data into a buffer
+ */
+#define UDI_BUF_INSERT(callback, gcb, new_data, size, dst_buf, dst_off) \
+       udi_buf_write(callback, gcb, new_data, size, dst_buf, dst_off, 0, UDI_NULL_BUF_PATH)
+
+/**
+ * \brief Removes data from a buffer (data afterwards will be moved forewards)
+ */
+#define UDI_BUF_DELETE(callback, gcb, size, dst_buf, dst_off) \
+       udi_buf_write(callback, gcb, NULL, 0, dst_buf, dst_off, size, UDI_NULL_BUF_PATH)
+
+/**
+ * \brief Duplicates \a src_buf
+ */
+#define UDI_BUF_DUP(callback, gcb, src_buf, path_handle) \
+       udi_buf_copy(callback, gcb, src_buf, 0, (src_buf)->buf_size, NULL, 0, 0, path_handle)
+
+
+/**
+ * \brief Copies data from one buffer to another
+ */
+extern void udi_buf_copy(
+       udi_buf_copy_call_t *callback,
+       udi_cb_t        *gcb,
+       udi_buf_t       *src_buf,
+       udi_size_t      src_off,
+       udi_size_t      src_len,
+       udi_buf_t       *dst_buf,
+       udi_size_t      dst_off,
+       udi_size_t      dst_len,
+       udi_buf_path_t path_handle );
+
+/**
+ * \brief Copies data from driver space to a buffer
+ */
+extern void udi_buf_write(
+       udi_buf_write_call_t *callback,
+       udi_cb_t        *gcb,
+       const void      *src_mem,
+       udi_size_t      src_len,
+       udi_buf_t       *dst_buf,
+       udi_size_t      dst_off,
+       udi_size_t      dst_len,
+       udi_buf_path_t path_handle
+       );
+
+/**
+ * \brief Reads data from a buffer into driver space
+ */
+extern void udi_buf_read(
+       udi_buf_t       *src_buf,
+       udi_size_t      src_off,
+       udi_size_t      src_len,
+       void    *dst_mem );
+
+/**
+ * \brief Frees a buffer
+ */
+extern void udi_buf_free(udi_buf_t *buf);
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/cb.h b/KernelLand/Modules/Interfaces/UDI/include/udi/cb.h
new file mode 100644 (file)
index 0000000..76db5c6
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * \file udi_cb.h
+ */
+#ifndef _UDI_CB_H_
+#define _UDI_CB_H_
+
+typedef struct udi_cb_s        udi_cb_t;
+typedef void udi_cb_alloc_call_t(udi_cb_t *gcb, udi_cb_t *new_cb);
+typedef void udi_cb_alloc_batch_call_t(udi_cb_t *gcb, udi_cb_t *first_new_cb);
+typedef void udi_cancel_call_t(udi_cb_t *gcb);
+
+#define UDI_GCB(mcb)   (&(mcb)->gcb)
+#define UDI_MCB(gcb, cb_type)  ((cb_type *)(gcb))
+
+/**
+ * \brief Describes a generic control block
+ * \note Semi-opaque
+ */
+struct udi_cb_s
+{
+       /**
+        * \brief Channel associated with the control block
+        */
+       udi_channel_t   channel;
+       /**
+        * \brief Current state
+        * \note Driver changable
+        */
+       void    *context;
+       /**
+        * \brief CB's scratch area
+        */
+       void    *scratch;
+       /**
+        * \brief ???
+        */
+       void    *initiator_context;
+       /**
+        * \brief Request Handle?
+        */
+       udi_origin_t    origin;
+};
+
+extern void udi_cb_alloc (
+       udi_cb_alloc_call_t     *callback,
+       udi_cb_t        *gcb,
+       udi_index_t     cb_idx,
+       udi_channel_t   default_channel
+       );
+
+extern void udi_cb_alloc_dynamic(
+       udi_cb_alloc_call_t     *callback,
+       udi_cb_t        *gcb,
+       udi_index_t     cb_idx,
+       udi_channel_t   default_channel,
+       udi_size_t      inline_size,
+       udi_layout_t    *inline_layout
+       );
+
+extern void udi_cb_alloc_batch(
+       udi_cb_alloc_batch_call_t       *callback,
+       udi_cb_t        *gcb,
+       udi_index_t     cb_idx,
+       udi_index_t     count,
+       udi_boolean_t   with_buf,
+       udi_size_t      buf_size,
+       udi_buf_path_t  path_handle
+       );
+
+extern void udi_cb_free(udi_cb_t *cb);
+
+extern void udi_cancel(udi_cancel_call_t *callback, udi_cb_t *gcb);
+
+
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/imc.h b/KernelLand/Modules/Interfaces/UDI/include/udi/imc.h
new file mode 100644 (file)
index 0000000..e5b3f3b
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+ * \file udi_imc.h
+ * \brief Inter-Module Communication
+ */
+#ifndef _UDI_IMC_H_
+#define _UDI_IMC_H_
+
+typedef void udi_channel_anchor_call_t(udi_cb_t *gcb, udi_channel_t anchored_channel);
+typedef void udi_channel_spawn_call_t(udi_cb_t *gcb, udi_channel_t new_channel);
+
+typedef struct udi_channel_event_cb_s  udi_channel_event_cb_t;
+
+typedef void udi_channel_event_ind_op_t(udi_channel_event_cb_t *cb);
+
+/**
+ * \brief Anchors a channel end to the current region
+ */
+extern void udi_channel_anchor(
+       udi_channel_anchor_call_t *callback, udi_cb_t *gcb,
+       udi_channel_t channel, udi_index_t ops_idx, void *channel_context
+       );
+
+/**
+ * \brief Created a new channel between two regions
+ */
+extern void udi_channel_spawn(
+       udi_channel_spawn_call_t *callback,
+       udi_cb_t *gcb,
+       udi_channel_t channel,
+       udi_index_t spawn_idx,
+       udi_index_t ops_idx,
+       void *channel_context
+       );
+
+/**
+ * \brief Attaches a new context pointer to the current channel
+ */
+extern void udi_channel_set_context(
+       udi_channel_t target_channel,
+       void *channel_context
+       );
+/**
+ * \brief 
+ */
+extern void udi_channel_op_abort(
+       udi_channel_t target_channel,
+       udi_cb_t *orig_cb
+       );
+
+/**
+ * \brief Closes an open channel
+ */
+extern void udi_channel_close(udi_channel_t channel);
+
+/**
+ * \brief Describes a channel event
+ */
+struct udi_channel_event_cb_s
+{
+       udi_cb_t gcb;
+       udi_ubit8_t event;
+       union {
+               struct {
+                       udi_cb_t *bind_cb;
+               } internal_bound;
+               struct {
+                       udi_cb_t *bind_cb;
+                       udi_ubit8_t parent_ID;
+                       udi_buf_path_t *path_handles;
+               } parent_bound;
+               udi_cb_t *orig_cb;
+       }       params;
+};
+/* Channel event types */
+#define UDI_CHANNEL_CLOSED                0
+#define UDI_CHANNEL_BOUND                 1
+#define UDI_CHANNEL_OP_ABORTED            2
+
+/**
+ * \brief Proxy function 
+ */
+extern void udi_channel_event_ind(udi_channel_event_cb_t *cb);
+
+/**
+ * \brief Called when channel event is completed
+ */
+extern void udi_channel_event_complete(
+       udi_channel_event_cb_t *cb, udi_status_t status
+       );
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/init.h b/KernelLand/Modules/Interfaces/UDI/include/udi/init.h
new file mode 100644 (file)
index 0000000..a6d5bb4
--- /dev/null
@@ -0,0 +1,315 @@
+/**
+ * \file udi_init.h
+ */
+#ifndef _UDI_INIT_H_
+#define _UDI_INIT_H_
+
+typedef struct udi_init_s              udi_init_t;
+typedef struct udi_primary_init_s      udi_primary_init_t;
+typedef struct udi_secondary_init_s    udi_secondary_init_t;
+typedef struct udi_ops_init_s  udi_ops_init_t;
+typedef struct udi_cb_init_s   udi_cb_init_t;
+typedef struct udi_cb_select_s udi_cb_select_t;
+typedef struct udi_gcb_init_s  udi_gcb_init_t;
+
+typedef struct udi_init_context_s      udi_init_context_t;
+typedef struct udi_limits_s            udi_limits_t;
+typedef struct udi_chan_context_s      udi_chan_context_t;
+typedef struct udi_child_chan_context_s        udi_child_chan_context_t;
+
+typedef void   udi_op_t(void);
+typedef udi_op_t * const       udi_ops_vector_t;
+
+/**
+ * \brief UDI Initialisation Structure
+ * 
+ * Defines how to initialise and use a UDI driver
+ */
+struct udi_init_s
+{
+       /**
+        * \brief Defines the primary region
+        * \note For secondary modules this must be NULL
+        */
+       udi_primary_init_t      *primary_init_info;
+       
+       /**
+        * \brief Defines all secondary regions
+        * Pointer to a list (so, essentially an array) of ::udi_secondary_init_t
+        * It is terminated by an entry with ::udi_secondary_init_t.region_idx
+        * set to zero.
+        * \note If NULL, it is to be treated as an empty list
+        */
+       udi_secondary_init_t    *secondary_init_list;
+       
+       /**
+        * \brief Channel operations
+        * Pointer to a ::udi_ops_init_t.ops_idx == 0  terminated list that
+        * defines the channel opterations usage for each ops vector implemented
+        * in this module.
+        * \note Must contain at least one entry for each metalanguage used
+        */
+       udi_ops_init_t  *ops_init_list;
+       
+       /**
+        * \brief Control Blocks
+        */
+       udi_cb_init_t   *cb_init_list;
+       
+       /**
+        * \brief Generic Control Blocks
+        */
+       udi_gcb_init_t  *gcb_init_list;
+       
+       /**
+        * \brief Overrides for control blocks
+        * Allows a control block to override the ammount of scratch space it
+        * gets for a specific ops vector.
+        */
+       udi_cb_select_t *cb_select_list;
+};
+
+
+/**
+ * \name Flags for ::udi_primary_init_t.mgmt_op_flags
+ * \{
+ */
+
+/**
+ * \brief Tells the environment that this operation may take some time
+ * Used as a hint in scheduling tasks
+ */
+#define UDI_OP_LONG_EXEC       0x01
+
+/**
+ * \}
+ */
+
+/**
+ * \brief Describes the Primary Region
+ * Tells the environment how to set up the driver's primary region.
+ */
+struct udi_primary_init_s
+{
+       /**
+        * \brief Management Ops Vector
+        * Pointer to a list of functions for the Management Metalanguage
+        */
+       udi_mgmt_ops_t  *mgmt_ops;
+       
+       /**
+        * \brief Flags for \a mgmt_ops
+        * Each entry in \a mgmt_ops is acommanied by an entry in this array.
+        * Each entry contains the flags that apply to the specified ops vector.
+        * \see UDI_OP_LONG_EXEC
+        */
+       const udi_ubit8_t       *mgmt_op_flags;
+       
+       /**
+        * \brief Scratch space size
+        * Specifies the number of bytes to allocate for each control block
+        * passed by the environment.
+        * \note must not exceed ::UDI_MAX_SCRATCH
+        */
+       udi_size_t      mgmt_scratch_requirement;
+       
+       /**
+        * \todo What is this?
+        */
+       udi_ubit8_t     enumeration_attr_list_length;
+       
+       /**
+        * \brief Size in bytes to allocate to each instance of the primary
+        *        region
+        * Essentially the size of the driver's instance state
+        * \note Must be at least sizeof(udi_init_context_t) and not more
+        *       than UDI_MIN_ALLOC_LIMIT
+        */
+       udi_size_t      rdata_size;
+       
+       /**
+        * \brief Size in bytes to allocate for each call to ::udi_enumerate_req
+        * \note Must not exceed UDI_MIN_ALLOC_LIMIT
+        */
+       udi_size_t      child_data_size;
+       
+       /**
+        * \brief Number of path handles for each parent bound to this driver
+        * \todo What the hell are path handles?
+        */
+       udi_ubit8_t     per_parent_paths;
+};
+
+/**
+ * \brief Tells the environment how to create a secondary region
+ */
+struct udi_secondary_init_s
+{
+       /**
+        * \brief Region Index
+        * Non-zero driver-dependent index value that identifies the region
+        * \note This corresponds to a "region" declaration in the udiprops.txt
+        *       file.
+        */
+       udi_index_t     region_idx;
+       /**
+        * \brief Number of bytes to allocate
+        * 
+        * \note Again, must be between sizeof(udi_init_context_t) and
+        *       UDI_MIN_ALLOC_LIMIT
+        */
+       udi_size_t      rdata_size;
+};
+
+/**
+ * \brief Defines channel endpoints (ways of communicating with the driver)
+ * 
+ */
+struct udi_ops_init_s
+{
+       /**
+        * \brief ops index number
+        * Used to uniquely this entry
+        * \note If this is zero, it marks the end of the list
+        */
+       udi_index_t     ops_idx;
+       /**
+        * \brief Metalanguage Index
+        * Defines what metalanguage is used
+        */
+       udi_index_t     meta_idx;
+       /**
+        * \brief Metalanguage Operation
+        * Defines what metalanguage operation is used
+        */
+       udi_index_t     meta_ops_num;
+       /**
+        * \brief Size of the context area
+        * \note If non-zero, must be at least 
+        */
+       udi_size_t      chan_context_size;
+       /**
+        * \brief Pointer to the operations
+        * Pointer to a <<meta>>_<<role>>_ops_t structure
+        */
+       udi_ops_vector_t        *ops_vector;
+       /**
+        * \brief Flags for each entry in \a ops_vector
+        */
+       //const udi_ubit8_t     *op_flags;
+};
+
+/**
+ * \brief Defines control blocks
+ * Much the same as ::udi_ops_init_t
+ */
+struct udi_cb_init_s
+{
+       udi_index_t     cb_idx;
+       udi_index_t     meta_idx;
+       udi_index_t     meta_cb_num;
+       udi_size_t      scratch_requirement;
+       /**
+        * \brief Size of inline memory
+        */
+       udi_size_t      inline_size;
+       /**
+        * \brief Layout of inline memory
+        */
+       udi_layout_t    *inline_layout;
+};
+
+/**
+ * \brief Overrides the scratch size for an operation
+ */
+struct udi_cb_select_s
+{
+       udi_index_t     ops_idx;
+       udi_index_t     cb_idx;
+};
+
+/**
+ * \brief General Control Blocks
+ * These control blocks can only be used as general data storage, not
+ * for any channel operations.
+ */
+struct udi_gcb_init_s
+{
+       udi_index_t     cb_idx;
+       udi_size_t      scratch_requirement;
+};
+
+
+// ===
+// ===
+/**
+ * \brief Environement Imposed Limits
+ */
+struct udi_limits_s
+{
+       /**
+        * \brief Maximum legal ammount of memory that can be allocated
+        */
+       udi_size_t      max_legal_alloc;
+       
+       /**
+        * \brief Maximum ammount of guaranteed memory
+        */
+       udi_size_t      max_safe_alloc;
+       /**
+        * \brief Maximum size of the final string from ::udi_trace_write
+        *        or ::udi_log_write
+        */
+       udi_size_t      max_trace_log_formatted_len;
+       /**
+        * \brief Maximum legal size of an instanct attribute value
+        */
+       udi_size_t      max_instance_attr_len;
+       /**
+        * \brief Minumum time difference (in nanoseconds between unique values
+        *        returned by ::udi_time_current
+        */
+       udi_ubit32_t    min_curtime_res;
+       /**
+        * \brief Minimum resolution of timers
+        * \see ::udi_timer_start_repeating, ::udi_timer_start
+        */
+       udi_ubit32_t    min_timer_res;
+} PACKED;
+
+/**
+ * \brief Primary Region Context data
+ */
+struct udi_init_context_s
+{
+       udi_index_t     region_idx;
+       udi_limits_t    limits;
+};
+
+/**
+ * \brief Channel context data
+ */
+struct udi_chan_context_s
+{
+       /**
+        * \brief Pointer to the driver instance's initial region data
+        */
+       void    *rdata;
+} PACKED;
+
+/**
+ * \brief Child Channel context
+ */
+struct udi_child_chan_context_s
+{
+       /**
+        * \brief Pointer to the driver instance's initial region data
+        */
+       void    *rdata;
+       /**
+        * \brief Some sort of unique ID number
+        */
+       udi_ubit32_t    child_ID;
+};
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/log.h b/KernelLand/Modules/Interfaces/UDI/include/udi/log.h
new file mode 100644 (file)
index 0000000..dccb124
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * \file udi_log.h
+ */
+#ifndef _UDI_LOG_H_
+#define _UDI_LOG_H_
+
+/**
+ * \brief Trace Event
+ */
+typedef udi_ubit32_t   udi_trevent_t;
+
+/**
+ * \brief Log Callback
+ */
+typedef void udi_log_write_call_t(udi_cb_t *gcb, udi_status_t correlated_status);
+
+/**
+ * \name Log Severities
+ * \brief Values for severity
+ * \{
+ */
+#define UDI_LOG_DISASTER       1
+#define UDI_LOG_ERROR          2
+#define UDI_LOG_WARNING                3
+#define UDI_LOG_INFORMATION    4
+/**
+ * \}
+ */
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/mem.h b/KernelLand/Modules/Interfaces/UDI/include/udi/mem.h
new file mode 100644 (file)
index 0000000..d29f25e
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * \file udi_mem.h
+ */
+#ifndef _UDI_MEM_H_
+#define _UDI_MEM_H_
+
+/**
+ * \brief Callback type for ::udi_mem_alloc
+ */
+typedef void udi_mem_alloc_call_t(udi_cb_t *gcb, void *new_mem);
+
+/**
+ * \brief Allocate memory
+ */
+extern void udi_mem_alloc(
+       udi_mem_alloc_call_t *callback,
+       udi_cb_t        *gcb,
+       udi_size_t      size,
+       udi_ubit8_t     flags
+       );
+
+/**
+ * \brief Values for ::udi_mem_alloc \a flags
+ * \{
+ */
+#define UDI_MEM_NOZERO               (1U<<0)   //!< No need to zero the memory
+#define UDI_MEM_MOVABLE              (1U<<1)   //!< Globally accessable memory?
+/**
+ * \}
+ */
+
+/**
+ * \brief Free allocated memory
+ */
+extern void udi_mem_free(void *target_mem);
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/meta_gio.h b/KernelLand/Modules/Interfaces/UDI/include/udi/meta_gio.h
new file mode 100644 (file)
index 0000000..d1cf86f
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+ * \file udi_meta_gio.h
+ */
+#ifndef _UDI_META_GIO_H_
+#define _UDI_META_GIO_H_
+
+typedef const struct udi_gio_provider_ops_s    udi_gio_provider_ops_t;
+typedef const struct udi_gio_client_ops_s      udi_gio_client_ops_t;
+typedef struct udi_gio_bind_cb_s       udi_gio_bind_cb_t;
+typedef struct udi_gio_xfer_cb_s       udi_gio_xfer_cb_t;
+typedef struct udi_gio_rw_params_s     udi_gio_rw_params_t;
+typedef struct udi_gio_event_cb_s      udi_gio_event_cb_t;
+
+typedef void   udi_gio_bind_req_op_t(udi_gio_bind_cb_t *cb);
+typedef void   udi_gio_unbind_req_op_t(udi_gio_bind_cb_t *cb);
+typedef void   udi_gio_xfer_req_op_t(udi_gio_bind_cb_t *cb);
+typedef void   udi_gio_event_res_op_t(udi_gio_bind_cb_t *cb);
+
+typedef void   udi_gio_bind_ack_op_t(
+       udi_gio_bind_cb_t *cb,
+       udi_ubit32_t    device_size_lo,
+       udi_ubit32_t    device_size_hi,
+       udi_status_t    status
+       );
+typedef void   udi_gio_unbind_ack_op_t(udi_gio_bind_cb_t *cb);
+typedef void   udi_gio_xfer_ack_op_t(udi_gio_bind_cb_t *cb);
+typedef void   udi_gio_xfer_nak_op_t(udi_gio_bind_cb_t *cb, udi_status_t status);
+typedef void   udi_gio_event_ind_op_t(udi_gio_bind_cb_t *cb);
+
+typedef udi_ubit8_t    udi_gio_op_t;
+/* Limit values for udi_gio_op_t */
+#define UDI_GIO_OP_CUSTOM                 16
+#define UDI_GIO_OP_MAX                    64
+/* Direction flag values for op */
+#define UDI_GIO_DIR_READ                  (1U<<6)
+#define UDI_GIO_DIR_WRITE                 (1U<<7)
+/* Standard Operation Codes */
+#define UDI_GIO_OP_READ       UDI_GIO_DIR_READ
+#define UDI_GIO_OP_WRITE      UDI_GIO_DIR_WRITE
+
+
+
+struct udi_gio_provider_ops_s
+{
+       udi_channel_event_ind_op_t      *channel_event_ind_op;
+       udi_gio_bind_req_op_t   *gio_bind_req_op;
+       udi_gio_unbind_req_op_t *gio_unbind_req_op;
+       udi_gio_xfer_req_op_t   *gio_xfer_req_op;
+       udi_gio_event_res_op_t  *gio_event_res_op;
+};
+/* Ops Vector Number */
+#define UDI_GIO_PROVIDER_OPS_NUM          1
+
+struct udi_gio_client_ops_s
+{
+       udi_channel_event_ind_op_t      *channel_event_ind_op;
+       udi_gio_bind_ack_op_t   *gio_bind_ack_op;
+       udi_gio_unbind_ack_op_t *gio_unbind_ack_op;
+       udi_gio_xfer_ack_op_t   *gio_xfer_ack_op;
+       udi_gio_xfer_nak_op_t   *gio_xfer_nak_op;
+       udi_gio_event_ind_op_t  *gio_event_ind_op;
+};
+/* Ops Vector Number */
+#define UDI_GIO_CLIENT_OPS_NUM            2
+
+struct udi_gio_bind_cb_s
+{
+       udi_cb_t        gcb;
+       udi_xfer_constraints_t  xfer_constraints;
+};
+/* Control Block Group Number */
+#define UDI_GIO_BIND_CB_NUM      1
+
+
+struct udi_gio_xfer_cb_s
+{
+       udi_cb_t        gcb;
+       udi_gio_op_t    op;
+       void    *tr_params;
+       udi_buf_t       *data_buf;
+};
+/* Control Block Group Number */
+#define UDI_GIO_XFER_CB_NUM      2
+
+struct udi_gio_rw_params_s
+{
+       udi_ubit32_t offset_lo;
+       udi_ubit32_t offset_hi;
+};
+
+struct udi_gio_event_cb_s
+{
+       udi_cb_t        gcb;
+       udi_ubit8_t     event_code;
+       void    *event_params;
+};
+/* Control Block Group Number */
+#define UDI_GIO_EVENT_CB_NUM     3
+
+
+extern void udi_gio_bind_req(udi_gio_bind_cb_t *cb);
+extern void udi_gio_bind_ack(
+       udi_gio_bind_cb_t       *cb,
+       udi_ubit32_t    device_size_lo,
+       udi_ubit32_t    device_size_hi,
+       udi_status_t    status
+       );
+
+extern void udi_gio_unbind_req(udi_gio_bind_cb_t *cb);
+extern void udi_gio_unbind_ack(udi_gio_bind_cb_t *cb);
+
+extern void udi_gio_xfer_req(udi_gio_xfer_cb_t *cb);
+extern void udi_gio_xfer_ack(udi_gio_xfer_cb_t *cb);
+extern void udi_gio_xfer_nak(udi_gio_xfer_cb_t *cb, udi_status_t status);
+
+extern void udi_gio_event_res(udi_gio_event_cb_t *cb);
+extern void udi_gio_event_ind(udi_gio_event_cb_t *cb);
+extern void udi_gio_event_res_unused(udi_gio_event_cb_t *cb);
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/meta_mgmt.h b/KernelLand/Modules/Interfaces/UDI/include/udi/meta_mgmt.h
new file mode 100644 (file)
index 0000000..97eccf2
--- /dev/null
@@ -0,0 +1,156 @@
+/**
+ * \file udi_meta_mgmt.h
+ */
+#ifndef _UDI_META_MGMT_H_
+#define _UDI_META_MGMT_H_
+
+typedef struct udi_mgmt_ops_s  udi_mgmt_ops_t;
+typedef struct udi_mgmt_cb_s   udi_mgmt_cb_t;
+typedef struct udi_usage_cb_s  udi_usage_cb_t;
+typedef struct udi_filter_element_s    udi_filter_element_t;
+typedef struct udi_enumerate_cb_s      udi_enumerate_cb_t;
+
+/**
+ * \name Specify Usage
+ * \{
+ */
+typedef void udi_usage_ind_op_t(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
+/* Values for resource_level */
+#define UDI_RESOURCES_CRITICAL     1
+#define UDI_RESOURCES_LOW          2
+#define UDI_RESOURCES_NORMAL       3
+#define UDI_RESOURCES_PLENTIFUL    4
+/* Proxy */
+extern void    udi_static_usage(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
+/**
+ * \}
+ */
+
+typedef void udi_usage_res_op_t(udi_usage_cb_t *cb);
+
+/**
+ * \name Enumerate this driver
+ * \{
+ */
+typedef void udi_enumerate_req_op_t(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
+/* Values for enumeration_level */
+#define UDI_ENUMERATE_START           1
+#define UDI_ENUMERATE_START_RESCAN    2
+#define UDI_ENUMERATE_NEXT            3
+#define UDI_ENUMERATE_NEW             4
+#define UDI_ENUMERATE_DIRECTED        5
+#define UDI_ENUMERATE_RELEASE         6
+/* Proxy */
+extern void udi_enumerate_no_children(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
+/**
+ * \}
+ */
+
+/**
+ * \name Enumeration Acknowlagement
+ * \{
+ */
+typedef void udi_enumerate_ack_op_t(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_result, udi_index_t ops_idx);
+/* Values for enumeration_result */
+#define UDI_ENUMERATE_OK             0
+#define UDI_ENUMERATE_LEAF           1
+#define UDI_ENUMERATE_DONE           2
+#define UDI_ENUMERATE_RESCAN         3
+#define UDI_ENUMERATE_REMOVED        4
+#define UDI_ENUMERATE_REMOVED_SELF   5
+#define UDI_ENUMERATE_RELEASED       6
+#define UDI_ENUMERATE_FAILED         255
+/**
+ * \}
+ */
+
+/**
+ * \name 
+ * \{
+ */
+typedef void udi_devmgmt_req_op_t(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
+
+typedef void udi_devmgmt_ack_op_t(udi_mgmt_cb_t *cb, udi_ubit8_t flags, udi_status_t status);
+/**
+ * \}
+ */
+typedef void udi_final_cleanup_req_op_t(udi_mgmt_cb_t *cb);
+typedef void udi_final_cleanup_ack_op_t(udi_mgmt_cb_t *cb);
+
+
+
+
+
+struct udi_mgmt_ops_s
+{
+       udi_usage_ind_op_t      *usage_ind_op;
+       udi_enumerate_req_op_t  *enumerate_req_op;
+       udi_devmgmt_req_op_t    *devmgmt_req_op;
+       udi_final_cleanup_req_op_t      *final_cleanup_req_op;
+};
+
+struct udi_mgmt_cb_s
+{
+       udi_cb_t        gcb;
+};
+
+struct udi_usage_cb_s
+{
+       udi_cb_t        gcb;
+       udi_trevent_t   trace_mask;
+       udi_index_t     meta_idx;
+};
+
+
+struct udi_filter_element_s
+{
+     char      attr_name[UDI_MAX_ATTR_NAMELEN];
+     udi_ubit8_t       attr_min[UDI_MAX_ATTR_SIZE];
+     udi_ubit8_t       attr_min_len;
+     udi_ubit8_t       attr_max[UDI_MAX_ATTR_SIZE];
+     udi_ubit8_t       attr_max_len;
+     udi_instance_attr_type_t  attr_type;
+     udi_ubit32_t      attr_stride;
+};
+struct udi_enumerate_cb_s
+{
+     udi_cb_t  gcb;
+     udi_ubit32_t      child_ID;
+     void      *child_data;
+     udi_instance_attr_list_t  *attr_list;
+     udi_ubit8_t       attr_valid_length;
+     const udi_filter_element_t        *filter_list;
+     udi_ubit8_t       filter_list_length;
+     udi_ubit8_t       parent_ID;
+};
+/* Special parent_ID filter values */
+#define UDI_ANY_PARENT_ID      0
+
+/**
+ * \brief 
+ */
+extern void    udi_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID );
+/**
+ * \brief Values for ::udi_devmgmt_req \a mgmt_op
+ */
+enum eDMGMT
+{
+       UDI_DMGMT_PREPARE_TO_SUSPEND = 1,
+       UDI_DMGMT_SUSPEND,
+       UDI_DMGMT_SHUTDOWN,
+       UDI_DMGMT_PARENT_SUSPENDED,
+       UDI_DMGMT_RESUME,
+       UDI_DMGMT_UNBIND
+};
+
+extern void    udi_devmgmt_ack(udi_mgmt_cb_t *cb, udi_ubit8_t flags, udi_status_t status);
+//!\brief Values for flags
+#define UDI_DMGMT_NONTRANSPARENT       (1U<<0)
+//!\brief Meta-Specific Status Codes
+#define UDI_DMGMT_STAT_ROUTING_CHANGE  (UDI_STAT_META_SPECIFIC|1)
+
+extern void udi_final_cleanup_req(udi_mgmt_cb_t *cb);
+extern void udi_final_cleanup_ack(udi_mgmt_cb_t *cb);
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi/strmem.h b/KernelLand/Modules/Interfaces/UDI/include/udi/strmem.h
new file mode 100644 (file)
index 0000000..f540a3e
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * \file udi_strmem.h
+ */
+#ifndef _UDI_STRMEM_H_
+#define _UDI_STRMEM_H_
+
+/**
+ * \brief Gets the length of a C style string
+ */
+extern udi_size_t      udi_strlen(const char *s);
+
+/**
+ * \brief Appends to a string
+ */
+extern char *udi_strcat(char *s1, const char *s2);
+extern char *udi_strncat(char *s1, const char *s2, udi_size_t n);
+
+/**
+ * \brief Compares Strings/Memory
+ */
+extern udi_sbit8_t udi_strcmp(const char *s1, const char *s2);
+extern udi_sbit8_t udi_strncmp(const char *s1, const char *s2, udi_size_t n);
+extern udi_sbit8_t udi_memcmp(const void *s1, const void *s2, udi_size_t n);
+
+extern char *udi_strcpy(char *s1, const char *s2);
+extern char *udi_strncpy(char *s1, const char *s2, udi_size_t n);
+extern void *udi_memcpy(void *s1, const void *s2, udi_size_t n);
+extern void *udi_memmove(void *s1, const void *s2, udi_size_t n);
+
+extern char *udi_strncpy_rtrim(char *s1, const char *s2, udi_size_t n);
+
+extern char *udi_strchr(const char *s, char c);
+extern char *udi_strrchr(const char *s, char c);
+extern void *udi_memchr (const void *s, udi_ubit8_t c, udi_size_t n);
+
+extern void *udi_memset(void *s, udi_ubit8_t c, udi_size_t n);
+extern udi_ubit32_t udi_strtou32(const char *s, char **endptr, int base);
+
+
+extern udi_size_t udi_snprintf(char *s, udi_size_t max_bytes, const char *format, ...);
+
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/include/udi_physio.h b/KernelLand/Modules/Interfaces/UDI/include/udi_physio.h
new file mode 100644 (file)
index 0000000..1397b1c
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * \file udi_physio.h
+ */
+#ifndef _UDI_PHYSIO_H_
+#define _UDI_PHYSIO_H_
+
+#include <udi.h>
+
+// === TYPEDEFS ===
+// DMA Core
+typedef _udi_handle_t  udi_dma_handle_t;
+#define        UDI_NULL_DMA_HANDLE     _NULL_HANDLE
+typedef Uint64 udi_busaddr64_t;        //!< \note Opaque
+typedef struct udi_scgth_element_32_s  udi_scgth_element_32_t;
+typedef struct udi_scgth_element_64_s  udi_scgth_element_64_t;
+typedef struct udi_scgth_s     udi_scgth_t;
+typedef _udi_handle_t  udi_dma_constraints_t;
+#define UDI_NULL_DMA_CONSTRAINTS       _NULL_HANDLE
+/**
+ * \name DMA constraints attributes
+ * \{
+ */
+typedef udi_ubit8_t udi_dma_constraints_attr_t;
+/* DMA Convenience Attribute Codes */
+#define UDI_DMA_ADDRESSABLE_BITS          100
+#define UDI_DMA_ALIGNMENT_BITS            101
+/* DMA Constraints on the Entire Transfer */
+#define UDI_DMA_DATA_ADDRESSABLE_BITS     110
+#define UDI_DMA_NO_PARTIAL                111
+/* DMA Constraints on the Scatter/Gather  List */
+#define UDI_DMA_SCGTH_MAX_ELEMENTS        120
+#define UDI_DMA_SCGTH_FORMAT              121
+#define UDI_DMA_SCGTH_ENDIANNESS          122
+#define UDI_DMA_SCGTH_ADDRESSABLE_BITS    123
+#define UDI_DMA_SCGTH_MAX_SEGMENTS        124
+/* DMA Constraints on Scatter/Gather Segments */
+#define UDI_DMA_SCGTH_ALIGNMENT_BITS      130
+#define UDI_DMA_SCGTH_MAX_EL_PER_SEG      131
+#define UDI_DMA_SCGTH_PREFIX_BYTES        132
+/* DMA Constraints on Scatter/Gather Elements */
+#define UDI_DMA_ELEMENT_ALIGNMENT_BITS    140
+#define UDI_DMA_ELEMENT_LENGTH_BITS       141
+#define UDI_DMA_ELEMENT_GRANULARITY_BITS 142
+/* DMA Constraints for Special Addressing */
+#define UDI_DMA_ADDR_FIXED_BITS           150
+#define UDI_DMA_ADDR_FIXED_TYPE           151
+#define UDI_DMA_ADDR_FIXED_VALUE_LO       152
+#define UDI_DMA_ADDR_FIXED_VALUE_HI       153
+/* DMA Constraints on DMA Access Behavior */
+#define UDI_DMA_SEQUENTIAL                160
+#define UDI_DMA_SLOP_IN_BITS              161
+#define UDI_DMA_SLOP_OUT_BITS             162
+#define UDI_DMA_SLOP_OUT_EXTRA            163
+#define UDI_DMA_SLOP_BARRIER_BITS         164
+/* Values for UDI_DMA_SCGTH_ENDIANNESS */
+#define UDI_DMA_LITTLE_ENDIAN             (1U<<6)
+#define UDI_DMA_BIG_ENDIAN                (1U<<5)
+/* Values for UDI_DMA_ADDR_FIXED_TYPE */
+#define UDI_DMA_FIXED_ELEMENT             1
+/**
+ * \}
+ */
+// DMA Constraints Management
+typedef struct udi_dma_constraints_attr_spec_s udi_dma_constraints_attr_spec_t;
+typedef void udi_dma_constraints_attr_set_call_t(
+       udi_cb_t *gcb, udi_dma_constraints_t new_constraints, udi_status_t status
+       );
+typedef        struct udi_dma_limits_s udi_dma_limits_t;
+
+
+// === STRUCTURES ===
+// --- DMA Constraints Management ---
+struct udi_dma_constraints_attr_spec_s
+{
+     udi_dma_constraints_attr_t        attr_type;
+     udi_ubit32_t      attr_value;
+};
+// --- DMA Core ---
+struct udi_dma_limits_s
+{
+     udi_size_t max_legal_contig_alloc;
+     udi_size_t max_safe_contig_alloc;
+     udi_size_t cache_line_size;
+};
+struct udi_scgth_element_32_s
+{
+     udi_ubit32_t      block_busaddr;
+     udi_ubit32_t      block_length;
+};
+struct udi_scgth_element_64_s
+{
+     udi_busaddr64_t   block_busaddr;
+     udi_ubit32_t      block_length;
+     udi_ubit32_t      el_reserved;
+};
+/* Extension Flag */
+#define UDI_SCGTH_EXT                    0x80000000
+struct udi_scgth_s
+{
+     udi_ubit16_t      scgth_num_elements;
+     udi_ubit8_t       scgth_format;
+     udi_boolean_t     scgth_must_swap;
+     union {
+          udi_scgth_element_32_t       *el32p;
+          udi_scgth_element_64_t       *el64p;
+     } scgth_elements;
+     union {
+          udi_scgth_element_32_t       el32;
+          udi_scgth_element_64_t       el64;
+     } scgth_first_segment;
+};
+/* Values for scgth_format */
+#define UDI_SCGTH_32                     (1U<<0)
+#define UDI_SCGTH_64                     (1U<<1)
+#define UDI_SCGTH_DMA_MAPPED             (1U<<6)
+#define UDI_SCGTH_DRIVER_MAPPED          (1U<<7)
+
+
+
+// === FUNCTIONS ===
+// --- DMA Constraints Management ---
+extern void udi_dma_constraints_attr_set(
+       udi_dma_constraints_attr_set_call_t     *callback,
+       udi_cb_t        *gcb,
+       udi_dma_constraints_t   src_constraints,
+       const udi_dma_constraints_attr_spec_t   *attr_list,
+       udi_ubit16_t    list_length,
+       udi_ubit8_t     flags
+       );
+/* Constraints Flags */
+#define UDI_DMA_CONSTRAINTS_COPY (1U<<0)
+
+extern void udi_dma_constraints_attr_reset(
+       udi_dma_constraints_t   constraints,
+       udi_dma_constraints_attr_t      attr_type
+       );
+
+extern void udi_dma_constraints_free(udi_dma_constraints_t constraints);
+
+#include <physio/meta_intr.h>
+#include <physio/meta_bus.h>
+
+
+#endif
diff --git a/KernelLand/Modules/Interfaces/UDI/logging.c b/KernelLand/Modules/Interfaces/UDI/logging.c
new file mode 100644 (file)
index 0000000..2e58e37
--- /dev/null
@@ -0,0 +1,18 @@
+/**
+ * \file logging.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === PROTOTYPES ===
+
+// === CODE ===
+void udi_log_write( udi_log_write_call_t *callback, udi_cb_t *gcb,
+       udi_trevent_t trace_event, udi_ubit8_t severity, udi_index_t meta_idx,
+       udi_status_t original_status, udi_ubit32_t msgnum, ... )
+{
+       Log("UDI Log");
+}
+
+EXPORT(udi_log_write);
diff --git a/KernelLand/Modules/Interfaces/UDI/main.c b/KernelLand/Modules/Interfaces/UDI/main.c
new file mode 100644 (file)
index 0000000..a4a1504
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Acess2 UDI Layer
+ */
+#define DEBUG  0
+#define VERSION        ((0<<8)|1)
+#include <acess.h>
+#include <modules.h>
+#include <udi.h>
+
+// === PROTOTYPES ===
+ int   UDI_Install(char **Arguments);
+ int   UDI_DetectDriver(void *Base);
+ int   UDI_LoadDriver(void *Base);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
+tModuleLoader  gUDI_Loader = {
+       NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
+};
+
+// === CODE ===
+/**
+ * \fn int UDI_Install(char **Arguments)
+ * \brief Stub intialisation routine
+ */
+int UDI_Install(char **Arguments)
+{
+       Module_RegisterLoader( &gUDI_Loader );
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Detects if a driver should be loaded by the UDI subsystem
+ */
+int UDI_DetectDriver(void *Base)
+{
+       if( Binary_FindSymbol(Base, "udi_init_info", NULL) == 0) {
+               return 0;
+       }
+       
+       return 1;
+}
+
+/**
+ * \fn int UDI_LoadDriver(void *Base)
+ */
+int UDI_LoadDriver(void *Base)
+{
+       udi_init_t      *info;
+       char    *udiprops = NULL;
+        int    udiprops_size = 0;
+        int    i;
+       // int  j;
+       
+       Log_Debug("UDI", "UDI_LoadDriver: (Base=%p)", Base);
+       
+       if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
+               Binary_Unload(Base);
+               return 0;
+       }
+       
+       if( Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops) == 0 ) {
+               Log_Warning("UDI", "_udiprops is not defined, this is usually bad");
+       }
+       else {
+               Uint    udiprops_end = 0;
+                int    i, j, nLines;
+               char    **udipropsptrs;
+               
+               if( Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end) == 0)
+                       Log_Warning("UDI", "_udiprops_end is not defined");
+               Log_Debug("UDI", "udiprops_end = %p", udiprops_end);
+               udiprops_size = udiprops_end - (Uint)udiprops;
+               Log_Debug("UDI", "udiprops = %p, udiprops_size = 0x%x", udiprops, udiprops_size);
+               
+               Debug_HexDump("UDI_LoadDriver", udiprops, udiprops_size);
+               
+               nLines = 1;
+               for( i = 0; i < udiprops_size; i++ )
+               {
+                       if( udiprops[i] == '\0' )
+                               nLines ++;
+               }
+               
+               Log_Debug("UDI", "nLines = %i", nLines);
+               
+               udipropsptrs = malloc( sizeof(char*)*nLines );
+               udipropsptrs[0] = udiprops;
+               j = 0;
+               for( i = 0; i < udiprops_size; i++ )
+               {
+                       if( udiprops[i] == '\0' ) {
+                               //Log_Debug("UDI", "udipropsptrs[%i] = '%s'", j, udipropsptrs[j]);
+                               udipropsptrs[j++] = &udiprops[i+1];
+                       }
+               }
+               Log_Debug("UDI", "udipropsptrs[%i] = '%s'", j, udipropsptrs[j]);
+               Log_Debug("UDI", "udiprops = \"%s\"", udiprops);
+       }
+       
+       
+       Log("primary_init_info = %p = {", info->primary_init_info);
+       {
+               Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
+               Log("  .usage_ind_op: %p() - 0x%02x",
+                       info->primary_init_info->mgmt_ops->usage_ind_op,
+                       info->primary_init_info->mgmt_op_flags[0]
+                       );
+               Log("  .enumerate_req_op: %p() - 0x%02x",
+                       info->primary_init_info->mgmt_ops->enumerate_req_op,
+                       info->primary_init_info->mgmt_op_flags[1]
+                       );
+               Log("  .devmgmt_req_op: %p() - 0x%02x",
+                       info->primary_init_info->mgmt_ops->devmgmt_req_op,
+                       info->primary_init_info->mgmt_op_flags[2]
+                       );
+               Log("  .final_cleanup_req_op: %p() - 0x%02x",
+                       info->primary_init_info->mgmt_ops->final_cleanup_req_op,
+                       info->primary_init_info->mgmt_op_flags[3]
+                       );
+               Log(" }");
+               Log(" .mgmt_scratch_requirement = 0x%x", info->primary_init_info->mgmt_scratch_requirement);
+               Log(" .enumeration_attr_list_length = 0x%x", info->primary_init_info->enumeration_attr_list_length);
+               Log(" .rdata_size = 0x%x", info->primary_init_info->rdata_size);
+               Log(" .child_data_size = 0x%x", info->primary_init_info->child_data_size);
+               Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
+       }
+       Log("}");
+       Log("secondary_init_list = %p", info->secondary_init_list);
+       Log("ops_init_list = %p", info->ops_init_list);
+       
+       for( i = 0; info->ops_init_list[i].ops_idx; i++ )
+       {
+               Log("info->ops_init_list[%i] = {", i);
+               Log(" .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
+               Log(" .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
+               Log(" .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
+               Log(" .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
+               Log(" .ops_vector = %p", info->ops_init_list[i].ops_vector);
+//             Log(" .op_flags = %p", info->ops_init_list[i].op_flags);
+               Log("}");
+       }
+       
+       return 0;
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/mem.c b/KernelLand/Modules/Interfaces/UDI/mem.c
new file mode 100644 (file)
index 0000000..a09d54c
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * \file mem.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === EXPORTS ===
+EXPORT(udi_mem_alloc);
+EXPORT(udi_mem_free);
+
+// === CODE ===
+void udi_mem_alloc(
+       udi_mem_alloc_call_t *callback,
+       udi_cb_t        *gcb,
+       udi_size_t      size,
+       udi_ubit8_t     flags
+       )
+{
+       void    *buf = malloc(size);
+       if(buf)
+       {
+               if( !(flags & UDI_MEM_NOZERO) )
+                       memset(buf, 0, size);
+       }
+       callback(gcb, buf);
+}
+
+void udi_mem_free(void *target_mem)
+{
+       free(target_mem);
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/meta_gio.c b/KernelLand/Modules/Interfaces/UDI/meta_gio.c
new file mode 100644 (file)
index 0000000..1618c27
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * \file meta_gio.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === EXPORTS ===
+EXPORT(udi_gio_bind_req);
+EXPORT(udi_gio_bind_ack);
+EXPORT(udi_gio_unbind_req);
+EXPORT(udi_gio_unbind_ack);
+EXPORT(udi_gio_xfer_req);
+EXPORT(udi_gio_xfer_ack);
+EXPORT(udi_gio_xfer_nak);
+EXPORT(udi_gio_event_res);
+EXPORT(udi_gio_event_ind);
+EXPORT(udi_gio_event_res_unused);
+
+// === CODE ===
+void udi_gio_bind_req(udi_gio_bind_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_gio_bind_ack(
+       udi_gio_bind_cb_t       *cb,
+       udi_ubit32_t    device_size_lo,
+       udi_ubit32_t    device_size_hi,
+       udi_status_t    status
+       )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_gio_unbind_req(udi_gio_bind_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_gio_unbind_ack(udi_gio_bind_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_gio_xfer_req(udi_gio_xfer_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_gio_xfer_ack(udi_gio_xfer_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_gio_xfer_nak(udi_gio_xfer_cb_t *cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_gio_event_res(udi_gio_event_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_gio_event_ind(udi_gio_event_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_gio_event_res_unused(udi_gio_event_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/meta_mgmt.c b/KernelLand/Modules/Interfaces/UDI/meta_mgmt.c
new file mode 100644 (file)
index 0000000..45a02c4
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * \file meta_mgmt.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === EXPORTS ===
+EXPORT(udi_devmgmt_req);
+EXPORT(udi_devmgmt_ack);
+EXPORT(udi_final_cleanup_req);
+EXPORT(udi_final_cleanup_ack);
+EXPORT(udi_static_usage);
+EXPORT(udi_enumerate_no_children);
+
+// === CODE ===
+void udi_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID )
+{      
+       ENTER("pcb imgmt_op iparent_ID", cb, mgmt_op, parent_ID);
+       LEAVE('-');
+}
+
+void udi_devmgmt_ack(udi_mgmt_cb_t *cb, udi_ubit8_t flags, udi_status_t status)
+{
+       ENTER("pcb xflags istatus", cb, flags, status);
+       LEAVE('-');
+}
+
+void udi_final_cleanup_req(udi_mgmt_cb_t *cb)
+{
+       ENTER("pcb", cb);
+       LEAVE('-');
+}
+
+void udi_final_cleanup_ack(udi_mgmt_cb_t *cb)
+{
+       ENTER("pcb", cb);
+       LEAVE('-');
+}
+
+void udi_static_usage(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_enumerate_no_children(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
+{
+       UNIMPLEMENTED();
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/physio.c b/KernelLand/Modules/Interfaces/UDI/physio.c
new file mode 100644 (file)
index 0000000..881c9f4
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * \file physio.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+#include <udi_physio.h>
+
+// === EXPORTS ===
+EXPORT(udi_dma_constraints_attr_reset);
+EXPORT(udi_dma_constraints_free);
+
+// === CODE ===
+void udi_dma_constraints_attr_reset(
+       udi_dma_constraints_t   constraints,
+       udi_dma_constraints_attr_t      attr_type
+       )
+{
+       UNIMPLEMENTED();
+}
+
+void udi_dma_constraints_free(udi_dma_constraints_t constraints)
+{
+       UNIMPLEMENTED();
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/physio/meta_bus.c b/KernelLand/Modules/Interfaces/UDI/physio/meta_bus.c
new file mode 100644 (file)
index 0000000..e1e6a47
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * \file physio/meta_bus.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+#include <udi_physio.h>
+
+// === EXPORTS ===
+EXPORT(udi_bus_unbind_req);
+EXPORT(udi_bus_unbind_ack);
+EXPORT(udi_bus_bind_req);
+EXPORT(udi_bus_bind_ack);
+
+// === CODE ===
+void udi_bus_unbind_req(udi_bus_bind_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_bus_unbind_ack(udi_bus_bind_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_bus_bind_req(udi_bus_bind_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_bus_bind_ack(
+       udi_bus_bind_cb_t       *cb,
+       udi_dma_constraints_t   dma_constraints,
+       udi_ubit8_t     preferred_endianness,
+       udi_status_t    status
+       )
+{
+       UNIMPLEMENTED();
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/physio/meta_intr.c b/KernelLand/Modules/Interfaces/UDI/physio/meta_intr.c
new file mode 100644 (file)
index 0000000..f4f5096
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * \file physio/meta_intr.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+#include <udi_physio.h>
+
+// === EXPORTS ===
+EXPORT(udi_intr_attach_req);
+EXPORT(udi_intr_attach_ack);
+EXPORT(udi_intr_attach_ack_unused);
+EXPORT(udi_intr_detach_req);
+EXPORT(udi_intr_detach_ack);
+EXPORT(udi_intr_detach_ack_unused);
+EXPORT(udi_intr_event_ind);
+
+// === CODE ===
+void udi_intr_attach_req(udi_intr_attach_cb_t *intr_attach_cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+void udi_intr_attach_ack_unused(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_intr_detach_req(udi_intr_detach_cb_t *intr_detach_cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
+{
+       UNIMPLEMENTED();
+}
+void udi_intr_detach_ack_unused(udi_intr_detach_cb_t *intr_detach_cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_intr_event_ind(udi_intr_event_cb_t *intr_event_cb, udi_ubit8_t flags)
+{
+       UNIMPLEMENTED();
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/physio_main.c b/KernelLand/Modules/Interfaces/UDI/physio_main.c
new file mode 100644 (file)
index 0000000..f5e7aa0
--- /dev/null
@@ -0,0 +1,16 @@
+/**
+ * \file logging.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <common.h>
+#include <udi.h>
+#include <udi_physio.h>
+
+// === CODE ===
+void udi_bus_bind_req(udi_bus_bind_cb_t *cb)
+{
+}
+
+void udi_bus_unbind_req(udi_bus_bind_cb_t *cb)
+{
+}
diff --git a/KernelLand/Modules/Interfaces/UDI/strmem.c b/KernelLand/Modules/Interfaces/UDI/strmem.c
new file mode 100644 (file)
index 0000000..53cc933
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * \file strmem.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+
+// === EXPORTS ===
+EXPORT(udi_snprintf);
+
+// === CODE ===
+udi_size_t udi_snprintf(char *s, udi_size_t max_bytes, const char *format, ...)
+{
+       udi_size_t      ret;
+       va_list args;
+       va_start(args, format);
+       
+       ret = vsnprintf(s, max_bytes, format, args);
+       
+       va_end(args);
+       return ret;
+}
diff --git a/KernelLand/Modules/Libraries/SunRPC/proto.h b/KernelLand/Modules/Libraries/SunRPC/proto.h
new file mode 100644 (file)
index 0000000..150fc42
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Acess2 Kernel
+ * - Sun RPC (RFC 1057) implementation
+ * proto.h
+ * - Protocol definition
+ */
+#ifndef _SUNRPC_PROTO_H_
+#define _SUNRPC_PROTO_H_
+
+struct sRPC_CallBody
+{
+       Uint32  RPCVers;        //!< Version (2)
+       Uint32  Program;        //!< Program Identifier
+       Uint32  Version;        //!< Program Version
+       
+};
+
+struct sRPC_Message
+{
+       tNet32  XID;    //!< Transaction Identifier
+       union
+       {
+               struct sRPC_CallBody    Call;
+       };
+};
+
+#endif
+
diff --git a/KernelLand/Modules/Makefile.tpl b/KernelLand/Modules/Makefile.tpl
new file mode 100644 (file)
index 0000000..f1c31a5
--- /dev/null
@@ -0,0 +1,75 @@
+
+# Acess2 Module/Driver Templater Makefile
+# Makefile.tpl
+
+_CPPFLAGS := $(CPPFLAGS)
+
+-include $(dir $(lastword $(MAKEFILE_LIST)))../Makefile.cfg
+
+LIBINCLUDES := $(addprefix -I$(ACESSDIR)/Modules/,$(DEPS))
+LIBINCLUDES := $(addsuffix /include,$(LIBINCLUDES))
+
+CPPFLAGS := -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include
+CPPFLAGS += -DARCH=$(ARCH) -DARCH_is_$(ARCH) -DARCHDIR_is_$(ARCHDIR)
+CPPFLAGS += $(_CPPFLAGS)
+CPPFLAGS += $(LIBINCLUDES)
+CFLAGS := -std=gnu99 -Wall -fno-stack-protector -g -O3
+
+ifneq ($(CATEGORY),)
+       FULLNAME := $(CATEGORY)_$(NAME)
+else
+       FULLNAME := $(NAME)
+endif
+
+CPPFLAGS += -D_MODULE_NAME_=\"$(FULLNAME)\"
+
+ifneq ($(BUILDTYPE),static)
+       _SUFFIX := dyn_$(ARCH)
+       BIN := ../$(FULLNAME).kmd.$(ARCH)
+       CFLAGS += $(DYNMOD_CFLAGS) -fPIC
+else
+       _SUFFIX := st_$(ARCH)
+       CFLAGS += $(KERNEL_CFLAGS)
+       BIN := ../$(NAME).xo.$(ARCH)
+endif
+
+OBJ := $(addprefix obj-$(_SUFFIX)/,$(OBJ))
+#OBJ := $(addsuffix .$(_SUFFIX),$(OBJ))
+
+DEPFILES := $(filter %.o,$(OBJ))
+DEPFILES := $(DEPFILES:%.o=%.d)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+       $(RM) $(BIN) $(BIN).dsm $(KOBJ) $(OBJ) $(DEPFILES) $(EXTRA)
+       $(RM) -r obj-$(_SUFFIX)
+
+install: $(BIN)
+ifneq ($(BUILDTYPE),static)
+       @$(xMKDIR) $(DISTROOT)/Modules/$(ARCH); true
+       $(xCP) $(BIN) $(DISTROOT)/Modules/$(ARCH)/$(NAME).kmd
+else
+endif
+
+
+ifneq ($(BUILDTYPE),static)
+$(BIN): %.kmd.$(ARCH): $(OBJ)
+       @echo --- $(LD) -o $@
+       @$(LD) --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ) -defsym=DriverInfo=_DriverInfo_$(FULLNAME) $(LDFLAGS)
+       @$(DISASM) $(BIN) > $(BIN).dsm
+else
+$(BIN): %.xo.$(ARCH): $(OBJ)
+       @echo --- $(LD) -o $@
+       @$(LD) -r -o $@ $(OBJ) $(LDFLAGS)
+endif
+
+obj-$(_SUFFIX)/%.o: %.c Makefile $(CFGFILES)
+       @echo --- $(CC) -o $@
+       @mkdir -p $(dir $@)
+       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
+       @$(CC) -M $(CPPFLAGS) -MT $@ -o obj-$(_SUFFIX)/$*.d $<
+
+-include $(DEPFILES)
diff --git a/KernelLand/Modules/Network/Makefile.tpl b/KernelLand/Modules/Network/Makefile.tpl
new file mode 100644 (file)
index 0000000..d5c0b3c
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = Network
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/Network/NE2000/Makefile b/KernelLand/Modules/Network/NE2000/Makefile
new file mode 100644 (file)
index 0000000..7e74022
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = ne2000.o
+NAME = NE2000
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Network/NE2000/ne2000.c b/KernelLand/Modules/Network/NE2000/ne2000.c
new file mode 100644 (file)
index 0000000..d05b2a3
--- /dev/null
@@ -0,0 +1,543 @@
+/* Acess2
+ * NE2000 Driver
+ * 
+ * See: ~/Sources/bochs/bochs.../iodev/ne2k.cc
+ */
+#define        DEBUG   1
+#define VERSION        ((0<<8)|50)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include <api_drv_network.h>
+#include <semaphore.h>
+
+// === CONSTANTS ===
+#define        MEM_START       0x40
+#define        MEM_END         0xC0
+#define RX_FIRST       (MEM_START)
+#define RX_LAST                (MEM_START+RX_BUF_SIZE-1)
+#define        RX_BUF_SIZE     0x40
+#define TX_FIRST       (MEM_START+RX_BUF_SIZE)
+#define TX_LAST                (MEM_END)
+#define        TX_BUF_SIZE     0x40
+#define        MAX_PACKET_QUEUE        10
+
+static const struct {
+       Uint16  Vendor;
+       Uint16  Device;
+} csaCOMPAT_DEVICES[] = {
+       {0x10EC, 0x8029},       // Realtek 8029
+       {0x10EC, 0x8129}        // Realtek 8129
+};
+#define NUM_COMPAT_DEVICES     ((int)(sizeof(csaCOMPAT_DEVICES)/sizeof(csaCOMPAT_DEVICES[0])))
+
+enum eNe2k_Page0Read {
+       CMD = 0,        //!< the master command register
+       CLDA0,          //!< Current Local DMA Address 0
+       CLDA1,          //!< Current Local DMA Address 1
+       BNRY,           //!< Boundary Pointer (for ringbuffer)
+       TSR,            //!< Transmit Status Register
+       NCR,            //!< collisions counter
+       FIFO,           //!< (for what purpose ??)
+       ISR,            //!< Interrupt Status Register
+       CRDA0,          //!< Current Remote DMA Address 0
+       CRDA1,          //!< Current Remote DMA Address 1
+       RSR = 0xC       //!< Receive Status Register
+};
+
+enum eNe2k_Page0Write {
+       PSTART = 1,     //!< page start (init only)
+       PSTOP,          //!< page stop  (init only)
+       TPSR = 4,       //!< transmit page start address
+       TBCR0,          //!< transmit byte count (low)
+       TBCR1,          //!< transmit byte count (high)
+       RSAR0 = 8,      //!< remote start address (lo)
+       RSAR1,  //!< remote start address (hi)
+       RBCR0,  //!< remote byte count (lo)
+       RBCR1,  //!< remote byte count (hi)
+       RCR,    //!< receive config register
+       TCR,    //!< transmit config register
+       DCR,    //!< data config register    (init)
+       IMR             //!< interrupt mask register (init)
+};
+
+enum eNe2k_Page1Read {
+       CURR = 7        //!< current page
+};
+
+// === TYPES ===
+typedef struct sNe2k_Card {
+       Uint16  IOBase; //!< IO Port Address from PCI
+       Uint8   IRQ;    //!< IRQ Assigned from PCI
+       
+       tSemaphore      Semaphore;      //!< Semaphore for incoming packets
+        int    NextRXPage;     //!< Next expected RX page
+       
+        int    NextMemPage;    //!< Next Card Memory page to use
+               
+       char    Name[2];        // "0"
+       tVFS_Node       Node;   //!< VFS Node
+       Uint8   MacAddr[6];     //!< Cached MAC address
+} tCard;
+
+// === PROTOTYPES ===
+ int   Ne2k_Install(char **Arguments);
+char   *Ne2k_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *Ne2k_FindDir(tVFS_Node *Node, const char *Name);
+ int   Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data);
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+
+ int   Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer);
+Uint8  Ne2k_int_GetWritePage(tCard *Card, Uint16 Length);
+void   Ne2k_IRQHandler(int IntNum, void *Ptr);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, Ne2k, Ne2k_Install, NULL, NULL);
+tVFS_NodeType  gNe2K_RootNodeType = {
+       .ReadDir = Ne2k_ReadDir,
+       .FindDir = Ne2k_FindDir,
+       .IOCtl = Ne2k_IOCtl
+       };
+tVFS_NodeType  gNe2K_DevNodeType = {
+       .Write = Ne2k_Write,
+       .Read = Ne2k_Read,
+       .IOCtl = Ne2k_IOCtl     
+       };
+tDevFS_Driver  gNe2k_DriverInfo = {
+       NULL, "ne2k",
+       {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Type = &gNe2K_RootNodeType
+       }
+};
+Uint16 gNe2k_BaseAddress;
+ int   giNe2k_CardCount = 0;
+tCard  *gpNe2k_Cards = NULL;
+
+// === CODE ===
+/**
+ * \fn int Ne2k_Install(char **Options)
+ * \brief Installs the NE2000 Driver
+ */
+int Ne2k_Install(char **Options)
+{
+        int    i, j, k;
+        int    count, base;
+       tPCIDev id;
+       
+       // --- Scan PCI Bus ---
+       // Count Cards
+       giNe2k_CardCount = 0;
+       for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
+       {
+               giNe2k_CardCount += PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device );
+       }
+       
+       if( giNe2k_CardCount == 0 )     return MODULE_ERR_NOTNEEDED;
+       
+       // Enumerate Cards
+       k = 0;
+       gpNe2k_Cards = calloc( giNe2k_CardCount, sizeof(tCard) );
+       
+       for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
+       {
+               count = PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device );
+               for( j = 0; j < count; j ++,k ++ )
+               {
+                       id = PCI_GetDevice( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, j );
+                       // Create Structure
+                       base = PCI_GetBAR( id, 0 );
+                       gpNe2k_Cards[ k ].IOBase = base;
+                       gpNe2k_Cards[ k ].IRQ = PCI_GetIRQ( id );
+                       gpNe2k_Cards[ k ].NextMemPage = 64;
+                       gpNe2k_Cards[ k ].NextRXPage = RX_FIRST;
+                       
+                       // Install IRQ Handler
+                       IRQ_AddHandler(gpNe2k_Cards[ k ].IRQ, Ne2k_IRQHandler, &gpNe2k_Cards[k]);
+                       
+                       // Reset Card
+                       outb( base + 0x1F, inb(base + 0x1F) );
+                       while( (inb( base+ISR ) & 0x80) == 0 );
+                       outb( base + ISR, 0x80 );
+                       
+                       // Initialise Card
+                       outb( base + CMD, 0x40|0x21 );  // Page 1, No DMA, Stop
+                       outb( base + CURR, RX_FIRST );  // Current RX page
+                       outb( base + CMD, 0x21 );       // No DMA and Stop
+                       outb( base + DCR, 0x49 );       // Set WORD mode
+                       outb( base + IMR, 0x00 );       // Interrupt Mask Register
+                       outb( base + ISR, 0xFF );
+                       outb( base + RCR, 0x20 );       // Reciever to Monitor
+                       outb( base + TCR, 0x02 );       // Transmitter OFF (TCR.LB = 1, Internal Loopback)
+                       
+                       // Read MAC Address
+                       outb( base + RBCR0, 6*4 );      // Remote Byte Count
+                       outb( base + RBCR1, 0 );
+                       outb( base + RSAR0, 0 );        // Clear Source Address
+                       outb( base + RSAR1, 0 );
+                       outb( base + CMD, 0x0A );       // Remote Read, Start
+                       gpNe2k_Cards[ k ].MacAddr[0] = inb(base+0x10);//        inb(base+0x10);
+                       gpNe2k_Cards[ k ].MacAddr[1] = inb(base+0x10);//        inb(base+0x10);
+                       gpNe2k_Cards[ k ].MacAddr[2] = inb(base+0x10);//        inb(base+0x10);
+                       gpNe2k_Cards[ k ].MacAddr[3] = inb(base+0x10);//        inb(base+0x10);
+                       gpNe2k_Cards[ k ].MacAddr[4] = inb(base+0x10);//        inb(base+0x10);
+                       gpNe2k_Cards[ k ].MacAddr[5] = inb(base+0x10);//        inb(base+0x10);
+                       
+                       outb( base+PSTART, RX_FIRST);   // Set Receive Start
+                       outb( base+BNRY, RX_LAST-1);    // Set Boundary Page
+                       outb( base+PSTOP, RX_LAST);     // Set Stop Page
+                       outb( base+ISR, 0xFF ); // Clear all ints
+                       outb( base+CMD, 0x22 ); // No DMA, Start
+                       outb( base+IMR, 0x3F ); // Set Interupt Mask
+                       outb( base+RCR, 0x0F ); // Set WRAP and allow all packet matches
+                       outb( base+TCR, 0x00 ); // Set Normal Transmitter mode
+                       outb( base+TPSR, 0x40); // Set Transmit Start
+                       
+                       Log_Log("Ne2k", "Card %i 0x%04x IRQ%i %02x:%02x:%02x:%02x:%02x:%02x",
+                               k, base, gpNe2k_Cards[ k ].IRQ,
+                               gpNe2k_Cards[k].MacAddr[0], gpNe2k_Cards[k].MacAddr[1],
+                               gpNe2k_Cards[k].MacAddr[2], gpNe2k_Cards[k].MacAddr[3],
+                               gpNe2k_Cards[k].MacAddr[4], gpNe2k_Cards[k].MacAddr[5]
+                               );
+                       
+                       // Set VFS Node
+                       gpNe2k_Cards[ k ].Name[0] = '0'+k;
+                       gpNe2k_Cards[ k ].Name[1] = '\0';
+                       gpNe2k_Cards[ k ].Node.ImplPtr = &gpNe2k_Cards[ k ];
+                       gpNe2k_Cards[ k ].Node.NumACLs = 0;     // Root Only
+                       gpNe2k_Cards[ k ].Node.CTime = now();
+                       gpNe2k_Cards[ k ].Node.Type = &gNe2K_DevNodeType;
+                       
+                       // Initialise packet semaphore
+                       // - Start at zero, no max
+                       Semaphore_Init( &gpNe2k_Cards[k].Semaphore, 0, 0, "NE2000", gpNe2k_Cards[ k ].Name );
+               }
+       }
+       
+       gNe2k_DriverInfo.RootNode.Size = giNe2k_CardCount;
+       DevFS_AddDevice( &gNe2k_DriverInfo );
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \fn char *Ne2k_ReadDir(tVFS_Node *Node, int Pos)
+ */
+char *Ne2k_ReadDir(tVFS_Node *Node, int Pos)
+{
+       char    ret[2];
+       if(Pos < 0 || Pos >= giNe2k_CardCount)  return NULL;
+       ret[0] = '0'+Pos;
+       ret[1] = '\0';
+       return strdup(ret);
+}
+
+/**
+ * \fn tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name)
+ */
+tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name)
+{
+       if(Name[0] == '\0' || Name[1] != '\0')  return NULL;
+       
+       return &gpNe2k_Cards[ Name[0]-'0' ].Node;
+}
+
+static const char *casIOCtls[] = { DRV_IOCTLNAMES, DRV_NETWORK_IOCTLNAMES, NULL };
+/**
+ * \fn int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
+ * \brief IOCtl calls for a network device
+ */
+int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch( ID )
+       {
+       BASE_IOCTLS(DRV_TYPE_NETWORK, "NE2000", VERSION, casIOCtls);
+       }
+       
+       // If this is the root, return
+       if( Node == &gNe2k_DriverInfo.RootNode ) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Device specific settings
+       switch( ID )
+       {
+       case NET_IOCTL_GETMAC:
+               if( !CheckMem(Data, 6) ) {
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               memcpy( Data, ((tCard*)Node->ImplPtr)->MacAddr, 6 );
+               LEAVE('i', 1);
+               return 1;
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+ * \brief Send a packet from the network card
+ */
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       tCard   *Card = (tCard*)Node->ImplPtr;
+       const Uint16    *buf = Buffer;
+        int    rem = Length;
+        int    page;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       // TODO: Lock
+       
+       // Sanity Check Length
+       if(Length > TX_BUF_SIZE*256) {
+               Log_Warning(
+                       "Ne2k",
+                       "Ne2k_Write - Attempting to send over TX_BUF_SIZE*256 (%i) bytes (%i)",
+                       TX_BUF_SIZE*256, Length
+                       );
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Make sure that the card is in page 0
+       outb(Card->IOBase + CMD, 0|0x22);       // Page 0, Start, NoDMA
+       
+       // Clear Remote DMA Flag
+       outb(Card->IOBase + ISR, 0x40); // Bit 6
+       
+       // Send Size - Transfer Byte Count Register
+       outb(Card->IOBase + TBCR0, Length & 0xFF);
+       outb(Card->IOBase + TBCR1, Length >> 8);
+       
+       // Send Size - Remote Byte Count Register
+       outb(Card->IOBase + RBCR0, Length & 0xFF);
+       outb(Card->IOBase + RBCR1, Length >> 8);
+       
+       // Set up transfer
+       outb(Card->IOBase + RSAR0, 0x00);       // Page Offset
+       page = Ne2k_int_GetWritePage(Card, Length);
+       outb(Card->IOBase + RSAR1, page);       // Page Offset
+       // Start
+       outb(Card->IOBase + CMD, 0|0x10|0x2);   // Page 0, Remote Write, Start
+       
+       // Send Data
+       for(rem = Length; rem > 0; rem -= 2) {
+               outw(Card->IOBase + 0x10, *buf++);
+       }
+       
+       while( !(inb(Card->IOBase + ISR) & 0x40) )      // Wait for Remote DMA Complete
+               ;       //Proc_Yield();
+       
+       outb( Card->IOBase + ISR, 0x40 );       // ACK Interrupt
+       
+       // Send Packet
+       outb(Card->IOBase + TPSR, page);
+       outb(Card->IOBase + CMD, 0|0x10|0x4|0x2);
+       
+       // Complete DMA
+       //outb(Card->IOBase + CMD, 0|0x20);
+       
+       LEAVE('i', Length);
+       return Length;
+}
+
+/**
+ * \fn Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Wait for and read a packet from the network card
+ */
+Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tCard   *Card = (tCard*)Node->ImplPtr;
+       Uint8   page;
+       Uint8   data[256];
+       struct {
+               Uint8   Status;
+               Uint8   NextPacketPage;
+               Uint16  Length; // Little Endian
+       }       *pktHdr;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       // Wait for packets
+       if( Semaphore_Wait( &Card->Semaphore, 1 ) != 1 )
+       {
+               // Error or interrupted
+               LEAVE_RET('i', 0);
+       }
+       
+       outb(Card->IOBase, 0x22 | (1 << 6));    // Page 6
+       LOG("CURR : 0x%02x", inb(Card->IOBase + CURR));
+       
+       // Get current read page
+       page = Card->NextRXPage;
+       LOG("page = %i", page);
+       
+       Ne2k_int_ReadDMA(Card, page, 1, data);
+       
+       pktHdr = (void*)data;
+       
+       LOG("pktHdr->Status = 0x%x", pktHdr->Status);
+       LOG("pktHdr->NextPacketPage = %i", pktHdr->NextPacketPage);
+       LOG("pktHdr->Length = 0x%03x", pktHdr->Length);
+       
+       // Have we read all the required bytes yet?
+       if(pktHdr->Length < 256 - 4)
+       {
+               if(Length > pktHdr->Length)
+                       Length = pktHdr->Length;
+               memcpy(Buffer, &data[4], Length);
+       }
+       // No? oh damn, now we need to allocate a buffer
+       else
+       {
+                int    pages = pktHdr->NextPacketPage - page;
+               char    *buf = malloc( pages*256 );
+               
+               LOG("pktHdr->Length (%i) > 256 - 4, allocated buffer %p", pktHdr->Length, buf);
+               
+               if(!buf)        LEAVE_RET('i', -1);
+               
+               // Copy the already read data
+               memcpy(buf, data, 256);
+               
+               // Read all the needed pages
+               page ++;
+               if(page == RX_LAST+1)   page = RX_FIRST;
+               
+               if( page + pages > RX_LAST )
+               {
+                        int    first_count = RX_LAST+1 - page;
+                        int    tmp = 0;
+                       tmp += Ne2k_int_ReadDMA(Card, page, first_count, buf+256);
+                       tmp += Ne2k_int_ReadDMA(Card, RX_FIRST, pages-1-first_count, buf+(first_count+1)*256);
+                       LOG("composite return count = %i", tmp);
+               }
+               else
+                       Ne2k_int_ReadDMA(Card, page, pages-1, buf+256);
+               
+               // Wrap length to the packet length
+               if(Length > pktHdr->Length)
+                       Length = pktHdr->Length;
+               else if( Length < pktHdr->Length ) {
+                       Log_Warning("NE2000", "Packet truncated! (%i bytes truncated to %i)",
+                               pktHdr->Length, Length);
+               }
+               memcpy(Buffer, &buf[4], Length);
+               
+               free(buf);
+       }
+       
+       // Write BNRY (maximum page for incoming packets)
+       if(pktHdr->NextPacketPage == RX_FIRST)
+               outb( Card->IOBase + BNRY, RX_LAST-1 );
+       else
+               outb( Card->IOBase + BNRY, pktHdr->NextPacketPage-1 );
+       // Set next RX Page and decrement the waiting list
+       Card->NextRXPage = pktHdr->NextPacketPage;
+       
+       LEAVE('i', Length);
+       return Length;
+}
+
+int Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer)
+{
+        int    i;
+       
+       // Sanity check
+       if( !(0 <= FirstPage && FirstPage < 256) ) {
+               Log_Warning("NE2000", "Ne2k_int_ReadDMA: BUG - FirstPage(%i) not 8-bit", FirstPage);
+               return -1;
+       }
+       if( !(0 <= NumPages && NumPages < 256) ) {
+               Log_Warning("NE2000", "Ne2k_int_ReadDMA: BUG - NumPages(%i) not 8-bit", NumPages);
+               return -1;
+       }
+       
+       ENTER("pCard iFirstPage iNumPages pBuffer", Card, FirstPage, NumPages, Buffer);
+       
+       // Make sure that the card is in bank 0
+       outb(Card->IOBase + CMD, 0|0x22);       // Bank 0, Start, NoDMA
+       outb(Card->IOBase + ISR, 0x40); // Clear Remote DMA Flag
+       
+       // Set up transfer
+       outb(Card->IOBase + RBCR0, 0);
+       outb(Card->IOBase + RBCR1, NumPages);   // page count
+       outb(Card->IOBase + RSAR0, 0x00);       // Page Offset
+       outb(Card->IOBase + RSAR1, FirstPage);  // Page Number
+       outb(Card->IOBase + CMD, 0|0x08|0x2);   // Bank 0, Remote Read, Start
+       
+       // TODO: Less expensive
+       //while( !(inb(Card->IOBase + ISR) & 0x40) ) {
+       //      HALT();
+       //      LOG("inb(ISR) = 0x%02x", inb(Card->IOBase + ISR));
+       //}
+       HALT(); // Small delay?
+       
+       // Read data
+       for(i = 0; i < 128*NumPages; i ++)
+               ((Uint16*)Buffer)[i] = inw(Card->IOBase + 0x10);
+               
+       
+       outb(Card->IOBase + ISR, 0x40); // Clear Remote DMA Flag
+       
+       LEAVE('i', NumPages);
+       return NumPages;
+}
+
+/**
+ * \fn Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
+ */
+Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
+{
+       Uint8   ret = Card->NextMemPage;
+       
+       Card->NextMemPage += (Length + 0xFF) >> 8;
+       if(Card->NextMemPage >= TX_LAST) {
+               Card->NextMemPage -= TX_BUF_SIZE;
+       }
+       
+       return ret;
+}
+
+/**
+ * \fn void Ne2k_IRQHandler(int IntNum)
+ */
+void Ne2k_IRQHandler(int IntNum, void *Ptr)
+{
+       Uint8   byte;
+       tCard   *card = Ptr;
+
+       if(card->IRQ != IntNum) return;
+       
+       byte = inb( card->IOBase + ISR );
+       
+       LOG("byte = 0x%02x", byte);
+                       
+                       
+       // Reset All (save for RDMA), that's polled
+       outb( card->IOBase + ISR, 0xFF&(~0x40) );
+                       
+       // 0: Packet recieved (no error)
+       if( byte & 1 )
+       {
+               //if( card->NumWaitingPackets > MAX_PACKET_QUEUE )
+               //      card->NumWaitingPackets = MAX_PACKET_QUEUE;
+               if( Semaphore_Signal( &card->Semaphore, 1 ) != 1 ) {
+                       // Oops?
+               }
+       }
+       // 1: Packet sent (no error)
+       // 2: Recieved with error
+       // 3: Transmission Halted (Excessive Collisions)
+       // 4: Recieve Buffer Exhausted
+       // 5: 
+       // 6: Remote DMA Complete
+       // 7: Reset
+}
diff --git a/KernelLand/Modules/Network/PCnet-FASTIII/Makefile b/KernelLand/Modules/Network/PCnet-FASTIII/Makefile
new file mode 100644 (file)
index 0000000..1c7f3e9
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = rtl8139.o
+NAME = RTL8139
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c b/KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c
new file mode 100644 (file)
index 0000000..bb4f83a
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Acess2 PCnet-FAST III Driver
+ * - By John Hodge (thePowersGang)
+ */
+#define        DEBUG   0
+#define VERSION        ((0<<8)|10)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include <api_drv_network.h>
+#include <semaphore.h>
+
+// === CONSTANTS ===
+#define VENDOR_ID      0x1022
+#define DEVICE_ID      0x2000
+
+enum eRegs
+{
+       REG_APROM0      = 0x00,
+       REG_APROM4      = 0x04,
+       REG_APROM8      = 0x08,
+       REG_APROMC      = 0x0C,
+       REG_RDP         = 0x10, // 16 bit
+       REG_RAP         = 0x14, // 8-bit
+       REG_RESET       = 0x18, // 16-bit
+       REG_BDP         = 0x1C, // 16-bit
+};
+
+enum eCSR_Regs
+{
+       CSR_STATUS,     // CSR0 - Am79C973/Am79C975 Controller Status
+       CSR_IBA0,       // CSR1 - Initialization Block Address[15:0]
+       CSR_IBA1,       // CSR2 - Initialization Block Address[31:16]
+       CSR_INTMASK,    // CSR3 - Interrupt Masks and Deferral Control
+       
+       CSR_MAC0 = 12,  // CSR12 - Physical Address[15:0]
+       CSR_MAC1 = 13,  // CSR13 - Physical Address[31:16]
+       CSR_MAC2 = 14,  // CSR14 - Physical Address[47:32]
+       CSR_MODE = 15,  // CSR15 - Mode
+       
+       CSR_RXBASE0 = 24,       // CSR24 - Base Address of Receive Ring Lower
+       CSR_RXBASE1 = 25,       // CSR25 - Base Address of Receive Ring Upper
+       CSR_TXBASE0 = 30,       // CSR26 - Base Address of Transmit Ring Lower
+       CSR_TXBASE1 = 31,       // CSR27 - Base Address of Transmit Ring Upper
+       
+       CSR_RXLENGTH = 76,      // CSR76 - Receive Ring Length
+       CSR_TXLENGTH = 78,      // CSR78 - Transmit Ring Length
+};
+
+enum eBCR_Regs
+{
+       BCR_PHYCS = 32, // BCR32 - Internal PHY Control and Status
+       BCR_PHYADDR,    // BCR33 - Internal PHY Address
+       BCR_PHYMGMT,    // BCR34 - Internal PHY Management Data
+};
+
+// === TYPES ===
+typedef struct sCard
+{
+       Uint16  IOBase;
+       Uint8   IRQ;
+       
+        int    NumWaitingPackets;
+       
+       char    Name[2];
+       tVFS_Node       Node;
+       Uint8   MacAddr[6];
+}      tCard;
+
+// === PROTOTYPES ===
+ int   PCnet3_Install(char **Options);
+char   *PCnet3_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *PCnet3_FindDir(tVFS_Node *Node, const char *Filename);
+ int   PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
+Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Arg);
+void   PCnet3_IRQHandler(int Num);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, PCnet3, PCnet3_Install, NULL, NULL);
+tDevFS_Driver  gPCnet3_DriverInfo = {
+       NULL, "PCnet3",
+       {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .ReadDir = PCnet3_ReadDir,
+       .FindDir = PCnet3_FindDir,
+       .IOCtl = PCnet3_RootIOCtl
+       }
+};
+ int   giPCnet3_CardCount;
+tCard  *gaPCnet3_Cards;
+
+// === CODE ===
+/**
+ * \brief Installs the PCnet3 Driver
+ */
+int PCnet3_Install(char **Options)
+{
+        int    id = -1;
+        int    i = 0;
+       Uint16  base;
+       tCard   *card;
+       
+       giPCnet3_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
+       Log_Debug("PCnet3", "%i cards", giPCnet3_CardCount);
+       
+       if( giPCnet3_CardCount == 0 )   return MODULE_ERR_NOTNEEDED;
+       
+       gaPCnet3_Cards = calloc( giPCnet3_CardCount, sizeof(tCard) );
+       
+       while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1 )
+       {
+               card = &gaPCnet3_Cards[i];
+               base = PCI_GetBAR( id, 0 );
+               if( !(base & 1) ) {
+                       Log_Warning("PCnet3", "Driver does not support MMIO, skipping card");
+                       card->IOBase = 0;
+                       card->IRQ = 0;
+                       continue ;
+               }
+               base &= ~1;
+               card->IOBase = base;
+               card->IRQ = PCI_GetIRQ( id );
+               
+               // Install IRQ Handler
+               IRQ_AddHandler(card->IRQ, PCnet3_IRQHandler);
+               
+               
+               
+               Log_Log("PCnet3", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
+                       i, card->IOBase, card->IRQ,
+                       card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
+                       card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
+                       );
+               
+               i ++;
+       }
+       
+       gPCnet3_DriverInfo.RootNode.Size = giPCnet3_CardCount;
+       DevFS_AddDevice( &gPCnet3_DriverInfo );
+       
+       return MODULE_ERR_OK;
+}
+
+// --- Root Functions ---
+char *PCnet3_ReadDir(tVFS_Node *Node, int Pos)
+{
+       if( Pos < 0 || Pos >= giPCnet3_CardCount )      return NULL;
+       
+       return strdup( gaPCnet3_Cards[Pos].Name );
+}
+
+tVFS_Node *PCnet3_FindDir(tVFS_Node *Node, const char *Filename)
+{
+       //TODO: It might be an idea to supprt >10 cards
+       if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
+       if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
+       return &gaPCnet3_Cards[ Filename[0]-'0' ].Node;
+}
+
+const char *csaPCnet3_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
+int PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_RootIOCtls);
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+// --- File Functions ---
+Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tCard   *card = Node->ImplPtr;
+       Uint16  read_ofs, pkt_length;
+        int    new_read_ofs;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+retry:
+       if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
+       {
+               LEAVE_RET('i', 0);
+       }
+       
+       Mutex_Acquire( &card->ReadMutex );
+       
+       read_ofs = inw( card->IOBase + CAPR );
+       LOG("raw read_ofs = %i", read_ofs);
+       read_ofs = (read_ofs + 0x10) & 0xFFFF;
+       LOG("read_ofs = %i", read_ofs);
+       
+       pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
+       
+       // Calculate new read offset
+       new_read_ofs = read_ofs + pkt_length + 4;
+       new_read_ofs = (new_read_ofs + 3) & ~3; // Align
+       if(new_read_ofs > card->ReceiveBufferLength) {
+               LOG("wrapping read_ofs");
+               new_read_ofs -= card->ReceiveBufferLength;
+       }
+       new_read_ofs -= 0x10;   // I dunno
+       LOG("new_read_ofs = %i", new_read_ofs);
+       
+       // Check for errors
+       if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
+               // Update CAPR
+               outw(card->IOBase + CAPR, new_read_ofs);
+               Mutex_Release( &card->ReadMutex );
+               goto retry;     // I feel evil
+       }
+       
+       // Get packet
+       if( Length > pkt_length )       Length = pkt_length;
+       memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
+       
+       // Update CAPR
+       outw(card->IOBase + CAPR, new_read_ofs);
+       
+       Mutex_Release( &card->ReadMutex );
+       
+       LEAVE('i', Length);
+       
+       return Length;
+}
+
+Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    td;
+       Uint32  status;
+       tCard   *card = Node->ImplPtr;
+       
+       if( Length > 1500 )     return 0;       // MTU exceeded
+       
+       ENTER("pNode XLength pBuffer", Node, Length, Buffer);
+       
+       // TODO: Implement a semaphore for avaliable transmit buffers
+
+       // Find an avaliable descriptor
+       Mutex_Acquire(&card->CurTXProtector);
+       td = card->CurTXDescriptor;
+       card->CurTXDescriptor ++;
+       card->CurTXDescriptor %= 4;
+       Mutex_Release(&card->CurTXProtector);
+       // - Lock it
+       Mutex_Acquire( &card->TransmitInUse[td] );
+       
+       LOG("td = %i", td);
+       
+       // Transmit using descriptor `td`
+       LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]);
+       outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
+       LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]);
+       // Copy to buffer
+       memcpy(card->TransmitBuffers[td], Buffer, Length);
+       // Start
+       status = 0;
+       status |= Length & 0x1FFF;      // 0-12: Length
+       status |= 0 << 13;      // 13: OWN bit
+       status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
+       LOG("status = 0x%08x", status);
+       outd(card->IOBase + TSD0 + td*4, status);
+       
+       LEAVE('i', (int)Length);
+       
+       return Length;
+}
+
+const char *csaPCnet3_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
+int PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tCard   *card = Node->ImplPtr;
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_NodeIOCtls);
+       case NET_IOCTL_GETMAC:
+               if( !CheckMem(Data, 6) ) {
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               memcpy( Data, card->MacAddr, 6 );
+               LEAVE('i', 1);
+               return 1;
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+void PCnet3_IRQHandler(int Num)
+{
+        int    i, j;
+       tCard   *card;
+       Uint16  status;
+
+       LOG("Num = %i", Num);
+       
+       for( i = 0; i < giPCnet3_CardCount; i ++ )
+       {
+               card = &gaPCnet3_Cards[i];
+               if( Num != card->IRQ )  break;
+               
+               status = inw(card->IOBase + ISR);
+               LOG("status = 0x%02x", status);
+               
+               // Transmit OK, a transmit descriptor is now free
+               if( status & FLAG_ISR_TOK )
+               {
+                       for( j = 0; j < 4; j ++ )
+                       {
+                               if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
+                                       Mutex_Release( &card->TransmitInUse[j] );
+                                       // TODO: Update semaphore once implemented
+                               }
+                       }
+                       outw(card->IOBase + ISR, FLAG_ISR_TOK);
+               }
+               
+               // Recieve OK, inform read
+               if( status & FLAG_ISR_ROK )
+               {
+                        int    read_ofs, end_ofs;
+                        int    packet_count = 0;
+                        int    len;
+                       
+                       // Scan recieve buffer for packets
+                       end_ofs = inw(card->IOBase + CBA);
+                       read_ofs = card->SeenOfs;
+                       LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
+                       if( read_ofs > end_ofs )
+                       {
+                               while( read_ofs < card->ReceiveBufferLength )
+                               {
+                                       packet_count ++;
+                                       len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
+                                       LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
+                                               packet_count, read_ofs,
+                                               *(Uint16*)&card->ReceiveBuffer[read_ofs],
+                                               len
+                                               );
+                                       if(len > 2000) {
+                                               Log_Warning("PCnet3", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len);
+                                       }
+                                       read_ofs += len + 4;
+                                       read_ofs = (read_ofs + 3) & ~3; // Align
+                               }
+                               read_ofs -= card->ReceiveBufferLength;
+                               LOG("wrapped read_ofs");
+                       }
+                       while( read_ofs < end_ofs )
+                       {
+                               packet_count ++;
+                               LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
+                                       packet_count, read_ofs,
+                                       *(Uint16*)&card->ReceiveBuffer[read_ofs],
+                                       *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
+                                       );
+                               read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
+                               read_ofs = (read_ofs + 3) & ~3; // Align
+                       }
+                       if( read_ofs != end_ofs ) {
+                               Log_Warning("PCnet3", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs);
+                               read_ofs = end_ofs;
+                       }
+                       card->SeenOfs = read_ofs;
+                       
+                       LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
+                       
+                       if( packet_count )
+                       {
+                               if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) {
+                                       // Oops?
+                               }
+                               VFS_MarkAvaliable( &card->Node, 1 );
+                       }
+                       
+                       outw(card->IOBase + ISR, FLAG_ISR_ROK);
+               }
+       }
+}
diff --git a/KernelLand/Modules/Network/RTL8139/Makefile b/KernelLand/Modules/Network/RTL8139/Makefile
new file mode 100644 (file)
index 0000000..1c7f3e9
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = rtl8139.o
+NAME = RTL8139
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Network/RTL8139/rtl8139.c b/KernelLand/Modules/Network/RTL8139/rtl8139.c
new file mode 100644 (file)
index 0000000..1e9ac89
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Acess2 RTL8139 Driver
+ * - By John Hodge (thePowersGang)
+ */
+#define        DEBUG   0
+#define VERSION        ((0<<8)|20)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include <api_drv_network.h>
+#include <semaphore.h>
+
+// === CONSTANTS ===
+#define VENDOR_ID      0x10EC
+#define DEVICE_ID      0x8139
+
+enum eRTL8139_Regs
+{
+       // MAC Address
+       MAC0, MAC1, MAC2,
+       MAC3, MAC4, MAC5,
+       
+       // Multicast Registers
+       MAR0 = 0x08, MAR1, MAR2, MAR3,
+       MAR4, MAR5, MAR6, MAR7,
+       
+       // Transmit status of descriptors 0 - 3
+       TSD0 = 0x10,    TSD1 = 0x14,
+       TSD2 = 0x18,    TSD3 = 0x1C,
+       // Transmit start addresses
+       TSAD0 = 0x20,   TSAD1 = 0x24,
+       TSAD2 = 0x28,   TSAD3 = 0x2C,
+       
+       RBSTART = 0x30, //!< Recieve Buffer Start (DWord)
+       // Early Recieve Byte Count
+       ERBCR = 0x34,   // 16-bits
+       // Early RX Status Register
+       ERSR = 0x36,
+       
+       // ??, ??, ??, RST, RE, TE, ??, ??
+       CMD     = 0x37,
+       
+       CAPR    = 0x38, // Current address of packet read
+       CBA     = 0x3A, // Current Buffer Address - Total byte count in RX buffer
+       
+       IMR     = 0x3C, // Interrupt mask register
+       ISR     = 0x3E, // Interrupt status register
+       
+       TCR     = 0x40, // Transmit Configuration Register
+       RCR     = 0x44, // Recieve Configuration Register
+       TCTR    = 0x48, // 32-bit timer (count)
+       MPC     = 0x4C, // Missed packet count (due to RX overflow)
+       
+       CR_9346 = 0x50,
+       CONFIG0 = 0x51,
+       CONFIG1 = 0x52,
+       // 0x53 resvd
+       TIMERINT = 0x54,        // Fires a timeout when TCTR equals this value
+       
+};
+
+#define FLAG_ISR_TOK   0x04
+#define FLAG_ISR_ROK   0x01
+
+// === TYPES ===
+typedef struct sCard
+{
+       Uint16  IOBase;
+       Uint8   IRQ;
+       
+        int    NumWaitingPackets;
+       
+       char    *ReceiveBuffer;
+       tPAddr  PhysReceiveBuffer;
+        int    ReceiveBufferLength;
+        int    SeenOfs;        //!< End of the most recently seen packet (by IRQ)
+       tMutex  ReadMutex;
+       tSemaphore      ReadSemaphore;
+       
+       char    *TransmitBuffers[4];
+       tPAddr  PhysTransmitBuffers[4];
+       tMutex  TransmitInUse[4];
+       tMutex  CurTXProtector; //!< Protects \a .CurTXDescriptor
+        int    CurTXDescriptor;
+       
+       char    Name[2];
+       tVFS_Node       Node;
+       Uint8   MacAddr[6];
+}      tCard;
+
+// === PROTOTYPES ===
+ int   RTL8139_Install(char **Options);
+char   *RTL8139_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
+ int   RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
+Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+ int   RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
+void   RTL8139_IRQHandler(int Num, void *Ptr);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
+tVFS_NodeType  gRTL8139_RootNodeType = {
+       .ReadDir = RTL8139_ReadDir,
+       .FindDir = RTL8139_FindDir,
+       .IOCtl = RTL8139_IOCtl
+       };
+tVFS_NodeType  gRTL8139_DevNodeType = {
+       .Write = RTL8139_Write,
+       .Read = RTL8139_Read,
+       .IOCtl = RTL8139_IOCtl  
+       };
+tDevFS_Driver  gRTL8139_DriverInfo = {
+       NULL, "RTL8139",
+       {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Type = &gRTL8139_RootNodeType
+       }
+};
+ int   giRTL8139_CardCount;
+tCard  *gaRTL8139_Cards;
+
+// === CODE ===
+/**
+ * \brief Installs the RTL8139 Driver
+ */
+int RTL8139_Install(char **Options)
+{
+        int    id = -1;
+        int    i = 0;
+       Uint16  base;
+       tCard   *card;
+       
+       giRTL8139_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
+       
+       if( giRTL8139_CardCount == 0 )  return MODULE_ERR_NOTNEEDED;
+
+       Log_Debug("RTL8139", "%i cards", giRTL8139_CardCount);  
+       gaRTL8139_Cards = calloc( giRTL8139_CardCount, sizeof(tCard) );
+       
+       for( i = 0 ; (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1; i ++ )
+       {
+               card = &gaRTL8139_Cards[i];
+               base = PCI_GetBAR( id, 0 );
+               if( !(base & 1) ) {
+                       Log_Warning("RTL8139", "Driver does not support MMIO, skipping card (addr %x)",
+                               base);
+                       card->IOBase = 0;
+                       card->IRQ = 0;
+                       continue ;
+               }
+               base &= ~1;
+               card->IOBase = base;
+               card->IRQ = PCI_GetIRQ( id );
+               
+               // Install IRQ Handler
+               IRQ_AddHandler(card->IRQ, RTL8139_IRQHandler, card);
+               
+               // Power on
+               outb( base + CONFIG1, 0x00 );
+
+               // Reset (0x10 to CMD)
+               outb( base + CMD, 0x10 );       
+               while( inb(base + CMD) & 0x10 ) ;
+               
+               // Set up recieve buffer
+               // - Allocate 3 pages below 4GiB for the recieve buffer (Allows 8k+16+1500)
+               card->ReceiveBuffer = (void*)MM_AllocDMA( 3, 32, &card->PhysReceiveBuffer );
+               card->ReceiveBufferLength = 8*1024;
+               outd(base + RBSTART, (Uint32)card->PhysReceiveBuffer);
+               outd(base + CBA, 0);
+               outd(base + CAPR, 0);
+               // Set IMR to Transmit OK and Receive OK
+               outw(base + IMR, 0x5);
+               
+               // Set up transmit buffers
+               // - 2 non-contiguous pages (each page can fit 2 1500 byte packets)
+               card->TransmitBuffers[0] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[0] );
+               card->TransmitBuffers[1] = card->TransmitBuffers[0] + 0x800;
+               card->PhysTransmitBuffers[1] = card->PhysTransmitBuffers[0] + 0x800;
+               
+               card->TransmitBuffers[2] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[2] );
+               card->TransmitBuffers[3] = card->TransmitBuffers[2] + 0x800;
+               card->PhysTransmitBuffers[3] = card->PhysTransmitBuffers[2] + 0x800;
+               
+               outd(base + TSAD0, card->PhysTransmitBuffers[0]);
+               outd(base + TSAD1, card->PhysTransmitBuffers[1]);
+               outd(base + TSAD2, card->PhysTransmitBuffers[2]);
+               outd(base + TSAD3, card->PhysTransmitBuffers[3]);
+               
+               // Set recieve buffer size and recieve mask
+               // - Bit 7 being set tells the card to overflow the recieve buffer if needed
+               //   (i.e. when the packet starts at the end of the bufffer, it overflows up
+               //    to 1500 bytes)
+               outd(base + RCR, 0x8F);
+       
+               // Recive Enable and Transmit Enable    
+               outb(base + CMD, 0x0C);
+               
+               // Get the card's MAC address
+               card->MacAddr[0] = inb(base+MAC0);
+               card->MacAddr[1] = inb(base+MAC1);
+               card->MacAddr[2] = inb(base+MAC2);
+               card->MacAddr[3] = inb(base+MAC3);
+               card->MacAddr[4] = inb(base+MAC4);
+               card->MacAddr[5] = inb(base+MAC5);
+               
+               // Set VFS Node
+               card->Name[0] = '0'+i;
+               card->Name[1] = '\0';
+               card->Node.ImplPtr = card;
+               card->Node.NumACLs = 0;
+               card->Node.CTime = now();
+               card->Node.Type = &gRTL8139_DevNodeType;
+               
+               Log_Log("RTL8139", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
+                       i, card->IOBase, card->IRQ,
+                       card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
+                       card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
+                       );
+       }
+       
+       gRTL8139_DriverInfo.RootNode.Size = giRTL8139_CardCount;
+       DevFS_AddDevice( &gRTL8139_DriverInfo );
+       
+       return MODULE_ERR_OK;
+}
+
+// --- Root Functions ---
+char *RTL8139_ReadDir(tVFS_Node *Node, int Pos)
+{
+       if( Pos < 0 || Pos >= giRTL8139_CardCount )     return NULL;
+       
+       return strdup( gaRTL8139_Cards[Pos].Name );
+}
+
+tVFS_Node *RTL8139_FindDir(tVFS_Node *Node, const char *Filename)
+{
+       //TODO: It might be an idea to supprt >10 cards
+       if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
+       if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
+       return &gaRTL8139_Cards[ Filename[0]-'0' ].Node;
+}
+
+const char *csaRTL8139_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
+int RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_RootIOCtls);
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+// --- File Functions ---
+Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tCard   *card = Node->ImplPtr;
+       Uint16  read_ofs, pkt_length;
+        int    new_read_ofs;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+retry:
+       if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
+       {
+               LEAVE_RET('i', 0);
+       }
+       
+       Mutex_Acquire( &card->ReadMutex );
+       
+       read_ofs = inw( card->IOBase + CAPR );
+       LOG("raw read_ofs = %i", read_ofs);
+       read_ofs = (read_ofs + 0x10) & 0xFFFF;
+       LOG("read_ofs = %i", read_ofs);
+       
+       pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
+       
+       // Calculate new read offset
+       new_read_ofs = read_ofs + pkt_length + 4;
+       new_read_ofs = (new_read_ofs + 3) & ~3; // Align
+       if(new_read_ofs > card->ReceiveBufferLength) {
+               LOG("wrapping read_ofs");
+               new_read_ofs -= card->ReceiveBufferLength;
+       }
+       new_read_ofs -= 0x10;   // I dunno
+       LOG("new_read_ofs = %i", new_read_ofs);
+       
+       // Check for errors
+       if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
+               // Update CAPR
+               outw(card->IOBase + CAPR, new_read_ofs);
+               Mutex_Release( &card->ReadMutex );
+               goto retry;     // I feel evil
+       }
+       
+       // Get packet
+       if( Length > pkt_length )       Length = pkt_length;
+       memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
+       
+       // Update CAPR
+       outw(card->IOBase + CAPR, new_read_ofs);
+       
+       Mutex_Release( &card->ReadMutex );
+       
+       LEAVE('i', Length);
+       
+       return Length;
+}
+
+Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+        int    td;
+       Uint32  status;
+       tCard   *card = Node->ImplPtr;
+       
+       if( Length > 1500 )     return 0;       // MTU exceeded
+       
+       ENTER("pNode XLength pBuffer", Node, Length, Buffer);
+       
+       // TODO: Implement a semaphore for avaliable transmit buffers
+
+       // Find an avaliable descriptor
+       Mutex_Acquire(&card->CurTXProtector);
+       td = card->CurTXDescriptor;
+       card->CurTXDescriptor ++;
+       card->CurTXDescriptor %= 4;
+       Mutex_Release(&card->CurTXProtector);
+       // - Lock it
+       Mutex_Acquire( &card->TransmitInUse[td] );
+       
+       LOG("td = %i", td);
+       
+       // Transmit using descriptor `td`
+       LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]);
+       outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
+       LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]);
+       // Copy to buffer
+       memcpy(card->TransmitBuffers[td], Buffer, Length);
+       // Start
+       status = 0;
+       status |= Length & 0x1FFF;      // 0-12: Length
+       status |= 0 << 13;      // 13: OWN bit
+       status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
+       LOG("status = 0x%08x", status);
+       outd(card->IOBase + TSD0 + td*4, status);
+       
+       LEAVE('i', (int)Length);
+       
+       return Length;
+}
+
+const char *csaRTL8139_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
+int RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       tCard   *card = Node->ImplPtr;
+       ENTER("pNode iID pData", Node, ID, Data);
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_NodeIOCtls);
+       case NET_IOCTL_GETMAC:
+               if( !CheckMem(Data, 6) ) {
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               memcpy( Data, card->MacAddr, 6 );
+               LEAVE('i', 1);
+               return 1;
+       }
+       LEAVE('i', 0);
+       return 0;
+}
+
+void RTL8139_IRQHandler(int Num, void *Ptr)
+{
+        int    j;
+       tCard   *card = Ptr;
+       Uint16  status;
+
+       LOG("Num = %i", Num);
+       
+       if( Num != card->IRQ )  return;
+               
+       status = inw(card->IOBase + ISR);
+       LOG("status = 0x%02x", status);
+               
+       // Transmit OK, a transmit descriptor is now free
+       if( status & FLAG_ISR_TOK )
+       {
+               for( j = 0; j < 4; j ++ )
+               {
+                       if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
+                               Mutex_Release( &card->TransmitInUse[j] );
+                               // TODO: Update semaphore once implemented
+                       }
+               }
+               outw(card->IOBase + ISR, FLAG_ISR_TOK);
+       }
+       
+       // Recieve OK, inform read
+       if( status & FLAG_ISR_ROK )
+       {
+                int    read_ofs, end_ofs;
+                int    packet_count = 0;
+                int    len;
+               
+               // Scan recieve buffer for packets
+               end_ofs = inw(card->IOBase + CBA);
+               read_ofs = card->SeenOfs;
+               LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
+               if( read_ofs > end_ofs )
+               {
+                       while( read_ofs < card->ReceiveBufferLength )
+                       {
+                               packet_count ++;
+                               len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
+                               LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
+                                       packet_count, read_ofs,
+                                       *(Uint16*)&card->ReceiveBuffer[read_ofs],
+                                       len
+                                       );
+                               if(len > 2000) {
+                                       Log_Warning("RTL8139", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len);
+                               }
+                               read_ofs += len + 4;
+                               read_ofs = (read_ofs + 3) & ~3; // Align
+                       }
+                       read_ofs -= card->ReceiveBufferLength;
+                       LOG("wrapped read_ofs");
+               }
+               while( read_ofs < end_ofs )
+               {
+                       packet_count ++;
+                       LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
+                               packet_count, read_ofs,
+                               *(Uint16*)&card->ReceiveBuffer[read_ofs],
+                               *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
+                               );
+                       read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
+                       read_ofs = (read_ofs + 3) & ~3; // Align
+               }
+               if( read_ofs != end_ofs ) {
+                       Log_Warning("RTL8139", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs);
+                       read_ofs = end_ofs;
+               }
+               card->SeenOfs = read_ofs;
+               
+               LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
+               
+               if( packet_count )
+               {
+                       if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) {
+                               // Oops?
+                       }
+                       VFS_MarkAvaliable( &card->Node, 1 );
+               }
+               
+               outw(card->IOBase + ISR, FLAG_ISR_ROK);
+       }       
+}
diff --git a/KernelLand/Modules/Sound/SoundBlaster16/Makefile b/KernelLand/Modules/Sound/SoundBlaster16/Makefile
new file mode 100644 (file)
index 0000000..9384859
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o
+NAME = SoundBlaster16
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Sound/SoundBlaster16/main.c b/KernelLand/Modules/Sound/SoundBlaster16/main.c
new file mode 100644 (file)
index 0000000..f2d056c
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+ * Acess2 SoundBlaster16 Driver\r
+ */\r
+#define DEBUG  0\r
+#include <acess.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <api_drv_sound.h>\r
+\r
+#define INT\r
+\r
+// === TYPES ===\r
+typedef struct sSB16\r
+{\r
+       Uint16  Base;\r
+}      tSB16;\r
+\r
+// === CONSTANTS ===\r
+enum {\r
+       SB16_PORT_RESET = 0x6,\r
+       SB16_PORT_READ  = 0xA,\r
+       SB16_PORT_WRITE = 0xC,\r
+       SB16_PORT_AVAIL = 0xE\r
+};\r
+#define SB16_BASE_PORT 0x200\r
+enum {\r
+       SB16_CMD_RAW8    = 0x10,        // 8-bit DAC value follows\r
+       SB16_CMD_DMAFREQ = 0x40,        // followed by TIME_CONSTANT = 256 - 1000000 / frequency\r
+       SB16_CMD_DMASTOP = 0xD0,\r
+       SB16_CMD_SPKRON  = 0xD1,\r
+       SB16_CMD_SPKROFF = 0xD3,\r
+       SB16_CMD_DMACONT = 0xD4,\r
+       \r
+       // DMA Types (uses channel 1)\r
+       // - Followed by 16-bit length (well, length - 1)\r
+       SB16_CMD_DMA_8BIT = 0x14,\r
+};\r
+\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int   SB16_Install(char **Arguments);\r
+void   SB16_Uninstall();\r
+// Filesystem\r
+Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+ int   SB16_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0032, SoundBlaster16, SB16_Install, SB16_Uninstall, "PCI", NULL);\r
+tDevFS_Driver  gBGA_DriverStruct = {\r
+       NULL, "SoundBlaster16",\r
+       {\r
+       .Write = SB16_Write,\r
+       .IOCtl = SB16_IOCtl\r
+       }\r
+};\r
+\r
+// === CODE ===\r
+int SB16_Install(char **Arguments)\r
+{\r
+        int    jumper_port_setting = 1;        // 1-6 incl\r
+       \r
+       // Reset\r
+       outb(card->Base+SB16_PORT_RESET, 1);\r
+       // - Wait 3us\r
+       outb(card->Base+SB16_PORT_RESET, 0);\r
+       \r
+       SB16_ReadDSP(card);\r
+       \r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+void SB16_Uninstall()\r
+{\r
+}\r
+\r
+/**\r
+ * \fn Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{      \r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn int SB16_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+ * \brief Handle messages to the device\r
+ */\r
+int SB16_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+       return -1;\r
+}\r
+\r
+//\r
+int SB16_WriteDSP(tSB16 *Card, Uint8 Value)\r
+{\r
+       // Wait for the card to be ready\r
+       while( inb(Card->Base+SB16_PORT_WRITE) & 0x80 )\r
+               ;\r
+       \r
+       outb(Card->Base+SB16_PORT_WRITE, Value);\r
+       \r
+       return 0;\r
+}\r
+\r
+Uint8 SB16_ReadDSP(tSB16 *Card)\r
+{\r
+       // Wait for bit 7 of AVAIL\r
+       while( !(inb(card->Base+SB16_PORT_AVAIL) & 0x80) )\r
+               ;\r
+       return inb(card->Base+SB16_PORT_READ);\r
+}\r
diff --git a/KernelLand/Modules/Sound/SoundBlaster16/sbdsp.txt b/KernelLand/Modules/Sound/SoundBlaster16/sbdsp.txt
new file mode 100644 (file)
index 0000000..94364cd
--- /dev/null
@@ -0,0 +1,442 @@
+
+                  ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+                  Â³ Programming the SoundBlaster DSP Â³
+                  Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+                  Written for the PC-GPE by Mark Feldman
+              e-mail address : [email protected]
+                               [email protected]
+
+             ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+             Â³      THIS FILE MAY NOT BE DISTRIBUTED     Â³
+             Â³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. Â³
+             Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Disclaimer Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+I assume no responsibility whatsoever for any effect that this file, the
+information contained therein or the use thereof has on you, your sanity,
+computer, spouse, children, pets or anything else related to you or your
+existance. No warranty is provided nor implied with this information.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Introduction Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+The SoundBlaster is capable of both FM and digitised sounds. The FM wave
+is fully Adlib compatible, so check the ADLIB.TXT file for info
+on how to program it. This file will concentrate on recording and playback
+of digital samples through the SoundBlaster CT-DSP 1321 chip.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ The SoundBlaster DSP I/O Ports Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+The DSP (Digital Sound Processor) chip is programmed through 4 ports which
+are determined by the SoundBlaster base address jumper setting:
+
+                    RESET    2x6h
+
+                READ DATA    2xAh
+
+WRITE COMMAND/DATA output
+WRITE BUFFER STATUS input    2xCh
+
+
+           DATA AVAILABLE    2xEh
+
+where x = 1 for base address jumper setting 210h
+      x = 2 for base address jumper setting 220h
+      .
+      .
+      x = 6 for base address jumper setting 260h
+
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Resetting the DSP Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+You have to reset the DSP before you program it. This is done with the
+following procedure :
+
+1) Write a 1 to the SoundBlaster RESET port (2x6h)
+2) Wait for 3 micro-seconds
+3) Write a 0 to the SoundBlaster RESET port (2x6h)
+4) Read the byte from the DATA AVAILABLE (2xEh) port until bit 7 = 1
+5) Poll for a ready byte (AAh) from the READ DATA port (2xAh). Before
+   reading the READ DATA port it is avdvisable.
+
+The DSP usually takes somewhere around 100 micro-seconds to reset itself.
+If it fails to do within a reasonable time (say 200 micro-seconds) then
+an error has occurred, possibly an incorrect I/O address is being used.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Writing to the DSP Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+A value can be written to the DSP with the following procedure :
+
+1) Read the DSP's WRITE BUFFER STATUS port (2xCh) until bit 7 = 0
+2) Write the value to the WRITE COMMAND/DATA port (2xCh)
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Reading the DSP Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+A value can be read from the DSP with the following procedure :
+
+1) Read the DSP's DATA AVAILABLE port (2xEh) until bit 7 = 1
+2) Read the data from the READ DATA port (2xAh)
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Turning the speaker on and controlling DMA Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+Speaker and DMA control are handled by writing one of the following bytes
+to the DSP:
+
+                     ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+                     Â³ Value   Description     Â³
+                     ÃƒÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
+                     Â³ D0h    DMA Stop         Â³
+                     Â³ D1h    Turn speaker on  Â³
+                     Â³ D3h    Turn speaker off Â³
+                     Â³ D4h    DMA Continue     Â³
+                     Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+DMA is discussed below. The DMA commands shown here can be used to pause
+the sample during DMA playback playback.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Writing to the DAC Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+The DAC (Digital to Analog Converter) is the part of the card which converts
+a sample number (ie 0 -> 255) to a sound level. To generate a square sound
+wave at maximum volume (for example) you could alternate writing 0's and
+255's to the DAC.
+
+Programming the DAC in direct mode involves the main program setting the
+DAC to a desired value. Only 8 bit DAC is available in direct mode. To set
+the DAC level you write the value 10h to the DSP followed by the sample
+number (0 -> 255). Note that no sound will be heard unless the speaker has
+been turned on. In direct mode the main program is responsible for the
+timing between samples, the DAC can output sound samples as fast as the
+calling program can change it. Typically the timer interrupt is reprogrammed
+and used to generate the timing required for a sample playback. Info on
+programming the PIT chip can be found in the PIT.TXT file.
+
+The DAC can also be programmed to accept values sent to it via the DMA
+chip. Draeden has written an excellent article on programming the DMA chip
+(see DMA_VLA.TXT) so only a brief example of it's use will be given here.
+The important thing to remember is that the DMA chip cannot transfer data
+which crosses between page breaks. If the data does cross page breaks then
+it will have to be split up into several transfers, with one page per
+transfer.
+
+Setting the playback frequency for the DMA transfer is done by writing
+the value 40h to the DSP followed by TIME_CONSTANT, where
+TIME_CONSTANT = 256 - 1000000 / frequency
+
+There are several types of DMA transfers available. The following table
+lists them:
+
+      ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+      Â³DMA_TYPE_VALUE   Description             Frequency Range    Â³
+      ÃƒÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
+      Â³    14h          8 bit                   4KHz -> 23 KHz     Â³
+      Â³    74h          4 bit ADPCM             4KHz -> 12 KHz     Â³
+      Â³    75h          4 bit ADPCM with        4KHz -> 12 KHz     Â³
+      Â³                 reference byte                             Â³
+      Â³    76h          2.6 bit ADPCM           4KHz -> 13 KHz     Â³
+      Â³    77h          2.6 bit ADPCM with      4KHz -> 13 KHz     Â³
+      Â³                 reference byte                             Â³
+      Â³    16h          2 bit ADPCM             4KHz -> 11 KHz     Â³
+      Â³    17h          2 bit ADPCM with        4KHz -> 11 KHz     Â³
+      Â³                 reference byte                             Â³
+      Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+ADPCM stands for Adaptive Pulse Code Modulation, a sound compression
+technique where the difference between successive samples is stored rather
+than their actual values. In the modes with reference bytes, the first
+byte is the actual starting value. Having modes with and without reference
+bytes means you can output successive blocks without the need for a
+reference byte at the start of each one.
+
+The procedure for doing a DMA transfer is as follows:
+
+1) Load the sound data into memory
+2) Set up the DMA chip for the tranfer
+3) Set the DSP TIME_CONSTANT to the sampling rate
+4) Write DMA_TYPE_VALUE value to the DSP
+5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
+   DATA_LENGTH = number of bytes to send - 1
+
+Note that the DMA chip must be programmed before the BSP.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Reading from the ADC Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+Reading samples from the ADC (Analog to Digital Converter) can also be
+done in either direct or DMA mode.
+
+To read a sample in direct mode write the value 20h to the DSP and then
+read the value from the DSP. Simple as that!
+
+To set up the DSP for a DMA transfer, follow this procedure :
+
+1) Get a memory buffer ready to hold the sample
+2) Set up the DMA chip for the transfer
+3) Set the DSP TIME_CONSTANT to the sampling rate
+4) Write the value 24h to the DSP
+5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
+   DATA_LENGTH = number of bytes to read - 1
+
+Note that the DMA chip must be programmed before the BSP.
+
+DMA reads only support 8 bit mode, compressed modes are done by software and
+stored in the voc file. I haven't tried to figure out how the compression is
+done. If someone does figure it out I'd like to know about it!
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Programming the DMA Chip Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+As mentioned before, Draeden has written a very good article on the dma
+chip, but here is a brief run down on what you would need to do to program
+the DMA channel 1 for the DSP in real mode:
+
+1) Calculate the 20 bit address of the memory buffer you are using
+   where Base Address = Segment * 16 + Offset
+   eg 1234h:5678h = 179B8h
+2) Send the value 05h to port 0Ah (mask off channel 1)
+3) Send the value 00h to port 0Ch (clear the internal DMA flip/flop)
+4) Send the value 49h to port 0Bh (for playback) or
+                  45h to port 0Bh (for recording)
+5) Write the LSB (bits 0 -> 7) of the 20 bit memory address to port 02h
+6) Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort 02h
+7) Write the Page (bits 16 -> 19) of the 20 bit memory address to port 83h
+8) Send the LSB of DATA_LENGTH to port 03h
+9) Send the MSB of DATA_LENGTH to port 03h
+10) Send the value 01h to port 0Ah (enable channel 1)
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ End of DMA Interrupt Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+When a DMA transfer is complete an interrupt is generated. The actual
+interrupt number depends on the SoundBlaster card's IRQ jumper setting:
+
+                         ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+                         Â³ IRQ Jumper             Â³
+                         Â³  Setting     Interrupt Â³
+                         ÃƒÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
+                         Â³    2            0Ah    Â³
+                         Â³    3            0Bh    Â³
+                         Â³    5            0Dh    Â³
+                         Â³    7            0Fh    Â³
+                         Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+To service one of these interrupts you must perform these 3 tasks:
+
+1) Acknowledge the DSP interrupt by reading the DATA AVAILABLE port (2xEh)
+   once.
+2) If there are more blocks to transfer then set them up
+3) Output value 20h (EOI) to the interrupt controller port 20h
+
+Of course, as with any hardware interrupt you must also leave the
+state of the system (registers etc..) the way it was when the interrupt
+was called.
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ A Simple DSP Pascal Unit Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+{
+
+  DSP.PAS - A demo SoundBlaster DSP unit for real mode
+
+  By Mark Feldman
+}
+
+Unit DSP;
+
+Interface
+
+{ ResetDSP returns true if reset was successful
+  base should be 1 for base address 210h, 2 for 220h etc... }
+function ResetDSP(base : word) : boolean;
+
+{ Write DAC sets the speaker output level }
+procedure WriteDAC(level : byte);
+
+{ ReadDAC reads the microphone input level }
+function ReadDAC : byte;
+
+{ SpeakerOn connects the DAC to the speaker }
+function SpeakerOn: byte;
+
+{ SpeakerOff disconnects the DAC from the speaker,
+  but does not affect the DAC operation }
+function SpeakerOff: byte;
+
+{ Functions to pause DMA playback }
+procedure DMAStop;
+procedure DMAContinue;
+
+{ Playback plays a sample of a given size back at a given frequency using
+  DMA channel 1. The sample must not cross a page boundry }
+procedure Playback(sound : Pointer; size : word; frequency : word);
+
+Implementation
+
+Uses Crt;
+
+var      DSP_RESET : word;
+     DSP_READ_DATA : word;
+    DSP_WRITE_DATA : word;
+  DSP_WRITE_STATUS : word;
+    DSP_DATA_AVAIL : word;
+
+function ResetDSP(base : word) : boolean;
+begin
+
+  base := base * $10;
+
+  { Calculate the port addresses }
+  DSP_RESET := base + $206;
+  DSP_READ_DATA := base + $20A;
+  DSP_WRITE_DATA := base + $20C;
+  DSP_WRITE_STATUS := base + $20C;
+  DSP_DATA_AVAIL := base + $20E;
+
+  { Reset the DSP, and give some nice long delays just to be safe }
+  Port[DSP_RESET] := 1;
+  Delay(10);
+  Port[DSP_RESET] := 0;
+  Delay(10);
+  if (Port[DSP_DATA_AVAIL] And $80 = $80) And
+     (Port[DSP_READ_DATA] = $AA) then
+    ResetDSP := true
+  else
+    ResetDSP := false;
+end;
+
+procedure WriteDSP(value : byte);
+begin
+  while Port[DSP_WRITE_STATUS] And $80 <> 0 do;
+  Port[DSP_WRITE_DATA] := value;
+end;
+
+function ReadDSP : byte;
+begin
+  while Port[DSP_DATA_AVAIL] and $80 = 0 do;
+  ReadDSP := Port[DSP_READ_DATA];
+end;
+
+procedure WriteDAC(level : byte);
+begin
+  WriteDSP($10);
+  WriteDSP(level);
+end;
+
+function ReadDAC : byte;
+begin
+  WriteDSP($20);
+  ReadDAC := ReadDSP;
+end;
+
+function SpeakerOn: byte;
+begin
+  WriteDSP($D1);
+end;
+
+function SpeakerOff: byte;
+begin
+  WriteDSP($D3);
+end;
+
+procedure DMAContinue;
+begin
+  WriteDSP($D4);
+end;
+
+procedure DMAStop;
+begin
+  WriteDSP($D0);
+end;
+
+procedure Playback(sound : Pointer; size : word; frequency : word);
+var time_constant : word;
+     page, offset : word;
+begin
+
+  SpeakerOn;
+
+  size := size - 1;
+
+  { Set up the DMA chip }
+  offset := Seg(sound^) Shl 4 + Ofs(sound^);
+  page := (Seg(sound^) + Ofs(sound^) shr 4) shr 12;
+  Port[$0A] := 5;
+  Port[$0C] := 0;
+  Port[$0B] := $49;
+  Port[$02] := Lo(offset);
+  Port[$02] := Hi(offset);
+  Port[$83] := page;
+  Port[$03] := Lo(size);
+  Port[$03] := Hi(size);
+  Port[$0A] := 1;
+
+  { Set the playback frequency }
+  time_constant := 256 - 1000000 div frequency;
+  WriteDSP($40);
+  WriteDSP(time_constant);
+
+  { Set the playback type (8-bit) }
+  WriteDSP($14);
+  WriteDSP(Lo(size));
+  WriteDSP(Hi(size));
+end;
+
+end.
+
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ References Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+Title : The SoundBlaster Developpers Kit
+Publishers : Creative Labs Inc
+             Creative Technology PTE LTD
+
+Title : Sound Blaster - The Official Book
+Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge
+Publishers : Osborne/McGraw Hill
+ISBN : 0-07-881907-5
+
+Some of the information in this file was either obtained from or verified
+by the source code in a public domain library called SOUNDX by Peter
+Sprenger. I haven't tried using his library yet (I don't have a C compiler
+at the moment) but it looks very well done and contains numerous sound card
+detection routines. Says Peter : "It would be nice, that when you make
+something commercial with my routines, that you send me a copy of your
+project or send me some bucks, just enough for pizza and coke to support my
+night programming sessions. If you send me nothing, ok. But USE the stuff,
+if you can need it!". Heh...a REAL programmer!
+
+ftpsite: ftp.uwp.edu
+directory: /pub/msdos/demos/programming/game-dev/source
+filename: soundx.zip
+
+ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
+³ Sound Familiar? Â³
+ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
+
+What the...why is there a faint glimmer of sunlight outside? HOLY $#!^!! It's
+5:30am! I'm goin' to bed!
+
diff --git a/KernelLand/Modules/Storage/ATA/Makefile b/KernelLand/Modules/Storage/ATA/Makefile
new file mode 100644 (file)
index 0000000..2292342
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = main.o io.o mbr.o
+NAME = ATA
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Storage/ATA/common.h b/KernelLand/Modules/Storage/ATA/common.h
new file mode 100644 (file)
index 0000000..891d2bb
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Acess2 IDE Harddisk Driver
+ * - main.c
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <acess.h>
+#include <vfs.h>
+
+// === CONSTANTS ===
+#define        MAX_ATA_DISKS   4
+#define        SECTOR_SIZE     512
+#define        ATA_TIMEOUT     2000    // 2s timeout
+// Needed out of io.c because it's the max for Read/WriteDMA
+#define        MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
+
+// === STRUCTURES ===
+typedef struct
+{
+       Uint8   BootCode[0x1BE];
+       struct {
+               Uint8   Boot;
+               Uint8   Unused1;        // Also CHS Start
+               Uint16  StartHi;        // Also CHS Start
+               Uint8   SystemID;
+               Uint8   Unused2;        // Also CHS Length
+               Uint16  LengthHi;       // Also CHS Length
+               Uint32  LBAStart;
+               Uint32  LBALength;
+       } __attribute__ ((packed)) Parts[4];
+       Uint16  BootFlag;       // = 0xAA 55
+} __attribute__ ((packed))     tMBR;
+
+typedef struct
+{
+       Uint64  Start;
+       Uint64  Length;
+       char    Name[4];
+       tVFS_Node       Node;
+}      tATA_Partition;
+
+typedef struct
+{
+       Uint64  Sectors;
+       char    Name[2];
+       tVFS_Node       Node;
+        int    NumPartitions;
+       tATA_Partition  *Partitions;
+}      tATA_Disk;
+
+// === GLOBALS ===
+extern tATA_Disk       gATA_Disks[];
+
+// === FUNCTIONS ===
+// --- Common ---
+extern void    ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
+
+// --- MBR Parsing ---
+extern void    ATA_ParseMBR(int Disk, tMBR *MBR);
+
+// --- IO Functions ---
+extern int     ATA_SetupIO(void);
+extern Uint64  ATA_GetDiskSize(int Disk);
+extern int     ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
+extern int     ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer);
+
+#endif
diff --git a/KernelLand/Modules/Storage/ATA/io.c b/KernelLand/Modules/Storage/ATA/io.c
new file mode 100644 (file)
index 0000000..b8a15d0
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Acess2 IDE Harddisk Driver
+ * - io.c
+ *
+ * Disk Input/Output control
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>   // Needed for error codes
+#include <drv_pci.h>
+#include "common.h"
+
+// === MACROS ===
+#define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
+
+// === Constants ===
+#define        IDE_PRI_BASE    0x1F0
+#define IDE_PRI_CTRL   0x3F6
+#define        IDE_SEC_BASE    0x170
+#define IDE_SEC_CTRL   0x376
+
+#define        IDE_PRDT_LAST   0x8000
+/**
+ \enum HddControls
+ \brief Commands to be sent to HDD_CMD
+*/
+enum HddControls {
+       HDD_PIO_R28 = 0x20,
+       HDD_PIO_R48 = 0x24,
+       HDD_DMA_R48 = 0x25,
+       HDD_PIO_W28 = 0x30,
+       HDD_PIO_W48 = 0x34,
+       HDD_DMA_W48 = 0x35,
+       HDD_DMA_R28 = 0xC8,
+       HDD_DMA_W28 = 0xCA,
+       HDD_IDENTIFY = 0xEC
+};
+
+// === TYPES ===
+/**
+ * \brief PRDT Entry
+ */
+typedef struct
+{
+       Uint32  PBufAddr;       // Physical Buffer Address
+       Uint16  Bytes;  // Size of transfer entry
+       Uint16  Flags;  // Flags
+} __attribute__ ((packed))     tPRDT_Ent;
+
+/**
+ * \brief Structure returned by the ATA IDENTIFY command
+ */
+typedef struct
+{
+       Uint16  Flags;          // 1
+       Uint16  Usused1[9];     // 10
+       char    SerialNum[20];  // 20
+       Uint16  Usused2[3];     // 23
+       char    FirmwareVer[8]; // 27
+       char    ModelNumber[40];        // 47
+       Uint16  SectPerInt;     // 48 - Low byte only
+       Uint16  Unused3;        // 49
+       Uint16  Capabilities[2];        // 51
+       Uint16  Unused4[2];     // 53
+       Uint16  ValidExtData;   // 54
+       Uint16  Unused5[5];      // 59
+       Uint16  SizeOfRWMultiple;       // 60
+       Uint32  Sectors28;      // LBA 28 Sector Count
+       Uint16  Unused6[100-62];
+       Uint64  Sectors48;      // LBA 48 Sector Count
+       Uint16  Unused7[256-104];
+} __attribute__ ((packed))     tIdentify;
+
+// === PROTOTYPES ===
+ int   ATA_SetupIO(void);
+Uint64 ATA_GetDiskSize(int Disk);
+Uint16 ATA_GetBasePort(int Disk);
+// Read/Write DMA
+ int   ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
+ int   ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer);
+// IRQs
+void   ATA_IRQHandlerPri(int UNUSED(IRQ), void *UNUSED(Ptr));
+void   ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr));
+// Controller IO
+Uint8  ATA_int_BusMasterReadByte(int Ofs);
+Uint32 ATA_int_BusMasterReadDWord(int Ofs);
+void   ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
+void   ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
+
+// === GLOBALS ===
+// - BusMaster IO Addresses
+Uint32 gATA_BusMasterBase;     //!< True Address (IO/MMIO)
+Uint8  *gATA_BusMasterBasePtr; //!< Paging Mapped MMIO (If needed)
+// - IRQs
+ int   gATA_IRQPri = 14;
+ int   gATA_IRQSec = 15;
+volatile int   gaATA_IRQs[2] = {0};
+// - Locks to avoid tripping
+tMutex glaATA_ControllerLock[2];
+// - Buffers!
+Uint8  gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
+// - PRDTs
+tPRDT_Ent      gATA_PRDTs[2] = {
+       {0, 512, IDE_PRDT_LAST},
+       {0, 512, IDE_PRDT_LAST}
+};
+tPAddr gaATA_PRDT_PAddrs[2];
+
+// === CODE ===
+/**
+ * \brief Sets up the ATA controller's DMA mode
+ */
+int ATA_SetupIO(void)
+{
+        int    ent;
+
+       ENTER("");
+
+       // Get IDE Controller's PCI Entry
+       ent = PCI_GetDeviceByClass(0x010100, 0xFFFF00, -1);
+       LOG("ent = %i", ent);
+       gATA_BusMasterBase = PCI_GetBAR(ent, 4);
+       if( gATA_BusMasterBase == 0 ) {
+               Log_Warning("ATA", "It seems that there is no Bus Master Controller on this machine. Get one");
+               // TODO: Use PIO mode instead
+               LEAVE('i', MODULE_ERR_NOTNEEDED);
+               return MODULE_ERR_NOTNEEDED;
+       }
+       
+       LOG("BAR5 = 0x%x", PCI_GetBAR(ent, 5));
+       LOG("IRQ = %i", PCI_GetIRQ(ent));
+       
+       // Map memory
+       if( !(gATA_BusMasterBase & 1) )
+       {
+               if( gATA_BusMasterBase < 0x100000 )
+                       gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
+               else
+                       gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
+               LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
+       }
+       else {
+               // Bit 0 is left set as a flag to other functions
+               LOG("gATA_BusMasterBase = IO 0x%x", gATA_BusMasterBase & ~1);
+       }
+
+       // Register IRQs and get Buffers
+       IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri, NULL );
+       IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec, NULL );
+
+       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
+       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
+
+       LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
+
+       gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
+       LOG("gaATA_PRDT_PAddrs[0] = 0x%x", gaATA_PRDT_PAddrs[0]);
+       ATA_int_BusMasterWriteDWord(4, gaATA_PRDT_PAddrs[0]);
+       
+       gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
+       LOG("gaATA_PRDT_PAddrs[1] = 0x%x", gaATA_PRDT_PAddrs[1]);
+       ATA_int_BusMasterWriteDWord(12, gaATA_PRDT_PAddrs[1]);
+
+       // Enable controllers
+       outb(IDE_PRI_BASE+1, 1);
+       outb(IDE_SEC_BASE+1, 1);
+       outb(IDE_PRI_CTRL, 0);
+       outb(IDE_SEC_CTRL, 0);
+       
+       // Make sure interrupts are ACKed
+       ATA_int_BusMasterWriteByte(2, 0x4);
+       ATA_int_BusMasterWriteByte(10, 0x4);
+
+       // return
+       LEAVE('i', MODULE_ERR_OK);
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Get the size (in sectors) of a disk
+ * \param Disk Disk to get size of
+ * \return Number of sectors reported
+ * 
+ * Does an ATA IDENTIFY
+ */
+Uint64 ATA_GetDiskSize(int Disk)
+{
+       union {
+               Uint16  buf[256];
+               tIdentify       identify;
+       }       data;
+       Uint16  base;
+       Uint8   val;
+        int    i;
+       ENTER("iDisk", Disk);
+
+       base = ATA_GetBasePort( Disk );
+
+       // Send Disk Selector
+       if(Disk & 1)    // Slave
+               outb(base+6, 0xB0);
+       else    // Master
+               outb(base+6, 0xA0);
+       IO_DELAY();
+       
+       // Check for a floating bus
+       if( 0xFF == inb(base+7) ) {
+               LOG("Floating bus");
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       // Check for the controller
+       // - Write to two RW ports and attempt to read back
+       outb(base+0x02, 0x66);
+       outb(base+0x03, 0xFF);
+       if(inb(base+0x02) != 0x66 || inb(base+0x03) != 0xFF) {
+               LOG("No controller");
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       // Send ATA IDENTIFY
+       outb(base+7, HDD_IDENTIFY);
+       IO_DELAY();
+       val = inb(base+7);      // Read status
+       LOG("val = 0x%02x", val);
+       if(val == 0) {
+               LEAVE('i', 0);
+               return 0;       // Disk does not exist
+       }
+
+       // Poll until BSY clears or ERR is set
+       // TODO: Timeout?
+       while( (val & 0x80) && !(val & 1) )
+               val = inb(base+7);
+       LOG("BSY unset (0x%x)", val);
+       // and, wait for DRQ to set
+       while( !(val & 0x08) && !(val & 1))
+               val = inb(base+7);
+       LOG("DRQ set (0x%x)", val);
+
+       // Check for an error
+       if(val & 1) {
+               LEAVE('i', 0);
+               return 0;       // Error occured, so return false
+       }
+
+       // Read Data
+       for( i = 0; i < 256; i++ )
+               data.buf[i] = inw(base);
+
+       // Return the disk size
+       if(data.identify.Sectors48 != 0) {
+               LEAVE('X', data.identify.Sectors48);
+               return data.identify.Sectors48;
+       }
+       else {
+               LEAVE('x', data.identify.Sectors28);
+               return data.identify.Sectors28;
+       }
+}
+
+/**
+ * \fn Uint16 ATA_GetPortBase(int Disk)
+ * \brief Returns the base port for a given disk
+ */
+Uint16 ATA_GetBasePort(int Disk)
+{
+       switch(Disk)
+       {
+       case 0: case 1:         return IDE_PRI_BASE;
+       case 2: case 3:         return IDE_SEC_BASE;
+       }
+       return 0;
+}
+
+/**
+ * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ * \return Boolean Failure
+ */
+int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+        int    cont = (Disk>>1)&1;     // Controller ID
+        int    disk = Disk & 1;
+       Uint16  base;
+       Sint64  timeoutTime;
+
+       ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
+
+       // Check if the count is small enough
+       if(Count > MAX_DMA_SECTORS) {
+               Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)",
+                       Count, MAX_DMA_SECTORS);
+               LEAVE('i');
+               return 1;
+       }
+       
+       // Hack to make debug hexdump noticable
+       #if 1
+       memset(Buffer, 0xFF, Count*SECTOR_SIZE);
+       #endif
+
+       // Get exclusive access to the disk controller
+       Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
+
+       // Set Size
+       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+
+       // Get Port Base
+       base = ATA_GetBasePort(Disk);
+
+       // Reset IRQ Flag
+       gaATA_IRQs[cont] = 0;
+
+       #if 1
+       if( cont == 0 ) {
+               outb(IDE_PRI_CTRL, 4);
+               IO_DELAY();
+               outb(IDE_PRI_CTRL, 0);
+       }
+       else {
+               outb(IDE_SEC_CTRL, 4);
+               IO_DELAY();
+               outb(IDE_SEC_CTRL, 0);
+       }
+       #endif
+
+       // Set up transfer
+       if( Address > 0x0FFFFFFF )      // Use LBA48
+       {
+               outb(base+0x6, 0x40 | (disk << 4));
+               IO_DELAY();
+               outb(base+0x2, 0 >> 8); // Upper Sector Count
+               outb(base+0x3, Address >> 24);  // Low 2 Addr
+               outb(base+0x4, Address >> 28);  // Mid 2 Addr
+               outb(base+0x5, Address >> 32);  // High 2 Addr
+       }
+       else
+       {
+               // Magic, Disk, High Address nibble
+               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
+               //outb(base+0x06, 0xA0 | (disk << 4) | ((Address >> 24) & 0x0F));
+               IO_DELAY();
+       }
+
+       //outb(base+0x01, 0x01);        //?
+       outb(base+0x02, Count & 0xFF);          // Sector Count
+       outb(base+0x03, Address & 0xFF);                // Low Addr
+       outb(base+0x04, (Address >> 8) & 0xFF); // Middle Addr
+       outb(base+0x05, (Address >> 16) & 0xFF);        // High Addr
+
+       LOG("Starting Transfer");
+       
+       // HACK: Ensure the PRDT is reset
+       ATA_int_BusMasterWriteDWord(cont*8+4, gaATA_PRDT_PAddrs[cont]);
+       ATA_int_BusMasterWriteByte(cont*8, 4);  // Reset IRQ
+       
+       LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
+       if( Address > 0x0FFFFFFF )
+               outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
+       else
+               outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
+
+       // Start transfer
+       ATA_int_BusMasterWriteByte( cont * 8, 9 );      // Read and start
+
+       // Wait for transfer to complete
+       timeoutTime = now() + ATA_TIMEOUT;
+       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
+       {
+               HALT();
+       }
+
+       // Complete Transfer
+       ATA_int_BusMasterWriteByte( cont * 8, 8 );      // Read and stop
+
+       #if DEBUG
+       {
+               Uint8   val = inb(base+0x7);
+               LOG("Status byte = 0x%02x, Controller Status = 0x%02x",
+                       val, ATA_int_BusMasterReadByte(cont * 8 + 2));
+       }
+       #else
+       inb(base+0x7);
+       #endif
+
+       if( gaATA_IRQs[cont] == 0 )
+       {
+               if( ATA_int_BusMasterReadByte(cont * 8 + 2) & 0x4 ) {
+                       Log_Error("ATA", "BM Status reports an interrupt, but none recieved");
+                       ATA_int_BusMasterWriteByte(cont*8 + 2, 4);      // Clear interrupt
+                       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
+                       Mutex_Release( &glaATA_ControllerLock[ cont ] );
+                       LEAVE('i', 0);
+                       return 0;
+               }
+
+               #if 1
+               Debug_HexDump("ATA", Buffer, 512);
+               #endif
+               
+               // Release controller lock
+               Mutex_Release( &glaATA_ControllerLock[ cont ] );
+               Log_Warning("ATA",
+                       "Read timeout on disk %i (Reading sector 0x%llx)",
+                       Disk, Address);
+               // Return error
+               LEAVE('i', 1);
+               return 1;
+       }
+       else {
+               LOG("Transfer Completed & Acknowledged");
+               // Copy to destination buffer
+               memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
+               // Release controller lock
+               Mutex_Release( &glaATA_ControllerLock[ cont ] );
+
+               LEAVE('i', 0);
+               return 0;
+       }
+}
+
+/**
+ * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ * \brief Write up to \a MAX_DMA_SECTORS to a disk
+ * \param Disk Disk ID to write to
+ * \param Address      LBA of first sector
+ * \param Count        Number of sectors to write (must be >= \a MAX_DMA_SECTORS)
+ * \param Buffer       Source buffer for data
+ * \return Boolean Failure
+ */
+int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer)
+{
+        int    cont = (Disk>>1)&1;     // Controller ID
+        int    disk = Disk & 1;
+       Uint16  base;
+       Sint64  timeoutTime;
+
+       // Check if the count is small enough
+       if(Count > MAX_DMA_SECTORS)     return 1;
+
+       // Get exclusive access to the disk controller
+       Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
+
+       // Set Size
+       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+
+       // Get Port Base
+       base = ATA_GetBasePort(Disk);
+
+       // Reset IRQ Flag
+       gaATA_IRQs[cont] = 0;
+       
+       // Set up transfer
+       outb(base+0x01, 0x00);
+       if( Address > 0x0FFFFFFF )      // Use LBA48
+       {
+               outb(base+0x6, 0x40 | (disk << 4));
+               outb(base+0x2, 0 >> 8); // Upper Sector Count
+               outb(base+0x3, Address >> 24);  // Low 2 Addr
+               outb(base+0x3, Address >> 28);  // Mid 2 Addr
+               outb(base+0x3, Address >> 32);  // High 2 Addr
+       }
+       else
+       {
+               // Magic, Disk, High Address nibble
+               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
+       }
+
+       outb(base+0x02, (Uint8) Count);         // Sector Count
+       outb(base+0x03, (Uint8) Address);               // Low Addr
+       outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
+       outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
+       if( Address > 0x0FFFFFFF )
+               outb(base+0x07, HDD_DMA_W48);   // Write Command (LBA48)
+       else
+               outb(base+0x07, HDD_DMA_W28);   // Write Command (LBA28)
+
+       // Copy to output buffer
+       memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
+
+       // Start transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 1 );     // Write and start
+
+       // Wait for transfer to complete
+       timeoutTime = now() + ATA_TIMEOUT;
+       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
+       {
+               HALT();
+       }
+
+       // Complete Transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
+
+       // If the IRQ is unset, return error
+       if( gaATA_IRQs[cont] == 0 ) {
+               // Release controller lock
+               Mutex_Release( &glaATA_ControllerLock[ cont ] );
+               return 1;       // Error
+       }
+       else {
+               Mutex_Release( &glaATA_ControllerLock[ cont ] );
+               return 0;
+       }
+}
+
+/**
+ * \brief Primary ATA Channel IRQ handler
+ */
+void ATA_IRQHandlerPri(int UNUSED(IRQ), void *UNUSED(Ptr))
+{
+       Uint8   val;
+
+       // IRQ bit set for Primary Controller
+       val = ATA_int_BusMasterReadByte( 0x2 );
+       LOG("IRQ val = 0x%x", val);
+       if(val & 4) {
+               LOG("IRQ hit (val = 0x%x)", val);
+               ATA_int_BusMasterWriteByte( 0x2, 4 );
+               gaATA_IRQs[0] = 1;
+               return ;
+       }
+}
+
+/**
+ * \brief Second ATA Channel IRQ handler
+ */
+void ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr))
+{
+       Uint8   val;
+       // IRQ bit set for Secondary Controller
+       val = ATA_int_BusMasterReadByte( 0xA );
+       LOG("IRQ val = 0x%x", val);
+       if(val & 4) {
+               LOG("IRQ hit (val = 0x%x)", val);
+               ATA_int_BusMasterWriteByte( 0xA, 4 );
+               gaATA_IRQs[1] = 1;
+               return ;
+       }
+}
+
+/**
+ * \brief Read an 8-bit value from a Bus Master register
+ * \param Ofs  Register offset
+ */
+Uint8 ATA_int_BusMasterReadByte(int Ofs)
+{
+       if( gATA_BusMasterBase & 1 )
+               return inb( (gATA_BusMasterBase & ~1) + Ofs );
+       else
+               return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
+}
+
+/**
+ * \brief Read an 32-bit value from a Bus Master register
+ * \param Ofs  Register offset
+ */
+Uint32 ATA_int_BusMasterReadDWord(int Ofs)
+{
+       if( gATA_BusMasterBase & 1 )
+               return ind( (gATA_BusMasterBase & ~1) + Ofs );
+       else
+               return *(Uint32*)(gATA_BusMasterBasePtr + Ofs);
+}
+
+/**
+ * \brief Writes a byte to a Bus Master Register
+ * \param Ofs  Register Offset
+ * \param Value        Value to write
+ */
+void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
+{
+       if( gATA_BusMasterBase & 1 )
+               outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
+       else
+               *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
+}
+
+/**
+ * \brief Writes a 32-bit value to a Bus Master Register
+ * \param Ofs  Register offset
+ * \param Value        Value to write
+ */
+void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
+{
+       if( gATA_BusMasterBase & 1 )
+               outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
+       else
+               *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
+}
diff --git a/KernelLand/Modules/Storage/ATA/main.c b/KernelLand/Modules/Storage/ATA/main.c
new file mode 100644 (file)
index 0000000..41228d8
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * Acess2 IDE Harddisk Driver
+ * - main.c
+ */
+#define DEBUG  0
+#define VERSION        0x0032
+#include <acess.h>
+#include <modules.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <api_drv_common.h>
+#include <api_drv_disk.h>
+#include "common.h"
+
+// === MACROS ===
+#define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
+
+// === PROTOTYPES ===
+ int   ATA_Install(char **Arguments);
+void   ATA_SetupPartitions(void);
+void   ATA_SetupVFS(void);
+ int   ATA_ScanDisk(int Disk);
+void   ATA_ParseGPT(int Disk);
+void   ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
+Uint16 ATA_GetBasePort(int Disk);
+// Filesystem Interface
+char   *ATA_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *ATA_FindDir(tVFS_Node *Node, const char *Name);
+Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+ int   ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
+// Read/Write Interface/Quantiser
+Uint   ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+Uint   ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
+tVFS_NodeType  gATA_RootNodeType = {
+       .TypeName = "ATA Root Node",
+       .ReadDir = ATA_ReadDir,
+       .FindDir = ATA_FindDir
+       };
+tVFS_NodeType  gATA_DiskNodeType = {
+       .TypeName = "ATA Volume",
+       .Read = ATA_ReadFS,
+       .Write = ATA_WriteFS,
+       .IOCtl = ATA_IOCtl
+       };
+tDevFS_Driver  gATA_DriverInfo = {
+       NULL, "ata",
+       {
+               .NumACLs = 1,
+               .Size = -1,
+               .Flags = VFS_FFLAG_DIRECTORY,
+               .ACLs = &gVFS_ACL_EveryoneRX,
+               .Type = &gATA_RootNodeType
+       }
+};
+tATA_Disk      gATA_Disks[MAX_ATA_DISKS];
+ int   giATA_NumNodes;
+tVFS_Node      **gATA_Nodes;
+
+// === CODE ===
+/**
+ * \brief Initialise the ATA driver
+ */
+int ATA_Install(char **Arguments)
+{
+       int     ret;
+
+       ret = ATA_SetupIO();
+       if(ret) return ret;
+
+       ATA_SetupPartitions();
+
+       ATA_SetupVFS();
+
+       if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
+               return MODULE_ERR_MISC;
+
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Scan all disks, looking for partitions
+ */
+void ATA_SetupPartitions(void)
+{
+        int    i;
+       for( i = 0; i < MAX_ATA_DISKS; i ++ )
+       {
+               if( !ATA_ScanDisk(i) ) {
+                       gATA_Disks[i].Name[0] = '\0';   // Mark as unused
+                       continue;
+               }
+       }
+}
+
+/**
+ * \brief Sets up the ATA drivers VFS information and registers with DevFS
+ */
+void ATA_SetupVFS(void)
+{
+        int    i, j, k;
+
+       // Count number of nodes needed
+       giATA_NumNodes = 0;
+       for( i = 0; i < MAX_ATA_DISKS; i++ )
+       {
+               if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
+               giATA_NumNodes ++;
+               giATA_NumNodes += gATA_Disks[i].NumPartitions;
+       }
+
+       // Allocate Node space
+       gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
+
+       // Set nodes
+       k = 0;
+       for( i = 0; i < MAX_ATA_DISKS; i++ )
+       {
+               if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
+               gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
+               for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
+                       gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
+       }
+
+       gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
+}
+
+/**
+ * \brief Scan a disk, getting the size and any paritions
+ * \param Disk Disk ID to scan
+ */
+int ATA_ScanDisk(int Disk)
+{
+       tVFS_Node       *node;
+       tMBR    mbr;
+
+       ENTER("iDisk", Disk);
+       
+       // Get the disk size
+       gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
+       if(gATA_Disks[ Disk ].Sectors == 0)
+       {
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
+
+       // Create Name
+       gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
+       gATA_Disks[ Disk ].Name[1] = '\0';
+
+       #if 1
+       {
+               Uint64  val = gATA_Disks[ Disk ].Sectors / 2;
+               char    *units = "KiB";
+               if( val > 4*1024 ) {
+                       val /= 1024;
+                       units = "MiB";
+               }
+               else if( val > 4*1024 ) {
+                       val /= 1024;
+                       units = "GiB";
+               }
+               else if( val > 4*1024 ) {
+                       val /= 1024;
+                       units = "TiB";
+               }
+               Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
+                       gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
+       }
+       #endif
+
+       // Get pointer to vfs node and populate it
+       node = &gATA_Disks[ Disk ].Node;
+       node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
+       node->NumACLs = 0;      // Means Superuser only can access it
+       node->Inode = (Disk << 8) | 0xFF;
+       node->ImplPtr = gATA_Disks[ Disk ].Name;
+
+       node->ATime = node->MTime = node->CTime = now();
+
+       node->Type = &gATA_DiskNodeType;
+
+       // --- Scan Partitions ---
+       LOG("Reading MBR");
+       // Read Boot Sector
+       if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
+               Log_Warning("ATA", "Error in reading MBR on %i", Disk);
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       // Check for a GPT table
+       if(mbr.Parts[0].SystemID == 0xEE)
+               ATA_ParseGPT(Disk);
+       else    // No? Just parse the MBR
+               ATA_ParseMBR(Disk, &mbr);
+       
+       #if DEBUG >= 2
+       ATA_ReadDMA( Disk, 1, 1, &mbr );
+       Debug_HexDump("ATA_ScanDisk", &mbr, 512);
+       #endif
+
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
+ * \brief Fills a parition's information structure
+ */
+void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
+{
+       ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
+       Part->Start = Start;
+       Part->Length = Length;
+       Part->Name[0] = 'A'+Disk;
+       if(Num >= 10) {
+               Part->Name[1] = '1'+Num/10;
+               Part->Name[2] = '1'+Num%10;
+               Part->Name[3] = '\0';
+       } else {
+               Part->Name[1] = '1'+Num;
+               Part->Name[2] = '\0';
+       }
+       Part->Node.NumACLs = 0; // Only root can read/write raw block devices
+       Part->Node.Inode = (Disk << 8) | Num;
+       Part->Node.ImplPtr = Part->Name;
+
+       Part->Node.Type = &gATA_DiskNodeType;
+       Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
+       LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
+       LEAVE('-');
+}
+
+/**
+ * \fn void ATA_ParseGPT(int Disk)
+ * \brief Parses the GUID Partition Table
+ */
+void ATA_ParseGPT(int Disk)
+{
+       ///\todo Support GPT Disks
+       Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
+}
+
+/**
+ * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
+ */
+char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
+{
+       if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
+       return strdup( gATA_Nodes[Pos]->ImplPtr );
+}
+
+/**
+ * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
+ */
+tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
+{
+        int    part;
+       tATA_Disk       *disk;
+       
+       // Check first character
+       if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
+               return NULL;
+       disk = &gATA_Disks[Name[0]-'A'];
+       // Raw Disk
+       if(Name[1] == '\0') {
+               if( disk->Sectors == 0 && disk->Name[0] == '\0')
+                       return NULL;
+               return &disk->Node;
+       }
+
+       // Partitions
+       if(Name[1] < '0' || '9' < Name[1])      return NULL;
+       if(Name[2] == '\0') {   // <= 9
+               part = Name[1] - '0';
+               part --;
+               return &disk->Partitions[part].Node;
+       }
+       // > 9
+       if('0' > Name[2] || '9' < Name[2])      return NULL;
+       if(Name[3] != '\0')     return NULL;
+
+       part = (Name[1] - '0') * 10;
+       part += Name[2] - '0';
+       part --;
+       return &disk->Partitions[part].Node;
+
+}
+
+/**
+ * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ */
+Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    disk = Node->Inode >> 8;
+        int    part = Node->Inode & 0xFF;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+       // Raw Disk Access
+       if(part == 0xFF)
+       {
+               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
+                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
+       }
+       // Partition
+       else
+       {
+               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
+               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
+       }
+
+       {
+               int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
+               //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
+               //Debug_HexDump("ATA_ReadFS", Buffer, Length);
+               LEAVE('i', ret);
+               return ret;
+       }
+}
+
+/**
+ * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+ */
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+        int    disk = Node->Inode >> 8;
+        int    part = Node->Inode & 0xFF;
+
+       // Raw Disk Access
+       if(part == 0xFF)
+       {
+               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
+                       return 0;
+               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
+                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
+       }
+       // Partition
+       else
+       {
+               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+                       return 0;
+               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
+               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
+       }
+
+       Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
+       Debug_HexDump("ATA_WriteFS", Buffer, Length);
+       return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
+}
+
+const char     *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
+/**
+ * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief IO Control Funtion
+ */
+int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
+{
+       switch(Id)
+       {
+       BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
+       
+       case DISK_IOCTL_GETBLOCKSIZE:
+               return 512;     
+       
+       default:
+               return 0;
+       }
+       return 0;
+}
+
+// --- Disk Access ---
+/**
+ * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ */
+Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+{
+        int    ret;
+       Uint    offset;
+       Uint    done = 0;
+
+       // Pass straight on to ATA_ReadDMAPage if we can
+       if(Count <= MAX_DMA_SECTORS)
+       {
+               ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
+               if(ret == 0)    return 0;
+               return Count;
+       }
+
+       // Else we will have to break up the transfer
+       offset = 0;
+       while(Count > MAX_DMA_SECTORS)
+       {
+               ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
+               // Check for errors
+               if(ret != 1)    return done;
+               // Change Position
+               done += MAX_DMA_SECTORS;
+               Count -= MAX_DMA_SECTORS;
+               offset += MAX_DMA_SECTORS*SECTOR_SIZE;
+       }
+
+       ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
+       if(ret != 1)    return 0;
+       return done+Count;
+}
+
+/**
+ * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
+ */
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
+{
+        int    ret;
+       Uint    offset;
+       Uint    done = 0;
+
+       // Pass straight on to ATA_WriteDMA, if we can
+       if(Count <= MAX_DMA_SECTORS)
+       {
+               ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
+               if(ret == 0)    return 0;
+               return Count;
+       }
+
+       // Else we will have to break up the transfer
+       offset = 0;
+       while(Count > MAX_DMA_SECTORS)
+       {
+               ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
+               // Check for errors
+               if(ret != 1)    return done;
+               // Change Position
+               done += MAX_DMA_SECTORS;
+               Count -= MAX_DMA_SECTORS;
+               offset += MAX_DMA_SECTORS*SECTOR_SIZE;
+       }
+
+       ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
+       if(ret != 1)    return 0;
+       return done+Count;
+}
diff --git a/KernelLand/Modules/Storage/ATA/mbr.c b/KernelLand/Modules/Storage/ATA/mbr.c
new file mode 100644 (file)
index 0000000..a294ca8
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Acess2 IDE Harddisk Driver
+ * - MBR Parsing Code
+ * mbr.c
+ */
+#define DEBUG  0
+#include <acess.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+void   ATA_ParseMBR(int Disk, tMBR *MBR);
+Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
+
+// === GLOBALS ===
+
+// === CODE ===
+/**
+ * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
+ */
+void ATA_ParseMBR(int Disk, tMBR *MBR)
+{
+        int    i, j = 0, k = 4;
+       Uint64  extendedLBA;
+       Uint64  base, len;
+       
+       ENTER("iDisk", Disk);
+       
+       // Count Partitions
+       gATA_Disks[Disk].NumPartitions = 0;
+       extendedLBA = 0;
+       for( i = 0; i < 4; i ++ )
+       {
+               if( MBR->Parts[i].SystemID == 0 )       continue;
+               if(     MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 // LBA 28
+               ||      MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 // LBA 48
+                       )
+               {
+                       if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
+                               LOG("Extended Partition at 0x%llx", MBR->Parts[i].LBAStart);
+                               if(extendedLBA != 0) {
+                                       Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+                                       continue;
+                               }
+                               extendedLBA = MBR->Parts[i].LBAStart;
+                               continue;
+                       }
+                       LOG("Primary Partition at 0x%llx", MBR->Parts[i].LBAStart);
+                       
+                       gATA_Disks[Disk].NumPartitions ++;
+                       continue;
+               }
+               // Invalid Partition, so don't count it
+       }
+       while(extendedLBA != 0)
+       {
+               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
+               if( extendedLBA == -1 ) break;
+               gATA_Disks[Disk].NumPartitions ++;
+       }
+       LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
+       
+       // Create patition array
+       gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
+       
+       // --- Fill Partition Info ---
+       extendedLBA = 0;
+       for( j = 0, i = 0; i < 4; i ++ )
+       {
+               LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
+               if( MBR->Parts[i].SystemID == 0 )       continue;
+               if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
+               {
+                       base = MBR->Parts[i].LBAStart;
+                       len = MBR->Parts[i].LBALength;
+               }
+               else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 58
+               {
+                       base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
+                       len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
+               }
+               else
+                       continue;
+               
+               if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
+                       if(extendedLBA != 0) {
+                               Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
+                               continue;
+                       }
+                       extendedLBA = base;
+                       continue;
+               }
+               // Create Partition
+               ATA_int_MakePartition(
+                       &gATA_Disks[Disk].Partitions[j], Disk, j,
+                       base, len
+                       );
+               j ++;
+               
+       }
+       // Scan extended partitions
+       while(extendedLBA != 0)
+       {
+               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
+               if(extendedLBA == -1)   break;
+               ATA_int_MakePartition(
+                       &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
+                       );
+       }
+       
+       LEAVE('-');
+}
+
+/**
+ * \brief Reads an extended partition
+ * \return LBA of next Extended, -1 on error, 0 for last
+ */
+Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
+{
+       Uint64  link = 0;
+        int    bFoundPart = 0;;
+        int    i;
+       tMBR    mbr;
+       Uint64  base, len;
+       
+       if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
+               return -1;      // Stop on Errors
+       
+       for( i = 0; i < 4; i ++ )
+       {
+               if( mbr.Parts[i].SystemID == 0 )        continue;
+               
+               // LBA 24
+               if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
+                       base = mbr.Parts[i].LBAStart;
+                       len = mbr.Parts[i].LBALength;
+               }
+               // LBA 48
+               else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
+                       base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
+                       len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
+               }
+               else {
+                       Log_Warning("ATA MBR",
+                               "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
+                               mbr.Parts[i].Boot, Disk, Addr, i
+                               );
+                       return -1;
+               }
+               
+               switch(mbr.Parts[i].SystemID)
+               {
+               case 0xF:
+               case 0x5:
+                       if(link != 0) {
+                               Log_Warning("ATA MBR",
+                                       "Disk %i has two forward links in the extended partition",
+                                       Disk
+                                       );
+                               return -1;
+                       }
+                       link = base;
+                       break;
+               default:
+                       if(bFoundPart) {
+                               Warning("ATA MBR",
+                                       "Disk %i has more than one partition in the extended partition at 0x%llx",
+                                       Disk, Addr
+                                       );
+                               return -1;
+                       }
+                       bFoundPart = 1;
+                       *Base = base;
+                       *Length = len;
+                       break;
+               }
+       }
+       
+       if(!bFoundPart) {
+               Log_Warning("ATA MBR",
+                       "No partition in extended partiton, Disk %i 0x%llx",
+                       Disk, Addr);
+               return -1;
+       }
+       
+       return link;
+}
diff --git a/KernelLand/Modules/Storage/FDD/Makefile b/KernelLand/Modules/Storage/FDD/Makefile
new file mode 100644 (file)
index 0000000..1596553
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = fdd.o
+NAME = FDD
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Storage/FDD/fdd.c b/KernelLand/Modules/Storage/FDD/fdd.c
new file mode 100644 (file)
index 0000000..9cf808d
--- /dev/null
@@ -0,0 +1,957 @@
+/*
+ * AcessOS 0.1
+ * Floppy Disk Access Code
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <api_drv_disk.h>
+#include <dma.h>
+#include <iocache.h>
+
+#define WARN   0
+
+// === CONSTANTS ===
+// --- Current Version
+#define FDD_VERSION     ((0<<8)|(75))
+
+// --- Options
+#define FDD_SEEK_TIMEOUT       10      // Timeout for a seek operation
+#define MOTOR_ON_DELAY 500             // Miliseconds
+#define MOTOR_OFF_DELAY        2000    // Miliseconds
+#define        FDD_MAX_READWRITE_ATTEMPTS      16
+
+// === TYPEDEFS ===
+/**
+ * \brief Representation of a floppy drive
+ */
+typedef struct sFloppyDrive
+{
+        int    type;
+       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off
+        int    track[2];
+        int    timer;
+       tVFS_Node       Node;
+       #if !USE_CACHE
+       tIOCache        *CacheHandle;
+       #endif
+} t_floppyDevice;
+
+/**
+ * \brief Cached Sector
+ */
+typedef struct {
+       Uint64  timestamp;
+       Uint16  disk;
+       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)
+       Uint8   data[512];
+} t_floppySector;
+
+// === CONSTANTS ===
+static const char      *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };
+static const int       cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };
+static const short     cPORTBASE[] = { 0x3F0, 0x370 };
+#if DEBUG
+static const char      *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};
+#endif
+
+enum FloppyPorts {
+       PORT_STATUSA    = 0x0,
+       PORT_STATUSB    = 0x1,
+       PORT_DIGOUTPUT  = 0x2,
+       PORT_MAINSTATUS = 0x4,
+       PORT_DATARATE   = 0x4,
+       PORT_DATA       = 0x5,
+       PORT_DIGINPUT   = 0x7,
+       PORT_CONFIGCTRL = 0x7
+};
+
+#define CMD_FLAG_MULTI_TRACK   0x80    //!< Multitrack
+#define CMD_FLAG_MFM_ENCODING  0x40    //!< MFM Encoding Mode (Always set for read/write/format/verify)
+#define CMD_FLAG_SKIP_MODE     0x20    //!< Skip Mode (don't use)
+enum FloppyCommands {
+       CMD_READ_TRACK      = 0x02,
+       CMD_SPECIFY         = 0x03,
+       CMD_SENSE_STATUS    = 0x04,
+       CMD_WRITE_DATA      = 0x05,
+       CMD_READ_DATA       = 0x06,
+       CMD_RECALIBRATE     = 0x07,
+       CMD_SENSE_INTERRUPT = 0x08,
+       CMD_WRITE_DEL_DATA  = 0x09,
+       CMD_READ_SECTOR_ID  = 0x0A,
+       // 0x0B - ?
+       CMD_READ_DEL_DATA       = 0x0C,
+       CMD_FORMAT_TRACK    = 0x0D,
+       // 0x0E - ?
+       CMD_SEEK_TRACK      = 0x0F,
+       CMD_VERSION         = 0x10,
+       
+       CMD_LOCK            = 0x14,     //!< Save controller parameters
+       
+       CMD_CONFIGURE       = 0x13
+};
+
+// === PROTOTYPES ===
+// --- Filesystem
+ int   FDD_Install(char **Arguments);
+void   FDD_UnloadModule();
+// --- VFS Methods
+char   *FDD_ReadDir(tVFS_Node *Node, int pos);
+tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
+ int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
+// --- Functions for IOCache/DrvUtil
+Uint   FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);
+// --- Raw Disk Access
+ int   FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);
+ int   FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);
+// --- Helpers
+ int   FDD_WaitIRQ();
+void   FDD_IRQHandler(int Num, void *Ptr);
+void   FDD_SenseInt(int base, Uint8 *sr0, Uint8 *cyl);
+
+ int   FDD_Reset(int id);
+void   FDD_Recalibrate(int disk);
+ int   FDD_Reconfigure(int ID);
+
+ int   FDD_int_SeekTrack(int disk, int head, int track);
+void   FDD_int_TimerCallback(void *Arg);
+void   FDD_int_StopMotor(int Disk);
+void   FDD_int_StopMotorCallback(void *Arg);
+void   FDD_int_StartMotor(int Disk);
+ int   FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);
+
+ int   FDD_int_SendByte(int base, Uint8 Byte);
+ int   FDD_int_GetByte(int base, Uint8 *Byte);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "x86_ISADMA", NULL);
+t_floppyDevice gFDD_Devices[2];
+tMutex glFDD;
+volatile int   gbFDD_IrqFired = 0;
+tDevFS_Driver  gFDD_DriverInfo = {
+       NULL, "fdd",
+       {
+       .Size = -1,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .ReadDir = FDD_ReadDir,
+       .FindDir = FDD_FindDir,
+       .IOCtl = FDD_IOCtl
+       }
+};
+
+// === CODE ===
+/**
+ * \fn int FDD_Install(char **Arguments)
+ * \brief Installs floppy driver
+ */
+int FDD_Install(char **Arguments)
+{
+       Uint8 data;
+       char    **args = Arguments;
+       
+       // Determine Floppy Types (From CMOS)
+       outb(0x70, 0x10);
+       data = inb(0x71);
+       gFDD_Devices[0].type = data >> 4;
+       gFDD_Devices[1].type = data & 0xF;
+       gFDD_Devices[0].track[0] = -1;
+       gFDD_Devices[1].track[1] = -1;
+       
+       Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);
+       
+       if( data == 0 ) {
+               return MODULE_ERR_NOTNEEDED;
+       }
+       
+       // Handle arguments
+       if(args) {
+               for(;*args;args++)
+               {
+                       if(strcmp(*args, "disable")==0)
+                               return MODULE_ERR_NOTNEEDED;
+               }
+       }
+       
+       // Install IRQ6 Handler
+       IRQ_AddHandler(6, FDD_IRQHandler, NULL);
+
+       // Ensure the FDD version is 0x90
+       {
+               Uint8   tmp = 0;
+               FDD_int_SendByte(cPORTBASE[0], CMD_VERSION);
+               FDD_int_GetByte(cPORTBASE[0], &tmp);
+               if( tmp != 0x90 ) {
+                       Log_Error("FDD", "Version(0x%2x) != 0x90", tmp);
+                       return MODULE_ERR_NOTNEEDED;
+               }
+       }
+
+       // Configure
+       FDD_Reconfigure(0);
+
+       // Reset Primary FDD Controller
+       if( FDD_Reset(0) != 0 ) {
+               return MODULE_ERR_MISC;
+       }
+
+       #if 0
+       {
+                int    retries;
+               // Recalibrate disks
+               LOG("Recalibrate disks (16x seek)");
+               retries = 16;
+               while(FDD_int_SeekTrack(0, 0, 1) == 0 && retries --)
+                       Threads_Yield();        // set track
+               if(retries < 0) LEAVE_RET('i', -1);
+       
+               retries = 16;
+               while(FDD_int_SeekTrack(0, 1, 1) == 0 && retries --)
+                       Threads_Yield();        // set track
+               if(retries < 0) LEAVE_RET('i', -1);
+       }
+       #endif
+       
+       
+       // Initialise Root Node
+       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
+               = gFDD_DriverInfo.RootNode.ATime = now();
+       
+       // Initialise Child Nodes
+       gFDD_Devices[0].Node.Inode = 0;
+       gFDD_Devices[0].Node.Flags = 0;
+       gFDD_Devices[0].Node.NumACLs = 0;
+       gFDD_Devices[0].Node.Read = FDD_ReadFS;
+       gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS;
+       memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));
+       
+       gFDD_Devices[1].Node.Inode = 1;
+       
+       // Set Lengths
+       gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];
+       gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];
+       
+       // Create Sector Cache
+       if( cFDD_SIZES[data >> 4] )
+       {
+               gFDD_Devices[0].CacheHandle = IOCache_Create(
+                       FDD_WriteSector, 0, 512,
+                       gFDD_Devices[0].Node.Size / (512*4)
+                       );      // Cache is 1/4 the size of the disk
+       }
+       if( cFDD_SIZES[data & 15] )
+       {
+               gFDD_Devices[1].CacheHandle = IOCache_Create(
+                       FDD_WriteSector, 0, 512,
+                       gFDD_Devices[1].Node.Size / (512*4)
+                       );      // Cache is 1/4 the size of the disk
+       }
+       
+       // Register with devfs
+       DevFS_AddDevice(&gFDD_DriverInfo);
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Prepare the module for removal
+ */
+void FDD_UnloadModule()
+{
+        int    i;
+       DevFS_DelDevice( &gFDD_DriverInfo );
+       Mutex_Acquire(&glFDD);
+       for(i=0;i<4;i++) {
+               Time_RemoveTimer(gFDD_Devices[i].timer);
+               FDD_int_StopMotor(i);
+       }
+       Mutex_Release(&glFDD);
+       //IRQ_Clear(6);
+}
+
+/**
+ * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)
+ * \brief Read Directory
+ */
+char *FDD_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
+{
+       char    name[2] = "0\0";
+
+       if(Pos >= 2 || Pos < 0) return NULL;
+       
+       if(gFDD_Devices[Pos].type == 0) return VFS_SKIP;
+       
+       name[0] += Pos;
+       
+       return strdup(name);
+}
+
+/**
+ * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *filename);
+ * \brief Find File Routine (for vfs_node)
+ */
+tVFS_Node *FDD_FindDir(tVFS_Node *UNUSED(Node), const char *Filename)
+{
+        int    i;
+       
+       ENTER("sFilename", Filename);
+       
+       // Sanity check string
+       if(Filename == NULL) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Check string length (should be 1)
+       if(Filename[0] == '\0' || Filename[1] != '\0') {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // Get First character
+       i = Filename[0] - '0';
+       
+       // Check for 1st disk and if it is present return
+       if(i == 0 && gFDD_Devices[0].type != 0) {
+               LEAVE('p', &gFDD_Devices[0].Node);
+               return &gFDD_Devices[0].Node;
+       }
+       
+       // Check for 2nd disk and if it is present return
+       if(i == 1 && gFDD_Devices[1].type != 0) {
+               LEAVE('p', &gFDD_Devices[1].Node);
+               return &gFDD_Devices[1].Node;
+       }
+       
+       // Else return null
+       LEAVE('n');
+       return NULL;
+}
+
+static const char      *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
+/**
+ * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data)
+ * \brief Stub ioctl function
+ */
+int FDD_IOCtl(tVFS_Node *UNUSED(Node), int ID, void *Data)
+{
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_DISK, "FDD", FDD_VERSION, casIOCTLS);
+       
+       case DISK_IOCTL_GETBLOCKSIZE:   return 512;     
+       
+       default:
+               return 0;
+       }
+}
+
+/**
+ * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read Data from a disk
+*/
+Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    ret;
+       
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       
+       if(Node == NULL) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       if(Node->Inode != 0 && Node->Inode != 1) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode);
+       LEAVE('i', ret);
+       return ret;
+}
+
+/**
+ * \brief Reads \a Count contiguous sectors from a disk
+ * \param SectorAddr   Address of the first sector
+ * \param Count        Number of sectors to read
+ * \param Buffer       Destination Buffer
+ * \param Disk Disk Number
+ * \return Number of sectors read
+ * \note Used as a ::DrvUtil_ReadBlock helper
+ */
+Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)
+{
+       Uint    ret = 0;
+       while(Count --)
+       {
+               if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 )
+                       return ret;
+               
+               Buffer = (void*)( (tVAddr)Buffer + 512 );
+               SectorAddr ++;
+               ret ++;
+       }
+       return ret;
+}
+
+int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)
+{
+        int    cyl, head, sec;
+        int    spt, base;
+        int    i;
+        int    lba = SectorAddr;
+       Uint8   st0=0, st1=0, st2=0, bps=0;     // Status Values
+       
+       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
+       
+       base = cPORTBASE[Disk >> 1];
+       
+       LOG("Calculating Disk Dimensions");
+       // Get CHS position
+       if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1)
+       {
+               LEAVE('i', -1);
+               return -1;
+       }
+       LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);
+
+       // Start the motor      
+       Mutex_Acquire(&glFDD);  // Lock to stop the motor stopping on us
+       Time_RemoveTimer(gFDD_Devices[Disk].timer);     // Remove Old Timer
+       // Start motor if needed
+       if(gFDD_Devices[Disk].motorState != 2)  FDD_int_StartMotor(Disk);
+       Mutex_Release(&glFDD);
+       
+       // Wait for spinup
+       LOG("Wait for the motor to spin up");
+       while(gFDD_Devices[Disk].motorState == 1)       Threads_Yield();
+       
+       LOG("Acquire Spinlock");
+       Mutex_Acquire(&glFDD);
+       
+       // Read Data from DMA
+       LOG("Setting DMA for read");
+       DMA_SetChannel(2, 512, !Write); // Read/Write 512 Bytes from channel 2
+       
+       LOG("Sending command");
+       
+       #define SENDB(__data)   if(FDD_int_SendByte(base, __data)) { FDD_Reset(Disk >> 1); continue; }
+
+       for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
+       {
+               FDD_int_SeekTrack(Disk, head, cyl);
+               if( Write ) {
+                       SENDB(CMD_WRITE_DATA|CMD_FLAG_MFM_ENCODING);
+               }
+               else {
+                       SENDB(CMD_READ_DATA|CMD_FLAG_MFM_ENCODING);
+               }
+               SENDB( (head << 2) | (Disk&1) );
+               SENDB(cyl & 0xFF);
+               SENDB(head & 0xFF);
+               SENDB(sec & 0xFF);
+               SENDB(0x02);    // Bytes Per Sector (Real BPS=128*2^{val})
+               SENDB(spt);     // SPT
+               SENDB(0x1B);    // Gap Length (27 is default)
+               SENDB(0xFF);    // Data Length
+               
+               // Wait for IRQ
+               if( Write ) {
+                       LOG("Writing Data");
+                       DMA_WriteData(2, 512, Buffer);
+                       LOG("Waiting for Data to be written");
+                       if( FDD_WaitIRQ() ) { FDD_Reset(Disk>>1); continue; }
+               }
+               else {
+                       LOG("Waiting for data to be read");
+                       if( FDD_WaitIRQ() ) { FDD_Reset(Disk>>1); continue; }
+                       LOG("Reading Data");
+                       DMA_ReadData(2, 512, Buffer);
+               }
+               
+               // Clear Input Buffer
+               LOG("Clearing Input Buffer");
+               // Status Values
+               FDD_int_GetByte(base, &st0);
+               FDD_int_GetByte(base, &st1);
+               FDD_int_GetByte(base, &st2);
+               
+               // Cylinder, Head and Sector (mutilated in some way)
+               FDD_int_GetByte(base, NULL);    // Cylinder
+               FDD_int_GetByte(base, NULL);    // Head
+               FDD_int_GetByte(base, NULL);    // Sector
+               // Should be the BPS set above (0x02)
+               FDD_int_GetByte(base, &bps);
+               
+               // Check Status
+               // - Error Code
+               if(st0 & 0xC0) {
+                       LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);
+                       continue;
+               }
+               // - Status Flags
+               if(st0 & 0x08) {        LOG("Drive not ready"); continue;       }
+               if(st1 & 0x80) {        LOG("End of Cylinder"); continue;       }
+               if(st1 & 0x20) {        LOG("CRC Error");       continue;       }
+               if(st1 & 0x10) {        LOG("Controller Timeout");      continue;       }
+               if(st1 & 0x04) {        LOG("No Data Found");   continue;       }
+               if(st1 & 0x01 || st2 & 0x01) {
+                       LOG("No Address mark found");
+                       continue;
+               }
+               if(st2 & 0x40) {        LOG("Deleted address mark");    continue;       }
+               if(st2 & 0x20) {        LOG("CRC error in data");       continue;       }
+               if(st2 & 0x10) {        LOG("Wrong Cylinder");  continue;       }
+               if(st2 & 0x04) {        LOG("uPD765 sector not found"); continue;       }
+               if(st2 & 0x02) {        LOG("Bad Cylinder");    continue;       }
+               
+               if(bps != 0x2) {
+                       LOG("Returned BPS = 0x%02x, not 0x02", bps);
+                       continue;
+               }
+               
+               if(st1 & 0x02) {
+                       LOG("Floppy not writable");
+                       // Return error without triggering the attempt count check
+                       i = FDD_MAX_READWRITE_ATTEMPTS+1;
+                       break;
+               }
+               
+               // Success!
+               break;
+       }
+       #undef SENDB
+       
+       // Release Spinlock
+       LOG("Realeasing Spinlock and setting motor to stop");
+       Mutex_Release(&glFDD);
+       
+       if(i == FDD_MAX_READWRITE_ATTEMPTS) {
+               Log_Warning("FDD", "Exceeded %i attempts in %s the disk",
+                       FDD_MAX_READWRITE_ATTEMPTS,
+                       (Write ? "writing to" : "reading from")
+                       );
+       }
+       
+       // Don't turn the motor off now, wait for a while
+       FDD_int_StopMotor(Disk);
+
+       // Error check
+       if( i < FDD_MAX_READWRITE_ATTEMPTS ) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       else {
+               LEAVE('i', 1);
+               return 1;
+       }
+}
+
+/**
+ * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
+ * \brief Read a sector from disk
+ * \todo Make real-hardware safe (account for read errors)
+ */
+int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
+{
+        int    ret;
+       
+       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
+       
+       if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       // Pass to general function
+       ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer);
+
+       if( ret == 0 ) {
+               IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );
+               LEAVE('i', 1);
+               return 1;
+       }
+       else {
+               LOG("Reading failed");
+               LEAVE('i', 0);
+               return 0;
+       }
+}
+
+/**
+ * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
+ * \brief Write a sector to the floppy disk
+ * \note Not Implemented
+ */
+int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
+{
+       Log_Warning("FDD", "Read Only at the moment");
+       return -1;
+}
+
+/**
+ * \brief Seek disk to selected track
+ */
+int FDD_int_SeekTrack(int disk, int head, int track)
+{
+       Uint8   sr0=0, cyl=0;
+        int    base, i, bUnclean;
+       
+       base = cPORTBASE[disk>>1];
+       
+       // Check if seeking is needed
+       if(gFDD_Devices[disk].track[head] == track)
+               return 1;
+       
+       // - Seek Head 0
+       for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
+       {
+               if(i && bUnclean)       FDD_Reset(disk >> 1);
+               bUnclean = 1;
+               if(FDD_int_SendByte(base, CMD_SEEK_TRACK))      continue;
+               if(FDD_int_SendByte(base, (head<<2)|(disk&1)))  continue;
+               if(FDD_int_SendByte(base, track))       continue;
+               FDD_WaitIRQ();
+               FDD_SenseInt(base, &sr0, &cyl); // Wait for IRQ
+
+               bUnclean = 0;
+               if( cyl != track )
+                       continue;       // Try again
+               if( (sr0 & 0xF0) != 0x20 ) {
+                       LOG("sr0 = 0x%x", sr0);
+                       continue ;
+               }
+       
+               break;
+       }
+
+       if( i == FDD_MAX_READWRITE_ATTEMPTS ) {
+               Log_Warning("FDD", "Unable to seek to track %i on disk %i",
+                       track, disk);
+               return 0;
+       }       
+
+       // Set Track in structure
+       gFDD_Devices[disk].track[head] = track;
+
+       LOG("Time_Delay(100)"); 
+       // Wait for Head to settle
+       Time_Delay(100);
+       
+       return 1;
+}
+
+/**
+ * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
+ * \brief Get Dimensions of a disk
+ */
+int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
+{
+       switch(type) {
+       case 0:
+               return 0;
+       
+       // 360Kb 5.25"
+       case 1:
+               *spt = 9;
+               *s = (lba % 9) + 1;
+               *c = lba / 18;
+               *h = (lba / 9) & 1;
+               break;
+       
+       // 1220Kb 5.25"
+       case 2:
+               *spt = 15;
+               *s = (lba % 15) + 1;
+               *c = lba / 30;
+               *h = (lba / 15) & 1;
+               break;
+       
+       // 720Kb 3.5"
+       case 3:
+               *spt = 9;
+               *s = (lba % 9) + 1;
+               *c = lba / 18;
+               *h = (lba / 9) & 1;
+               break;
+       
+       // 1440Kb 3.5"
+       case 4:
+               *spt = 18;
+               *s = (lba % 18) + 1;
+               *c = lba / 36;
+               *h = (lba / 18) & 1;
+               //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);
+               break;
+               
+       // 2880Kb 3.5"
+       case 5:
+               *spt = 36;
+               *s = (lba % 36) + 1;
+               *c = lba / 72;
+               *h = (lba / 32) & 1;
+               break;
+               
+       default:
+               return -2;
+       }
+       return 1;
+}
+
+/**
+ * \fn void FDD_IRQHandler(int Num)
+ * \brief Handles IRQ6
+ */
+void FDD_IRQHandler(int Num, void *Ptr)
+{
+       gbFDD_IrqFired = 1;
+}
+
+/**
+ * \brief Wait for the FDD IRQ to fire
+ * \return Boolean failure (1 for timeout)
+ */
+inline int FDD_WaitIRQ()
+{
+       tTime   end = now() + 2000;
+       
+       // Wait for IRQ
+       while(!gbFDD_IrqFired && now() < end)
+               Threads_Yield();
+
+       if( !gbFDD_IrqFired ) {
+               Log_Warning("FDD", "FDD_WaitIRQ - Timeout");
+               return 1;
+       }       
+
+       gbFDD_IrqFired = 0;
+       return 0;
+}
+
+void FDD_SenseInt(int base, Uint8 *sr0, Uint8 *cyl)
+{
+       FDD_int_SendByte(base, CMD_SENSE_INTERRUPT);
+       FDD_int_GetByte(base, sr0);
+       FDD_int_GetByte(base, cyl);
+}
+
+/**
+ * void FDD_int_SendByte(int base, char byte)
+ * \brief Sends a command to the controller
+ */
+int FDD_int_SendByte(int base, Uint8 byte)
+{
+       tTime   end = now() + 1000;     // 1s
+       
+       while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
+               Threads_Yield();        //Delay
+//             Time_Delay(10); //Delay
+
+       if( inb(base + PORT_MAINSTATUS) & 0x40 ) {
+               Log_Warning("FDD", "FDD_int_SendByte: DIO set, is this ok?");
+               return -2;
+       }
+       
+       if( now() > end )
+       {
+               Log_Warning("FDD", "FDD_int_SendByte: Timeout sending byte 0x%x to base 0x%x", byte, base);
+               return 1;
+       }
+       outb(base + PORT_DATA, byte);
+//     Log_Debug("FDD", "FDD_int_SendByte: Sent 0x%02x to 0x%x", byte, base);
+       return 0;
+}
+
+/**
+ * int FDD_int_GetByte(int base, char byte)
+ * \brief Receive data from fdd controller
+ */
+int FDD_int_GetByte(int base, Uint8 *value)
+{
+       tTime   end = now() + 1000;     // 1s
+       
+       while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
+               Time_Delay(10);
+       
+       if( !(inb(base + PORT_MAINSTATUS) & 0x40) ) {
+               Log_Warning("FDD", "FDD_int_GetByte: DIO unset, is this ok?");
+               return -2;
+       }
+
+       if( now() > end )
+       {
+               Log_Warning("FDD", "FDD_int_GetByte: Timeout reading byte from base 0x%x", base);
+               return -1;
+       }
+       
+       if(value)
+               *value = inb(base + PORT_DATA);
+       else
+               inb(base + PORT_DATA);
+       return 0;
+}
+
+/**
+ * \brief Recalibrate the specified disk
+ */
+void FDD_Recalibrate(int disk)
+{
+       ENTER("idisk", disk);
+       
+       LOG("Starting Motor");
+       FDD_int_StartMotor(disk);
+       // Wait for Spinup
+       while(gFDD_Devices[disk].motorState <= 1)       Threads_Yield();
+       
+       LOG("Sending Calibrate Command");
+       FDD_int_SendByte(cPORTBASE[disk>>1], CMD_RECALIBRATE);
+       FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);
+       
+       LOG("Waiting for IRQ");
+       FDD_WaitIRQ();
+       FDD_SenseInt(cPORTBASE[disk>>1], NULL, NULL);
+       
+       LOG("Stopping Motor");
+       FDD_int_StopMotor(disk);
+       LEAVE('-');
+}
+
+/**
+ * \brief Reconfigure the controller
+ */
+int FDD_Reconfigure(int ID)
+{
+       Uint16  base = cPORTBASE[ID];
+       
+       ENTER("iID", ID);
+       
+       FDD_int_SendByte(base, CMD_CONFIGURE);
+       FDD_int_SendByte(base, 0);
+       // Implied seek enabled, FIFO Enabled, Drive Polling Disabled, data buffer threshold 8 bytes
+       FDD_int_SendByte(base, (1 << 6) | (0 << 5) | (0 << 4) | 7);
+       FDD_int_SendByte(base, 0);      // Precompensation - use default
+       
+       // Commit
+       FDD_int_SendByte(base, CMD_LOCK|CMD_FLAG_MULTI_TRACK);
+       FDD_int_GetByte(base, NULL);
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \brief Reset the specified FDD controller
+ */
+int FDD_Reset(int id)
+{
+       Uint16  base = cPORTBASE[id];
+       Uint8   motor_state;
+       
+       ENTER("iID", id);
+
+       // Reset the card
+       motor_state = inb(base + PORT_DIGOUTPUT) & 0xF0;
+       outb(base + PORT_DIGOUTPUT, motor_state|0);     // Disable FDC
+       Time_Delay(1);
+       outb(base + PORT_DIGOUTPUT, motor_state|8|4);   // Re-enable FDC (DMA and Enable)
+       
+       // Set the data rate
+       outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s
+
+       // Wait for IRQ
+       LOG("Awaiting IRQ");
+       
+       FDD_WaitIRQ();
+
+       FDD_SenseInt(base, NULL, NULL);
+       
+       // Specify
+       FDD_int_SendByte(base, CMD_SPECIFY);    // Step and Head Load Times
+       FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)
+       FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1
+
+       LOG("Recalibrating Disk");
+       FDD_Recalibrate((id<<1)|0);
+       FDD_Recalibrate((id<<1)|1);
+
+       LEAVE_RET('i', 0);
+}
+
+/**
+ * \fn void FDD_int_TimerCallback()
+ * \brief Called by timer
+ */
+void FDD_int_TimerCallback(void *Arg)
+{
+        int    disk = (Uint)Arg;
+       ENTER("iarg", disk);
+       if(gFDD_Devices[disk].motorState == 1)
+               gFDD_Devices[disk].motorState = 2;
+       Time_RemoveTimer(gFDD_Devices[disk].timer);
+       gFDD_Devices[disk].timer = -1;
+       LEAVE('-');
+}
+
+/**
+ * \fn void FDD_int_StartMotor(char disk)
+ * \brief Starts FDD Motor
+ */
+void FDD_int_StartMotor(int disk)
+{
+       Uint8   state;
+       if( gFDD_Devices[disk].motorState != 0 )        return ;
+       // Set motor ON bit
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
+       state |= 1 << (4+disk);
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
+       // Mark as spinning up
+       gFDD_Devices[disk].motorState = 1;
+       // Schedule a timer for when it's up to speed
+       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)(Uint)disk);
+}
+
+/**
+ * \brief Schedule the drive motor to stop
+ * \param Disk Disk number to stop
+ */
+void FDD_int_StopMotor(int Disk)
+{
+       // Ignore if the motor is aready off
+       if( gFDD_Devices[Disk].motorState == 0 )        return ;
+       
+       // Don't double-schedule timer
+       if( gFDD_Devices[Disk].timer != -1 )
+       {
+               Time_RemoveTimer( gFDD_Devices[Disk].timer );
+       }
+       
+       gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotorCallback, (void*)(Uint)Disk);
+}
+
+/**
+ * \brief Stops FDD Motor
+ */
+void FDD_int_StopMotorCallback(void *Arg)
+{
+       Uint8   state, disk = (Uint)Arg;
+
+       // Mutex is only locked if disk is in use
+       if( Mutex_IsLocked(&glFDD) )    return ;
+
+       ENTER("iDisk", disk);
+
+       // Clear motor on bit   
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
+       state &= ~( 1 << (4+disk) );
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
+       
+       // Mark as off
+       gFDD_Devices[disk].motorState = 0;
+
+       LEAVE('-');
+}
+
diff --git a/KernelLand/Modules/Storage/FDDv2/Makefile b/KernelLand/Modules/Storage/FDDv2/Makefile
new file mode 100644 (file)
index 0000000..97aae0c
--- /dev/null
@@ -0,0 +1,8 @@
+#
+#
+
+DEPS = x86/ISADMA
+OBJ = main.o fdc.o
+NAME = FDDv2
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Storage/FDDv2/common.h b/KernelLand/Modules/Storage/FDDv2/common.h
new file mode 100644 (file)
index 0000000..4d6a4f7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Acess2 82077AA FDC
+ * - By John Hodge (thePowersGang)
+ *
+ * common.h
+ * - Common definitions
+ */
+#ifndef _FDC_COMMON_H_
+#define _FDC_COMMON_H_
+
+#include <mutex.h>
+#include <timers.h>
+
+// === CONSTANTS ===
+#define MAX_DISKS      8       // 4 per controller, 2 controllers
+#define TRACKS_PER_DISK        (1440*2/18)
+#define BYTES_PER_TRACK        (18*512)
+
+// === TYPEDEFS ===
+typedef struct sFDD_Drive      tDrive;
+
+// === STRUCTURES ===
+struct sFDD_Drive
+{
+        int    bValid;
+        int    bInserted;
+        int    MotorState;
+       tTimer  *Timer;
+
+       tMutex  Mutex;
+       
+       void    *TrackData[TRACKS_PER_DISK];    // Whole tracks are read
+};
+
+// === FUNCTIONS ===
+extern int     FDD_SetupIO(void);
+extern int     FDD_int_ReadWriteTrack(int Disk, int Track, int bWrite, void *Buffer);
+
+// === GLOBALS ===
+extern tDrive  gaFDD_Disks[MAX_DISKS];
+
+#endif
+
diff --git a/KernelLand/Modules/Storage/FDDv2/fdc.c b/KernelLand/Modules/Storage/FDDv2/fdc.c
new file mode 100644 (file)
index 0000000..e86b31c
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Acess2 82077AA FDC
+ * - By John Hodge (thePowersGang)
+ *
+ * fdc.c
+ * - FDC IO Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include "common.h"
+#include <dma.h>
+#include <timers.h>
+
+// === CONSTANTS ===
+#define MOTOR_ON_DELAY 500
+#define MOTOR_OFF_DELAY        2000
+
+enum eMotorState
+{
+       MOTOR_OFF,
+       MOTOR_ATSPEED,
+};
+
+enum eFDC_Registers
+{
+       FDC_DOR  = 0x02,        // Digital Output Register
+       FDC_MSR  = 0x04,        // Master Status Register (Read Only)
+       FDC_FIFO = 0x05,        // FIFO port
+       FDC_CCR  = 0x07         // Configuration Control Register (write only)
+};
+
+enum eFDC_Commands
+{
+       CMD_SPECIFY = 3,            // Specify parameters
+       CMD_WRITE_DATA = 5,         // Write Data
+       CMD_READ_DATA = 6,          // Read Data
+       CMD_RECALIBRATE = 7,        // Recalibrate a drive
+       CMD_SENSE_INTERRUPT = 8,    // Sense (Ack) an interrupt
+       CMD_SEEK = 15,              // Seek to a track
+};
+
+// === PROTOTYPES ===
+ int   FDD_SetupIO(void);
+ int   FDD_int_ReadWriteTrack(int Disk, int Track, int bWrite, void *Buffer);
+ int   FDD_int_SeekToTrack(int Disk, int Track);
+ int   FDD_int_Calibrate(int Disk);
+ int   FDD_int_Reset(int Disk);
+// --- FIFO
+ int   FDD_int_WriteData(Uint16 Base, Uint8 Data);
+ int   FDD_int_ReadData(Uint16 Base, Uint8 *Data);
+void   FDD_int_SenseInterrupt(Uint16 Base, Uint8 *ST0, Uint8 *Cyl);
+// --- Motor Control
+ int   FDD_int_StartMotor(int Disk);
+ int   FDD_int_StopMotor(int Disk);
+void   FDD_int_StopMotorCallback(void *Ptr);
+// --- Helpers
+ int   FDD_int_HandleST0Error(const char *Fcn, int Disk, Uint8 ST0);
+Uint16 FDD_int_GetBase(int Disk, int *Drive);
+// --- Interrupt
+void   FDD_int_ClearIRQ(void);
+ int   FDD_int_WaitIRQ(void);
+void   FDD_int_IRQHandler(int IRQ, void *Ptr);
+
+// === GLOBALS ===
+/**
+ * \brief Marker for IRQ6
+ * \todo Convert into a semaphore?
+ */
+ int   gbFDD_IRQ6Fired;
+/**
+ * \brief Protector for DMA and IRQ6
+ */
+tMutex gFDD_IOMutex;
+
+// === CODE ===
+/**
+ * \brief Set up FDC IO
+ * \return Boolean failure
+ *
+ * Registers the IRQ handler and resets the controller
+ */
+int FDD_SetupIO(void)
+{
+       // Install IRQ6 Handler
+       IRQ_AddHandler(6, FDD_int_IRQHandler, NULL);
+       
+       // Reset controller
+       FDD_int_Reset(0);
+       // TODO: All controllers
+       
+       return 0;
+}
+
+/**
+ * \brief Read/Write data from/to a disk
+ * \param Disk Global disk number
+ * \param Track Track number (Cyl*2+Head)
+ * \param bWrite Toggle write mode
+ * \param Buffer Destination/Source buffer
+ * \return Boolean failure
+ */
+int FDD_int_ReadWriteTrack(int Disk, int Track, int bWrite, void *Buffer)
+{
+       Uint8   cmd;
+        int    i, _disk;
+       Uint16  base = FDD_int_GetBase(Disk, &_disk);
+        int    cyl = Track >> 1, head = Track & 1;
+
+       ENTER("iDisk iTrack ibWrite pBuffer", Disk, Track, bWrite, Buffer);
+
+       Mutex_Acquire( &gFDD_IOMutex );
+       
+       // Initialise DMA for read/write
+       // TODO: Support non 1.44MiB FDs
+       DMA_SetChannel(2, BYTES_PER_TRACK, !bWrite);
+       
+       // Select command
+       if( bWrite )
+               cmd = CMD_WRITE_DATA | 0xC0;
+       else
+               cmd = CMD_READ_DATA | 0xC0;
+
+       LOG("cmd = 0x%x", cmd);
+       
+       // Seek
+       if( FDD_int_SeekToTrack(Disk, Track) ) {
+               Mutex_Release( &gFDD_IOMutex );
+               LEAVE('i', -1);
+               return -1;
+       }
+       LOG("Track seek done");
+
+       for( i = 0; i < 20; i ++ )
+       {
+               LOG("Starting motor");
+               FDD_int_StartMotor(Disk);
+
+               // Write data
+               if( bWrite )
+                       DMA_WriteData(2, BYTES_PER_TRACK, Buffer);      
+       
+               LOG("Sending command stream");
+               FDD_int_WriteData(base, cmd);
+               FDD_int_WriteData(base, (head << 2) | _disk);
+               FDD_int_WriteData(base, cyl);
+               FDD_int_WriteData(base, head);
+               FDD_int_WriteData(base, 1);     // First Sector
+               FDD_int_WriteData(base, 2);     // Bytes per sector (128*2^n)
+               FDD_int_WriteData(base, 18);    // 18 tracks (full disk) - TODO: Non 1.44
+               FDD_int_WriteData(base, 0x1B);  // Gap length - TODO: again
+               FDD_int_WriteData(base, 0xFF);  // Data length - ?
+       
+               LOG("Waiting for IRQ");
+               FDD_int_WaitIRQ();
+       
+               // No Sense Interrupt
+               
+               LOG("Reading result");
+               Uint8   st0=0, st1=0, st2=0, bps=0;
+               FDD_int_ReadData(base, &st0);
+               FDD_int_ReadData(base, &st1);   // st1
+               FDD_int_ReadData(base, &st2);   // st2
+               FDD_int_ReadData(base, NULL);   // rcy - Mutilated Cyl
+               FDD_int_ReadData(base, NULL);   // rhe - Mutilated Head
+               FDD_int_ReadData(base, NULL);   // rse - Mutilated sector
+               FDD_int_ReadData(base, &bps);   // bps - Should be the same as above
+
+               if( st0 & 0xc0 ) {
+                       FDD_int_HandleST0Error(__func__, Disk, st0);
+                       continue ;
+               }
+       
+               if( st2 & 0x02 ) {
+                       Log_Debug("FDD", "Disk %i is not writable", Disk);
+                       Mutex_Release( &gFDD_IOMutex );
+                       LEAVE('i', 2);
+                       return 2;
+               }
+               
+               if( st0 & 0x08 ) {
+                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: Drive not ready");
+                       continue ;
+               }
+
+
+               if( st1 & 0x80 ) {
+                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: End of cylinder");
+                       continue ;
+               }
+
+               if( st1 & (0x20|0x10|0x04|0x01) ) {
+                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: st1 = 0x%x", st1);
+                       continue;
+               }
+               
+               if( st2 & (0x40|0x20|0x10|0x04|0x01) ) {
+                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: st2 = 0x%x", st2);
+                       continue ;
+               }
+               
+               if( bps != 0x2 ) {
+                       Log_Debug("FDD", "Wanted bps = 2 (512), got %i", bps);
+                       continue ;
+               }
+
+               // Read back data
+               if( !bWrite )
+                       DMA_ReadData(2, BYTES_PER_TRACK, Buffer);
+               
+               LOG("All data done");
+               FDD_int_StopMotor(Disk);
+               Mutex_Release( &gFDD_IOMutex );
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       Log_Debug("FDD", "%i retries exhausted", i);
+       FDD_int_StopMotor(Disk);
+       Mutex_Release( &gFDD_IOMutex );
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \brief Seek to a specific track
+ * \param Disk Global disk number
+ * \param Track Track number (Cyl*2+Head)
+ * \return Boolean failure
+ */
+int FDD_int_SeekToTrack(int Disk, int Track)
+{
+       Uint8   st0=0, res_cyl=0;
+        int    cyl, head;
+        int    _disk;
+       Uint16  base = FDD_int_GetBase(Disk, &_disk);;
+
+       ENTER("iDisk iTrack", Disk, Track);
+       
+       cyl = Track / 2;
+       head = Track % 2;
+
+       LOG("cyl = %i, head = %i", cyl, head);
+       
+       FDD_int_StartMotor(Disk);
+       
+       for( int i = 0; i < 10; i ++ )
+       {
+               LOG("Sending command");
+               FDD_int_ClearIRQ();
+               FDD_int_WriteData(base, CMD_SEEK);
+               FDD_int_WriteData(base, (head << 2) + _disk);
+               FDD_int_WriteData(base, cyl);
+       
+               LOG("Waiting for IRQ");
+               FDD_int_WaitIRQ();
+               FDD_int_SenseInterrupt(base, &st0, &res_cyl);
+       
+               if( st0 & 0xC0 )
+               {
+                       FDD_int_HandleST0Error(__func__, Disk, st0);
+                       continue ;
+               }
+               
+               if( res_cyl == cyl ) {
+                       FDD_int_StopMotor(Disk);
+                       LEAVE('i', 0);
+                       return 0;
+               }
+       }
+       
+       Log_Error("FDD", "FDD_int_SeekToTrack: 10 retries exhausted\n");
+       FDD_int_StopMotor(Disk);
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \brief Calibrate a drive
+ * \param Disk Global disk number
+ */
+int FDD_int_Calibrate(int Disk)
+{
+        int    _disk;
+       Uint16  base = FDD_int_GetBase(Disk, &_disk);
+       FDD_int_StartMotor(Disk);
+       
+       for( int i = 0; i < 10; i ++ )
+       {
+               Uint8   st0=0, cyl = -1;
+       
+               FDD_int_ClearIRQ();     
+               FDD_int_WriteData(base, CMD_RECALIBRATE);
+               FDD_int_WriteData(base, _disk);
+               
+               FDD_int_WaitIRQ();
+       
+               FDD_int_SenseInterrupt(base, &st0, &cyl);
+               
+               if( st0 & 0xC0 ) {
+                       FDD_int_HandleST0Error(__func__, Disk, st0);
+                       continue ;
+               }
+               
+               if( cyl == 0 )
+               {
+                       FDD_int_StopMotor(Disk);
+                       return 0;
+               }
+       }
+       
+       Log_Error("FDD", "FDD_int_Calibrate: Retries exhausted");
+       
+       return 1;
+}
+
+/**
+ * \brief Reset a controller
+ * \param Base Controller base address
+ */
+int FDD_int_Reset(int Disk)
+{
+       Uint8   tmp;
+        int    _disk;
+       Uint16  base = FDD_int_GetBase(Disk, &_disk);
+
+       tmp = inb(base + FDC_DOR) & 0xF0;
+       outb( base + FDC_DOR, 0x00 );
+       Time_Delay(1);
+       outb( base + FDC_DOR, tmp | 0x0C );
+
+       FDD_int_SenseInterrupt(base, NULL, NULL);
+
+       outb(base + FDC_CCR, 0x00);     // 500KB/s
+
+       FDD_int_WriteData(base, CMD_SPECIFY);   // Step and Head Load Times
+       FDD_int_WriteData(base, 0xDF);  // Step Rate Time, Head Unload Time (Nibble each)
+       FDD_int_WriteData(base, 0x02);  // Head Load Time >> 1
+
+       // TODO: Recalibrate all present disks
+       FDD_int_Calibrate(Disk);
+       return 0;
+}
+
+/**
+ * \brief Write a byte to the FIFO
+ */
+int FDD_int_WriteData(Uint16 Base, Uint8 Data)
+{
+       for( int i = 0; i < 100; i ++ )
+       {
+               if( inb(Base + FDC_MSR) & 0x80 )
+               {
+                       outb(Base + FDC_FIFO, Data);
+                       return 0;
+               }
+               Time_Delay(10);
+       }
+       Log_Error("FDD", "Write timeout");
+       return 1;
+}
+
+/**
+ * \brief Read a byte from the FIFO
+ */
+int FDD_int_ReadData(Uint16 Base, Uint8 *Data)
+{
+       for( int i = 0; i < 100; i ++ )
+       {
+               if( inb(Base + FDC_MSR) & 0x80 )
+               {
+                       Uint8 tmp = inb(Base + FDC_FIFO);
+                       if(Data) *Data = tmp;
+                       return 0;
+               }
+               Time_Delay(10);
+       }
+       Log_Error("FDD", "Read timeout");
+       return 1;
+}
+
+/**
+ * \brief Acknowledge an interrupt
+ * \param Base Controller base address
+ * \param ST0  Location to store the ST0 value
+ * \param Cyl  Current cylinder
+ */
+void FDD_int_SenseInterrupt(Uint16 Base, Uint8 *ST0, Uint8 *Cyl)
+{
+       FDD_int_WriteData(Base, CMD_SENSE_INTERRUPT);
+       FDD_int_ReadData(Base, ST0);
+       FDD_int_ReadData(Base, Cyl);
+}
+
+/**
+ * \brief Start the motor on a disk
+ */
+int FDD_int_StartMotor(int Disk)
+{
+        int    _disk;
+       Uint16  base = FDD_int_GetBase(Disk, &_disk);
+       
+       // Clear the motor off timer    
+       Time_RemoveTimer(gaFDD_Disks[Disk].Timer);
+       gaFDD_Disks[Disk].Timer = NULL;
+
+       // Check if the motor is already on
+       if( gaFDD_Disks[Disk].MotorState == MOTOR_ATSPEED )
+               return 0;
+
+       // Turn motor on
+       outb(base + FDC_DOR, inb(base+FDC_DOR) | (1 << (_disk + 4)));
+
+       // Wait for it to reach speed
+       Time_Delay(MOTOR_ON_DELAY);
+
+       gaFDD_Disks[Disk].MotorState = MOTOR_ATSPEED;
+
+       return 0;
+}
+
+/**
+ * \brief Schedule the motor to stop
+ */
+int FDD_int_StopMotor(int Disk)
+{
+       if( gaFDD_Disks[Disk].MotorState != MOTOR_ATSPEED )
+               return 0;
+       if( gaFDD_Disks[Disk].Timer != NULL )
+               return 0;
+
+       gaFDD_Disks[Disk].Timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotorCallback, (void*)(tVAddr)Disk);
+
+       return 0;
+}
+
+/**
+ * \brief Actually stop the motor
+ * \param Ptr  Actaully the global disk number
+ */
+void FDD_int_StopMotorCallback(void *Ptr)
+{
+        int    Disk = (tVAddr)Ptr;
+        int    _disk;
+       Uint16  base = FDD_int_GetBase(Disk, &_disk);
+
+       gaFDD_Disks[Disk].Timer = NULL;
+       gaFDD_Disks[Disk].MotorState = MOTOR_OFF;
+       
+       outb(base + FDC_DOR, inb(base+FDC_DOR) & ~(1 << (_disk + 4)));
+
+       return ;
+}
+
+/**
+ * \brief Converts a global disk number into a controller and drive
+ * \param Disk Global disk number
+ * \param Drive        Destination for controller disk number
+ * \return Controller base address
+ */
+Uint16 FDD_int_GetBase(int Disk, int *Drive)
+{
+       if(Drive)       *Drive = Disk & 3;
+       switch(Disk >> 2)
+       {
+       case 0: return 0x3F0;
+       case 1: return 0x370;
+       default:
+               return 0;
+       }
+}
+
+/**
+ * \brief Convert a ST0 error value into a message
+ * \param Fcn  Calling function name
+ * \parma Disk Global disk number
+ * \param ST0  ST0 Value
+ * \return Boolean failure
+ */
+int FDD_int_HandleST0Error(const char *Fcn, int Disk, Uint8 ST0)
+{
+       static const char *status_type[] = {
+               0, "Error", "Invalid", "Drive Error"
+       };
+
+       Log_Debug("FDD", "%s: Disk %i ST0 Status = %s (0x%x & 0xC0 = 0x%x)",
+               Fcn, Disk, status_type[ST0 >> 6], ST0, ST0 & 0xC0
+               );
+       return 0;
+}
+
+/**
+ * \brief Clear the IRQ fired flag
+ */
+void FDD_int_ClearIRQ(void)
+{
+       gbFDD_IRQ6Fired = 0;
+}
+
+/**
+ * \brief Wait for an IRQ to fire
+ */
+int FDD_int_WaitIRQ(void)
+{
+       while(gbFDD_IRQ6Fired == 0)
+               Threads_Yield();
+       return 0;
+}
+
+/**
+ * \brief IRQ Handler
+ * \param IRQ  IRQ Number (unused)
+ * \param Ptr  Data Pointer (unused)
+ */
+void FDD_int_IRQHandler(int IRQ, void *Ptr)
+{
+       gbFDD_IRQ6Fired = 1;
+}
+
diff --git a/KernelLand/Modules/Storage/FDDv2/main.c b/KernelLand/Modules/Storage/FDDv2/main.c
new file mode 100644 (file)
index 0000000..bec157c
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Acess2 82077AA FDC
+ * - By John Hodge (thePowersGang)
+ *
+ * fdc.c
+ * - Core file
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include "common.h"
+#include <api_drv_disk.h>
+
+// === CONSTANTS ===
+#define FDD_VERSION    VER2(1,10)
+
+// === STRUCTURES ===
+
+// === PROTOTYPES ===
+ int   FDD_Install(char **Arguments);
+ int   FDD_RegisterFS(void);
+// --- VFS
+char   *FDD_ReadDir(tVFS_Node *Node, int pos);
+tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
+ int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
+// --- Helpers
+ int   FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, FDD_VERSION, Storage_FDDv2, FDD_Install, NULL, "x86_ISADMA", NULL);
+tDrive gaFDD_Disks[MAX_DISKS];
+tVFS_Node      gaFDD_DiskNodes[MAX_DISKS];
+tVFS_NodeType  gFDD_RootNodeType = {
+       .TypeName = "FDD Root Node",
+       .ReadDir = FDD_ReadDir,
+       .FindDir = FDD_FindDir,
+       .IOCtl = FDD_IOCtl
+       };
+tVFS_NodeType  gFDD_DevNodeType = {
+       .TypeName = "FDD Device",
+       .Read = FDD_ReadFS,
+       .Write = NULL   // FDD_WriteFS?
+       };
+tDevFS_Driver  gFDD_DriverInfo = {
+       NULL, "fdd",
+       {
+       .Size = -1,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRX,
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Type = &gFDD_RootNodeType
+       }
+       };
+
+// === CODE ===
+int FDD_Install(char **Arguments)
+{
+       // Query CMOS memory
+       {
+               Uint8   data;
+               outb(0x70, 0x10);
+               data = inb(0x71);
+               
+               // NOTE: CMOS only reports 2 disks
+               if( (data & 0xF0) == 0x40 )
+                       gaFDD_Disks[0].bValid = gaFDD_Disks[0].bInserted = 1;
+               if( (data & 0x0F) == 0x04 )
+                       gaFDD_Disks[1].bValid = gaFDD_Disks[1].bInserted = 1;
+               
+               if( gaFDD_Disks[0].bValid == 0 && gaFDD_Disks[1].bValid == 0 )
+                       return MODULE_ERR_NOTNEEDED;
+       }
+       
+       // Initialise controller
+       FDD_SetupIO();
+
+       FDD_RegisterFS();
+
+       return 0;
+}
+
+/**
+ * \brief Register the FDD driver with DevFS
+ */
+int FDD_RegisterFS(void)
+{
+       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
+               = gFDD_DriverInfo.RootNode.ATime = now();
+
+       for( int i = 0; i < MAX_DISKS; i ++ )
+       {
+               if( !gaFDD_Disks[i].bValid )    continue ;
+       
+               // Initialise Child Nodes
+               gaFDD_DiskNodes[i].Inode = i;
+               gaFDD_DiskNodes[i].Flags = 0;
+               gaFDD_DiskNodes[i].NumACLs = 0;
+               gaFDD_DiskNodes[i].Type = &gFDD_DevNodeType;
+               gaFDD_DiskNodes[i].Size = 1440*1024;    // TODO: Non 1.44 disks
+       }
+       
+       DevFS_AddDevice( &gFDD_DriverInfo );
+       return 0;
+}
+
+/**
+ * \brief Get the name of the \a Pos th item in the driver root
+ * \param Node Root node (unused)
+ * \param Pos  Position
+ * \return Heap string of node name
+ */
+char *FDD_ReadDir(tVFS_Node *Node, int Pos)
+{
+       char    ret_tpl[2];
+       if(Pos < 0 || Pos > MAX_DISKS )
+               return NULL;
+       if(gaFDD_Disks[Pos].bValid)
+               return VFS_SKIP;
+       
+       ret_tpl[0] = '0' + Pos;
+       ret_tpl[1] = '\0';
+       return strdup(ret_tpl);
+}
+
+/**
+ * \brief Get a node by name
+ * \param Node Root node (unused)
+ * \param Name Drive name
+ * \return Pointer to node structure
+ */
+tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *Name)
+{
+        int    pos;
+       if( '0' > Name[0] || Name[0] > '9' )    return NULL;
+       if( Name[1] != '\0' )   return NULL;
+       
+       pos = Name[0] - '0';
+       
+       return &gaFDD_DiskNodes[pos];
+}
+
+static const char      *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
+/**
+ * \brief Driver root IOCtl Handler
+ * \param Node Root node (unused)
+ * \param ID   IOCtl ID
+ * \param Data IOCtl specific data pointer
+ */
+int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+       switch(ID)
+       {
+       BASE_IOCTLS(DRV_TYPE_DISK, "FDDv2", FDD_VERSION, casIOCTLS);
+       
+       case DISK_IOCTL_GETBLOCKSIZE:   return 512;
+       
+       default:
+               return -1;
+       }
+}
+
+/**
+ * \brief Read from a disk
+ * \param Node Disk node
+ * \param Offset       Byte offset in disk
+ * \param Length       Number of bytes to read
+ * \param Buffer       Destination buffer
+ * \return Number of bytes read
+ */
+Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    disk = Node->Inode;
+        int    track;
+        int    rem_len;
+       char    *dest = Buffer;
+
+       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+       if( Offset > Node->Size )       LEAVE_RET('i', 0);
+       if( Length > Node->Size )       Length = Node->Size;
+       if( Offset + Length > Node->Size )
+               Length = Node->Size - Offset;
+       if( Length == 0 )       return 0;
+
+       rem_len = Length;
+
+       track = Offset / BYTES_PER_TRACK;
+       Offset %= BYTES_PER_TRACK;      
+
+       if( Offset )
+       {
+                int    len;
+               if(rem_len > BYTES_PER_TRACK - Offset)
+                       len = BYTES_PER_TRACK - Offset;
+               else
+                       len = rem_len;
+               FDD_int_ReadWriteWithinTrack(disk, track, 0, Offset, len, dest);
+               dest += len;
+               rem_len -= len;
+               track ++;
+       }
+
+       if( rem_len > 0)
+       {
+               while( rem_len > BYTES_PER_TRACK )
+               {
+                       FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, BYTES_PER_TRACK, dest);
+                       dest += BYTES_PER_TRACK;
+                               rem_len -= BYTES_PER_TRACK;
+                       track ++;
+               }
+
+               FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, rem_len, dest);
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
+
+/**
+ * \brief Read from a track
+ */
+int FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer)
+{
+       if( Offset > BYTES_PER_TRACK || Length > BYTES_PER_TRACK )
+               return 1;
+       if( Offset + Length > BYTES_PER_TRACK )
+               return 1;
+
+       if( Length == 0 )
+               return 0;
+       
+       ENTER("iDisk iTrack bbWrite xOffset xLength pBuffer",
+               Disk, Track, bWrite, Offset, Length, Buffer);
+       
+       Mutex_Acquire( &gaFDD_Disks[Disk].Mutex );
+
+       // If the cache doesn't exist, create it
+       if( !gaFDD_Disks[Disk].TrackData[Track] )
+       {
+               gaFDD_Disks[Disk].TrackData[Track] = malloc( BYTES_PER_TRACK );
+               // Don't bother reading if this is a whole track write
+               if( !(bWrite && Offset == 0 && Length == BYTES_PER_TRACK) )
+               {
+                       LOG("Reading track");
+                       FDD_int_ReadWriteTrack(Disk, Track, 0, gaFDD_Disks[Disk].TrackData[Track]);
+               }
+       }
+       
+       // Read/Write
+       if( bWrite )
+       {
+               // Write to cache then commit cache to disk
+               char    *dest = gaFDD_Disks[Disk].TrackData[Track];
+               LOG("Write to cache");
+               memcpy( dest + Offset, Buffer, Length );
+               FDD_int_ReadWriteTrack(Disk, Track, 1, gaFDD_Disks[Disk].TrackData[Track]);
+       }
+       else
+       {
+               // Read from cache
+               char    *src = gaFDD_Disks[Disk].TrackData[Track];
+               LOG("Read from cache");
+               memcpy(Buffer, src + Offset, Length);
+       }
+       
+       Mutex_Release( &gaFDD_Disks[Disk].Mutex );
+
+       LEAVE('i', 0);
+       return 0;
+}
diff --git a/KernelLand/Modules/Storage/LVM/Makefile b/KernelLand/Modules/Storage/LVM/Makefile
new file mode 100644 (file)
index 0000000..1f87112
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Acess2 Logical Volume Manager
+# - Handles MBR Partitions (and eventually others)
+# 
+
+OBJ = main.o mbr.o
+NAME = LVM
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/Storage/LVM/lvm.h b/KernelLand/Modules/Storage/LVM/lvm.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/KernelLand/Modules/Storage/LVM/lvm_int.h b/KernelLand/Modules/Storage/LVM/lvm_int.h
new file mode 100644 (file)
index 0000000..36f2eb2
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Acess2 Logical Volume Manager
+ * - By John Hodge (thePowersGang)
+ *
+ * lvm_int.h
+ * - Internal definitions
+ */
+
diff --git a/KernelLand/Modules/Storage/LVM/main.c b/KernelLand/Modules/Storage/LVM/main.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/KernelLand/Modules/Storage/LVM/mbr.c b/KernelLand/Modules/Storage/LVM/mbr.c
new file mode 100644 (file)
index 0000000..8cbb5b1
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Acess2 IDE Harddisk Driver
+ * - MBR Parsing Code
+ * mbr.c
+ */
+#define DEBUG  0
+#include <acess.h>
+#include "lvm_int.h"
+
+// === PROTOTYPES ===
+void   LVM_MBR_Initialise(int Disk, tMBR *MBR);
+Uint64 LVM_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
+
+// === GLOBALS ===
+
+// === CODE ===
+/**
+ * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
+ */
+void ATA_ParseMBR(int Disk, tMBR *MBR)
+{
+        int    i, j = 0, k = 4;
+       Uint64  extendedLBA;
+       Uint64  base, len;
+       
+       ENTER("iDisk", Disk);
+       
+       // Count Partitions
+       gATA_Disks[Disk].NumPartitions = 0;
+       extendedLBA = 0;
+       for( i = 0; i < 4; i ++ )
+       {
+               if( MBR->Parts[i].SystemID == 0 )       continue;
+               if(     MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 // LBA 28
+               ||      MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 // LBA 48
+                       )
+               {
+                       if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
+                               LOG("Extended Partition at 0x%llx", MBR->Parts[i].LBAStart);
+                               if(extendedLBA != 0) {
+                                       Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+                                       continue;
+                               }
+                               extendedLBA = MBR->Parts[i].LBAStart;
+                               continue;
+                       }
+                       LOG("Primary Partition at 0x%llx", MBR->Parts[i].LBAStart);
+                       
+                       gATA_Disks[Disk].NumPartitions ++;
+                       continue;
+               }
+               // Invalid Partition, so don't count it
+       }
+       while(extendedLBA != 0)
+       {
+               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
+               if( extendedLBA == -1 ) break;
+               gATA_Disks[Disk].NumPartitions ++;
+       }
+       LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
+       
+       // Create patition array
+       gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
+       
+       // --- Fill Partition Info ---
+       extendedLBA = 0;
+       for( j = 0, i = 0; i < 4; i ++ )
+       {
+               LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
+               if( MBR->Parts[i].SystemID == 0 )       continue;
+               if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
+               {
+                       base = MBR->Parts[i].LBAStart;
+                       len = MBR->Parts[i].LBALength;
+               }
+               else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 58
+               {
+                       base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
+                       len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
+               }
+               else
+                       continue;
+               
+               if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
+                       if(extendedLBA != 0) {
+                               Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
+                               continue;
+                       }
+                       extendedLBA = base;
+                       continue;
+               }
+               // Create Partition
+               ATA_int_MakePartition(
+                       &gATA_Disks[Disk].Partitions[j], Disk, j,
+                       base, len
+                       );
+               j ++;
+               
+       }
+       // Scan extended partitions
+       while(extendedLBA != 0)
+       {
+               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
+               if(extendedLBA == -1)   break;
+               ATA_int_MakePartition(
+                       &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
+                       );
+       }
+       
+       LEAVE('-');
+}
+
+/**
+ * \brief Reads an extended partition
+ * \return LBA of next Extended, -1 on error, 0 for last
+ */
+Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
+{
+       Uint64  link = 0;
+        int    bFoundPart = 0;;
+        int    i;
+       tMBR    mbr;
+       Uint64  base, len;
+       
+       if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
+               return -1;      // Stop on Errors
+       
+       for( i = 0; i < 4; i ++ )
+       {
+               if( mbr.Parts[i].SystemID == 0 )        continue;
+               
+               // LBA 24
+               if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
+                       base = mbr.Parts[i].LBAStart;
+                       len = mbr.Parts[i].LBALength;
+               }
+               // LBA 48
+               else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
+                       base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
+                       len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
+               }
+               else {
+                       Log_Warning("ATA MBR",
+                               "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
+                               mbr.Parts[i].Boot, Disk, Addr, i
+                               );
+                       return -1;
+               }
+               
+               switch(mbr.Parts[i].SystemID)
+               {
+               case 0xF:
+               case 0x5:
+                       if(link != 0) {
+                               Log_Warning("ATA MBR",
+                                       "Disk %i has two forward links in the extended partition",
+                                       Disk
+                                       );
+                               return -1;
+                       }
+                       link = base;
+                       break;
+               default:
+                       if(bFoundPart) {
+                               Warning("ATA MBR",
+                                       "Disk %i has more than one partition in the extended partition at 0x%llx",
+                                       Disk, Addr
+                                       );
+                               return -1;
+                       }
+                       bFoundPart = 1;
+                       *Base = base;
+                       *Length = len;
+                       break;
+               }
+       }
+       
+       if(!bFoundPart) {
+               Log_Warning("ATA MBR",
+                       "No partition in extended partiton, Disk %i 0x%llx",
+                       Disk, Addr);
+               return -1;
+       }
+       
+       return link;
+}
diff --git a/KernelLand/Modules/Storage/LVM/volumes.c b/KernelLand/Modules/Storage/LVM/volumes.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/KernelLand/Modules/Storage/Makefile.tpl b/KernelLand/Modules/Storage/Makefile.tpl
new file mode 100644 (file)
index 0000000..d5291f6
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = Storage
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/USB/Core/Makefile b/KernelLand/Modules/USB/Core/Makefile
new file mode 100644 (file)
index 0000000..4d6e684
--- /dev/null
@@ -0,0 +1,10 @@
+#
+#
+
+OBJ  = main.o
+OBJ += usb.o usb_lowlevel.o usb_devinit.o usb_io.o usb_poll.o
+OBJ += hub.o
+CPPFLAGS = -Iinclude
+NAME = Core
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/USB/Core/hub.c b/KernelLand/Modules/USB/Core/hub.c
new file mode 100644 (file)
index 0000000..849e8a3
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * hub.c
+ * - Basic hub driver
+ */
+#define DEBUG  1
+#include <usb_hub.h>
+
+#define MAX_PORTS      32      // Not actually a max, but used for DeviceRemovable
+
+
+#define GET_STATUS     0
+#define CLEAR_FEATURE  1
+// resvd
+#define SET_FEATURE    3
+
+#define PORT_CONNECTION        0
+#define PORT_ENABLE    1
+#define PORT_SUSPEND   2
+#define PORT_OVER_CURRENT      3
+#define PORT_RESET     4
+#define PORT_POWER     8
+#define PORT_LOW_SPEED 9
+#define C_PORT_CONNECTION      16
+#define C_PORT_ENABLE  17
+#define C_PORT_SUSPEND 18
+#define C_PORT_OVER_CURRENT    19
+#define C_PORT_RESET   20
+#define PORT_TEST      21
+#define PORT_INDICATOR 21
+
+struct sHubDescriptor
+{
+       Uint8   DescLength;
+       Uint8   DescType;       // = 0x29
+       Uint8   NbrPorts;
+       Uint16  HubCharacteristics;
+       Uint8   PwrOn2PwrGood;  // 2 ms intervals
+       Uint8   HubContrCurrent;        // Max internal current (mA)
+       Uint8   DeviceRemovable[MAX_PORTS];
+};
+
+struct sHubInfo
+{
+       tUSBHub *HubPtr;
+        int    PowerOnDelay;   // in ms
+        int    nPorts;
+       Uint8   DeviceRemovable[];
+};
+
+// === PROTOTYPES ===
+void   Hub_Connected(tUSBInterface *Dev);
+void   Hub_Disconnected(tUSBInterface *Dev);
+void   Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
+void   Hub_int_HandleChange(tUSBInterface *Dev, int Port);
+
+// === GLOBALS ===
+tUSBDriver     gUSBHub_Driver = {
+       .Name = "Hub",
+       .Match = {.Class = {0x090000, 0xFF0000}},
+       .Connected = Hub_Connected,
+       .Disconnected = Hub_Disconnected,
+       .MaxEndpoints = 1,
+       .Endpoints = {
+               {0x83, Hub_PortStatusChange}
+       }
+};
+
+// === CODE ===
+#if 0
+int Hub_DriverInitialise(char **Arguments)
+{
+       USB_RegisterDriver( &gUSBHub_Driver );
+       return 0;
+}
+#endif
+
+void Hub_Connected(tUSBInterface *Dev)
+{
+       struct sHubDescriptor   hub_desc;
+       struct sHubInfo *info;  
+
+       // Read hub descriptor (Class descriptor 0x29)
+       USB_ReadDescriptor(Dev, 0x129, 0, sizeof(hub_desc), &hub_desc);
+
+       LOG("%i Ports", hub_desc.NbrPorts);
+       LOG("Takes %i ms for power to stabilise", hub_desc.PwrOn2PwrGood*2);
+
+       // Allocate infomation structure
+       info = malloc(sizeof(*info) + (hub_desc.NbrPorts+7)/8);
+       if(!info) {
+               Log_Error("USBHub", "malloc() failed");
+               return ;
+       }
+       USB_SetDeviceDataPtr(Dev, info);
+
+       // Fill data
+       info->nPorts = hub_desc.NbrPorts;
+       info->PowerOnDelay = hub_desc.PwrOn2PwrGood * 2;
+       memcpy(info->DeviceRemovable, hub_desc.DeviceRemovable, (hub_desc.NbrPorts+7)/8);
+       // Register
+       info->HubPtr = USB_RegisterHub(Dev, info->nPorts);
+
+       // Register poll on endpoint
+       USB_StartPollingEndpoint(Dev, 1);
+}
+
+void Hub_Disconnected(tUSBInterface *Dev)
+{
+       struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
+       USB_RemoveHub(info->HubPtr);
+       free(info);
+}
+
+void Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+{
+       Uint8   *status = Data;
+       struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
+        int    i;
+       for( i = 0; i < info->nPorts; i += 8, status ++ )
+       {
+               if( i/8 >= Length )     break;
+               if( *status == 0 )      continue;
+       
+               for( int j = 0; j < 8; j ++ )
+                       if( *status & (1 << j) )
+                               Hub_int_HandleChange(Dev, i+j);
+       }
+}
+
+void Hub_int_HandleChange(tUSBInterface *Dev, int Port)
+{
+       struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
+       Uint16  status[2];      // Status, Change
+       
+       // Get port status
+       USB_Request(Dev, 0, 0xA3, GET_STATUS, 0, Port, 4, status);
+
+       LOG("Port %i: status = {0b%b, 0b%b}", Port, status[0], status[1]);
+       
+       // Handle connections / disconnections
+       if( status[1] & 0x0001 )
+       {
+               if( status[0] & 0x0001 ) {
+                       // Connected
+                       // - Power on port
+                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_POWER, Port, 0, NULL);
+                       Time_Delay(info->PowerOnDelay);
+                       // - Reset
+                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_RESET, Port, 0, NULL);
+                       Time_Delay(20); // Spec says 10ms after reset, but how long is reset?
+                       // - Enable
+                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_ENABLE, Port, 0, NULL);
+                       // - Poke USB Stack
+                       USB_DeviceConnected(info->HubPtr, Port);
+               }
+               else {
+                       // Disconnected
+                       USB_DeviceDisconnected(info->HubPtr, Port);
+               }
+               
+               USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_CONNECTION, Port, 0, NULL);
+       }
+       
+       // Reset change
+       if( status[1] & 0x0010 )
+       {
+               if( status[0] & 0x0010 ) {
+                       // Reset complete
+               }
+               else {
+                       // Useful?
+               }
+               // ACK
+               USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_RESET, Port, 0, NULL);
+       }
+}
diff --git a/KernelLand/Modules/USB/Core/include/usb_core.h b/KernelLand/Modules/USB/Core/include/usb_core.h
new file mode 100644 (file)
index 0000000..43af16f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_core.h
+ * - Core USB IO Header 
+ */
+#ifndef _USB_CORE_H_
+#define _USB_CORE_H_
+
+#include <acess.h>
+
+typedef struct sUSBInterface   tUSBInterface;
+typedef struct sUSBDriver      tUSBDriver;
+
+typedef void   (*tUSB_DataCallback)(tUSBInterface *Dev, int EndPt, int Length, void *Data);
+
+/**
+ */
+struct sUSBDriver
+{
+       tUSBDriver      *Next;
+       
+       const char      *Name;
+
+        int    MatchType;      // 0: Interface, 1: Device, 2: Vendor
+       union { 
+               struct {
+                       // 23:16 - Interface Class
+                       // 15:8  - Interface Sub Class
+                       // 7:0   - Interface Protocol
+                       Uint32  ClassCode;
+                       Uint32  ClassMask;
+               } Class;
+               struct {
+                       Uint16  VendorID;
+                       Uint16  DeviceID;
+               } VendorDev;
+       } Match;
+
+       void    (*Connected)(tUSBInterface *Dev);
+       void    (*Disconnected)(tUSBInterface *Dev);
+
+        int    MaxEndpoints;   
+       struct {
+               // USB Attrbute byte
+               // NOTE: Top bit indicates the direction (1=Input)
+               Uint8   Attributes;
+               // Data availiable Callback
+               tUSB_DataCallback       DataAvail;
+       } Endpoints[];
+};
+
+extern void    *USB_GetDeviceDataPtr(tUSBInterface *Dev);
+extern void    USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
+
+extern void    USB_StartPollingEndpoint(tUSBInterface *Dev, int Endpoint);
+extern void    USB_ReadDescriptor(tUSBInterface *Dev, int Type, int Index, int Length, void *Data);
+extern void    USB_Request(tUSBInterface *Dev, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
+// TODO: Async
+extern void    USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
+extern void    USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
+extern void    USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback);
+
+#endif
+
diff --git a/KernelLand/Modules/USB/Core/include/usb_host.h b/KernelLand/Modules/USB/Core/include/usb_host.h
new file mode 100644 (file)
index 0000000..c5f3e39
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_host.h
+ * - USB Host Controller Interface
+ */
+#ifndef _USB_HOST_H_
+#define _USB_HOST_H_
+
+#include "usb_core.h"
+#include "usb_hub.h"
+
+typedef struct sUSBHostDef     tUSBHostDef;
+
+typedef void   (*tUSBHostCb)(void *DataPtr, void *Data, int Length);
+
+typedef void   *(*tUSBHostOp)(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb CB, void *CbData, void *Data, size_t Length);
+
+/**
+ * \brief Defines a USB Host Controller type
+ */
+struct sUSBHostDef
+{
+       tUSBHostOp      SendIN;
+       tUSBHostOp      SendOUT;
+       tUSBHostOp      SendSETUP;
+
+        int    (*IsOpComplete)(void *Ptr, void *OpPtr);
+
+       void    (*CheckPorts)(void *Ptr);
+};
+
+extern tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
+
+#endif
+
diff --git a/KernelLand/Modules/USB/Core/include/usb_hub.h b/KernelLand/Modules/USB/Core/include/usb_hub.h
new file mode 100644 (file)
index 0000000..6b32d49
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_hub.h
+ * - Core Hub Definitions
+ */
+#ifndef _USB_HUB_H_
+#define _USB_HUB_H_
+
+#include "usb_core.h"
+
+typedef struct sUSBHub tUSBHub;
+
+/**
+ * \brief Register a device as a hub
+ * 
+ * Used by the hub class initialisation routine.
+ */
+extern tUSBHub *USB_RegisterHub(tUSBInterface *Device, int nPorts);
+extern void    USB_RemoveHub(tUSBHub *Hub);
+
+extern void    USB_DeviceConnected(tUSBHub *Hub, int Port);
+extern void    USB_DeviceDisconnected(tUSBHub *Hub, int Port);
+
+#endif
+
diff --git a/KernelLand/Modules/USB/Core/main.c b/KernelLand/Modules/USB/Core/main.c
new file mode 100644 (file)
index 0000000..df7f174
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Acess2
+ * USB Stack
+ */
+#define VERSION        ( (0<<8)| 5 )
+#define DEBUG  1
+#include <acess.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <modules.h>
+#include "usb.h"
+
+// === IMPORTS ===
+extern void    USB_PollThread(void *unused);
+extern void    USB_AsyncThread(void *Unused);
+
+// === PROTOTYPES ===
+ int   USB_Install(char **Arguments);
+void   USB_Cleanup(void);
+char   *USB_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *USB_FindDir(tVFS_Node *Node, const char *Name);
+ int   USB_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_Core, USB_Install, NULL, NULL);
+tVFS_NodeType  gUSB_RootNodeType = {
+       .ReadDir = USB_ReadDir,
+       .FindDir = USB_FindDir,
+       .IOCtl = USB_IOCtl
+};
+tDevFS_Driver  gUSB_DrvInfo = {
+       NULL, "usb", {
+               .NumACLs = 1,
+               .ACLs = &gVFS_ACL_EveryoneRX,
+               .Flags = VFS_FFLAG_DIRECTORY,
+               .Type = &gUSB_RootNodeType
+       }
+};
+tUSBHost       *gUSB_Hosts = NULL;
+
+// === CODE ===
+/**
+ * \brief Called once module is loaded
+ */
+int USB_Install(char **Arguments)
+{
+       Log_Warning("USB", "Not Complete - Devel Only");
+       
+       Proc_SpawnWorker(USB_PollThread, NULL);
+       Proc_SpawnWorker(USB_AsyncThread, NULL);
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Called just before module is unloaded
+ */
+void USB_Cleanup()
+{
+}
+
+/**
+ * \fn char *USB_ReadDir(tVFS_Node *Node, int Pos)
+ * \brief Read from the USB root
+ */
+char *USB_ReadDir(tVFS_Node *Node, int Pos)
+{
+       return NULL;
+}
+
+/**
+ * \fn tVFS_Node *USB_FindDir(tVFS_Node *Node, const char *Name)
+ * \brief Locate an entry in the USB root
+ */
+tVFS_Node *USB_FindDir(tVFS_Node *Node, const char *Name)
+{
+       return NULL;
+}
+
+/**
+ * \brief Handles IOCtl Calls to the USB driver
+ */
+int USB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       return 0;
+}
diff --git a/KernelLand/Modules/USB/Core/usb.c b/KernelLand/Modules/USB/Core/usb.c
new file mode 100644 (file)
index 0000000..b319580
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb.c
+ * - USB Structure
+ */
+#define DEBUG  1
+#include <acess.h>
+#include <vfs.h>
+#include <drv_pci.h>
+#include "usb.h"
+
+// === IMPORTS ===
+extern tUSBHost        *gUSB_Hosts;
+extern tUSBDriver gUSBHub_Driver;
+
+// === STRUCTURES ===
+
+// === PROTOTYPES ===
+tUSBHub        *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
+
+// === GLOBALS ===
+tUSBDriver     *gpUSB_InterfaceDrivers = &gUSBHub_Driver;
+
+// === CODE ===
+tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts)
+{
+       tUSBHost        *host;
+       
+       host = malloc(sizeof(tUSBHost) + nPorts*sizeof(void*));
+       if(!host) {
+               // Oh, bugger.
+               return NULL;
+       }
+       host->HostDef = HostDef;
+       host->Ptr = ControllerPtr;
+       memset(host->AddressBitmap, 0, sizeof(host->AddressBitmap));
+
+       host->RootHubDev.ParentHub = NULL;
+       host->RootHubDev.Host = host;
+       host->RootHubDev.Address = 0;
+
+//     host->RootHubIf.Next = NULL;
+       host->RootHubIf.Dev = &host->RootHubDev;
+       host->RootHubIf.Driver = NULL;
+       host->RootHubIf.Data = NULL;
+       host->RootHubIf.nEndpoints = 0;
+
+       host->RootHub.Interface = &host->RootHubIf;
+       host->RootHub.nPorts = nPorts;
+       memset(host->RootHub.Devices, 0, sizeof(void*)*nPorts);
+
+       // TODO: Lock
+       host->Next = gUSB_Hosts;
+       gUSB_Hosts = host;
+
+       return &host->RootHub;
+}
+
+// --- Drivers ---
+void USB_RegisterDriver(tUSBDriver *Driver)
+{
+       Log_Warning("USB", "TODO: Implement USB_RegisterDriver");
+}
+
+tUSBDriver *USB_int_FindDriverByClass(Uint32 ClassCode)
+{
+       ENTER("xClassCode", ClassCode);
+       for( tUSBDriver *ret = gpUSB_InterfaceDrivers; ret; ret = ret->Next )
+       {
+               LOG(" 0x%x & 0x%x == 0x%x?", ClassCode, ret->Match.Class.ClassMask, ret->Match.Class.ClassCode);
+               if( (ClassCode & ret->Match.Class.ClassMask) == ret->Match.Class.ClassCode )
+               {
+                       LOG("Found '%s'", ret->Name);
+                       LEAVE('p', ret);
+                       return ret;
+               }
+       }
+       LEAVE('n');
+       return NULL;
+}
+
+// --- Hub Registration ---
+// NOTE: Doesn't do much nowdays
+tUSBHub *USB_RegisterHub(tUSBInterface *Device, int PortCount)
+{
+       tUSBHub *ret;
+       
+       ret = malloc(sizeof(tUSBHub) + sizeof(ret->Devices[0])*PortCount);
+       ret->Interface = Device;
+       ret->nPorts = PortCount;
+       memset(ret->Devices, 0, sizeof(ret->Devices[0])*PortCount);
+       return ret;
+}
+
+void USB_RemoveHub(tUSBHub *Hub)
+{
+       for( int i = 0; i < Hub->nPorts; i ++ )
+       {
+               if( Hub->Devices[i] )
+               {
+                       USB_DeviceDisconnected( Hub, i );
+               }
+       }
+       free(Hub);
+}
+
diff --git a/KernelLand/Modules/USB/Core/usb.h b/KernelLand/Modules/USB/Core/usb.h
new file mode 100644 (file)
index 0000000..5a13363
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ * 
+ * usb.h
+ * - USB Internal definitions
+ */
+#ifndef _USB_H_
+#define _USB_H_
+
+#include <usb_core.h>
+#include <usb_hub.h>
+#include <usb_host.h>
+
+typedef struct sUSBHost        tUSBHost;
+typedef struct sUSBDevice      tUSBDevice;
+typedef struct sUSBEndpoint    tUSBEndpoint;
+
+// === STRUCTURES ===
+/**
+ * \brief USB Hub data
+ */
+struct sUSBHub
+{
+       tUSBInterface   *Interface;
+       
+        int    nPorts;
+       tUSBDevice      *Devices[];
+};
+
+struct sUSBEndpoint
+{
+       tUSBEndpoint    *Next;  // (usb_poll.c) Clock list
+       tUSBInterface   *Interface;
+        int    EndpointIdx;    // Interface endpoint index
+        int    EndpointNum;    // Device endpoint num
+       
+        int    PollingPeriod;  // In 1ms intervals
+        int    MaxPacketSize;  // In bytes
+       Uint8   Type;   // Same as sUSBDriver.Endpoints.Type
+       
+        int    PollingAtoms;   // (usb_poll.c) Period in clock list
+       void    *InputData;
+};
+
+/**
+ * \brief Structure for a device's interface
+ */
+struct sUSBInterface
+{
+//     tUSBInterface   *Next;
+       tUSBDevice      *Dev;
+
+       tUSBDriver      *Driver;
+       void    *Data;
+       
+        int    nEndpoints;
+       tUSBEndpoint    Endpoints[];
+};
+
+/**
+ * \brief Defines a single device on the USB Bus
+ */
+struct sUSBDevice
+{
+       tUSBHub *ParentHub;
+
+       /**
+        * \brief Host controller used
+        */
+       tUSBHost        *Host;
+        int    Address;
+
+        int    nInterfaces;
+       tUSBInterface   *Interfaces[];
+};
+
+struct sUSBHost
+{
+       struct sUSBHost *Next;
+       
+       tUSBHostDef     *HostDef;
+       void    *Ptr;
+       
+       Uint8   AddressBitmap[128/8];
+       
+       tUSBDevice      RootHubDev;
+       tUSBInterface   RootHubIf;
+       tUSBHub RootHub;
+};
+
+extern tUSBDriver      *USB_int_FindDriverByClass(Uint32 ClassCode);
+
+#endif
diff --git a/KernelLand/Modules/USB/Core/usb_devinit.c b/KernelLand/Modules/USB/Core/usb_devinit.c
new file mode 100644 (file)
index 0000000..d01d7d1
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Acess 2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_devinit.c
+ * - USB Device Initialisation
+ */
+#define DEBUG  1
+
+#include <acess.h>
+#include <vfs.h>
+#include <drv_pci.h>
+#include "usb.h"
+#include "usb_proto.h"
+#include "usb_lowlevel.h"
+
+// === PROTOTYPES ===
+void   USB_DeviceConnected(tUSBHub *Hub, int Port);
+void   USB_DeviceDisconnected(tUSBHub *Hub, int Port);
+void   *USB_GetDeviceDataPtr(tUSBInterface *Dev);
+void   USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
+ int   USB_int_AllocateAddress(tUSBHost *Host);
+
+// === CODE ===
+void USB_DeviceConnected(tUSBHub *Hub, int Port)
+{
+       tUSBDevice      tmpdev;
+       tUSBDevice      *dev = &tmpdev;
+       if( Port >= Hub->nPorts )       return ;
+       if( Hub->Devices[Port] )        return ;
+
+       ENTER("pHub iPort", Hub, Port);
+
+       // Device should be in 'Default' state
+       
+       // Create structure
+       dev->ParentHub = Hub;
+       dev->Host = Hub->Interface->Dev->Host;
+       dev->Address = 0;
+
+       // 1. Assign an address
+       dev->Address = USB_int_AllocateAddress(dev->Host);
+       if(dev->Address == 0) {
+               Log_Error("USB", "No addresses avaliable on host %p", dev->Host);
+               free(dev);
+               LEAVE('-');
+               return ;
+       }
+       USB_int_SendSetupSetAddress(dev->Host, dev->Address);
+       LOG("Assigned address %i", dev->Address);
+       
+       // 2. Get device information
+       {
+               struct sDescriptor_Device       desc;
+               LOG("Getting device descriptor");
+               // Endpoint 0, Desc Type 1, Index 0
+               USB_int_ReadDescriptor(dev, 0, 1, 0, sizeof(desc), &desc);
+               
+               LOG("Device Descriptor = {");
+               LOG(" .Length = %i", desc.Length);
+               LOG(" .Type = %i", desc.Type);
+               LOG(" .USBVersion = 0x%04x", desc.USBVersion);
+               LOG(" .DeviceClass = 0x%02x", desc.DeviceClass);
+               LOG(" .DeviceSubClass = 0x%02x", desc.DeviceSubClass);
+               LOG(" .DeviceProtocol = 0x%02x", desc.DeviceProtocol);
+               LOG(" .MaxPacketSize = 0x%02x", desc.MaxPacketSize);
+               LOG(" .VendorID = 0x%04x", desc.VendorID);
+               LOG(" .ProductID = 0x%04x", desc.ProductID);
+               LOG(" .DeviceID = 0x%04x", desc.DeviceID);
+               LOG(" .ManufacturerStr = Str %i", desc.ManufacturerStr);
+               LOG(" .ProductStr = Str %i", desc.ProductStr);
+               LOG(" .SerialNumberStr = Str %i", desc.SerialNumberStr);
+               LOG(" .NumConfigurations = %i", desc.SerialNumberStr);
+               LOG("}");
+               
+               if( desc.ManufacturerStr )
+               {
+                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ManufacturerStr);
+                       LOG("ManufacturerStr = '%s'", tmp);
+                       free(tmp);
+               }
+               if( desc.ProductStr )
+               {
+                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ProductStr);
+                       LOG("ProductStr = '%s'", tmp);
+                       free(tmp);
+               }
+               if( desc.SerialNumberStr )
+               {
+                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.SerialNumberStr);
+                       LOG("SerialNumbertStr = '%s'", tmp);
+                       free(tmp);
+               }
+       }
+
+       // TODO: Support alternate configurations
+       
+       // 3. Get configurations
+       for( int i = 0; i < 1; i ++ )
+       {
+               struct sDescriptor_Configuration        desc;
+               void    *full_buf;
+               char    *cur_ptr;
+       
+               USB_int_ReadDescriptor(dev, 0, 2, i, sizeof(desc), &desc);
+               LOG("Configuration Descriptor %i = {", i);
+               LOG(" .Length = %i", desc.Length);
+               LOG(" .Type = %i", desc.Type);
+               LOG(" .TotalLength = 0x%x", LittleEndian16(desc.TotalLength));
+               LOG(" .NumInterfaces = %i", desc.NumInterfaces);
+               LOG(" .ConfigurationValue = %i", desc.ConfigurationValue);
+               LOG(" .ConfigurationStr = %i", desc.ConfigurationStr);
+               LOG(" .AttributesBmp = 0b%b", desc.AttributesBmp);
+               LOG(" .MaxPower = %i (*2mA)", desc.MaxPower);
+               LOG("}");
+               if( desc.ConfigurationStr ) {
+                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ConfigurationStr);
+                       LOG("ConfigurationStr = '%s'", tmp);
+                       free(tmp);
+               }
+
+               // TODO: Split here and allow some method of selection
+
+               // Allocate device now that we have the configuration
+               dev = malloc(sizeof(tUSBDevice) + desc.NumInterfaces * sizeof(void*));
+               memcpy(dev, &tmpdev, sizeof(tUSBDevice));
+               dev->nInterfaces = desc.NumInterfaces;
+       
+               // Allocate a temp buffer for config info
+               cur_ptr = full_buf = malloc( LittleEndian16(desc.TotalLength) );
+               USB_int_ReadDescriptor(dev, 0, 2, i, desc.TotalLength, full_buf);
+
+               cur_ptr += desc.Length;
+
+               // TODO: Interfaces
+               for( int j = 0; j < desc.NumInterfaces; j ++ )
+               {
+                       struct sDescriptor_Interface *iface;
+                       tUSBInterface   *dev_if;
+                       iface = (void*)cur_ptr;
+                       // TODO: Sanity check with remaining space
+                       cur_ptr += sizeof(*iface);
+
+                       LOG("Interface %i/%i = {", i, j);
+                       LOG(" .InterfaceNum = %i", iface->InterfaceNum);
+                       LOG(" .NumEndpoints = %i", iface->NumEndpoints);
+                       LOG(" .InterfaceClass = 0x%x", iface->InterfaceClass);
+                       LOG(" .InterfaceSubClass = 0x%x", iface->InterfaceSubClass);
+                       LOG(" .InterfaceProcol = 0x%x", iface->InterfaceProtocol);
+
+                       if( iface->InterfaceStr ) {
+                               char    *tmp = USB_int_GetDeviceString(dev, 0, iface->InterfaceStr);
+                               LOG(" .InterfaceStr = %i '%s'", iface->InterfaceStr, tmp);
+                               free(tmp);
+                       }
+                       LOG("}");
+
+                       dev_if = malloc(sizeof(tUSBInterface) + iface->NumEndpoints*sizeof(dev_if->Endpoints[0]));
+                       dev_if->Dev = dev;
+                       dev_if->Driver = NULL;
+                       dev_if->Data = NULL;
+                       dev_if->nEndpoints = iface->NumEndpoints;
+                       dev->Interfaces[j] = dev_if;
+
+                       // Copy interface data
+                       for( int k = 0; k < iface->NumEndpoints; k ++ )
+                       {
+                               struct sDescriptor_Endpoint *endpt;
+                               endpt = (void*)cur_ptr;
+                               // TODO: Sanity check with remaining space
+                               cur_ptr += sizeof(*endpt);
+                               
+                               LOG("Endpoint %i/%i/%i = {", i, j, k);
+                               LOG(" .Address = 0x%2x", endpt->Address);
+                               LOG(" .Attributes = 0b%8b", endpt->Attributes);
+                               LOG(" .MaxPacketSize = %i", LittleEndian16(endpt->MaxPacketSize));
+                               LOG(" .PollingInterval = %i", endpt->PollingInterval);
+                               LOG("}");
+                               
+                               dev_if->Endpoints[k].Next = NULL;
+                               dev_if->Endpoints[k].Interface = dev_if;
+                               dev_if->Endpoints[k].EndpointIdx = k;
+                               dev_if->Endpoints[k].EndpointNum = endpt->Address & 0x7F;
+                               dev_if->Endpoints[k].PollingPeriod = endpt->PollingInterval;
+                               dev_if->Endpoints[k].MaxPacketSize = LittleEndian16(endpt->MaxPacketSize);
+                               dev_if->Endpoints[k].Type = endpt->Attributes | (endpt->Address & 0x80);
+                               dev_if->Endpoints[k].PollingAtoms = 0;
+                               dev_if->Endpoints[k].InputData = NULL;
+                       }
+                       
+                       // Initialise driver
+                       dev_if->Driver = USB_int_FindDriverByClass(
+                                ((int)iface->InterfaceClass << 16)
+                               |((int)iface->InterfaceSubClass << 8)
+                               |((int)iface->InterfaceProtocol << 0)
+                               );
+                       if(!dev_if->Driver) {
+                               Log_Notice("USB", "No driver for Class %02x:%02x:%02x",
+                                       iface->InterfaceClass, iface->InterfaceSubClass, iface->InterfaceProtocol
+                                       );
+                       }
+                       else {
+                               dev_if->Driver->Connected( dev_if );
+                       }
+               }
+               
+               free(full_buf);
+       }
+
+       // Done.
+       LEAVE('-');
+}
+
+void USB_DeviceDisconnected(tUSBHub *Hub, int Port)
+{
+       
+}
+
+void *USB_GetDeviceDataPtr(tUSBInterface *Dev) { return Dev->Data; }
+void USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr) { Dev->Data = Ptr; }
+
+int USB_int_AllocateAddress(tUSBHost *Host)
+{
+        int    i;
+       for( i = 1; i < 128; i ++ )
+       {
+               if(Host->AddressBitmap[i/8] & (1 << (i%8)))
+                       continue ;
+               Host->AddressBitmap[i/8] |= 1 << (i%8);
+               return i;
+       }
+       return 0;
+}
+
+void USB_int_DeallocateAddress(tUSBHost *Host, int Address)
+{
+       Host->AddressBitmap[Address/8] &= ~(1 << (Address%8));
+}
+
diff --git a/KernelLand/Modules/USB/Core/usb_io.c b/KernelLand/Modules/USB/Core/usb_io.c
new file mode 100644 (file)
index 0000000..25ff59d
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_io.c
+ * - High-level IO
+ */
+#define DEBUG  0
+
+#include <usb_core.h>
+#include "usb.h"
+#include "usb_lowlevel.h"
+#include <workqueue.h>
+
+typedef struct sAsyncOp        tAsyncOp;
+
+struct sAsyncOp
+{
+       tAsyncOp        *Next;
+       tUSBEndpoint    *Endpt;
+        int    Length;
+       void    *Data;
+};
+
+// === PROTOTYPES ===
+void   USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data);
+void   USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
+void   USB_AsyncCallback(void *Ptr, void *Buf, int Length);
+void   USB_AsyncThread(void *unused);
+
+// === GLOBALS ===
+tWorkqueue     gUSB_AsyncQueue;
+
+// === CODE ===
+void USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data)
+{
+       USB_int_ReadDescriptor(Iface->Dev, 0, Type, Index, Length, Data);
+}
+
+void USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data)
+{
+        int    endpt;
+
+       // Sanity check
+       if(Endpoint < 0 || Endpoint >= Iface->nEndpoints)
+               return ;        
+
+       // Get endpoint number
+       if(Endpoint)
+               endpt = Iface->Endpoints[Endpoint-1].EndpointNum;
+       else
+               endpt = 0;
+       
+       USB_int_Request(Iface->Dev->Host, Iface->Dev->Address, endpt, Type, Req, Value, Index, Len, Data);
+}
+
+
+void USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+{
+       Log_Warning("USB", "TODO: Implement USB_SendData");
+}
+
+void USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+{
+       Log_Warning("USB", "TODO: Implement USB_RecvData");
+}
+
+void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback)
+{
+       tAsyncOp *op;
+       tUSBHost *host;
+
+       ENTER("pDev iEndpoint iLength pDataBuf", Dev, Endpoint, Length, DataBuf); 
+
+       op = malloc(sizeof(*op));
+       op->Next = NULL;
+       op->Endpt = &Dev->Endpoints[Endpoint-1];
+       op->Length = Length;
+       op->Data = DataBuf;
+
+       // TODO: Handle transfers that are larger than one packet
+
+       host = Dev->Dev->Host;
+       LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum);
+       host->HostDef->SendIN(
+               host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum,
+               0, USB_AsyncCallback, op,
+               DataBuf, Length
+               );
+       
+       LEAVE('-');
+
+//     Log_Warning("USB", "TODO: Implement USB_RecvDataA");
+}
+
+void USB_AsyncCallback(void *Ptr, void *Buf, int Length)
+{
+       tAsyncOp *op = Ptr;
+       op->Length = Length;
+       LOG("adding %p to work queue", op);
+       Workqueue_AddWork(&gUSB_AsyncQueue, op);
+}
+
+void USB_AsyncThread(void *Unused)
+{
+       Threads_SetName("USB Async IO Thread");
+       for(;;)
+       {
+               tAsyncOp *op = Workqueue_GetWork(&gUSB_AsyncQueue);
+               tUSBInterface   *iface = op->Endpt->Interface;
+
+               LOG("op = %p", op);     
+
+               iface->Driver->Endpoints[op->Endpt->EndpointIdx].DataAvail(
+                       iface, op->Endpt->EndpointIdx,
+                       op->Length, op->Data);
+       }
+}
+
diff --git a/KernelLand/Modules/USB/Core/usb_lowlevel.c b/KernelLand/Modules/USB/Core/usb_lowlevel.c
new file mode 100644 (file)
index 0000000..0e53bad
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Acess 2 USB Stack
+ * - By John Hodge (thePowersGang)
+ * 
+ * usb_lowlevel.c
+ * - Low Level IO
+ */
+#define DEBUG  1
+#include <acess.h>
+#include "usb.h"
+#include "usb_proto.h"
+#include "usb_lowlevel.h"
+
+// === PROTOTYPES ===
+void   *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
+ int   USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
+ int   USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
+char   *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
+ int   _UTF16to8(Uint16 *Input, int InputLen, char *Dest);
+
+// === CODE ===
+void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
+{
+       void    *hdl;
+       // TODO: Sanity check (and check that Type is valid)
+       struct sDeviceRequest   req;
+       req.ReqType = Type;
+       req.Request = Req;
+       req.Value = LittleEndian16( Val );
+       req.Index = LittleEndian16( Indx );
+       req.Length = LittleEndian16( Len );
+       
+       hdl = Host->HostDef->SendSETUP(Host->Ptr, Addr, EndPt, 0, NULL, NULL, &req, sizeof(req));
+
+       // TODO: Data toggle?
+       // TODO: Multi-packet transfers
+       if( Type & 0x80 )
+       {
+               void    *hdl2;
+               
+               hdl = Host->HostDef->SendIN(Host->Ptr, Addr, EndPt, 0, NULL, NULL, Data, Len);
+
+               hdl2 = Host->HostDef->SendOUT(Host->Ptr, Addr, EndPt, 0, NULL, NULL, NULL, 0);
+               while( Host->HostDef->IsOpComplete(Host->Ptr, hdl2) == 0 )
+                       Time_Delay(1);
+       }
+       else
+       {
+               void    *hdl2;
+               
+               if( Len > 0 )
+                       hdl = Host->HostDef->SendOUT(Host->Ptr, Addr, EndPt, 0, NULL, NULL, Data, Len);
+               else
+                       hdl = NULL;
+               
+               // Status phase (DataToggle=1)
+               hdl2 = Host->HostDef->SendIN(Host->Ptr, Addr, EndPt, 1, NULL, NULL, NULL, 0);
+               while( Host->HostDef->IsOpComplete(Host->Ptr, hdl2) == 0 )
+                       Time_Delay(1);
+       }
+       return hdl;
+}
+
+int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address)
+{
+       USB_int_Request(Host, 0, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
+       return 0;
+}
+
+int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest)
+{
+       const int       ciMaxPacketSize = 0x400;
+       struct sDeviceRequest   req;
+        int    bToggle = 0;
+       void    *final;
+
+       req.ReqType = 0x80;
+       switch( Type & 0xF00 )
+       {
+       case 0x000:     req.ReqType |= (0 << 5);        break;  // Standard
+       case 0x100:     req.ReqType |= (1 << 5);        break;  // Class
+       case 0x200:     req.ReqType |= (2 << 5);        break;  // Vendor
+       }
+
+       req.Request = 6;        // GET_DESCRIPTOR
+       req.Value = LittleEndian16( ((Type & 0xFF) << 8) | (Index & 0xFF) );
+       req.Index = LittleEndian16( 0 );        // TODO: Language ID
+       req.Length = LittleEndian16( Length );
+       
+       Dev->Host->HostDef->SendSETUP(
+               Dev->Host->Ptr, Dev->Address, Endpoint,
+               0, NULL, NULL,
+               &req, sizeof(req)
+               );
+       
+       bToggle = 1;
+       while( Length > ciMaxPacketSize )
+       {
+               Dev->Host->HostDef->SendIN(
+                       Dev->Host->Ptr, Dev->Address, Endpoint,
+                       bToggle, NULL, NULL,
+                       Dest, ciMaxPacketSize
+                       );
+               bToggle = !bToggle;
+               Length -= ciMaxPacketSize;
+       }
+
+       final = Dev->Host->HostDef->SendIN(
+               Dev->Host->Ptr, Dev->Address, Endpoint,
+               bToggle, INVLPTR, NULL,
+               Dest, Length
+               );
+
+       while( Dev->Host->HostDef->IsOpComplete(Dev->Host->Ptr, final) == 0 )
+               Time_Delay(1);
+
+       return 0;
+}
+
+char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index)
+{
+       struct sDescriptor_String       str;
+        int    src_len, new_len;
+       char    *ret;
+
+       if(Index == 0)  return strdup("");
+       
+       USB_int_ReadDescriptor(Dev, Endpoint, 3, Index, sizeof(str), &str);
+       if(str.Length < 2) {
+               Log_Error("USB", "String %p:%i:%i:%i descriptor is undersized (%i)",
+                       Dev->Host, Dev->Address, Endpoint, Index, str.Length);
+               return NULL;
+       }
+//     if(str.Length > sizeof(str)) {
+//             // IMPOSSIBLE!
+//             Log_Error("USB", "String is %i bytes, which is over prealloc size (%i)",
+//                     str.Length, sizeof(str)
+//                     );
+//     }
+       src_len = (str.Length - 2) / sizeof(str.Data[0]);
+
+       LOG("&str = %p, src_len = %i", &str, src_len);
+
+       new_len = _UTF16to8(str.Data, src_len, NULL);   
+       ret = malloc( new_len + 1 );
+       _UTF16to8(str.Data, src_len, ret);
+       ret[new_len] = 0;
+       return ret;
+}
+
+int _UTF16to8(Uint16 *Input, int InputLen, char *Dest)
+{
+        int    str_len, cp_len;
+       Uint32  saved_bits = 0;
+       str_len = 0;
+       for( int i = 0; i < InputLen; i ++)
+       {
+               Uint32  cp;
+               Uint16  val = Input[i];
+               if( val >= 0xD800 && val <= 0xDBFF )
+               {
+                       // Multibyte - Leading
+                       if(i + 1 > InputLen) {
+                               cp = '?';
+                       }
+                       else {
+                               saved_bits = (val - 0xD800) << 10;
+                               saved_bits += 0x10000;
+                               continue ;
+                       }
+               }
+               else if( val >= 0xDC00 && val <= 0xDFFF )
+               {
+                       if( !saved_bits ) {
+                               cp = '?';
+                       }
+                       else {
+                               saved_bits |= (val - 0xDC00);
+                               cp = saved_bits;
+                       }
+               }
+               else
+                       cp = val;
+
+               cp_len = WriteUTF8((Uint8*)Dest, cp);
+               if(Dest)
+                       Dest += cp_len;
+               str_len += cp_len;
+
+               saved_bits = 0;
+       }
+       
+       return str_len;
+}
+
diff --git a/KernelLand/Modules/USB/Core/usb_lowlevel.h b/KernelLand/Modules/USB/Core/usb_lowlevel.h
new file mode 100644 (file)
index 0000000..9159cba
--- /dev/null
@@ -0,0 +1,16 @@
+/**
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ * 
+ * usb_lowlevel.h
+ * - Low-Level USB IO Functions
+ */
+#ifndef _USB_LOWLEVEL_H_
+#define _USB_LOWLEVEL_H_
+
+extern void    *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
+extern int     USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
+extern int     USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
+extern char    *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
+
+#endif
diff --git a/KernelLand/Modules/USB/Core/usb_poll.c b/KernelLand/Modules/USB/Core/usb_poll.c
new file mode 100644 (file)
index 0000000..b6927fe
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_poll.c
+ * - Endpoint polling
+ */
+#define DEBUG  1
+#include <usb_core.h>
+#include "usb.h"
+
+#define POLL_ATOM      25      // 25ms atom
+#define POLL_MAX       256     // Max period that can be nominated
+#define POLL_SLOTS     ((int)(POLL_MAX/POLL_ATOM))
+
+// === IMPORTS ===
+extern tUSBHost        *gUSB_Hosts;
+
+// === PROTOTYPES ===
+void   USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint);
+
+// === GLOBALS ===
+tUSBEndpoint   *gUSB_PollQueues[POLL_MAX/POLL_ATOM];
+ int   giUSB_PollPosition;     // Index into gUSB_PollQueues
+
+// === CODE ===
+void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint)
+{
+       tUSBEndpoint    *endpt;
+
+       // Some sanity checks
+       if(Endpoint <= 0 || Endpoint > Iface->nEndpoints)       return ;
+       endpt = &Iface->Endpoints[Endpoint-1];
+       if(endpt->PollingPeriod > POLL_MAX || endpt->PollingPeriod <= 0)
+               return ;
+
+       // TODO: Check that this endpoint isn't already on the queue
+
+       endpt->InputData = malloc(endpt->MaxPacketSize);
+
+       // Determine polling period in atoms
+       endpt->PollingAtoms = (endpt->PollingPeriod + POLL_ATOM-1) / POLL_ATOM;
+       if(endpt->PollingAtoms > POLL_SLOTS)    endpt->PollingAtoms = POLL_SLOTS;
+       // Add to poll queue
+       // TODO: Locking
+       {
+                int    idx = giUSB_PollPosition + 1;
+               if(idx >= POLL_SLOTS)   idx -= POLL_SLOTS;
+               endpt->Next = gUSB_PollQueues[idx];
+               gUSB_PollQueues[idx] = endpt;
+       }
+}
+
+/**
+ * \brief USB polling thread
+ */
+int USB_PollThread(void *unused)
+{
+       Threads_SetName("USB Polling Thread");
+       for(;;)
+       {
+               tUSBEndpoint    *ep, *prev;
+
+               if(giUSB_PollPosition == 0)
+               {
+                       // Check hosts
+                       for( tUSBHost *host = gUSB_Hosts; host; host = host->Next )
+                       {
+                               host->HostDef->CheckPorts(host->Ptr);
+                       }
+               }
+
+//             Log_Debug("USBPoll", "giUSB_PollPosition = %i", giUSB_PollPosition);
+
+               // A little evil for neater code
+               prev = (void*)( (tVAddr)&gUSB_PollQueues[giUSB_PollPosition] - offsetof(tUSBEndpoint, Next) );
+
+               // Process queue
+//             LOG("giUSB_PollPosition = %i", giUSB_PollPosition);
+               for( ep = gUSB_PollQueues[giUSB_PollPosition]; ep; prev = ep, ep = ep->Next )
+               {
+                        int    period_in_atoms = ep->PollingAtoms;
+//                     LOG("%i: ep = %p", giUSB_PollPosition, ep);
+
+                       // Check for invalid entries
+                       if(period_in_atoms < 0 || period_in_atoms > POLL_ATOM)
+                       {
+                               Log_Warning("USB", "Endpoint on polling queue with invalid period");
+                               continue ;
+                       }
+                       // Check for entries to delete
+                       if(period_in_atoms == 0)
+                       {
+                               // Remove
+                               prev->Next = ep->Next;
+                               ep->PollingAtoms = -1;  // Mark as removed
+                               ep = prev;      // Make sure prev is kept valid
+                               continue ;
+                       }
+
+                       // Read data
+                       // TODO: Check the endpoint
+                       // TODO: Async checking?
+                       // - Send the read request on all of them then wait for the first to complete
+                       USB_RecvDataA(
+                               ep->Interface, ep->EndpointIdx+1,
+                               ep->MaxPacketSize, ep->InputData,
+                               ep->Interface->Driver->Endpoints[ep->EndpointIdx].DataAvail
+                               );
+                               
+                       // Call callback
+
+                       // Reschedule
+                       if( period_in_atoms != POLL_SLOTS )
+                       {
+                                int    newqueue_id = (giUSB_PollPosition + period_in_atoms) % POLL_SLOTS;
+                               tUSBEndpoint    **newqueue = &gUSB_PollQueues[newqueue_id];
+                               
+                               prev->Next = ep->Next;
+                               
+                               ep->Next = *newqueue;
+                               *newqueue = ep;
+                               ep = prev;
+                       }
+               }
+               giUSB_PollPosition ++;
+               if(giUSB_PollPosition == POLL_SLOTS)
+                       giUSB_PollPosition = 0;
+               // TODO: Check for a longer delay
+               Time_Delay(POLL_ATOM);
+       }
+}
+
diff --git a/KernelLand/Modules/USB/Core/usb_proto.h b/KernelLand/Modules/USB/Core/usb_proto.h
new file mode 100644 (file)
index 0000000..5641dd2
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ * 
+ * usb_proto.h
+ * - USB Core Protocol Definitions
+ */
+#ifndef _USB_PROTO_H_
+#define _USB_PROTO_H_
+
+struct sDeviceRequest
+{
+       Uint8   ReqType;
+       Uint8   Request;
+       Uint16  Value;
+       Uint16  Index;
+       Uint16  Length;
+};
+
+/*
+ */
+struct sDescriptor_Device
+{
+       Uint8   Length;
+       Uint8   Type;   // = 1
+       Uint16  USBVersion;     // BCD, 0x210 = 2.10
+       Uint8   DeviceClass;
+       Uint8   DeviceSubClass;
+       Uint8   DeviceProtocol;
+       Uint8   MaxPacketSize;
+       
+       Uint16  VendorID;
+       Uint16  ProductID;
+       Uint16  DeviceID;       // BCD
+       
+       Uint8   ManufacturerStr;
+       Uint8   ProductStr;
+       Uint8   SerialNumberStr;
+       
+       Uint8   NumConfigurations;
+} PACKED;
+
+struct sDescriptor_Configuration
+{
+       Uint8   Length;
+       Uint8   Type;   // = 2
+       
+       Uint16  TotalLength;
+       Uint8   NumInterfaces;
+       Uint8   ConfigurationValue;
+       Uint8   ConfigurationStr;
+       Uint8   AttributesBmp;
+       Uint8   MaxPower;       // in units of 2 mA
+} PACKED;
+
+struct sDescriptor_String
+{
+       Uint8   Length;
+       Uint8   Type;   // = 3
+       
+       Uint16  Data[128-1];    // (256 bytes - 2 bytes) / Uint16
+} PACKED;
+
+struct sDescriptor_Interface
+{
+       Uint8   Length;
+       Uint8   Type;   // = 4
+       
+       Uint8   InterfaceNum;
+       Uint8   AlternateSetting;
+       Uint8   NumEndpoints;   // Excludes endpoint 0
+       
+       Uint8   InterfaceClass; // 
+       Uint8   InterfaceSubClass;
+       Uint8   InterfaceProtocol;
+       
+       Uint8   InterfaceStr;
+} PACKED;
+
+struct sDescriptor_Endpoint
+{
+       Uint8   Length;
+       Uint8   Type;   // = 5
+       Uint8   Address;        // 3:0 Endpoint Num, 7: Direction (1=IN)
+       /**
+        * 1:0 - Transfer Type
+        * - 00 = Control
+        * - 01 = Isochronous
+        * - 10 = Bulk
+        * - 11 = Interrupt
+        * 3:2 - Synchronisation type (Isonchronous only)
+        * - 00 = No Synchronisation
+        * - 01 = Asynchronous
+        * - 10 = Adaptive
+        * - 11 = Synchronous
+        * 5:4 - Usage type (Isonchronous only)
+        * - 00 = Data endpoint
+        * - 01 = Feedback endpoint
+        */
+       Uint8   Attributes;
+       
+       Uint16  MaxPacketSize;
+       
+       /**
+        * 
+        */
+       Uint8   PollingInterval;
+} PACKED;
+
+#endif
+
diff --git a/KernelLand/Modules/USB/HID/hid.h b/KernelLand/Modules/USB/HID/hid.h
new file mode 100644 (file)
index 0000000..373496e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Acess2 USB Stack HID Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * hid.h
+ * - Core header
+ */
+#ifndef _HID_H_
+#define _HID_H_
+
+// Report Descriptor Types
+// - 0: Main
+//  > 8: Input - Axis/Button etc
+//  > 9: Output - LED/Position
+//  > B: Feature -
+//  > A: Collection - Group of Input/Output/Feature
+//  > C: End collection
+// - 1: Global (Not restored on main)
+// - 2: Local
+//  > 
+// - 3: Reserved/Unused
+
+// I/O/F Data Values
+#define HID_IOF_CONSTANT       0x001   //!< Host Read-only
+#define HID_IOF_VARIABLE       0x002   //!< 
+
+struct sLongItem
+{
+       Uint8   Header; // 0xFE (Tag 15, Type 3, Size 2)
+       Uint8   DataSize;
+       Uint8   Tag;
+};
+
+struct sDescriptor_HID
+{
+       Uint8   Length;
+       Uint8   Type;   // 
+       Uint16  Version;        // 0x0111 = 1.11
+       Uint8   CountryCode;
+       Uint8   NumDescriptors; // >= 1
+       struct {
+               Uint8   DescType;
+               Uint16  DescLen;
+       } Descriptors[];
+}
+
+#endif
diff --git a/KernelLand/Modules/USB/HID/keysyms.h b/KernelLand/Modules/USB/HID/keysyms.h
new file mode 100644 (file)
index 0000000..558464e
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Acess2 USB Stack HID Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_keysyms.h
+ * - USB HID Keyboard Symbols
+ */
+#ifndef _USB_KEYSYMS_H_
+#define _USB_KEYSYMS_H_
+
+enum eUSB_Keysyms
+{
+       KEYSYM_NONE,
+       KEYSYM_ERRORROLLOVER,
+       KEYSYM_POSTFAIL,
+       KEYSYM_ERRORUNDEFINED,
+       // 0x04 / 4
+       KEYSYM_a, KEYSYM_b, KEYSYM_c,
+       KEYSYM_d, KEYSYM_e, KEYSYM_f,
+       KEYSYM_g, KEYSYM_h, KEYSYM_i,
+       KEYSYM_j, KEYSYM_k, KEYSYM_l,
+       KEYSYM_m, KEYSYM_n, KEYSYM_o,
+       KEYSYM_p, KEYSYM_q, KEYSYM_r,
+       KEYSYM_s, KEYSYM_t, KEYSYM_u,
+       KEYSYM_v, KEYSYM_w, KEYSYM_x,
+       KEYSYM_y, KEYSYM_z,
+       
+       // 0x1E / 30
+       KEYSYM_1, KEYSYM_2,
+       KEYSYM_3, KEYSYM_4,
+       KEYSYM_5, KEYSYM_6,
+       KEYSYM_7, KEYSYM_8,
+       KEYSYM_9, KEYSYM_0,
+       
+       KEYSYM_RETURN,  // Enter
+       KEYSYM_ESC,     // Esc.
+       KEYSYM_BACKSP,  // Backspace
+       KEYSYM_TAB,     // Tab
+       KEYSYM_SPACE,   // Spacebar
+       KEYSYM_MINUS,   // - _
+       KEYSYM_EQUALS,  // = +
+       KEYSYM_SQUARE_OPEN,     // [ {
+       KEYSYM_SQUARE_CLOSE,    // ] }
+       KEYSYM_BACKSLASH,       // \ |
+       KEYSYM_HASH_TILDE,      // # ~ (Non-US)
+       KEYSYM_SEMICOLON,       // ; :
+       KEYSYM_QUOTE,   // ' "
+       KEYSYM_GRAVE_TILDE,     // Grave Accent, Tilde
+       KEYSYM_COMMA,   // , <
+       KEYSYM_PERIOD,  // . >
+       KEYSYM_SLASH,   // / ?
+       KEYSYM_CAPS,    // Caps Lock
+       KEYSYM_F1, KEYSYM_F2,
+       KEYSYM_F3, KEYSYM_F4,
+       KEYSYM_F5, KEYSYM_F6,
+       KEYSYM_F7, KEYSYM_F8,
+       KEYSYM_F9, KEYSYM_F10,
+       KEYSYM_F11, KEYSYM_F12,
+       KEYSYM_PRINTSCREEN,
+       KEYSYM_SCROLLLOCK,
+       KEYSYM_PAUSE,
+       KEYSYM_INSERT,
+       KEYSYM_HOME,
+       KEYSYM_PGUP,
+       KEYSYM_DELETE,
+       KEYSYM_END,
+       KEYSYM_PGDN,
+       KEYSYM_RIGHTARROW,
+       KEYSYM_LEFTARROW,
+       KEYSYM_DOWNARROW,
+       KEYSYM_UPARROW,
+       
+       KEYSYM_NUMLOCK,
+       KEYSYM_KPSLASH,
+       KEYSYM_KPSTAR,
+       KEYSYM_KPMINUS,
+       KEYSYM_KPPLUS,
+       KEYSYM_KPENTER,
+       KEYSYM_KP1,
+       KEYSYM_KP2,
+       KEYSYM_KP3,
+       KEYSYM_KP4,
+       KEYSYM_KP5,
+       KEYSYM_KP7,
+       KEYSYM_KP8,
+       KEYSYM_KP9
+       KEYSYM_KP0,
+       KEYSYM_KPPERIOD,
+       
+       KEYSYM_NONUS_BACKSLASH,
+       KEYSYM_APPLICATION,     // Windows Key
+       KEYSYM_POWER,
+       KEYSYM_KPEQUALS,
+       
+       KEYSYM_F13, KEYSYM_F14,
+       KEYSYM_F15, KEYSYM_F16,
+       KEYSYM_F17, KEYSYM_F18,
+       KEYSYM_F19, KEYSYM_F20,
+       KEYSYM_F21, KEYSYM_F22,
+       KEYSYM_F23, KEYSYM_F24,
+       KEYSYM_EXECUTE,
+       KEYSYM_HELP,
+       KEYSYM_MENU,
+       KEYSYM_SELECT,
+       KEYSYM_STOP,
+       KEYSYM_AGAIN,
+       KEYSYM_UNDO,
+       KEYSYM_CUT,
+       KEYSYM_COPY,
+       KEYSYM_PASTE,
+       KEYSYM_FIND,
+       KEYSYM_MUTE,
+       KEYSYM_VOLUP,
+       KEYSYM_VOLDN,
+       KEYSYM_LOCKING_CAPS,    // Physically toggles
+       KEYSYM_LOGKING_NUM,
+       KEYSYM_LOGKING_SCROLL,
+       KEYSYM_KPCOMMA
+       
+       // TODO: Define the rest
+};
+
+#endif
+
diff --git a/KernelLand/Modules/USB/HID/main.c b/KernelLand/Modules/USB/HID/main.c
new file mode 100644 (file)
index 0000000..31375b0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Acess2 USB Stack HID Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Driver Core
+ */
+#define DEBUG  0
+#define VERSION        VER2(0,1)
+#include <acess.h>
+#include <usb_core.h>
+
+// === PROTOTYPES ===
+ int   HID_Initialise(const char **Arguments);
+void   HID_DeviceConnected(tUSBInterface *Dev);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_HID, HID_Initialise, NULL, "USB_Core", NULL);
+tUSBDriver     gHID_Driver = {
+       .Name = "HID",
+       .Match = {.Class = {0x030000, 0xFF0000}},
+       .Connected = HID_DeviceConnected,
+};
+
+// === CODE ===
+int HID_Initialise(const char **Arguments)
+{
+       USB_RegisterDriver( &gHID_Driver );
+       return 0;
+}
+
+void HID_DeviceConnected(tUSBInterface *Dev)
+{
+       
+}
+
diff --git a/KernelLand/Modules/USB/Makefile.tpl b/KernelLand/Modules/USB/Makefile.tpl
new file mode 100644 (file)
index 0000000..8df7098
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = USB
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/USB/OHCI/ohci.h b/KernelLand/Modules/USB/OHCI/ohci.h
new file mode 100644 (file)
index 0000000..30eeb96
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Acess2 OHCI Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * ohci.h
+ * - Core Header
+ */
+#ifndef _OHCI_H_
+#define _OHCI_H_
+
+struct sEndpointDesc
+{
+       //  0: 6 = Address
+       //  7:10 = Endpoint Num
+       // 11:12 = Direction (TD, OUT, IN, TD)
+       // 13    = Speed (Full, Low)
+       // 14    = Skip entry
+       // 15    = Format (Others, Isochronous)
+       // 16:26 = Max Packet Size
+       // 27:31 = AVAIL
+       Uint32  Flags;
+       //  0: 3 = AVAIL
+       //  4:31 = TailP
+       Uint32  TailP;  // Last TD in queue
+       //  0    = Halted (Queue stopped due to error)
+       //  1    = Data toggle carry
+       //  2: 3 = ZERO
+       //  4:31 = HeadP
+       Uint32  HeadP;  // First TD in queue
+       //  0: 3 = AVAIL
+       //  4:31 = NextED
+       Uint32  NextED; // Next endpoint descriptor
+};
+
+struct sGeneralTD
+{
+       //  0:17 = AVAIL
+       // 18    = Buffer Rounding (Allow an undersized packet)
+       // 19:20 = Direction (SETUP, OUT, IN, Resvd)
+       // 21:23 = Delay Interrupt (Frame count, 7 = no int)
+       // 24:25 = Data Toggle (ToggleCarry, ToggleCarry, 0, 1)
+       // 26:27 = Error Count
+       // 28:31 = Condition Code
+       Uint32  Flags;
+       
+       // Base address of packet (or current when being read)
+       Uint32  CBP;
+       
+       Uint32  NextTD;
+       
+       // Address of final byte in buffer
+       Uint32  BE;
+};
+
+struct sIsochronousTD
+{
+       //  0:15 = Starting Frame
+       // 16:20 = AVAIL
+       // 21:23 = Delay Interrupt
+       // 24:26 = Frame Count - 1 (1, 2, 3, 4, 5, 6, 7, 8)
+       // 27    = AVAIL
+       // 28:31 = Condition Code
+       Uint32  Flags;
+       
+       //  0:11 = AVAIL
+       // 12:31 = Page number of first byte in buffer
+       Uint32  BP0;    // Buffer Page 0
+       
+       Uint32  NextTD;
+       
+       // Address of last byte in buffer
+       Uint32  BufferEnd;
+       
+       //  0:11 = Page Offset
+       // 12    = Page selector (BufferPage0, BufferEnd)
+       // 13:15 = Unused?
+       Uint16  Offsets[8];
+};
+
+#endif
+
diff --git a/KernelLand/Modules/USB/UHCI/Makefile b/KernelLand/Modules/USB/UHCI/Makefile
new file mode 100644 (file)
index 0000000..798159a
--- /dev/null
@@ -0,0 +1,8 @@
+#
+#
+
+OBJ = uhci.o
+CPPFLAGS = -I../Core/include
+NAME = UHCI
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c
new file mode 100644 (file)
index 0000000..7b40b14
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * Acess 2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * Universal Host Controller Interface
+ */
+#define DEBUG  0
+#define VERSION        VER2(0,5)
+#include <acess.h>
+#include <vfs.h>
+#include <drv_pci.h>
+#include <modules.h>
+#include <usb_host.h>
+#include "uhci.h"
+
+// === CONSTANTS ===
+#define        MAX_CONTROLLERS 4
+#define NUM_TDs        1024
+
+// === PROTOTYPES ===
+ int   UHCI_Initialise(char **Arguments);
+void   UHCI_Cleanup();
+tUHCI_TD       *UHCI_int_AllocateTD(tUHCI_Controller *Cont);
+void   UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD);
+void   *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void   *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void   *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData,  void *Buf, size_t Length);
+void   *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+ int   UHCI_IsTransferComplete(void *Ptr, void *Handle);
+ int   UHCI_Int_InitHost(tUHCI_Controller *Host);
+void   UHCI_CheckPortUpdate(void *Ptr);
+void   UHCI_InterruptHandler(int IRQ, void *Ptr);
+// 
+static void    _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value);
+static void    _OutWord(tUHCI_Controller *Host, int Reg, Uint16 Value);
+static void    _OutDWord(tUHCI_Controller *Host, int Reg, Uint32 Value);
+static Uint16  _InWord(tUHCI_Controller *Host, int Reg);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_UHCI, UHCI_Initialise, NULL, "USB_Core", NULL);
+tUHCI_TD       gaUHCI_TDPool[NUM_TDs];
+tUHCI_Controller       gUHCI_Controllers[MAX_CONTROLLERS];
+tUSBHostDef    gUHCI_HostDef = {
+       .SendIN = UHCI_DataIN,
+       .SendOUT = UHCI_DataOUT,
+       .SendSETUP = UHCI_SendSetup,
+       .CheckPorts = UHCI_CheckPortUpdate,
+       .IsOpComplete = UHCI_IsTransferComplete
+       };
+
+// === CODE ===
+/**
+ * \fn int UHCI_Initialise()
+ * \brief Called to initialise the UHCI Driver
+ */
+int UHCI_Initialise(char **Arguments)
+{
+        int    i=0, id=-1;
+        int    ret;
+       
+       ENTER("");
+       
+       // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices
+       while( (id = PCI_GetDeviceByClass(0x0C0300, 0xFFFFFF, id)) >= 0 && i < MAX_CONTROLLERS )
+       {
+               tUHCI_Controller        *cinfo = &gUHCI_Controllers[i];
+               Uint32  base_addr;
+               // NOTE: Check "protocol" from PCI?
+               
+               cinfo->PciId = id;
+               base_addr = PCI_GetBAR(id, 4);
+               
+               if( base_addr & 1 )
+               {
+                       cinfo->IOBase = base_addr & ~1;
+                       cinfo->MemIOMap = NULL;
+               }
+               else
+               {
+                       cinfo->MemIOMap = (void*)MM_MapHWPages(base_addr, 1);
+               }
+               cinfo->IRQNum = PCI_GetIRQ(id);
+               
+               Log_Debug("UHCI", "Controller PCI #%i: IO Base = 0x%x, IRQ %i",
+                       id, base_addr, cinfo->IRQNum);
+               
+               IRQ_AddHandler(cinfo->IRQNum, UHCI_InterruptHandler, cinfo);
+       
+               // Initialise Host
+               ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]);
+               // Detect an error
+               if(ret != 0) {
+                       LEAVE('i', ret);
+                       return ret;
+               }
+               
+               cinfo->RootHub = USB_RegisterHost(&gUHCI_HostDef, cinfo, 2);
+               LOG("cinfo->RootHub = %p", cinfo->RootHub);
+
+               i ++;
+       }
+
+       if(i == 0) {
+               LEAVE('i', MODULE_ERR_NOTNEEDED);
+               return MODULE_ERR_NOTNEEDED;
+       }
+
+       if(i == MAX_CONTROLLERS) {
+               Log_Warning("UHCI", "Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest");
+       }
+       LEAVE('i', MODULE_ERR_OK);
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \fn void UHCI_Cleanup()
+ * \brief Called just before module is unloaded
+ */
+void UHCI_Cleanup()
+{
+}
+
+tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont)
+{
+        int    i;
+       for(i = 0; i < NUM_TDs; i ++)
+       {
+               if(gaUHCI_TDPool[i].Link == 0) {
+                       gaUHCI_TDPool[i].Link = 1;
+                       gaUHCI_TDPool[i].Control = 1 << 23;
+                       return &gaUHCI_TDPool[i];
+               }
+               // Still in use? Skip
+               if( gaUHCI_TDPool[i].Control & (1 << 23) )
+                       continue ;
+               // Is there a callback on it? Skip
+               if( gaUHCI_TDPool[i]._info.Callback )
+                       continue ;
+               // TODO: Garbage collect, but that means removing from the list too
+               #if 0
+               // Ok, this is actually unused
+               gaUHCI_TDPool[i].Link = 1;
+               gaUHCI_TDPool[i].Control = 1 << 23;
+               return &gaUHCI_TDPool[i];
+               #endif
+       }
+       return NULL;
+}
+
+tUHCI_TD *UHCI_int_GetTDFromPhys(tPAddr PAddr)
+{
+       // TODO: Fix this to work with a non-contiguous pool
+       static tPAddr   td_pool_base;
+       const int pool_size = NUM_TDs;
+        int    offset;
+       if(!td_pool_base)       td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
+       offset = (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
+       if( offset < 0 || offset >= pool_size )
+       {
+               Log_Error("UHCI", "TD PAddr %P not from pool", PAddr);
+               return NULL;
+       }
+       return gaUHCI_TDPool + offset;
+}
+
+void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD)
+{
+        int    next_frame = (_InWord(Cont, FRNUM) + 2) & (1024-1);
+       tUHCI_TD        *prev_td;
+       Uint32  link;
+
+       // TODO: How to handle FRNUM incrementing while we are in this function?
+
+       // Empty list
+       if( Cont->FrameList[next_frame] & 1 )
+       {
+               // TODO: Ensure 32-bit paddr
+               Cont->FrameList[next_frame] = MM_GetPhysAddr( (tVAddr)TD );
+               TD->Control |= (1 << 24);       // Ensure that there is an interrupt for each used frame
+               LOG("next_frame = %i", next_frame);     
+               return;
+       }
+
+       // Find the end of the list
+       link = Cont->FrameList[next_frame];
+       do {
+               prev_td = UHCI_int_GetTDFromPhys(link);
+               link = prev_td->Link;
+       } while( !(link & 1) );
+       
+       // Append
+       prev_td->Link = MM_GetPhysAddr( (tVAddr)TD );
+
+       LOG("next_frame = %i, prev_td = %p", next_frame, prev_td);
+}
+
+/**
+ * \brief Send a transaction to the USB bus
+ * \param Cont Controller pointer
+ * \param Addr Function Address * 16 + Endpoint
+ * \param bTgl Data toggle value
+ */
+void *UHCI_int_SendTransaction(
+       tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl,
+       tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
+{
+       tUHCI_TD        *td;
+
+       if( Length > 0x400 )    return NULL;    // Controller allows up to 0x500, but USB doesn't
+
+       td = UHCI_int_AllocateTD(Cont);
+
+       if( !td ) {
+               // TODO: Wait for one to free?
+               Log_Error("UHCI", "No avaliable TDs, transaction dropped");
+               return NULL;
+       }
+
+       td->Link = 1;
+       td->Control = (Length - 1) & 0x7FF;
+       td->Control |= (1 << 23);
+       td->Token  = ((Length - 1) & 0x7FF) << 21;
+       td->Token |= (bTgl & 1) << 19;
+       td->Token |= (Addr & 0xF) << 15;
+       td->Token |= ((Addr/16) & 0xFF) << 8;
+       td->Token |= Type;
+
+       // TODO: Ensure 32-bit paddr
+       if( ((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE ) {
+               Log_Warning("UHCI", "TODO: Support non single page transfers (%x + %x > %x)",
+                       (tVAddr)Data & (PAGE_SIZE-1), Length, PAGE_SIZE
+                       );
+               // TODO: Need to enable IOC to copy the data back
+//             td->BufferPointer = 
+               td->_info.bCopyData = 1;
+               return NULL;
+       }
+       else {
+               td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
+               td->_info.bCopyData = 0;
+       }
+
+       // Interrupt on completion
+       if( Cb ) {
+               td->Control |= (1 << 24);
+               LOG("IOC Cb=%p CbData=%p", Cb, CbData);
+               td->_info.Callback = Cb;        // NOTE: if ERRPTR then the TD is kept allocated until checked
+               td->_info.CallbackPtr = CbData;
+       }
+       
+       td->_info.DataPtr = Data;
+
+       UHCI_int_AppendTD(Cont, td);
+
+       return td;
+}
+
+void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+{
+       return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x69, DataTgl, Cb, CbData, Buf, Length);
+}
+
+void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+{
+       return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0xE1, DataTgl, Cb, CbData, Buf, Length);
+}
+
+void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+{
+       return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, Cb, CbData, Buf, Length);
+}
+
+int UHCI_IsTransferComplete(void *Ptr, void *Handle)
+{
+       tUHCI_TD        *td = Handle;
+        int    ret;
+       ret = !(td->Control & (1 << 23));
+       if(ret) {
+               td->_info.Callback = NULL;
+               td->Link = 0;
+       }
+       return ret;
+}
+
+// === INTERNAL FUNCTIONS ===
+/**
+ * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host)
+ * \brief Initialises a UHCI host controller
+ * \param Host Pointer - Host to initialise
+ */
+int UHCI_Int_InitHost(tUHCI_Controller *Host)
+{
+       ENTER("pHost", Host);
+
+       _OutWord( Host, USBCMD, 4 );    // GRESET
+       // TODO: Wait for at least 10ms
+       _OutWord( Host, USBCMD, 0 );    // GRESET
+       
+       // Allocate Frame List
+       // - 1 Page, 32-bit address
+       // - 1 page = 1024  4 byte entries
+       Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList);
+       if( !Host->FrameList ) {
+               Log_Warning("UHCI", "Unable to allocate frame list, aborting");
+               LEAVE('i', -1);
+               return -1;
+       }
+       LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList);
+       memsetd( Host->FrameList, 1, 1024 );    // Clear List (Disabling all entries)
+       
+       //! \todo Properly fill frame list
+       
+       // Set frame length to 1 ms
+       _OutByte( Host, SOFMOD, 64 );
+       
+       // Set Frame List
+       _OutDWord( Host, FLBASEADD, Host->PhysFrameList );
+       _OutWord( Host, FRNUM, 0 );
+       
+       // Enable Interrupts
+       _OutWord( Host, USBINTR, 0x000F );
+       PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 );
+
+       // Enable processing
+       _OutWord( Host, USBCMD, 0x0001 );
+
+       LEAVE('i', 0);
+       return 0;
+}
+
+void UHCI_CheckPortUpdate(void *Ptr)
+{
+       tUHCI_Controller        *Host = Ptr;
+       // Enable ports
+       for( int i = 0; i < 2; i ++ )
+       {
+                int    port = PORTSC1 + i*2;
+               Uint16  status;
+       
+               status = _InWord(Host, port);
+               // Check for port change
+               if( !(status & 0x0002) )        continue;
+               _OutWord(Host, port, 0x0002);
+               
+               // Check if the port is connected
+               if( !(status & 1) )
+               {
+                       // Tell the USB code it's gone.
+                       USB_DeviceDisconnected(Host->RootHub, i);
+                       continue;
+               }
+               else
+               {
+                       LOG("Port %i has something", i);
+                       // Reset port (set bit 9)
+                       LOG("Reset");
+                       _OutWord(Host, port, 0x0200);
+                       Time_Delay(50); // 50ms delay
+                       _OutWord(Host, port, _InWord(Host, port) & ~0x0200);
+                       // Enable port
+                       LOG("Enable");
+                       Time_Delay(50); // 50ms delay
+                       _OutWord(Host, port, _InWord(Host, port) | 0x0004);
+                       // Tell USB there's a new device
+                       USB_DeviceConnected(Host->RootHub, i);
+               }
+       }
+}
+
+void UHCI_InterruptHandler(int IRQ, void *Ptr)
+{
+       tUHCI_Controller *Host = Ptr;
+        int    frame = (_InWord(Host, FRNUM) - 1) & 0x3FF;
+       Uint16  status = _InWord(Host, USBSTS);
+//     Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x, frame = %i", status, frame);
+       
+       // Interrupt-on-completion
+       if( status & 1 )
+       {
+               tPAddr  link;
+               
+               for( int i = 0; i < 10; i ++ )
+               {
+                       link = Host->FrameList[frame];
+                       Host->FrameList[frame] = 1;
+                       while( link && !(link & 1) )
+                       {
+                               tUHCI_TD *td = UHCI_int_GetTDFromPhys(link);
+                                int    byte_count = (td->Control&0x7FF)+1;
+                               LOG("link = 0x%x, td = %p, byte_count = %i", link, td, byte_count);
+                               // Handle non-page aligned destination
+                               // TODO: This will break if the destination is not in global memory
+                               if(td->_info.bCopyData)
+                               {
+                                       void *ptr = (void*)MM_MapTemp(td->BufferPointer);
+                                       Log_Debug("UHCI", "td->_info.DataPtr = %p", td->_info.DataPtr);
+                                       memcpy(td->_info.DataPtr, ptr, byte_count);
+                                       MM_FreeTemp((tVAddr)ptr);
+                               }
+                               // Callback
+                               if(td->_info.Callback && td->_info.Callback != INVLPTR)
+                               {
+                                       LOG("Calling cb %p", td->_info.Callback);
+                                       td->_info.Callback(td->_info.CallbackPtr, td->_info.DataPtr, byte_count);
+                                       td->_info.Callback = NULL;
+                               }
+                               link = td->Link;
+                               if( td->_info.Callback != INVLPTR )
+                                       td->Link = 0;
+                       }
+                       
+                       if(frame == 0)
+                               frame = 0x3ff;
+                       else
+                               frame --;
+               }
+               
+//             Host->LastCleanedFrame = frame;
+       }
+
+       LOG("status = 0x%02x", status);
+       _OutWord(Host, USBSTS, status);
+}
+
+void _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value)
+{
+       if( Host->MemIOMap )
+               ((Uint8*)Host->MemIOMap)[Reg] = Value;
+       else
+               outb(Host->IOBase + Reg, Value);
+}
+
+void _OutWord(tUHCI_Controller *Host, int Reg, Uint16 Value)
+{
+       if( Host->MemIOMap )
+               Host->MemIOMap[Reg/2] = Value;
+       else
+               outw(Host->IOBase + Reg, Value);
+}
+
+void _OutDWord(tUHCI_Controller *Host, int Reg, Uint32 Value)
+{
+       if( Host->MemIOMap )
+               ((Uint32*)Host->MemIOMap)[Reg/4] = Value;
+       else
+               outd(Host->IOBase + Reg, Value);
+}
+
+Uint16 _InWord(tUHCI_Controller *Host, int Reg)
+{
+       if( Host->MemIOMap )
+               return Host->MemIOMap[Reg/2];
+       else
+               return inw(Host->IOBase + Reg);
+}
+
diff --git a/KernelLand/Modules/USB/UHCI/uhci.h b/KernelLand/Modules/USB/UHCI/uhci.h
new file mode 100644 (file)
index 0000000..a93459a
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * AcessOS Version 1
+ * USB Stack
+ * - Universal Host Controller Interface
+ */
+#ifndef _UHCI_H_
+#define _UHCI_H_
+
+// === TYPES ===
+typedef struct sUHCI_Controller        tUHCI_Controller;
+typedef struct sUHCI_TD        tUHCI_TD;
+typedef struct sUHCI_QH        tUHCI_QH;
+
+// === STRUCTURES ===
+struct sUHCI_Controller
+{
+       /**
+        * \brief PCI Device ID
+        */
+       Uint16  PciId;
+       
+       /**
+        * \brief IO Base Address
+        */
+       Uint16  IOBase;
+       
+       /**
+        * \brief Memory Mapped-IO base address
+        */
+       Uint16  *MemIOMap;
+
+       /**
+        * \brief IRQ Number assigned to the device
+        */
+        int    IRQNum;
+
+       /**
+        * \brief Number of the last frame to be cleaned
+        */
+        int    LastCleanedFrame;
+       
+       /**
+        * \brief Frame list
+        * 
+        * 31:4 - Frame Pointer
+        * 3:2 - Reserved
+        * 1 - QH/TD Selector
+        * 0 - Terminate (Empty Pointer)
+        */
+       Uint32  *FrameList;
+       
+       /**
+        * \brief Physical Address of the Frame List
+        */
+       tPAddr  PhysFrameList;
+
+       tUSBHub *RootHub;
+};
+
+struct sUHCI_TD
+{
+       /**
+        * \brief Next Entry in list
+        * 
+        * 31:4 - Address
+        * 3 - Reserved
+        * 2 - Depth/Breadth Select
+        * 1 - QH/TD Select
+        * 0 - Terminate (Last in List)
+        */
+       Uint32  Link;
+       
+       /**
+        * \brief Control and Status Field
+        * 
+        * 31:30 - Reserved
+        * 29 - Short Packet Detect (Input Only)
+        * 28:27 - Number of Errors Allowed
+        * 26 - Low Speed Device (Communicating with a low speed device)
+        * 25 - Isynchonious Select
+        * 24 - Interrupt on Completion (IOC)
+        * 23:16 - Status
+        *     23 - Active
+        *     22 - Stalled
+        *     21 - Data Buffer Error
+        *     20 - Babble Detected
+        *     19 - NAK Detected
+        *     18 - CRC/Timout Error
+        *     17 - Bitstuff Error
+        *     16 - Reserved
+        * 15:11 - Reserved
+        * 10:0 - Actual Length (Number of bytes transfered)
+        */
+       Uint32  Control;
+       
+       /**
+        * \brief Packet Header
+        * 
+        * 31:21 - Maximum Length (0=1, Max 0x4FF, 0x7FF=0)
+        * 20 - Reserved
+        * 19 - Data Toggle
+        * 18:15 - Endpoint
+        * 14:8 - Device Address
+        * 7:0 - PID (Packet Identifcation) - Only 96, E1, 2D allowed
+        *
+        * 0x96 = Data IN
+        * 0xE1 = Data Out
+        * 0x2D = Setup
+        */
+       Uint32  Token;
+       
+       /**
+        * \brief Pointer to the data to send
+        */
+       Uint32  BufferPointer;
+
+       struct
+       {
+               tUSBHostCb      Callback;
+               void    *CallbackPtr;
+               void    *DataPtr;
+                int    bCopyData;
+       } _info;
+} __attribute__((aligned(16)));
+
+struct sUHCI_QH
+{
+       /**
+        * \brief Next Entry in list
+        * 
+        * 31:4 - Address
+        * 3:2 - Reserved
+        * 1 - QH/TD Select
+        * 0 - Terminate (Last in List)
+        */
+       Uint32  Next;
+
+       
+       /**
+        * \brief Next Entry in list
+        * 
+        * 31:4 - Address
+        * 3:2 - Reserved
+        * 1 - QH/TD Select
+        * 0 - Terminate (Last in List)
+        */
+       Uint32  Child;
+};
+
+// === ENUMERATIONS ===
+enum eUHCI_IOPorts {
+       /**
+        * \brief USB Command Register
+        * 
+        * 15:8 - Reserved
+        * 7 - Maximum Packet Size selector (1: 64 bytes, 0: 32 bytes)
+        * 6 - Configure Flag (No Hardware Effect)
+        * 5 - Software Debug (Don't think it will be needed)
+        * 4 - Force Global Resume
+        * 3 - Enter Global Suspend Mode
+        * 2 - Global Reset (Resets all devices on the bus)
+        * 1 - Host Controller Reset (Reset just the controller)
+        * 0 - Run/Stop
+        */
+       USBCMD  = 0x00,
+       /**
+        * \brief USB Status Register
+        * 
+        * 15:6 - Reserved
+        * 5 - HC Halted, set to 1 when USBCMD:RS is set to 0
+        * 4 - Host Controller Process Error (Errors related to the bus)
+        * 3 - Host System Error (Errors related to the OS/PCI Bus)
+        * 2 - Resume Detect (Set if a RESUME command is sent to the Controller)
+        * 1 - USB Error Interrupt
+        * 0 - USB Interrupts (Set if a transaction with the IOC bit set is completed)
+        */
+       USBSTS  = 0x02,
+       /**
+        * \brief USB Interrupt Enable Register
+        * 
+        * 15:4 - Reserved
+        * 3 - Short Packet Interrupt Enable
+        * 2 - Interrupt on Complete (IOC) Enable
+        * 1 - Resume Interrupt Enable
+        * 0 - Timout / CRC Error Interrupt Enable
+        */
+       USBINTR = 0x04,
+       /**
+        * \brief Frame Number (Index into the Frame List)
+        * 
+        * 15:11 - Reserved
+        * 10:0 - Index (Incremented each approx 1ms)
+        */
+       FRNUM   = 0x06,
+       /**
+        * \brief Frame List Base Address
+        * 
+        * 31:12 - Pysical Address >> 12
+        * 11:0 - Reserved (Set to Zero)
+        */
+       FLBASEADD = 0x08,       // 32-bit
+       /**
+        * \brief Start-of-frame Modify Register
+        * \note 8-bits only
+        * 
+        * Sets the size of a frame
+        * Frequency = (11936+n)/12000 kHz
+        * 
+        * 7 - Reserved
+        * 6:0 -
+        */
+       SOFMOD = 0x0C,  // 8bit
+       /**
+        * \brief Port Status and Controll Register (Port 1)
+        * 
+        * 15:13 - Reserved
+        * 12 - Suspend
+        * 11:10 - Reserved
+        * 9 - Port Reset
+        * 8 - Low Speed Device Attached
+        * 5:4 - Line Status
+        * 3 - Port Enable/Disable Change - Used for detecting device removal
+        * 2 - Port Enable/Disable
+        * 1 - Connect Status Change
+        * 0 - Current Connect Status
+        */
+       PORTSC1 = 0x10,
+       /**
+        * \brief Port Status and Controll Register (Port 2)
+        * 
+        * See ::PORTSC1
+        */
+       PORTSC2 = 0x12
+};
+
+#endif
diff --git a/KernelLand/Modules/armv7/GIC/Makefile b/KernelLand/Modules/armv7/GIC/Makefile
new file mode 100644 (file)
index 0000000..d4a72b6
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ := gic.o
+NAME := GIC
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/armv7/GIC/gic.c b/KernelLand/Modules/armv7/GIC/gic.c
new file mode 100644 (file)
index 0000000..8dbab3a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * ARMv7 GIC Support
+ * - By John Hodge (thePowersGang)
+ * 
+ * gic.c
+ * - GIC Core
+ */
+#define DEBUG  1
+
+#include <acess.h>
+#include <modules.h>
+#include "gic.h"
+#include <options.h>
+
+#define N_IRQS 1024
+
+// === IMPORTS ===
+extern void    *gpIRQHandler;
+
+// === TYPES ===
+typedef void (*tIRQ_Handler)(int, void*);
+
+// === PROTOTYPES ===
+ int   GIC_Install(char **Arguments);
+void   GIC_IRQHandler(void);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x100, armv7_GIC, GIC_Install, NULL, NULL);
+Uint32 *gpGIC_DistributorBase;
+Uint32 *gpGIC_InterfaceBase;
+tPAddr gGIC_DistributorAddr;
+tPAddr gGIC_InterfaceAddr;
+tIRQ_Handler   gaIRQ_Handlers[N_IRQS];
+void   *gaIRQ_HandlerData[N_IRQS];
+
+// === CODE ===
+int GIC_Install(char **Arguments)
+{
+       // Realview PB
+       gGIC_InterfaceAddr   = 0x1e000000;
+       gGIC_DistributorAddr = 0x1e001000;
+
+       // Initialise
+       gpGIC_InterfaceBase = (void*)MM_MapHWPages(gGIC_InterfaceAddr, 1);
+       LOG("gpGIC_InterfaceBase = %p", gpGIC_InterfaceBase);
+       gpGIC_DistributorBase = (void*)MM_MapHWPages(gGIC_DistributorAddr, 1);
+       LOG("gpGIC_DistributorBase = %p", gpGIC_DistributorBase);
+
+       gpGIC_InterfaceBase[GICC_PMR] = 0xFF;   
+       gpGIC_InterfaceBase[GICC_CTLR] = 1;     // Enable CPU
+       gpGIC_DistributorBase[GICD_CTLR] = 1;   // Enable Distributor
+
+       gpIRQHandler = GIC_IRQHandler;
+
+       __asm__ __volatile__ ("cpsie if");      // Enable IRQs and FIQs
+
+       return MODULE_ERR_OK;
+}
+
+void GIC_IRQHandler(void)
+{
+       Uint32  num = gpGIC_InterfaceBase[GICC_IAR];
+//     Log_Debug("GIC", "IRQ 0x%x", num);
+       gaIRQ_Handlers[num]( num, gaIRQ_HandlerData[num] );
+       gpGIC_InterfaceBase[GICC_EOIR] = num;
+}
+
+int IRQ_AddHandler(int IRQ, tIRQ_Handler Handler, void *Ptr)
+{
+       if( IRQ < 0 || IRQ >= N_IRQS-32 ) {
+               return 1;
+       }
+       
+       LOG("IRQ = %i", IRQ);
+       IRQ += 32;      // 32 internal IRQs
+       LOG("IRQ = %i (after adjust)", IRQ);
+       LOG("mask = 0x%x", 1 << (IRQ & (31-1)));
+       gpGIC_DistributorBase[GICD_ISENABLER0+IRQ/32] = 1 << (IRQ & (32-1));
+       ((Uint8*)&gpGIC_DistributorBase[GICD_ITARGETSR0])[IRQ] = 1;
+       
+//     Log_Warning("GIC", "TODO: Implement IRQ_AddHandler");
+       
+       if( gaIRQ_Handlers[IRQ] )
+               return 2;
+       
+       gaIRQ_Handlers[IRQ] = Handler;
+       gaIRQ_HandlerData[IRQ] = Ptr;
+       
+       return 0;
+}
+
diff --git a/KernelLand/Modules/armv7/GIC/gic.h b/KernelLand/Modules/armv7/GIC/gic.h
new file mode 100644 (file)
index 0000000..d7a5a8d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * ARMv7 GIC Support
+ * - By John Hodge (thePowersGang)
+ * 
+ * gic.h
+ * - GIC Core Definitions
+ */
+#ifndef _ARM7_GIC_H_
+#define _ARM7_GIC_H_
+
+enum eGICD_Registers
+{
+       GICD_CTLR       = 0x000/4,      // Distributor Control Register
+       GICD_TYPER      = 0x004/4,      // Interrupt Controller Type
+       GICD_IIDR       = 0x008/4,      // Distributor Implementer Identifcation
+       
+       GICD_IGROUPR0   = 0x080/4,      // Interrupt Group Register (#0)
+       GICD_ISENABLER0 = 0x100/4,      // Interrupt Set-Enable Register #0 (128*8=1024)
+       GICD_ICENABLER0 = 0x180/4,      // Interrupt Clear-Enable Register #0
+       GICD_ISPENDR0   = 0x200/4,      // Interrupt Set-Pending Register #0
+       GICD_ICPENDR0   = 0x280/4,      // Interrupt Clear-Pending Register #0
+       GICD_ISACTIVER0 = 0x300/4,      // Interrupt Set-Active Register (GICv2)
+       GICD_ICACTIVER0 = 0x380/4,      // Interrupt Clear-Active Register (GICv2)
+       
+       GICD_IPRIORITYR0 = 0x400/4,     // Interrupt priority registers (254*4 = )
+       
+       GICD_ITARGETSR0 = 0x800/4,      // Interrupt Processor Targets Register (8*4)
+
+       GICD_ICFGR0     = 0xC00/4,      // Interrupt Configuration Register (64*4)
+       GICD_NSACR0     = 0xE00/4,      // Non-secure Access Control Register (64*4)
+       GICD_SIGR       = 0xF00/4,      // Software Generated Interrupt Register (Write Only)
+       GICD_CPENDSGIR0 = 0xF10/4,      // SGI Clear-Pending Registers (4*4)
+       GICD_SPENDSGIR0 = 0xF20/4,      // SGI Set-Pending Registers (4*4)
+};
+
+enum eGICC_Registers
+{
+       GICC_CTLR   = 0x000/4,  // CPU Interface Control Register
+       GICC_PMR    = 0x004/4,  // Interrupt Priority Mask Register
+       GICC_BPR    = 0x008/4,  // Binary Point Register
+       GICC_IAR    = 0x00C/4,  // Interrupt Acknowledge Register
+       GICC_EOIR   = 0x010/4,  // End of Interrupt Register
+       GICC_RPR    = 0x014/4,  // Running Priority Register
+       GICC_HPPIR  = 0x018/4,  // Highest Priority Pending Interrupt Register
+       GICC_ABPR   = 0x01C/4,  // Aliased Binary Point Register
+       GICC_AIAR   = 0x020/4,  // Aliased Interrupt Acknowledge Register,
+       GICC_AEOIR  = 0x024/4,  // Aliased End of Interrupt Register
+       GICC_AHPPIR = 0x028/4,  // Aliased Highest Priority Pending Interrupt Register
+
+       GICC_APR0   = 0x0D0/4,  // Active Priorities Registers (4*4)
+       GICC_NSAPR0 = 0x0E0/4,  // Non-secure Active Priorities Registers (4*4)
+       
+       GICC_IIDR   = 0x0FC/4,  // CPU Interface Identifcation Register
+       GICC_DIR    = 0x0FC/4,  // Deactivate Interrupt Register (Write Only)
+};
+
+#endif
diff --git a/KernelLand/Modules/armv7/Makefile.tpl b/KernelLand/Modules/armv7/Makefile.tpl
new file mode 100644 (file)
index 0000000..58eb3c9
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = armv7
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/link.ld b/KernelLand/Modules/link.ld
new file mode 100644 (file)
index 0000000..503f63d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Acess2 Kernel Modules
+ * Linker Script
+ */
+
+ENTRY(ModuleEntry)
+OUTPUT_FORMAT(elf32-i386)
+
+SECTIONS 
+{
+       . = 0 + SIZEOF_HEADERS;
+       
+       .text : AT(ADDR(.text)) {
+               textzero = .;
+               *(.text)
+       }
+       
+       .rodata ALIGN(0x1000): AT(ADDR(.rodata)) {
+               *(.rodata)
+               *(.rdata)
+               DriverInfo = .;
+               *(KMODULES)
+       }
+       
+       .data ALIGN (0x1000) : AT(ADDR(.data)) {
+               *(.data)
+       }
+
+       .bss : AT(ADDR(.bss)) {
+               _sbss = .;
+               *(COMMON)
+               *(.bss)
+               _ebss = .;
+       }
+}
diff --git a/KernelLand/Modules/x86/ISADMA/Makefile b/KernelLand/Modules/x86/ISADMA/Makefile
new file mode 100644 (file)
index 0000000..b74c63f
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ := dma.o
+NAME := ISADMA
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/x86/ISADMA/dma.c b/KernelLand/Modules/x86/ISADMA/dma.c
new file mode 100644 (file)
index 0000000..732a93c
--- /dev/null
@@ -0,0 +1,122 @@
+/*\r
+ * AcessOS 1.0\r
+ * DMA Driver\r
+ */\r
+#include <acess.h>\r
+#include <modules.h>\r
+\r
+#define DMA_SIZE       (0x2400)\r
+#define DMA_ADDRESS(c) ((c)*DMA_SIZE+0x500)    //Save Space for IDT and BDA\r
+\r
+#define LOWB(x)        ((x)&0xFF)\r
+#define HIB(x) (((x)>>8)&0xFF)\r
+#define HIW(x) (((x)>>16)&0xFFFF)\r
+\r
+// === TYPES ===\r
+typedef struct\r
+{\r
+        int    mode;\r
+       char    *address;\r
+} t_dmaChannel;\r
+\r
+// === PROTOTYPES ===\r
+ int   DMA_Install(char **Arguments);\r
+void   DMA_SetChannel(int Channel, int length, int read);\r
+ int   DMA_ReadData(int channel, int count, void *buffer);\r
+ int   DMA_WriteData(int channel, int count, const void *buffer);\r
+\r
+// === CONSTANTS ===\r
+const Uint8 cMASKPORT [8] = { 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 };\r
+const Uint8 cMODEPORT [8] = { 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 };\r
+const Uint8 cCLEARPORT[8] = { 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 };\r
+const Uint8 cPAGEPORT [8] = { 0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A };\r
+const Uint8 cADDRPORT [8] = { 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC };\r
+const Uint8 cCOUNTPORT[8] = { 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE };\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0100, x86_ISADMA, DMA_Install, NULL, NULL);\r
+char   *dma_addresses[8];\r
+t_dmaChannel   dma_channels[8];\r
+\r
+// === CODE ===\r
+/**\r
+ * \brief Initialise DMA channels\r
+ * \param Arguments    Arguments passed at boot time\r
+ */\r
+int DMA_Install(char **Arguments)\r
+{\r
+       Uint    i;\r
+       for(i=8;i--;)\r
+       {\r
+               outb( cMASKPORT[i], 0x04 | (i & 0x3) ); // mask channel\r
+               outb( cCLEARPORT[i], 0x00 );\r
+               outb( cMODEPORT[i], 0x48 | (i & 0x3) ); //Read Flag\r
+               outb( 0xd8, 0xff);      //Reset Flip-Flop\r
+               outb( cADDRPORT[i], LOWB(DMA_ADDRESS(i)) );     // send address\r
+               outb( cADDRPORT[i], HIB(DMA_ADDRESS(i)) );      // send address\r
+               outb( 0xd8, 0xff);      //Reset Flip-Flop\r
+               outb( cCOUNTPORT[i], LOWB(DMA_SIZE) );      // send size\r
+               outb( cCOUNTPORT[i], HIB(DMA_SIZE) );       // send size\r
+               outb( cPAGEPORT[i], LOWB(HIW(DMA_ADDRESS(i))) );        // send page\r
+               outb( cMASKPORT[i], i & 0x3 );              // unmask channel\r
+               \r
+               dma_channels[i].mode = 0;\r
+               dma_addresses[i] = (char*)DMA_ADDRESS(i);\r
+               dma_addresses[i] += KERNEL_BASE;\r
+       }\r
+       return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \fn void DMA_SetChannel(int Channel, int length, int read)\r
+ * \brief Set DMA Channel Length and RW\r
+ */\r
+void DMA_SetChannel(int Channel, int length, int read)\r
+{\r
+       Uint    chan = Channel & 7;\r
+       read = !!read;\r
+       if(length > DMA_SIZE)   length = DMA_SIZE;\r
+       length --;      //Adjust for DMA\r
+       outb( cMASKPORT[chan], 0x04 | (chan & 0x3) );           // mask channel\r
+       outb( cCLEARPORT[chan], 0x00 );\r
+       outb( cMODEPORT[chan], (0x44 + (!read)*4) | (chan & 0x3) );\r
+       outb( cADDRPORT[chan], LOWB(DMA_ADDRESS(chan)) );               // send address\r
+       outb( cADDRPORT[chan], HIB(DMA_ADDRESS(chan)) );                // send address\r
+       outb( cPAGEPORT[chan], HIW(DMA_ADDRESS(chan)) );                // send page\r
+       outb( cCOUNTPORT[chan], LOWB(length) );      // send size\r
+       outb( cCOUNTPORT[chan], HIB(length) );       // send size\r
+       outb( cMASKPORT[chan], chan & 0x3 );              // unmask channel\r
+       dma_addresses[chan] = (char*)DMA_ADDRESS(chan);\r
+       dma_addresses[chan] += KERNEL_BASE;\r
+}\r
+\r
+/**\r
+ * \fn void DMA_ReadData(int channel, int count, void *buffer)\r
+ * \brief Read data from a DMA buffer\r
+ */\r
+int DMA_ReadData(int channel, int count, void *buffer)\r
+{\r
+       if(channel < 0 || channel > 7)\r
+               return -1;\r
+       if(count < 0 || count > DMA_SIZE)\r
+               return -2;\r
+       //LogF("memcpy(*0x%x, dma_channels[channel].address, count)\n", buffer\r
+       memcpy(buffer, dma_addresses[channel], count);\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn void DMA_WriteData(int channel, int count, void *buffer)\r
+ * \brief Write data to a DMA buffer\r
+ */\r
+int DMA_WriteData(int channel, int count, const void *buffer)\r
+{\r
+       if(channel < 0 || channel > 7)\r
+               return -1;\r
+       if(count < 0 || count > DMA_SIZE)\r
+               return -2;\r
+       \r
+       memcpy(dma_addresses[channel], buffer, count);\r
+       \r
+       return 0;\r
+}\r
diff --git a/KernelLand/Modules/x86/ISADMA/include/dma.h b/KernelLand/Modules/x86/ISADMA/include/dma.h
new file mode 100644 (file)
index 0000000..b1a6d1a
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Acess2 DMA Driver
+ */
+#ifndef _DMA_H_
+#define _DMA_H_
+
+extern void    DMA_SetChannel(int channel, int length, int read);
+extern int     DMA_ReadData(int channel, int count, void *buffer);
+extern int     DMA_WriteData(int channel, int count, void *buffer);
+
+#endif
diff --git a/KernelLand/Modules/x86/Makefile.tpl b/KernelLand/Modules/x86/Makefile.tpl
new file mode 100644 (file)
index 0000000..61b234f
--- /dev/null
@@ -0,0 +1,3 @@
+CATEGORY = x86
+
+-include ../../Makefile.tpl
diff --git a/KernelLand/Modules/x86/VGAText/Makefile b/KernelLand/Modules/x86/VGAText/Makefile
new file mode 100644 (file)
index 0000000..8f1aee6
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ := vga.o
+NAME := VGAText
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/x86/VGAText/vga.c b/KernelLand/Modules/x86/VGAText/vga.c
new file mode 100644 (file)
index 0000000..41f0bd0
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Acess2 VGA Controller Driver
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <fs_devfs.h>
+#include <api_drv_video.h>
+#include <modules.h>
+
+// === CONSTANTS ===
+#define        VGA_WIDTH       80
+#define        VGA_HEIGHT      25
+
+// === PROTOTYPES ===
+ int   VGA_Install(char **Arguments);
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
+ int   VGA_IOCtl(tVFS_Node *Node, int Id, void *Data);
+Uint8  VGA_int_GetColourNibble(Uint16 col);
+Uint16 VGA_int_GetWord(const tVT_Char *Char);
+void   VGA_int_SetCursor(Sint16 x, Sint16 y);
+// --- 2D Acceleration Functions --
+void   VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
+void   VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x000A, x86_VGAText, VGA_Install, NULL, NULL);
+tVFS_NodeType  gVGA_NodeType = {
+       //.Read = VGA_Read,
+       .Write = VGA_Write,
+       .IOCtl = VGA_IOCtl
+       };
+tDevFS_Driver  gVGA_DevInfo = {
+       NULL, "x86_VGAText",
+       {
+       .NumACLs = 0,
+       .Size = VGA_WIDTH*VGA_HEIGHT*sizeof(tVT_Char),
+       .Type = &gVGA_NodeType
+       }
+};
+Uint16 *gVGA_Framebuffer = (void*)( KERNEL_BASE|0xB8000 );
+ int   giVGA_BufferFormat = VIDEO_BUFFMT_TEXT;
+tDrvUtil_Video_2DHandlers      gVGA_2DFunctions = {
+       NULL,
+       VGA_2D_Fill,
+       VGA_2D_Blit
+};
+
+// === CODE ===
+/**
+ * \fn int VGA_Install(char **Arguments)
+ */
+int VGA_Install(char **Arguments)
+{
+       Uint8   byte;
+       
+       // Enable Bright Backgrounds
+       inb(0x3DA);     // Reset flipflop
+       outb(0x3C0, 0x30);      // Index 0x10, PAS
+       byte = inb(0x3C1);
+       byte &= ~8;     // Disable Blink
+       outb(0x3C0, byte);      // Write value
+       
+       
+       // Install DevFS
+       DevFS_AddDevice( &gVGA_DevInfo );
+       
+       return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Writes a string of bytes to the VGA controller
+ */
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
+{
+       if( giVGA_BufferFormat == VIDEO_BUFFMT_TEXT )
+       {
+                int    num = Length / sizeof(tVT_Char);
+                int    ofs = Offset / sizeof(tVT_Char);
+                int    i = 0;
+               const tVT_Char  *chars = Buffer;
+               Uint16  word;
+               
+               //ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+               
+               for( ; num--; i ++, ofs ++)
+               {
+                       word = VGA_int_GetWord( &chars[i] );
+                       gVGA_Framebuffer[ ofs ] = word;
+               }
+               
+               //LEAVE('X', Length);
+               return Length;
+       }
+       else if( giVGA_BufferFormat == VIDEO_BUFFMT_2DSTREAM )
+       {
+               return DrvUtil_Video_2DStream(NULL, Buffer, Length, &gVGA_2DFunctions, sizeof(gVGA_2DFunctions));
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+/**
+ * \fn int VGA_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief IO Control Call
+ */
+int VGA_IOCtl(tVFS_Node *Node, int ID, void *Data)
+{
+        int    rv;
+       switch(ID)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_VIDEO;
+       case DRV_IOCTL_IDENT:   memcpy(Data, "VGA\0", 4);       return 1;
+       case DRV_IOCTL_VERSION: *(int*)Data = 50;       return 1;
+       case DRV_IOCTL_LOOKUP:  return 0;
+       
+       case VIDEO_IOCTL_GETSETMODE:    return 0;       // Mode 0 only
+       case VIDEO_IOCTL_FINDMODE:
+               if( !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)) )        return -1;
+               ((tVideo_IOCtl_Mode*)Data)->id = 0;     // Text Only!
+       case VIDEO_IOCTL_MODEINFO:
+               if( !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)) )        return -1;
+               if( ((tVideo_IOCtl_Mode*)Data)->id != 0)        return 0;
+               ((tVideo_IOCtl_Mode*)Data)->width = VGA_WIDTH*giVT_CharWidth;
+               ((tVideo_IOCtl_Mode*)Data)->height = VGA_HEIGHT*giVT_CharHeight;
+               ((tVideo_IOCtl_Mode*)Data)->bpp = 4;
+               return 1;
+       
+       case VIDEO_IOCTL_SETBUFFORMAT:
+               if( !CheckMem(Data, sizeof(int)) )      return -1;
+               switch( *(int*)Data )
+               {
+               case VIDEO_BUFFMT_TEXT:
+               case VIDEO_BUFFMT_2DSTREAM:
+                       rv = giVGA_BufferFormat;
+                       giVGA_BufferFormat = *(int*)Data;
+//                     Log_Debug("VGA", "Buffer format set to %i", giVGA_BufferFormat);
+                       return rv;
+               default:
+                       break;
+               }
+               return -1;
+       
+       case VIDEO_IOCTL_SETCURSOR:
+               VGA_int_SetCursor( ((tVideo_IOCtl_Pos*)Data)->x, ((tVideo_IOCtl_Pos*)Data)->y );
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)
+ * \brief Converts a 12-bit colour into a VGA 4-bit colour
+ */
+Uint8 VGA_int_GetColourNibble(Uint16 col)
+{
+       Uint8   ret = 0;
+        int    bright = 0;
+       
+       col = col & 0xCCC;
+       col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
+       bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
+       
+       switch(col)
+       {
+       //      Black
+       case 0x00:      ret = 0x0;      break;
+       // Dark Grey
+       case 0x15:      ret = 0x8;      break;
+       // Blues
+       case 0x01:
+       case 0x02:      ret = 0x1;      break;
+       case 0x03:      ret = 0x9;      break;
+       // Green
+       case 0x04:
+       case 0x08:      ret = 0x2;      break;
+       case 0x0C:      ret = 0xA;      break;
+       // Reds
+       case 0x10:
+       case 0x20:      ret = 0x4;      break;
+       case 0x30:      ret = 0xC;      break;
+       // Light Grey
+       case 0x2A:      ret = 0x7;      break;
+       // White
+       case 0x3F:      ret = 0xF;      break;
+       
+       default:
+               ret |= (col & 0x03 ? 1 : 0);
+               ret |= (col & 0x0C ? 2 : 0);
+               ret |= (col & 0x30 ? 4 : 0);
+               ret |= (bright ? 8 : 0);
+               break;
+       }
+       return ret;
+}
+
+/**
+ * \fn Uint16 VGA_int_GetWord(tVT_Char *Char)
+ * \brief Convers a character structure to a VGA character word
+ */
+Uint16 VGA_int_GetWord(const tVT_Char *Char)
+{
+       Uint16  ret;
+       Uint16  col;
+       
+       // Get Character
+       if(Char->Ch < 128)
+               ret = Char->Ch;
+       else {
+               switch(Char->Ch)
+               {
+               default:        ret = 0;        break;
+               }
+       }
+       
+       col = VGA_int_GetColourNibble(Char->BGCol);
+       ret |= col << 12;
+       
+       col = VGA_int_GetColourNibble(Char->FGCol);
+       ret |= col << 8;
+       
+       return ret;
+}
+
+/**
+ * \fn void VGA_int_SetCursor(Sint16 x, Sint16 y)
+ * \brief Updates the cursor position
+ */
+void VGA_int_SetCursor(Sint16 x, Sint16 y)
+{
+        int    pos = x+y*VGA_WIDTH;
+       if(x == -1 || y == -1)
+               pos = -1;
+       outb(0x3D4, 14);
+       outb(0x3D5, pos >> 8);
+       outb(0x3D4, 15);
+       outb(0x3D5, pos);
+}
+
+void VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
+{
+       tVT_Char        ch;
+       Uint16  word, *buf;
+
+       X /= giVT_CharWidth;
+       W /= giVT_CharWidth;
+       Y /= giVT_CharHeight;
+       H /= giVT_CharHeight;
+
+       ch.Ch = 0x20;
+       ch.BGCol  = (Colour & 0x0F0000) >> (16-8);
+       ch.BGCol |= (Colour & 0x000F00) >> (8-4);
+       ch.BGCol |= (Colour & 0x00000F);
+       word = VGA_int_GetWord(&ch);
+
+       Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
+
+       if( X > VGA_WIDTH || Y > VGA_HEIGHT )   return ;
+       if( X + W > VGA_WIDTH ) W = VGA_WIDTH - X;
+       if( Y + H > VGA_HEIGHT )        H = VGA_HEIGHT - Y;
+
+       buf = gVGA_Framebuffer + Y*VGA_WIDTH + X;
+
+       
+       while( H -- ) {
+                int    i;
+               for( i = 0; i < W; i ++ )
+                       *buf++ = word;
+               buf += VGA_WIDTH - W;
+       }
+}
+
+void VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
+{
+       Uint16  *src, *dst;
+
+       DstX /= giVT_CharWidth;
+       SrcX /= giVT_CharWidth;
+       W /= giVT_CharWidth;
+
+       DstY /= giVT_CharHeight;
+       SrcY /= giVT_CharHeight;
+       H /= giVT_CharHeight;
+
+//     Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
+
+       if( SrcX > VGA_WIDTH || SrcY > VGA_HEIGHT )     return ;
+       if( SrcX + W > VGA_WIDTH )      W = VGA_WIDTH - SrcX;
+       if( SrcY + H > VGA_HEIGHT )     H = VGA_HEIGHT - SrcY;
+       if( DstX > VGA_WIDTH || DstY > VGA_HEIGHT )     return ;
+       if( DstX + W > VGA_WIDTH )      W = VGA_WIDTH - DstX;
+       if( DstY + H > VGA_HEIGHT )     H = VGA_HEIGHT - DstY;
+
+
+       src = gVGA_Framebuffer + SrcY*VGA_WIDTH + SrcX;
+       dst = gVGA_Framebuffer + DstY*VGA_WIDTH + DstX;
+
+       if( src > dst )
+       {
+               // Simple copy
+               while( H-- ) {
+                       memcpy(dst, src, W*2);
+                       dst += VGA_WIDTH;
+                       src += VGA_WIDTH;
+               }
+       }
+       else
+       {
+               dst += H*VGA_WIDTH;
+               src += H*VGA_WIDTH;
+               while( H -- ) {
+                        int    i;
+                       dst -= VGA_WIDTH-W;
+                       src -= VGA_WIDTH-W;
+                       for( i = W; i --; )     *--dst = *--src;
+               }
+       }
+}
diff --git a/Modules/Display/BochsGA/Makefile b/Modules/Display/BochsGA/Makefile
deleted file mode 100644 (file)
index 2df219a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = bochsvbe.o
-NAME = BochsGA
-
--include ../Makefile.tpl
diff --git a/Modules/Display/BochsGA/bochsvbe.c b/Modules/Display/BochsGA/bochsvbe.c
deleted file mode 100644 (file)
index 806c1c1..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/**\r
- * Acess2 Bochs graphics adapter Driver\r
- * - By John Hodge (thePowersGang)\r
- *\r
- * bochsvbe.c\r
- * - Driver core\r
- */\r
-#define DEBUG  0\r
-#define VERSION        VER2(0,10)\r
-\r
-#include <acess.h>\r
-#include <errno.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include <fs_devfs.h>\r
-#include <drv_pci.h>\r
-#include <api_drv_video.h>\r
-\r
-// === TYPES ===\r
-typedef struct sBGA_Mode {\r
-       Uint16  width;\r
-       Uint16  height;\r
-       Uint16  bpp;\r
-       Uint32  fbSize;\r
-}      tBGA_Mode;\r
-\r
-// === CONSTANTS ===\r
-#define        BGA_LFB_MAXSIZE (1024*768*4)\r
-#define        VBE_DISPI_BANK_ADDRESS  0xA0000\r
-#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000\r
-#define VBE_DISPI_IOPORT_INDEX 0x01CE\r
-#define        VBE_DISPI_IOPORT_DATA   0x01CF\r
-#define        VBE_DISPI_DISABLED      0x00\r
-#define VBE_DISPI_ENABLED      0x01\r
-#define        VBE_DISPI_LFB_ENABLED   0x40\r
-#define        VBE_DISPI_NOCLEARMEM    0x80\r
-enum {\r
-       VBE_DISPI_INDEX_ID,\r
-       VBE_DISPI_INDEX_XRES,\r
-       VBE_DISPI_INDEX_YRES,\r
-       VBE_DISPI_INDEX_BPP,\r
-       VBE_DISPI_INDEX_ENABLE,\r
-       VBE_DISPI_INDEX_BANK,\r
-       VBE_DISPI_INDEX_VIRT_WIDTH,\r
-       VBE_DISPI_INDEX_VIRT_HEIGHT,\r
-       VBE_DISPI_INDEX_X_OFFSET,\r
-       VBE_DISPI_INDEX_Y_OFFSET\r
-};\r
-\r
-extern void MM_DumpTables(tVAddr Start, tVAddr End);\r
-\r
-// === PROTOTYPES ===\r
-// Driver\r
- int   BGA_Install(char **Arguments);\r
-void   BGA_Uninstall();\r
-// Internal\r
-void   BGA_int_WriteRegister(Uint16 reg, Uint16 value);\r
-Uint16 BGA_int_ReadRegister(Uint16 reg);\r
-void   BGA_int_SetBank(Uint16 bank);\r
-void   BGA_int_SetMode(Uint16 width, Uint16 height);\r
- int   BGA_int_UpdateMode(int id);\r
- int   BGA_int_FindMode(tVideo_IOCtl_Mode *info);\r
- int   BGA_int_ModeInfo(tVideo_IOCtl_Mode *info);\r
- int   BGA_int_MapFB(void *Dest);\r
-// Filesystem\r
-Uint64 BGA_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer);\r
-Uint64 BGA_Write(tVFS_Node *Node, Uint64 off, Uint64 len, const void *buffer);\r
- int   BGA_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, VERSION, BochsGA, BGA_Install, NULL, "PCI", NULL);\r
-tVFS_NodeType  gBGA_NodeType = {\r
-       .Read = BGA_Read,\r
-       .Write = BGA_Write,\r
-       .IOCtl = BGA_IOCtl\r
-       };\r
-tDevFS_Driver  gBGA_DriverStruct = {\r
-       NULL, "BochsGA",\r
-       {.Type = &gBGA_NodeType}\r
-       };\r
- int   giBGA_CurrentMode = -1;\r
-tVideo_IOCtl_Pos       gBGA_CursorPos = {-1,-1};\r
-Uint   *gBGA_Framebuffer;\r
-const tBGA_Mode        *gpBGA_CurrentMode;\r
-const tBGA_Mode        gBGA_Modes[] = {\r
-       {640,480,32, 640*480*4},\r
-       {800,600,32, 800*600*4},\r
-       {1024,768,32, 1024*768*4}\r
-};\r
-#define        BGA_MODE_COUNT  (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0]))\r
-tDrvUtil_Video_BufInfo gBGA_DrvUtil_BufInfo;\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int BGA_Install(char **Arguments)\r
- */\r
-int BGA_Install(char **Arguments)\r
-{\r
-        int    version = 0;\r
-       tPAddr  base;\r
-       tPCIDev dev;\r
-       \r
-       // Check BGA Version\r
-       version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
-       LOG("version = 0x%x", version);\r
-       \r
-       // NOTE: This driver was written for BGA versions >= 0xBOC2\r
-       // NOTE: However, Qemu is braindead and doesn't return the actual version\r
-       if( version != 0xB0C0 && ((version & 0xFFF0) != 0xB0C0 || version < 0xB0C2) ) {\r
-               Log_Warning("BGA", "Bochs Adapter Version is not compatible (need >= 0xB0C2), instead 0x%x", version);\r
-               return MODULE_ERR_NOTNEEDED;\r
-       }\r
-\r
-       // Get framebuffer base \r
-       dev = PCI_GetDevice(0x1234, 0x1111, 0);\r
-       if(dev == -1)\r
-               base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;\r
-       else\r
-               base = PCI_GetBAR(dev, 0);\r
-\r
-       // Map Framebuffer to hardware address\r
-       gBGA_Framebuffer = (void *) MM_MapHWPages(base, 768);   // 768 pages (3Mb)\r
-\r
-       // Install Device\r
-       if( DevFS_AddDevice( &gBGA_DriverStruct ) == -1 )\r
-       {\r
-               Log_Warning("BGA", "Unable to register with DevFS, maybe already loaded?");\r
-               return MODULE_ERR_MISC;\r
-       }\r
-               \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \brief Clean up driver resources before destruction\r
- */\r
-void BGA_Uninstall(void)\r
-{\r
-       DevFS_DelDevice( &gBGA_DriverStruct );\r
-       MM_UnmapHWPages( (tVAddr)gBGA_Framebuffer, 768 );\r
-}\r
-\r
-/**\r
- * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
- * \brief Read from the framebuffer\r
- */\r
-Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
-{\r
-       // Check Mode\r
-       if(giBGA_CurrentMode == -1)     return -1;\r
-       \r
-       // Check Offset and Length against Framebuffer Size\r
-       if(off+len > gpBGA_CurrentMode->fbSize)\r
-               return -1;\r
-       \r
-       // Copy from Framebuffer\r
-       memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);\r
-       return len;\r
-}\r
-\r
-/**\r
- * \brief Write to the framebuffer\r
- */\r
-Uint64 BGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
-{\r
-       if( giBGA_CurrentMode == -1 )   BGA_int_UpdateMode(0);\r
-       return DrvUtil_Video_WriteLFB(&gBGA_DrvUtil_BufInfo, Offset, Length, Buffer);\r
-}\r
-\r
-const char *csaBGA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
-/**\r
- * \brief Handle messages to the device\r
- */\r
-int BGA_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-        int    ret = -2;\r
-       ENTER("pNode iId pData", Node, ID, Data);\r
-       \r
-       switch(ID)\r
-       {\r
-       BASE_IOCTLS(DRV_TYPE_VIDEO, "BochsGA", VERSION, csaBGA_IOCtls);\r
-\r
-       case VIDEO_IOCTL_GETSETMODE:\r
-               if( Data )      BGA_int_UpdateMode(*(int*)(Data));\r
-               ret = giBGA_CurrentMode;\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_FINDMODE:\r
-               ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)Data);\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_MODEINFO:\r
-               ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_SETBUFFORMAT:\r
-               DrvUtil_Video_RemoveCursor( &gBGA_DrvUtil_BufInfo );\r
-               ret = gBGA_DrvUtil_BufInfo.BufferFormat;\r
-               if(Data)\r
-                       gBGA_DrvUtil_BufInfo.BufferFormat = *(int*)Data;\r
-               if(gBGA_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_SetCursor( &gBGA_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_SETCURSOR:\r
-               DrvUtil_Video_RemoveCursor( &gBGA_DrvUtil_BufInfo );\r
-               gBGA_CursorPos.x = ((tVideo_IOCtl_Pos*)Data)->x;\r
-               gBGA_CursorPos.y = ((tVideo_IOCtl_Pos*)Data)->y;\r
-               if(gBGA_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_DrawCursor(\r
-                               &gBGA_DrvUtil_BufInfo,\r
-                               gBGA_CursorPos.x*giVT_CharWidth,\r
-                               gBGA_CursorPos.y*giVT_CharHeight\r
-                               );\r
-               else\r
-                       DrvUtil_Video_DrawCursor(\r
-                               &gBGA_DrvUtil_BufInfo,\r
-                               gBGA_CursorPos.x, gBGA_CursorPos.y\r
-                               );\r
-               break;\r
-       \r
-       default:\r
-               LEAVE('i', -2);\r
-               return -2;\r
-       }\r
-       \r
-       LEAVE('i', ret);\r
-       return ret;\r
-}\r
-\r
-//== Internal Functions ==\r
-/**\r
- * \brief Writes to a BGA register\r
- */\r
-void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
-{\r
-       outw(VBE_DISPI_IOPORT_INDEX, reg);\r
-       outw(VBE_DISPI_IOPORT_DATA, value);\r
-}\r
-\r
-Uint16 BGA_int_ReadRegister(Uint16 reg)\r
-{\r
-       outw(VBE_DISPI_IOPORT_INDEX, reg);\r
-       return inw(VBE_DISPI_IOPORT_DATA);\r
-}\r
-\r
-/**\r
- * \brief Sets the video mode (32bpp only)\r
- */\r
-void BGA_int_SetMode(Uint16 Width, Uint16 Height)\r
-{\r
-       ENTER("iWidth iHeight", Width, Height);\r
-       BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\r
-       BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, Width);\r
-       BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, Height);\r
-       BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP, 32);\r
-       BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn int BGA_int_UpdateMode(int id)\r
- * \brief Set current vide mode given a mode id\r
- */\r
-int BGA_int_UpdateMode(int id)\r
-{\r
-       // Sanity Check\r
-       if(id < 0 || id >= BGA_MODE_COUNT)      return -1;\r
-       \r
-       BGA_int_SetMode(\r
-               gBGA_Modes[id].width,\r
-               gBGA_Modes[id].height);\r
-       \r
-       gBGA_DrvUtil_BufInfo.Framebuffer = gBGA_Framebuffer;\r
-       gBGA_DrvUtil_BufInfo.Pitch = gBGA_Modes[id].width * 4;\r
-       gBGA_DrvUtil_BufInfo.Width = gBGA_Modes[id].width;\r
-       gBGA_DrvUtil_BufInfo.Height = gBGA_Modes[id].height;\r
-       gBGA_DrvUtil_BufInfo.Depth = gBGA_Modes[id].bpp;\r
-\r
-       giBGA_CurrentMode = id;\r
-       gpBGA_CurrentMode = &gBGA_Modes[id];\r
-       return id;\r
-}\r
-\r
-/**\r
- * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
- * \brief Find a mode matching the given options\r
- */\r
-int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
-{\r
-        int    i;\r
-        int    best = 0, bestFactor = 1000;\r
-        int    tmp;\r
-        int    rqdProduct = info->width * info->height;\r
-       \r
-       ENTER("pinfo", info);\r
-       LOG("info = {width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);\r
-       \r
-       for(i = 0; i < BGA_MODE_COUNT; i++)\r
-       {\r
-               #if DEBUG >= 2\r
-               LOG("Mode %i (%ix%i,%ibpp), ", i, gBGA_Modes[i].width, gBGA_Modes[i].height, gBGA_Modes[i].bpp);\r
-               #endif\r
-\r
-               if( gBGA_Modes[i].bpp != info->bpp )\r
-                       continue ;              \r
-               \r
-               // Ooh! A perfect match\r
-               if(gBGA_Modes[i].width == info->width && gBGA_Modes[i].height == info->height)\r
-               {\r
-                       #if DEBUG >= 2\r
-                       LOG("Perfect");\r
-                       #endif\r
-                       best = i;\r
-                       break;\r
-               }\r
-\r
-\r
-               // If not, how close are we?\r
-               tmp = gBGA_Modes[i].width * gBGA_Modes[i].height - rqdProduct;\r
-               tmp = tmp < 0 ? -tmp : tmp;     // tmp = ABS(tmp)\r
-               \r
-               #if DEBUG >= 2\r
-               LOG("tmp = %i", tmp);\r
-               #endif\r
-               \r
-               if(tmp < bestFactor)\r
-               {\r
-                       bestFactor = tmp;\r
-                       best = i;\r
-               }\r
-       }\r
-       \r
-       info->id = best;\r
-       info->width = gBGA_Modes[best].width;\r
-       info->height = gBGA_Modes[best].height;\r
-       info->bpp = gBGA_Modes[best].bpp;\r
-\r
-       LEAVE('i', best);       \r
-       return best;\r
-}\r
-\r
-/**\r
- * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
- * \brief Get mode information\r
- */\r
-int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
-{\r
-       // Sanity Check\r
-       //if( !MM_IsUser( (Uint)info, sizeof(tVideo_IOCtl_Mode) ) ) {\r
-       //      return -EINVAL;\r
-       //}\r
-       \r
-       if(info->id < 0 || info->id >= BGA_MODE_COUNT)  return -1;\r
-       \r
-       info->width = gBGA_Modes[info->id].width;\r
-       info->height = gBGA_Modes[info->id].height;\r
-       info->bpp = gBGA_Modes[info->id].bpp;\r
-       \r
-       return 1;\r
-}\r
-\r
diff --git a/Modules/Display/Makefile.tpl b/Modules/Display/Makefile.tpl
deleted file mode 100644 (file)
index b543160..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = Video
-
--include ../../Makefile.tpl
diff --git a/Modules/Display/PL110/Makefile b/Modules/Display/PL110/Makefile
deleted file mode 100644 (file)
index 0f90347..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o
-NAME = PL110
-
--include ../Makefile.tpl
diff --git a/Modules/Display/PL110/main.c b/Modules/Display/PL110/main.c
deleted file mode 100644 (file)
index c3b6e52..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/**\r
- * Acess2 ARM PrimeCell Colour LCD Controller (PL110) Driver\r
- * - By John Hodge (thePowersGang)\r
- *\r
- * main.c\r
- * - Driver core\r
- *\r
- *\r
- * NOTE: The PL110 is set to 24bpp, but these are stored as 32-bit words.\r
- *       This corresponds to the Acess 32bpp mode, as the Acess 24bpp is packed\r
- */\r
-#define DEBUG  0\r
-#define VERSION        ((0<<8)|10)\r
-#include <acess.h>\r
-#include <errno.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include <fs_devfs.h>\r
-#include <drv_pci.h>\r
-#include <api_drv_video.h>\r
-#include <lib/keyvalue.h>\r
-#include <options.h>   // ARM Arch\r
-\r
-#define ABS(a) ((a)>0?(a):-(a))\r
-\r
-// === TYPEDEFS ===\r
-typedef struct sPL110  tPL110;\r
-\r
-struct sPL110\r
-{\r
-       Uint32  LCDTiming0;\r
-       Uint32  LCDTiming1;\r
-       Uint32  LCDTiming2;\r
-       Uint32  LCDTiming3;\r
-       \r
-       Uint32  LCDUPBase;\r
-       Uint32  LCDLPBase;\r
-       Uint32  LCDIMSC;\r
-       Uint32  LCDControl;\r
-       Uint32  LCDRIS;\r
-       Uint32  LCDMIS;\r
-       Uint32  LCDICR;\r
-       Uint32  LCDUPCurr;\r
-       Uint32  LCDLPCurr;\r
-};\r
-\r
-#ifndef PL110_BASE\r
-#define PL110_BASE     0x10020000      // Integrator\r
-#endif\r
-\r
-// === CONSTANTS ===\r
-const struct {\r
-       short W, H;\r
-}      caPL110_Modes[] = {\r
-       {640,480},\r
-       {800,600},\r
-       {1024,768}      // MAX\r
-};\r
-const int      ciPL110_ModeCount = sizeof(caPL110_Modes)/sizeof(caPL110_Modes[0]);\r
-\r
-// === PROTOTYPES ===\r
-// Driver\r
- int   PL110_Install(char **Arguments);\r
-void   PL110_Uninstall();\r
-// Internal\r
-// Filesystem\r
-Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, const void *buffer);\r
- int   PL110_IOCtl(tVFS_Node *node, int id, void *data);\r
-// -- Internals\r
- int   PL110_int_SetResolution(int W, int H);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
-tVFS_NodeType  gPL110_DevNodeType = {\r
-       .Read = PL110_Read,\r
-       .Write = PL110_Write,\r
-       .IOCtl = PL110_IOCtl\r
-       };\r
-tDevFS_Driver  gPL110_DriverStruct = {\r
-       NULL, "PL110",\r
-       {.Type = &gPL110_DevNodeType}\r
-};\r
-// -- Options\r
-tPAddr gPL110_PhysBase = PL110_BASE;\r
- int   gbPL110_IsVersatile = 1;\r
-// -- KeyVal parse rules\r
-const tKeyVal_ParseRules       gPL110_KeyValueParser = {\r
-       NULL,\r
-       {\r
-               {"Base", "P", &gPL110_PhysBase},\r
-               {"IsVersatile", "i", &gbPL110_IsVersatile},\r
-               {NULL, NULL, NULL}\r
-       }\r
-};\r
-// -- Driver state\r
- int   giPL110_CurrentMode = 0;\r
- int   giPL110_BufferMode;\r
- int   giPL110_Width = 640;\r
- int   giPL110_Height = 480;\r
-size_t giPL110_FramebufferSize;\r
-tPL110 *gpPL110_IOMem;\r
-tPAddr gPL110_FramebufferPhys;\r
-void   *gpPL110_Framebuffer;\r
-// -- Misc\r
-tDrvUtil_Video_BufInfo gPL110_DrvUtil_BufInfo;\r
-tVideo_IOCtl_Pos       gPL110_CursorPos;\r
-\r
-// === CODE ===\r
-/**\r
- */\r
-int PL110_Install(char **Arguments)\r
-{\r
-//     KeyVal_Parse(&gPL110_KeyValueParser, Arguments);\r
-       \r
-       gpPL110_IOMem = (void*)MM_MapHWPages(gPL110_PhysBase, 1);\r
-\r
-       PL110_int_SetResolution(caPL110_Modes[0].W, caPL110_Modes[0].H);\r
-\r
-       DevFS_AddDevice( &gPL110_DriverStruct );\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \brief Clean up resources for driver unloading\r
- */\r
-void PL110_Uninstall()\r
-{\r
-}\r
-\r
-/**\r
- * \brief Read from the framebuffer\r
- */\r
-Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
-{\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \brief Write to the framebuffer\r
- */\r
-Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
-{\r
-       gPL110_DrvUtil_BufInfo.BufferFormat = giPL110_BufferMode;\r
-       return DrvUtil_Video_WriteLFB(&gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
-}\r
-\r
-const char *csaPL110_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
-\r
-/**\r
- * \brief Handle messages to the device\r
- */\r
-int PL110_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-        int    ret = -2;\r
-       ENTER("pNode iID pData", Node, ID, Data);\r
-       \r
-       switch(ID)\r
-       {\r
-       BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaPL110_IOCtls);\r
-\r
-       case VIDEO_IOCTL_SETBUFFORMAT:\r
-               DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
-               ret = giPL110_BufferMode;\r
-               if(Data)        giPL110_BufferMode = *(int*)Data;\r
-               if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_SetCursor( &gPL110_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_GETSETMODE:\r
-               if(Data)\r
-               {\r
-                        int    newMode;\r
-                       \r
-                       if( !CheckMem(Data, sizeof(int)) )\r
-                               LEAVE_RET('i', -1);\r
-                       \r
-                       newMode = *(int*)Data;\r
-                       \r
-                       if(newMode < 0 || newMode >= ciPL110_ModeCount)\r
-                               LEAVE_RET('i', -1);\r
-\r
-                       if(newMode != giPL110_CurrentMode)\r
-                       {\r
-                               giPL110_CurrentMode = newMode;\r
-                               PL110_int_SetResolution( caPL110_Modes[newMode].W, caPL110_Modes[newMode].H );\r
-                       }\r
-               }\r
-               ret = giPL110_CurrentMode;\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_FINDMODE:\r
-               {\r
-               tVideo_IOCtl_Mode *mode = Data;\r
-                int    closest, closestArea, reqArea = 0;\r
-               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
-                       LEAVE_RET('i', -1);\r
-               if( mode->bpp != 32 )\r
-                       LEAVE_RET('i', 0);\r
-               if( mode->flags != 0 )\r
-                       LEAVE_RET('i', 0);\r
-\r
-               ret = 0;\r
-\r
-               for( int i = 0; i < ciPL110_ModeCount; i ++ )\r
-               {\r
-                        int    area;\r
-                       if(mode->width == caPL110_Modes[i].W && mode->height == caPL110_Modes[i].H) {\r
-                               mode->id = i;\r
-                               ret = 1;\r
-                               break;\r
-                       }\r
-                       \r
-                       area = caPL110_Modes[i].W * caPL110_Modes[i].H;\r
-                       if(!reqArea) {\r
-                               reqArea = mode->width * mode->height;\r
-                               closest = i;\r
-                               closestArea = area;\r
-                       }\r
-                       else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
-                               closest = i;\r
-                               closestArea = area;\r
-                       }\r
-               }\r
-               \r
-               if( ret == 0 )\r
-               {\r
-                       mode->id = closest;\r
-                       ret = 1;\r
-               }\r
-               mode->width = caPL110_Modes[mode->id].W;\r
-               mode->height = caPL110_Modes[mode->id].H;\r
-               break;\r
-               }\r
-       \r
-       case VIDEO_IOCTL_MODEINFO:\r
-               {\r
-               tVideo_IOCtl_Mode *mode = Data;\r
-               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
-                       LEAVE_RET('i', -1);\r
-               if(mode->id < 0 || mode->id >= ciPL110_ModeCount)\r
-                       LEAVE_RET('i', 0);\r
-               \r
-\r
-               mode->bpp = 32;\r
-               mode->flags = 0;\r
-               mode->width = caPL110_Modes[mode->id].W;\r
-               mode->height = caPL110_Modes[mode->id].H;\r
-\r
-               ret = 1;\r
-               break;\r
-               }\r
-       \r
-       case VIDEO_IOCTL_SETCURSOR:\r
-               if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
-                       LEAVE_RET('i', -1);\r
-\r
-               DrvUtil_Video_RemoveCursor( &gPL110_DrvUtil_BufInfo );\r
-               \r
-               gPL110_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
-               if(gPL110_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_DrawCursor(\r
-                               &gPL110_DrvUtil_BufInfo,\r
-                               gPL110_CursorPos.x*giVT_CharWidth,\r
-                               gPL110_CursorPos.y*giVT_CharHeight\r
-                               );\r
-               else\r
-                       DrvUtil_Video_DrawCursor(\r
-                               &gPL110_DrvUtil_BufInfo,\r
-                               gPL110_CursorPos.x,\r
-                               gPL110_CursorPos.y\r
-                               );\r
-               break;\r
-       \r
-       default:\r
-               LEAVE('i', -2);\r
-               return -2;\r
-       }\r
-       \r
-       LEAVE('i', ret);\r
-       return ret;\r
-}\r
-\r
-//\r
-//\r
-//\r
-\r
-/**\r
- * \brief Set the LCD controller resolution\r
- * \param W    Width (aligned to 16 pixels, cipped to 1024)\r
- * \param H    Height (clipped to 768)\r
- * \return Boolean failure\r
- */\r
-int PL110_int_SetResolution(int W, int H)\r
-{\r
-       W = (W + 15) & ~0xF;\r
-       if(W <= 0 || H <= 0) {\r
-               Log_Warning("PL110", "Attempted to set invalid resolution (%ix%i)", W, H);\r
-               return 1;\r
-       }\r
-       if(W > 1024)    W = 1024;\r
-       if(H > 768)     H = 768;\r
-\r
-       gpPL110_IOMem->LCDTiming0 = ((W/16)-1) << 2;\r
-       gpPL110_IOMem->LCDTiming1 = H-1;\r
-       gpPL110_IOMem->LCDTiming2 = (14 << 27);\r
-       gpPL110_IOMem->LCDTiming3 = 0;\r
-\r
-       if( gpPL110_Framebuffer ) {\r
-               MM_UnmapHWPages((tVAddr)gpPL110_Framebuffer, (giPL110_FramebufferSize+0xFFF)>>12);\r
-       }\r
-       giPL110_FramebufferSize = W*H*4;\r
-\r
-       gpPL110_Framebuffer = (void*)MM_AllocDMA( (giPL110_FramebufferSize+0xFFF)>>12, 32, &gPL110_FramebufferPhys );\r
-       gpPL110_IOMem->LCDUPBase = gPL110_FramebufferPhys;\r
-       gpPL110_IOMem->LCDLPBase = 0;\r
-\r
-       // Power on, BGR mode, ???, ???, enabled\r
-       Uint32  controlWord = (1 << 11)|(1 << 8)|(1 << 5)|(5 << 1)|1;\r
-       // According to qemu, the Versatile version has these two the wrong\r
-       // way around\r
-       if( gbPL110_IsVersatile )\r
-       {\r
-               gpPL110_IOMem->LCDIMSC = controlWord;   // Actually LCDControl\r
-               gpPL110_IOMem->LCDControl = 0;  // Actually LCDIMSC\r
-       }\r
-       else\r
-       {\r
-               gpPL110_IOMem->LCDIMSC = 0;\r
-               gpPL110_IOMem->LCDControl = controlWord;\r
-       }\r
-\r
-       giPL110_Width = W;\r
-       giPL110_Height = H;\r
-\r
-       // Update the DrvUtil buffer info\r
-       gPL110_DrvUtil_BufInfo.Framebuffer = gpPL110_Framebuffer;\r
-       gPL110_DrvUtil_BufInfo.Pitch = W * 4;\r
-       gPL110_DrvUtil_BufInfo.Width = W;\r
-       gPL110_DrvUtil_BufInfo.Height = H;\r
-       gPL110_DrvUtil_BufInfo.Depth = 32;\r
-       \r
-       return 0;\r
-}\r
diff --git a/Modules/Display/Tegra2Vid/Makefile b/Modules/Display/Tegra2Vid/Makefile
deleted file mode 100644 (file)
index ecab050..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o
-NAME = Tegra2Vid
-
--include ../Makefile.tpl
diff --git a/Modules/Display/Tegra2Vid/main.c b/Modules/Display/Tegra2Vid/main.c
deleted file mode 100644 (file)
index d9405be..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/**\r
- * main.c\r
- * - Driver core\r
- */\r
-#define DEBUG  0\r
-#define VERSION        ((0<<8)|10)\r
-#include <acess.h>\r
-#include <errno.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include <fs_devfs.h>\r
-#include <drv_pci.h>\r
-#include <api_drv_video.h>\r
-#include <lib/keyvalue.h>\r
-#include <options.h>   // ARM Arch\r
-#include "tegra2.h"\r
-\r
-#define ABS(a) ((a)>0?(a):-(a))\r
-\r
-// === PROTOTYPES ===\r
-// Driver\r
- int   Tegra2Vid_Install(char **Arguments);\r
-void   Tegra2Vid_Uninstall();\r
-// Internal\r
-// Filesystem\r
-Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
- int   Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data);\r
-// -- Internals\r
- int   Tegra2Vid_int_SetMode(int Mode);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, VERSION, Tegra2Vid, Tegra2Vid_Install, NULL, NULL);\r
-tDevFS_Driver  gTegra2Vid_DriverStruct = {\r
-       NULL, "Tegra2Vid",\r
-       {\r
-       .Read = Tegra2Vid_Read,\r
-       .Write = Tegra2Vid_Write,\r
-       .IOCtl = Tegra2Vid_IOCtl\r
-       }\r
-};\r
-// -- Options\r
-tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE;\r
- int   gbTegra2Vid_IsVersatile = 1;\r
-// -- KeyVal parse rules\r
-const tKeyVal_ParseRules       gTegra2Vid_KeyValueParser = {\r
-       NULL,\r
-       {\r
-               {"Base", "P", &gTegra2Vid_PhysBase},\r
-               {NULL, NULL, NULL}\r
-       }\r
-};\r
-// -- Driver state\r
- int   giTegra2Vid_CurrentMode = 0;\r
- int   giTegra2Vid_BufferMode;\r
-size_t giTegra2Vid_FramebufferSize;\r
-Uint32 *gpTegra2Vid_IOMem;\r
-tPAddr gTegra2Vid_FramebufferPhys;\r
-void   *gpTegra2Vid_Framebuffer;\r
-// -- Misc\r
-tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo;\r
-tVideo_IOCtl_Pos       gTegra2Vid_CursorPos;\r
-\r
-// === CODE ===\r
-/**\r
- */\r
-int Tegra2Vid_Install(char **Arguments)\r
-{\r
-//     KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);\r
-\r
-       gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);\r
-       {\r
-               Log_Debug("Tegra2Vid", "Display CMD Registers");\r
-               for( int i = 0x000; i <= 0x01A; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-               for( int i = 0x028; i <= 0x043; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-               Log_Debug("Tegra2Vid", "Display COM Registers");\r
-               for( int i = 0x300; i <= 0x329; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-               Log_Debug("Tegra2Vid", "Display DISP Registers");\r
-               for( int i = 0x400; i <= 0x446; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-               for( int i = 0x480; i <= 0x484; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-               for( int i = 0x4C0; i <= 0x4C1; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-\r
-               Log_Debug("Tegra2Vid", "WINC_A Registers");\r
-               for( int i = 0x700; i <= 0x714; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-               Log_Debug("Tegra2Vid", "WINBUF_A");\r
-               for( int i = 0x800; i <= 0x80A; i ++ )\r
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);\r
-       }\r
-//     return 1;\r
-       \r
-       giTegra2Vid_FramebufferSize =\r
-               (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF)\r
-               *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4;\r
-\r
-       Log_Debug("Tegra2Vid", "giTegra2Vid_FramebufferSize = 0x%x", giTegra2Vid_FramebufferSize);\r
-       gpTegra2Vid_Framebuffer = MM_MapHWPages(\r
-               gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0],\r
-               (giTegra2Vid_FramebufferSize+PAGE_SIZE-1)/PAGE_SIZE\r
-               );\r
-       memset(gpTegra2Vid_Framebuffer, 0x1F, 0x1000);\r
-\r
-\r
-//     Tegra2Vid_int_SetMode(4);\r
-\r
-       DevFS_AddDevice( &gTegra2Vid_DriverStruct );\r
-\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \brief Clean up resources for driver unloading\r
- */\r
-void Tegra2Vid_Uninstall()\r
-{\r
-}\r
-\r
-/**\r
- * \brief Read from the framebuffer\r
- */\r
-Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
-{\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \brief Write to the framebuffer\r
- */\r
-Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{\r
-       gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode;\r
-       return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer);\r
-}\r
-\r
-const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
-\r
-/**\r
- * \brief Handle messages to the device\r
- */\r
-int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-        int    ret = -2;\r
-       ENTER("pNode iID pData", Node, ID, Data);\r
-       \r
-       switch(ID)\r
-       {\r
-       BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);\r
-\r
-       case VIDEO_IOCTL_SETBUFFORMAT:\r
-               DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
-               ret = giTegra2Vid_BufferMode;\r
-               if(Data)        giTegra2Vid_BufferMode = *(int*)Data;\r
-               if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor );\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_GETSETMODE:\r
-               if(Data)\r
-               {\r
-                        int    newMode;\r
-                       \r
-                       if( !CheckMem(Data, sizeof(int)) )\r
-                               LEAVE_RET('i', -1);\r
-                       \r
-                       newMode = *(int*)Data;\r
-                       \r
-                       if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount)\r
-                               LEAVE_RET('i', -1);\r
-\r
-                       if(newMode != giTegra2Vid_CurrentMode)\r
-                       {\r
-                               giTegra2Vid_CurrentMode = newMode;\r
-                               Tegra2Vid_int_SetMode( newMode );\r
-                       }\r
-               }\r
-               ret = giTegra2Vid_CurrentMode;\r
-               break;\r
-       \r
-       case VIDEO_IOCTL_FINDMODE:\r
-               {\r
-               tVideo_IOCtl_Mode *mode = Data;\r
-                int    closest, closestArea, reqArea = 0;\r
-               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
-                       LEAVE_RET('i', -1);\r
-               if( mode->bpp != 32 )\r
-                       LEAVE_RET('i', 0);\r
-               if( mode->flags != 0 )\r
-                       LEAVE_RET('i', 0);\r
-\r
-               ret = 0;\r
-\r
-               for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ )\r
-               {\r
-                        int    area;\r
-                       if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) {\r
-                               mode->id = i;\r
-                               ret = 1;\r
-                               break;\r
-                       }\r
-                       \r
-                       area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H;\r
-                       if(!reqArea) {\r
-                               reqArea = mode->width * mode->height;\r
-                               closest = i;\r
-                               closestArea = area;\r
-                       }\r
-                       else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) {\r
-                               closest = i;\r
-                               closestArea = area;\r
-                       }\r
-               }\r
-               \r
-               if( ret == 0 )\r
-               {\r
-                       mode->id = closest;\r
-                       ret = 1;\r
-               }\r
-               mode->width = caTegra2Vid_Modes[mode->id].W;\r
-               mode->height = caTegra2Vid_Modes[mode->id].H;\r
-               break;\r
-               }\r
-       \r
-       case VIDEO_IOCTL_MODEINFO:\r
-               {\r
-               tVideo_IOCtl_Mode *mode = Data;\r
-               if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)))\r
-                       LEAVE_RET('i', -1);\r
-               if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount)\r
-                       LEAVE_RET('i', 0);\r
-               \r
-\r
-               mode->bpp = 32;\r
-               mode->flags = 0;\r
-               mode->width = caTegra2Vid_Modes[mode->id].W;\r
-               mode->height = caTegra2Vid_Modes[mode->id].H;\r
-\r
-               ret = 1;\r
-               break;\r
-               }\r
-       \r
-       case VIDEO_IOCTL_SETCURSOR:\r
-               if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
-                       LEAVE_RET('i', -1);\r
-\r
-               DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );\r
-               \r
-               gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data;\r
-               if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_DrawCursor(\r
-                               &gTegra2Vid_DrvUtil_BufInfo,\r
-                               gTegra2Vid_CursorPos.x*giVT_CharWidth,\r
-                               gTegra2Vid_CursorPos.y*giVT_CharHeight\r
-                               );\r
-               else\r
-                       DrvUtil_Video_DrawCursor(\r
-                               &gTegra2Vid_DrvUtil_BufInfo,\r
-                               gTegra2Vid_CursorPos.x,\r
-                               gTegra2Vid_CursorPos.y\r
-                               );\r
-               break;\r
-       \r
-       default:\r
-               LEAVE('i', -2);\r
-               return -2;\r
-       }\r
-       \r
-       LEAVE('i', ret);\r
-       return ret;\r
-}\r
-\r
-//\r
-//\r
-//\r
-\r
-int Tegra2Vid_int_SetMode(int Mode)\r
-{\r
-       const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];\r
-        int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; \r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0)  = (mode->HS << 16)  | mode->HS;\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0)  = (mode->VBP << 16) | mode->HBP;\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16)   | mode->W;\r
-\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (mode->H << 16) | mode->W;\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8;     // BASE888\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12;    // Could be 13 (BGR/RGB)\r
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (mode->H << 16) | mode->W;\r
-\r
-       Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);\r
-\r
-       if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize )\r
-       {\r
-               if( gpTegra2Vid_Framebuffer )\r
-               {\r
-                       // TODO: Free framebuffer for reallocation\r
-               }\r
-\r
-               giTegra2Vid_FramebufferSize = w*h*4;            \r
-\r
-               gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(\r
-                       (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,\r
-                       32,\r
-                       &gTegra2Vid_FramebufferPhys\r
-                       );\r
-               // TODO: Catch allocation failures\r
-               Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)",\r
-                               giTegra2Vid_FramebufferSize,\r
-                               gpTegra2Vid_Framebuffer,\r
-                               gTegra2Vid_FramebufferPhys\r
-                               );\r
-               \r
-               // Tell hardware\r
-               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;\r
-               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0;        // Y offset\r
-               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0;        // X offset\r
-       }\r
-\r
-       return 0;\r
-}\r
diff --git a/Modules/Display/Tegra2Vid/tegra2.h b/Modules/Display/Tegra2Vid/tegra2.h
deleted file mode 100644 (file)
index a3f126b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Acess2 NVidia Tegra2 Display Driver
- * - By John Hodge (thePowersGang)
- *
- * tegra2.h
- * - Driver definitions
- */
-#ifndef _TEGRA2_DISP_H_
-#define _TEGRA2_DISP_H_
-
-#define TEGRA2VID_BASE 0x54200000      // 0x40000 Large (256 KB)
-
-const struct sTegra2_Disp_Mode
-{
-       Uint16  W,   H;
-       Uint16  HFP, VFP;
-       Uint16  HS,  VS;
-       Uint16  HBP, VBP;
-}      caTegra2Vid_Modes[] = {
-       // TODO: VESA timings
-       {720,  487,  16,33,   63, 33,   59, 133},       // NTSC 2
-       {720,  576,  12,33,   63, 33,   69, 193},       // PAL 2 (VFP shown as 2/33, used 33)
-       {720,  483,  16, 6,   63,  6,   59,  30},       // 480p
-       {1280, 720,  70, 5,  804,  6,  220,  20},       // 720p
-       {1920,1080,  44, 4,  884,  5,  148,  36},       // 1080p
-       // TODO: Can all but HA/VA be constant and those select the resolution?
-};
-const int ciTegra2Vid_ModeCount = sizeof(caTegra2Vid_Modes)/sizeof(caTegra2Vid_Modes[0]);
-
-enum eTegra2_Disp_Regs
-{
-       DC_DISP_DISP_SIGNAL_OPTIONS0_0 = 0x400,
-       DC_DISP_DISP_SIGNAL_OPTIONS1_0, // 401
-       DC_DISP_DISP_WIN_OPTIONS_0,     // 402
-       DC_DISP_MEM_HIGH_PRIORITY_0,    // 403
-       DC_DISP_MEM_HIGH_PRIORITY_TIMER_0,      // 404
-       DC_DISP_DISP_TIMING_OPTIONS_0,  // 405
-       DC_DISP_REF_TO_SYNC_0,          // 406 (TrimSlice 0x0001 000B)
-       DC_DISP_SYNC_WIDTH_0,           // 407 (TrimSlice 0x0004 003A)
-       DC_DISP_BACK_PORCH_0,           // 408 (TrimSlice 0x0004 003A)
-       DC_DISP_DISP_ACTIVE_0,          // 409 (TrimSlice 0x0300 0400)
-       DC_DISP_FRONT_PORCH_0,          // 40A (TrimSlice 0x0004 003A)
-
-       DC_DISP_H_PULSE0_CONTROL_0,     // 40B
-
-       DC_DISP_DISP_COLOR_CONTROL_0 = 0x430,
-       
-       DC_WINC_A_COLOR_PALETTE_0 = 0x500,
-       DC_WINC_A_PALETTE_COLOR_EXT_0 = 0x600,
-       DC_WIN_A_WIN_OPTIONS_0 = 0x700,
-       DC_WIN_A_BYTE_SWAP_0,           // 701
-       DC_WIN_A_BUFFER_CONTROL_0,      // 702
-       DC_WIN_A_COLOR_DEPTH_0,         // 703
-       DC_WIN_A_POSITION_0,            // 704
-       DC_WIN_A_SIZE_0,                // 705 (TrimSlice 0x0300 0400)
-       DC_WIN_A_PRESCALED_SIZE_0,
-       DC_WIN_A_H_INITIAL_DDA_0,
-       DC_WIN_A_V_INITIAL_DDA_0,
-       DC_WIN_A_DDA_INCREMENT_0,
-       DC_WIN_A_LINE_STRIDE_0,
-       DC_WIN_A_BUF_STRIDE_0,
-       DC_WIN_A_BUFFER_ADDR_MODE_0,
-       DC_WIN_A_DV_CONTROL_0,
-       DC_WIN_A_BLEND_NOKEY_0,
-       
-       DC_WINBUF_A_START_ADDR_0 = 0x800,
-       DC_WINBUF_A_START_ADDR_NS_0,
-       DC_WINBUF_A_ADDR_H_OFFSET_0,
-       DC_WINBUF_A_ADDR_H_OFFSET_NS_0,
-       DC_WINBUF_A_ADDR_V_OFFSET_0,
-       DC_WINBUF_A_ADDR_V_OFFSET_NS_0,
-};
-
-#endif
-
diff --git a/Modules/Display/VESA/Makefile b/Modules/Display/VESA/Makefile
deleted file mode 100644 (file)
index d8da233..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o
-NAME = VESA
-
--include ../Makefile.tpl
diff --git a/Modules/Display/VESA/common.h b/Modules/Display/VESA/common.h
deleted file mode 100644 (file)
index eeaddd5..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-// === TYPES ===
-typedef struct sFarPtr
-{
-       Uint16  ofs;
-       Uint16  seg;
-}      tFarPtr;
-
-typedef struct sVesa_Mode
-{
-       Uint16  code;
-       Uint16  width, height;
-       Uint16  pitch, bpp;
-       Uint16  flags;
-       Uint32  fbSize;
-       Uint32  framebuffer;
-}      tVesa_Mode;
-
-typedef struct sVesa_CallModeInfo
-{
-       Uint16  attributes;
-       Uint8   winA,winB;
-       Uint16  granularity;
-       Uint16  winsize;
-       Uint16  segmentA, segmentB;
-       tFarPtr realFctPtr;
-       Uint16  pitch;  // Bytes per scanline
-
-       Uint16  Xres, Yres;
-       Uint8   Wchar, Ychar, planes, bpp, banks;
-       Uint8   memory_model, bank_size, image_pages;
-       Uint8   reserved0;
-
-       Uint8   red_mask, red_position;
-       Uint8   green_mask, green_position;
-       Uint8   blue_mask, blue_position;
-       Uint8   rsv_mask, rsv_position;
-       Uint8   directcolor_attributes;
-
-       Uint32  physbase;  // Your LFB address ;)
-       Uint32  reserved1;
-       Sint16  reserved2;
-}      tVesa_CallModeInfo;
-
-typedef struct sVesa_CallInfo
-{
-   char                signature[4];           // == "VESA"
-   Uint16      Version;        // == 0x0300 for Vesa 3.0
-   tFarPtr     OEMString;      // isa vbeFarPtr
-   Uint8       Capabilities[4];        
-   tFarPtr     VideoModes;     // isa vbeParPtr
-   Uint16      TotalMemory;    // as # of 64KB blocks
-}      tVesa_CallInfo;
-
-#endif
diff --git a/Modules/Display/VESA/main.c b/Modules/Display/VESA/main.c
deleted file mode 100644 (file)
index a85d313..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*\r
- * AcessOS 1\r
- * Video BIOS Extensions (Vesa) Driver\r
- */\r
-#define DEBUG  0\r
-#define VERSION        0x100\r
-\r
-#include <acess.h>\r
-#include <vfs.h>\r
-#include <api_drv_video.h>\r
-#include <fs_devfs.h>\r
-#include <modules.h>\r
-#include <vm8086.h>\r
-#include "common.h"\r
-\r
-// === CONSTANTS ===\r
-#define        FLAG_LFB        0x1\r
-#define VESA_DEFAULT_FRAMEBUFFER       (KERNEL_BASE|0xA0000)\r
-#define BLINKING_CURSOR        1\r
-#if BLINKING_CURSOR\r
-# define VESA_CURSOR_PERIOD    1000\r
-#endif\r
-\r
-// === PROTOTYPES ===\r
- int   Vesa_Install(char **Arguments);\r
-Uint64 Vesa_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);\r
- int   Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
- int   Vesa_Int_SetMode(int Mode);\r
- int   Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
- int   Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
-void   Vesa_int_HideCursor(void);\r
-void   Vesa_int_ShowCursor(void);\r
-void   Vesa_FlipCursor(void *Arg);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
-tVFS_NodeType  gVesa_NodeType = {\r
-       .Read = Vesa_Read,\r
-       .Write = Vesa_Write,\r
-       .IOCtl = Vesa_IOCtl\r
-       };\r
-tDevFS_Driver  gVesa_DriverStruct = {\r
-       NULL, "Vesa",\r
-       {.Type = &gVesa_NodeType}\r
-       };\r
-tMutex glVesa_Lock;\r
-tVM8086        *gpVesa_BiosState;\r
- int   giVesaDriverId = -1;\r
-// --- Video Modes ---\r
- int   giVesaCurrentMode = 0;\r
-tVesa_Mode     *gVesa_Modes;\r
-tVesa_Mode     *gpVesaCurMode;\r
- int   giVesaModeCount = 0;\r
- int   gbVesaModesChecked;\r
-// --- Framebuffer ---\r
-char   *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER;\r
- int   giVesaPageCount = 0;    //!< Framebuffer size in pages\r
-// --- Cursor Control ---\r
- int   giVesaCursorX = -1;\r
- int   giVesaCursorY = -1;\r
- int   giVesaCursorTimer = -1; // Invalid timer\r
- int   gbVesa_CursorVisible = 0;\r
-// --- 2D Video Stream Handlers ---\r
-tDrvUtil_Video_BufInfo gVesa_BufInfo;\r
-\r
-// === CODE ===\r
-int Vesa_Install(char **Arguments)\r
-{\r
-       tVesa_CallInfo  *info;\r
-       tFarPtr infoPtr;\r
-       Uint16  *modes;\r
-       int     i;\r
-       \r
-       // Allocate Info Block\r
-       gpVesa_BiosState = VM8086_Init();\r
-       info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
-       // Set Requested Version\r
-       memcpy(info->signature, "VBE2", 4);\r
-       // Set Registers\r
-       gpVesa_BiosState->AX = 0x4F00;\r
-       gpVesa_BiosState->ES = infoPtr.seg;     gpVesa_BiosState->DI = infoPtr.ofs;\r
-       // Call Interrupt\r
-       VM8086_Int(gpVesa_BiosState, 0x10);\r
-       if(gpVesa_BiosState->AX != 0x004F) {\r
-               Log_Warning("VESA", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
-               return MODULE_ERR_NOTNEEDED;\r
-       }\r
-       \r
-       //Log_Debug("VESA", "info->VideoModes = %04x:%04x", info->VideoModes.seg, info->VideoModes.ofs);\r
-       modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);\r
-       \r
-       // Read Modes\r
-       for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ );\r
-       gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
-       \r
-       Log_Debug("VESA", "%i Modes", giVesaModeCount);\r
-       \r
-       // Insert Text Mode\r
-       gVesa_Modes[0].width = 80;\r
-       gVesa_Modes[0].height = 25;\r
-       gVesa_Modes[0].bpp = 12;\r
-       gVesa_Modes[0].code = 0x3;\r
-       gVesa_Modes[0].flags = 1;\r
-       gVesa_Modes[0].fbSize = 80*25*2;\r
-       gVesa_Modes[0].framebuffer = 0xB8000;\r
-       \r
-       for( i = 1; i < giVesaModeCount; i++ )\r
-       {\r
-               gVesa_Modes[i].code = modes[i];\r
-       }\r
-\r
-//     VM8086_Deallocate( info );\r
-       \r
-       // Install Device\r
-       giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );\r
-       if(giVesaDriverId == -1)        return MODULE_ERR_MISC;\r
-       \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-void Vesa_int_FillModeList(void)\r
-{\r
-       if( !gbVesaModesChecked )\r
-       {\r
-                int    i;\r
-               tVesa_CallModeInfo      *modeinfo;\r
-               tFarPtr modeinfoPtr;\r
-               \r
-               modeinfo = VM8086_Allocate(gpVesa_BiosState, 512, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
-               for( i = 1; i < giVesaModeCount; i ++ )\r
-               {\r
-                       // Get Mode info\r
-                       gpVesa_BiosState->AX = 0x4F01;\r
-                       gpVesa_BiosState->CX = gVesa_Modes[i].code;\r
-                       gpVesa_BiosState->ES = modeinfoPtr.seg;\r
-                       gpVesa_BiosState->DI = modeinfoPtr.ofs;\r
-                       VM8086_Int(gpVesa_BiosState, 0x10);\r
-                       \r
-                       // Parse Info\r
-                       gVesa_Modes[i].flags = 0;\r
-                       if ( (modeinfo->attributes & 0x90) == 0x90 )\r
-                       {\r
-                               gVesa_Modes[i].flags |= FLAG_LFB;\r
-                               gVesa_Modes[i].framebuffer = modeinfo->physbase;\r
-                               gVesa_Modes[i].fbSize = modeinfo->Yres*modeinfo->pitch;\r
-                       } else {\r
-                               gVesa_Modes[i].framebuffer = 0;\r
-                               gVesa_Modes[i].fbSize = 0;\r
-                       }\r
-                       \r
-                       gVesa_Modes[i].pitch = modeinfo->pitch;\r
-                       gVesa_Modes[i].width = modeinfo->Xres;\r
-                       gVesa_Modes[i].height = modeinfo->Yres;\r
-                       gVesa_Modes[i].bpp = modeinfo->bpp;\r
-                       \r
-                       #if DEBUG\r
-                       Log_Log("VESA", "0x%x - %ix%ix%i",\r
-                               gVesa_Modes[i].code, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
-                       #endif\r
-               }\r
-       \r
-//             VM8086_Deallocate( modeinfo );\r
-               \r
-               gbVesaModesChecked = 1;\r
-       }\r
-}\r
-\r
-/* Read from the framebuffer\r
- */\r
-Uint64 Vesa_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer)\r
-{\r
-       #if DEBUG >= 2\r
-       Log("Vesa_Read: () - NULL\n");\r
-       #endif\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \brief Write to the framebuffer\r
- */\r
-Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
-{\r
-       if( gVesa_Modes[giVesaCurrentMode].framebuffer == 0 ) {\r
-               Log_Warning("VESA", "Vesa_Write - Non-LFB Modes not yet supported.");\r
-               return 0;\r
-       }\r
-\r
-       return DrvUtil_Video_WriteLFB(&gVesa_BufInfo, Offset, Length, Buffer);\r
-}\r
-\r
-const char *csaVESA_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL};\r
-/**\r
- * \brief Handle messages to the device\r
- */\r
-int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-        int    ret;\r
-       //Log_Debug("VESA", "Vesa_Ioctl: (Node=%p, ID=%i, Data=%p)", Node, ID, Data);\r
-       switch(ID)\r
-       {\r
-       BASE_IOCTLS(DRV_TYPE_VIDEO, "VESA", VERSION, csaVESA_IOCtls);\r
-\r
-       case VIDEO_IOCTL_GETSETMODE:\r
-               if( !Data )     return giVesaCurrentMode;\r
-               return Vesa_Int_SetMode( *(int*)Data );\r
-       \r
-       case VIDEO_IOCTL_FINDMODE:\r
-               return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);\r
-       case VIDEO_IOCTL_MODEINFO:\r
-               return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
-       \r
-       case VIDEO_IOCTL_SETBUFFORMAT:\r
-               Vesa_int_HideCursor();\r
-               ret = gVesa_BufInfo.BufferFormat;\r
-               if(Data)        gVesa_BufInfo.BufferFormat = *(int*)Data;\r
-               if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );\r
-               Vesa_int_ShowCursor();\r
-               return ret;\r
-       \r
-       case VIDEO_IOCTL_SETCURSOR:     // Set cursor position\r
-               Vesa_int_HideCursor();\r
-               giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;\r
-               giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;\r
-               Vesa_int_ShowCursor();\r
-               return 0;\r
-       \r
-       case VIDEO_IOCTL_SETCURSORBITMAP:\r
-               DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );\r
-               return 0;\r
-       }\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \brief Updates the video mode\r
- */\r
-int Vesa_Int_SetMode(int mode)\r
-{      \r
-       // Sanity Check values\r
-       if(mode < 0 || mode > giVesaModeCount)  return -1;\r
-\r
-       // Check for fast return\r
-       if(mode == giVesaCurrentMode)   return 1;\r
-       \r
-       Vesa_int_FillModeList();\r
-\r
-       Time_RemoveTimer(giVesaCursorTimer);\r
-       giVesaCursorTimer = -1;\r
-       \r
-       Mutex_Acquire( &glVesa_Lock );\r
-       \r
-       gpVesa_BiosState->AX = 0x4F02;\r
-       gpVesa_BiosState->BX = gVesa_Modes[mode].code;\r
-       if(gVesa_Modes[mode].flags & FLAG_LFB) {\r
-               gpVesa_BiosState->BX |= 0x4000; // Bit 14 - Use LFB\r
-       }\r
-       \r
-       // Set Mode\r
-       VM8086_Int(gpVesa_BiosState, 0x10);\r
-       \r
-       // Map Framebuffer\r
-       if( (tVAddr)gpVesa_Framebuffer != VESA_DEFAULT_FRAMEBUFFER )\r
-               MM_UnmapHWPages((tVAddr)gpVesa_Framebuffer, giVesaPageCount);\r
-       giVesaPageCount = (gVesa_Modes[mode].fbSize + 0xFFF) >> 12;\r
-       gpVesa_Framebuffer = (void*)MM_MapHWPages(gVesa_Modes[mode].framebuffer, giVesaPageCount);\r
-       \r
-       Log_Log("VESA", "Setting mode to %i (%ix%i %ibpp) %p[0x%x] maps %P",\r
-               mode,\r
-               gVesa_Modes[mode].width, gVesa_Modes[mode].height,\r
-               gVesa_Modes[mode].bpp,\r
-               gpVesa_Framebuffer, giVesaPageCount << 12, gVesa_Modes[mode].framebuffer\r
-               );\r
-       \r
-       // Record Mode Set\r
-       giVesaCurrentMode = mode;\r
-       gpVesaCurMode = &gVesa_Modes[giVesaCurrentMode];\r
-       \r
-       Mutex_Release( &glVesa_Lock );\r
-\r
-       gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
-       gVesa_BufInfo.Pitch = gVesa_Modes[mode].pitch;\r
-       gVesa_BufInfo.Width = gVesa_Modes[mode].width;\r
-       gVesa_BufInfo.Height = gVesa_Modes[mode].height;\r
-       gVesa_BufInfo.Depth = gVesa_Modes[mode].bpp;    \r
-\r
-       return 1;\r
-}\r
-\r
-int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
-{\r
-        int    i;\r
-        int    best = -1, bestFactor = 1000;\r
-        int    factor, tmp;\r
-       \r
-       ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
-\r
-       Vesa_int_FillModeList();\r
-       \r
-       for(i=0;i<giVesaModeCount;i++)\r
-       {\r
-               LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
-       \r
-               if(gVesa_Modes[i].width == data->width && gVesa_Modes[i].height == data->height)\r
-               {\r
-                       //if( (data->bpp == 32 || data->bpp == 24)\r
-                       // && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
-                       if( data->bpp == gVesa_Modes[i].bpp )\r
-                       {\r
-                               LOG("Perfect!");\r
-                               best = i;\r
-                               break;\r
-                       }\r
-               }\r
-               \r
-               tmp = gVesa_Modes[i].width * gVesa_Modes[i].height;\r
-               tmp -= data->width * data->height;\r
-               tmp = tmp < 0 ? -tmp : tmp;\r
-               factor = tmp * 1000 / (data->width * data->height);\r
-               \r
-               if( data->bpp == 8 && gVesa_Modes[i].bpp != 8 ) continue;\r
-               if( data->bpp == 16 && gVesa_Modes[i].bpp != 16 )       continue;\r
-               \r
-               if( (data->bpp == 32 || data->bpp == 24)\r
-                && (gVesa_Modes[i].bpp == 32 || gVesa_Modes[i].bpp == 24) )\r
-               {\r
-                       if( data->bpp == gVesa_Modes[i].bpp )\r
-                               factor /= 2;\r
-               }\r
-               else {\r
-                       if( data->bpp != gVesa_Modes[i].bpp )\r
-                               continue ;\r
-               }\r
-               \r
-               LOG("factor = %i", factor);\r
-               \r
-               if(factor < bestFactor)\r
-               {\r
-                       bestFactor = factor;\r
-                       best = i;\r
-               }\r
-       }\r
-       data->id = best;\r
-       data->width = gVesa_Modes[best].width;\r
-       data->height = gVesa_Modes[best].height;\r
-       data->bpp = gVesa_Modes[best].bpp;\r
-       LEAVE('i', best);\r
-       return best;\r
-}\r
-\r
-int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)\r
-{\r
-       if(data->id < 0 || data->id > giVesaModeCount)  return -1;\r
-\r
-       Vesa_int_FillModeList();\r
-\r
-       data->width = gVesa_Modes[data->id].width;\r
-       data->height = gVesa_Modes[data->id].height;\r
-       data->bpp = gVesa_Modes[data->id].bpp;\r
-       return 1;\r
-}\r
-\r
-void Vesa_int_HideCursor(void)\r
-{\r
-       DrvUtil_Video_RemoveCursor( &gVesa_BufInfo );\r
-       #if BLINKING_CURSOR\r
-       if(giVesaCursorTimer != -1) {\r
-               Time_RemoveTimer(giVesaCursorTimer);\r
-               giVesaCursorTimer = -1;\r
-       }\r
-       #endif\r
-}\r
-\r
-void Vesa_int_ShowCursor(void)\r
-{\r
-       gbVesa_CursorVisible = (giVesaCursorX >= 0);\r
-       if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-       {\r
-               DrvUtil_Video_DrawCursor(\r
-                       &gVesa_BufInfo,\r
-                       giVesaCursorX*giVT_CharWidth,\r
-                       giVesaCursorY*giVT_CharHeight\r
-                       );\r
-               #if BLINKING_CURSOR\r
-               giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, NULL);\r
-               #endif\r
-       }\r
-       else\r
-               DrvUtil_Video_DrawCursor(\r
-                       &gVesa_BufInfo,\r
-                       giVesaCursorX,\r
-                       giVesaCursorY\r
-                       );\r
-}\r
-\r
-/**\r
- * \brief Swaps the text cursor on/off\r
- */\r
-void Vesa_FlipCursor(void *Arg)\r
-{\r
-       if( gVesa_BufInfo.BufferFormat != VIDEO_BUFFMT_TEXT )\r
-               return ;\r
-\r
-       if( gbVesa_CursorVisible )\r
-               DrvUtil_Video_RemoveCursor(&gVesa_BufInfo);\r
-       else\r
-               DrvUtil_Video_DrawCursor(&gVesa_BufInfo,\r
-                       giVesaCursorX*giVT_CharWidth,\r
-                       giVesaCursorY*giVT_CharHeight\r
-                       );\r
-       gbVesa_CursorVisible = !gbVesa_CursorVisible;\r
-               \r
-       #if BLINKING_CURSOR\r
-       giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, Arg);\r
-       #endif\r
-}\r
-\r
diff --git a/Modules/Filesystems/Ext2/Makefile b/Modules/Filesystems/Ext2/Makefile
deleted file mode 100644 (file)
index 471ba49..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = ext2.o read.o dir.o write.o
-NAME = Ext2
-
--include ../Makefile.tpl
diff --git a/Modules/Filesystems/Ext2/dir.c b/Modules/Filesystems/Ext2/dir.c
deleted file mode 100644 (file)
index 5eb476f..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file dir.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG  1
-#define VERBOSE        0
-#include "ext2_common.h"
-
-// === MACROS ===
-#define BLOCK_DIR_OFS(_data, _block)   ((Uint16*)(_data)[(_block)])
-
-// === PROTOTYPES ===
-char   *Ext2_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
- int   Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
- int   Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
- int   Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
-// --- Helpers ---
-tVFS_Node      *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
-
-// === GLOBALS ===
-tVFS_NodeType  gExt2_DirType = {
-       .TypeName = "ext2-dir",
-       .ReadDir = Ext2_ReadDir,
-       .FindDir = Ext2_FindDir,
-       .MkNod = Ext2_MkNod,
-       .Relink = Ext2_Relink,
-       .Link = Ext2_Link,
-       .Close = Ext2_CloseFile
-       };
-tVFS_NodeType  gExt2_FileType = {
-       .TypeName = "ext2-file",
-       .Read = Ext2_Read,
-       .Write = Ext2_Write,
-       .Close = Ext2_CloseFile
-       };
-
-// === CODE ===
-/**
- * \brief Reads a directory entry
- * \param Node Directory node
- * \param Pos  Position of desired element
- */
-char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tExt2_Inode     inode;
-       tExt2_DirEnt    dirent;
-       Uint64  Base;   // Block's Base Address
-        int    block = 0;
-       Uint    ofs = 0;
-        int    entNum = 0;
-       tExt2_Disk      *disk = Node->ImplPtr;
-       Uint    size;
-       
-       ENTER("pNode iPos", Node, Pos);
-       
-       // Read directory's inode
-       Ext2_int_ReadInode(disk, Node->Inode, &inode);
-       size = inode.i_size;
-       
-       LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
-       
-       // Find Entry
-       // Get First Block
-       // - Do this ourselves as it is a simple operation
-       Base = inode.i_block[0] * disk->BlockSize;
-       // Scan directory
-       while(Pos -- && size > 0)
-       {
-               VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
-               ofs += dirent.rec_len;
-               size -= dirent.rec_len;
-               entNum ++;
-               
-               if(ofs >= disk->BlockSize) {
-                       block ++;
-                       if( ofs > disk->BlockSize ) {
-                               Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
-                                       entNum-1, Node->Inode);
-                       }
-                       ofs = 0;
-                       Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
-               }
-       }
-       
-       // Check for the end of the list
-       if(size <= 0) {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Read Entry
-       VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
-       //LOG("dirent.inode = %i", dirent.inode);
-       //LOG("dirent.rec_len = %i", dirent.rec_len);
-       //LOG("dirent.name_len = %i", dirent.name_len);
-       dirent.name[ dirent.name_len ] = '\0';  // Cap off string
-       
-       
-       // Ignore . and .. (these are done in the VFS)
-       if( (dirent.name[0] == '.' && dirent.name[1] == '\0')
-       ||  (dirent.name[0] == '.' && dirent.name[1] == '.' && dirent.name[2]=='\0')) {
-               LEAVE('p', VFS_SKIP);
-               return VFS_SKIP;        // Skip
-       }
-       
-       LEAVE('s', dirent.name);
-       // Create new node
-       return strdup(dirent.name);
-}
-
-/**
- * \brief Gets information about a file
- * \param Node Parent Node
- * \param Filename     Name of wanted file
- * \return VFS Node of file
- */
-tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename)
-{
-       tExt2_Disk      *disk = Node->ImplPtr;
-       tExt2_Inode     inode;
-       tExt2_DirEnt    dirent;
-       Uint64  Base;   // Block's Base Address
-        int    block = 0;
-       Uint    ofs = 0;
-        int    entNum = 0;
-       Uint    size;
-        int    filenameLen = strlen(Filename);
-       
-       // Read directory's inode
-       Ext2_int_ReadInode(disk, Node->Inode, &inode);
-       size = inode.i_size;
-       
-       // Get First Block
-       // - Do this ourselves as it is a simple operation
-       Base = inode.i_block[0] * disk->BlockSize;
-       // Find File
-       while(size > 0)
-       {
-               VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
-               dirent.name[ dirent.name_len ] = '\0';  // Cap off string
-               // If it matches, create a node and return it
-               if(dirent.name_len == filenameLen && strcmp(dirent.name, Filename) == 0)
-                       return Ext2_int_CreateNode( disk, dirent.inode );
-               // Increment pointers
-               ofs += dirent.rec_len;
-               size -= dirent.rec_len;
-               entNum ++;
-               
-               // Check for end of block
-               if(ofs >= disk->BlockSize) {
-                       block ++;
-                       if( ofs > disk->BlockSize ) {
-                               Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
-                                       entNum-1, Node->Inode);
-                       }
-                       ofs = 0;
-                       Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
-               }
-       }
-       
-       return NULL;
-}
-
-/**
- * \fn int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
- * \brief Create a new node
- */
-int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
-{
-       #if 0
-       tVFS_Node       *child;
-       Uint64  inodeNum;
-       tExt2_Inode     inode;
-       inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
-       
-       memset(&inode, 0, sizeof(tExt2_Inode));
-       
-       // File type
-       inode.i_mode = 0664;
-       if( Flags & VFS_FFLAG_READONLY )
-               inode.i_mode &= ~0222;
-       if( Flags & VFS_FFLAG_SYMLINK )
-               inode.i_mode |= EXT2_S_IFLNK;
-       else if( Flags & VFS_FFLAG_DIRECTORY )
-               inode.i_mode |= EXT2_S_IFDIR | 0111;
-       
-       inode.i_uid = Threads_GetUID();
-       inode.i_gid = Threads_GetGID();
-       inode.i_ctime =
-               inode.i_mtime =
-               inode.i_atime = now() / 1000;
-       
-       child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
-       return Ext2_Link(Parent, child, Name);
-       #else
-       return 1;
-       #endif
-}
-
-/**
- * \brief Rename a file
- * \param Node This (directory) node
- * \param OldName      Old name of file
- * \param NewName      New name for file
- * \return Boolean Failure - See ::tVFS_Node.Relink for info
- */
-int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
-{
-       return 1;
-}
-
-/**
- * \brief Links an existing node to a new name
- * \param Parent       Parent (directory) node
- * \param Node Node to link
- * \param Name New name for the node
- * \return Boolean Failure - See ::tVFS_Node.Link for info
- */
-int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
-{      
-       #if 0
-       tExt2_Disk      *disk = Node->ImplPtr;
-       tExt2_Inode     inode;
-       tExt2_DirEnt    dirent;
-       tExt2_DirEnt    newEntry;
-       Uint64  Base;   // Block's Base Address
-        int    block = 0, ofs = 0;
-       Uint    size;
-       void    *blockData;
-        int    bestMatch = -1, bestSize, bestBlock, bestOfs;
-        int    nEntries;
-       
-       blockData = malloc(disk->BlockSize);
-       
-       // Read child inode (get's the file type)
-       Ext2_int_ReadInode(disk, Child->Inode, &inode);
-       
-       // Create a stub entry
-       newEntry.inode = Child->Inode;
-       newEntry.name_len = strlen(Name);
-       newEntry.rec_len = (newEntry.name_len+3+8)&~3;
-       newEntry.type = inode.i_mode >> 12;
-       memcpy(newEntry.name, Name, newEntry.name_len);
-       
-       // Read directory's inode
-       Ext2_int_ReadInode(disk, Node->Inode, &inode);
-       size = inode.i_size;
-       
-       // Get a lock on the inode
-       Ext2_int_LockInode(disk, Node->Inode);
-       
-       // Get First Block
-       // - Do this ourselves as it is a simple operation
-       base = inode.i_block[0] * disk->BlockSize;
-       VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
-       block = 0;
-       // Find File
-       while(size > 0)
-       {
-               dirent = blockData + ofs;
-               // Sanity Check the entry
-               if(ofs + dirent->rec_len > disk->BlockSize) {
-                       Log_Warning("EXT2",
-                               "Directory entry %i of inode 0x%x extends over a block boundary",
-                               nEntries, (Uint)Node->Inode);
-               }
-               else {
-               
-                       // Free entry
-                       if(dirent->type == 0) {
-                               if( dirent->rec_len >= newEntry.rec_len
-                                && (bestMatch == -1 || bestSize > dirent->rec_len) )
-                               {
-                                       bestMatch = nEntries;
-                                       bestSize = dirent->rec_len;
-                                       bestBlock = block;
-                                       bestOfs = ofs;
-                               }
-                       }
-                       // Non free - check name to avoid duplicates
-                       else {
-                               if(strncmp(Name, dirent->name, dirent->name_len) == 0) {
-                                       Ext2_int_UnlockInode(disk, Node->Inode);
-                                       return 1;       // ERR_???
-                               }
-                       }
-               }
-               
-               // Increment the pointer
-               nEntries ++;
-               ofs += dirent->rec_len;
-               if( ofs >= disk->BlockSize ) {
-                       // Read the next block if needed
-                       BLOCK_DIR_OFS(Node->Data, block) = nEntries;
-                       block ++;
-                       ofs = 0;
-                       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-                       VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
-               }
-       }
-       
-       // Check if a free slot was found
-       if( bestMatch >= 0 ) {
-               // Read-Modify-Write
-               bestBlock = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock);
-               if( block > 0 )
-                       bestMatch = BLOCK_DIR_OFS(Node->Data, bestBlock);
-               VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
-               dirent = blockData + bestOfs;
-               memcpy(dirent, newEntry, newEntry.rec_len);
-               VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData );
-       }
-       else {
-               // Allocate block, Write
-               block = Ext2_int_AllocateBlock(Disk, block);
-               Log_Warning("EXT2", "");
-       }
-
-       Ext2_int_UnlockInode(disk, Node->Inode);
-       return 0;
-       #else
-       return 1;
-       #endif
-}
-
-// ---- INTERNAL FUNCTIONS ----
-/**
- * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
- * \brief Create a new VFS Node
- */
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
-{
-       tExt2_Inode     inode;
-       tVFS_Node       retNode;
-       tVFS_Node       *tmpNode;
-       
-       if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
-               return NULL;
-       
-       if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
-               return tmpNode;
-       
-       
-       // Set identifiers
-       retNode.Inode = InodeID;
-       retNode.ImplPtr = Disk;
-       
-       // Set file length
-       retNode.Size = inode.i_size;
-       retNode.Data = NULL;
-       
-       // Set Access Permissions
-       retNode.UID = inode.i_uid;
-       retNode.GID = inode.i_gid;
-       retNode.NumACLs = 3;
-       retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
-       
-       //  Set Function Pointers
-       retNode.Type = &gExt2_FileType;
-       
-       switch(inode.i_mode & EXT2_S_IFMT)
-       {
-       // Symbolic Link
-       case EXT2_S_IFLNK:
-               retNode.Flags = VFS_FFLAG_SYMLINK;
-               break;
-       // Regular File
-       case EXT2_S_IFREG:
-               retNode.Flags = 0;
-               retNode.Size |= (Uint64)inode.i_dir_acl << 32;
-               break;
-       // Directory
-       case EXT2_S_IFDIR:
-               retNode.Type = &gExt2_DirType;
-               retNode.Flags = VFS_FFLAG_DIRECTORY;
-               retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );
-               break;
-       // Unknown, Write protect it to be safe 
-       default:
-               retNode.Flags = VFS_FFLAG_READONLY;
-               break;
-       }
-       
-       // Set Timestamps
-       retNode.ATime = inode.i_atime * 1000;
-       retNode.MTime = inode.i_mtime * 1000;
-       retNode.CTime = inode.i_ctime * 1000;
-       
-       // Save in node cache and return saved node
-       return Inode_CacheNode(Disk->CacheID, &retNode);
-}
diff --git a/Modules/Filesystems/Ext2/ext2.c b/Modules/Filesystems/Ext2/ext2.c
deleted file mode 100644 (file)
index 7c4bf97..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*\r
- * Acess OS\r
- * Ext2 Driver Version 1\r
- */\r
-/**\r
- * \file fs/ext2.c\r
- * \brief Second Extended Filesystem Driver\r
- * \todo Implement file full write support\r
- */\r
-#define DEBUG  1\r
-#define VERBOSE        0\r
-#include "ext2_common.h"\r
-#include <modules.h>\r
-\r
-// === IMPORTS ===\r
-extern tVFS_NodeType   gExt2_DirType;\r
-\r
-// === PROTOTYPES ===\r
- int   Ext2_Install(char **Arguments);\r
-// Interface Functions\r
-tVFS_Node      *Ext2_InitDevice(const char *Device, const char **Options);\r
-void           Ext2_Unmount(tVFS_Node *Node);\r
-void           Ext2_CloseFile(tVFS_Node *Node);\r
-// Internal Helpers\r
- int           Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
-Uint64         Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
-Uint32         Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
-void           Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
-\r
-// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
-tExt2_Disk     gExt2_disks[6];\r
- int   giExt2_count = 0;\r
-tVFS_Driver    gExt2_FSInfo = {\r
-       "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
-       };\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int Ext2_Install(char **Arguments)\r
- * \brief Install the Ext2 Filesystem Driver\r
- */\r
-int Ext2_Install(char **Arguments)\r
-{\r
-       VFS_AddDriver( &gExt2_FSInfo );\r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- \brief Initializes a device to be read by by the driver\r
- \param Device String - Device to read from\r
- \param Options        NULL Terminated array of option strings\r
- \return Root Node\r
-*/\r
-tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)\r
-{\r
-       tExt2_Disk      *disk;\r
-        int    fd;\r
-        int    groupCount;\r
-       tExt2_SuperBlock        sb;\r
-       tExt2_Inode     inode;\r
-       \r
-       ENTER("sDevice pOptions", Device, Options);\r
-       \r
-       // Open Disk\r
-       fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);            //Open Device\r
-       if(fd == -1) {\r
-               Log_Warning("EXT2", "Unable to open '%s'", Device);\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Read Superblock at offset 1024\r
-       VFS_ReadAt(fd, 1024, 1024, &sb);        // Read Superblock\r
-       \r
-       // Sanity Check Magic value\r
-       if(sb.s_magic != 0xEF53) {\r
-               Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)",\r
-                       Device, sb.s_magic);\r
-               VFS_Close(fd);\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Get Group count\r
-       groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
-       LOG("groupCount = %i", groupCount);\r
-       \r
-       // Allocate Disk Information\r
-       disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
-       if(!disk) {\r
-               Log_Warning("EXT2", "Unable to allocate disk structure");\r
-               VFS_Close(fd);\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       disk->FD = fd;\r
-       memcpy(&disk->SuperBlock, &sb, 1024);\r
-       disk->GroupCount = groupCount;\r
-       \r
-       // Get an inode cache handle\r
-       disk->CacheID = Inode_GetHandle();\r
-       \r
-       // Get Block Size\r
-       LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
-       disk->BlockSize = 1024 << sb.s_log_block_size;\r
-       \r
-       // Read Group Information\r
-       VFS_ReadAt(\r
-               disk->FD,\r
-               sb.s_first_data_block * disk->BlockSize + 1024,\r
-               sizeof(tExt2_Group)*groupCount,\r
-               disk->Groups\r
-               );\r
-       \r
-       #if VERBOSE\r
-       LOG("Block Group 0");\r
-       LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
-       LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
-       LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
-       LOG("Block Group 1");\r
-       LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
-       LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
-       LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
-       #endif\r
-       \r
-       // Get root Inode\r
-       Ext2_int_ReadInode(disk, 2, &inode);\r
-       \r
-       // Create Root Node\r
-       memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
-       disk->RootNode.Inode = 2;       // Root inode ID\r
-       disk->RootNode.ImplPtr = disk;  // Save disk pointer\r
-       disk->RootNode.Size = -1;       // Fill in later (on readdir)\r
-       disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
-\r
-       disk->RootNode.Type = &gExt2_DirType;\r
-       \r
-       // Complete root node\r
-       disk->RootNode.UID = inode.i_uid;\r
-       disk->RootNode.GID = inode.i_gid;\r
-       disk->RootNode.NumACLs = 1;\r
-       disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
-       \r
-       #if DEBUG\r
-       LOG("inode.i_size = 0x%x", inode.i_size);\r
-       LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
-       #endif\r
-       \r
-       LEAVE('p', &disk->RootNode);\r
-       return &disk->RootNode;\r
-}\r
-\r
-/**\r
- * \fn void Ext2_Unmount(tVFS_Node *Node)\r
- * \brief Close a mounted device\r
- */\r
-void Ext2_Unmount(tVFS_Node *Node)\r
-{\r
-       tExt2_Disk      *disk = Node->ImplPtr;\r
-       \r
-       VFS_Close( disk->FD );\r
-       Inode_ClearCache( disk->CacheID );\r
-       memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
-       free(disk);\r
-}\r
-\r
-/**\r
- * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
- * \brief Close a file (Remove it from the cache)\r
- */\r
-void Ext2_CloseFile(tVFS_Node *Node)\r
-{\r
-       tExt2_Disk      *disk = Node->ImplPtr;\r
-       Inode_UncacheNode(disk->CacheID, Node->Inode);\r
-       return ;\r
-}\r
-\r
-//==================================\r
-//=       INTERNAL FUNCTIONS       =\r
-//==================================\r
-/**\r
- * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
- * \brief Read an inode into memory\r
- */\r
-int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
-{\r
-        int    group, subId;\r
-       \r
-       ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
-       \r
-       if(InodeId == 0)        return 0;\r
-       \r
-       InodeId --;     // Inodes are numbered starting at 1\r
-       \r
-       group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
-       subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
-       \r
-       LOG("group=%i, subId = %i", group, subId);\r
-       \r
-       // Read Inode\r
-       VFS_ReadAt(Disk->FD,\r
-               Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
-               sizeof(tExt2_Inode),\r
-               Inode);\r
-       \r
-       LEAVE('i', 1);\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \brief Write a modified inode out to disk\r
- */\r
-int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
-{\r
-        int    group, subId;\r
-       ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
-       \r
-       if(InodeId == 0) {\r
-               LEAVE('i', 0);\r
-               return 0;\r
-       }\r
-       \r
-       InodeId --;     // Inodes are numbered starting at 1\r
-       \r
-       group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
-       subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
-       \r
-       LOG("group=%i, subId = %i", group, subId);\r
-       \r
-       // Write Inode\r
-       VFS_WriteAt(Disk->FD,\r
-               Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
-               sizeof(tExt2_Inode),\r
-               Inode\r
-               );\r
-       \r
-       LEAVE('i', 1);\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
- * \brief Get the address of a block from an inode's list\r
- * \param Disk Disk information structure\r
- * \param Blocks       Pointer to an inode's block list\r
- * \param BlockNum     Block index in list\r
- */\r
-Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
-{\r
-       Uint32  *iBlocks;\r
-        int    dwPerBlock = Disk->BlockSize / 4;\r
-       \r
-       // Direct Blocks\r
-       if(BlockNum < 12)\r
-               return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
-       \r
-       // Single Indirect Blocks\r
-       iBlocks = malloc( Disk->BlockSize );\r
-       VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       \r
-       BlockNum -= 12;\r
-       if(BlockNum < dwPerBlock)\r
-       {\r
-               BlockNum = iBlocks[BlockNum];\r
-               free(iBlocks);\r
-               return (Uint64)BlockNum * Disk->BlockSize;\r
-       }\r
-       \r
-       BlockNum -= dwPerBlock;\r
-       // Double Indirect Blocks\r
-       if(BlockNum < dwPerBlock*dwPerBlock)\r
-       {\r
-               VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-               VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-               BlockNum = iBlocks[BlockNum%dwPerBlock];\r
-               free(iBlocks);\r
-               return (Uint64)BlockNum * Disk->BlockSize;\r
-       }\r
-       \r
-       BlockNum -= dwPerBlock*dwPerBlock;\r
-       // Triple Indirect Blocks\r
-       VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       BlockNum = iBlocks[BlockNum%dwPerBlock];\r
-       free(iBlocks);\r
-       return (Uint64)BlockNum * Disk->BlockSize;\r
-}\r
-\r
-/**\r
- * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
- * \brief Allocate an inode (from the current group preferably)\r
- * \param Disk EXT2 Disk Information Structure\r
- * \param Parent       Inode ID of the parent (used to locate the child nearby)\r
- */\r
-Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
-{\r
-//     Uint    block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
-       Log_Warning("EXT2", "Ext2_int_AllocateInode is unimplemented");\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
- * \brief Updates the superblock\r
- */\r
-void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
-{\r
-        int    bpg = Disk->SuperBlock.s_blocks_per_group;\r
-        int    ngrp = Disk->SuperBlock.s_blocks_count / bpg;\r
-        int    i;\r
-        \r
-       // Update Primary\r
-       VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
-       \r
-       // Secondaries\r
-       // at Block Group 1, 3^n, 5^n, 7^n\r
-       \r
-       // 1\r
-       if(ngrp <= 1)   return;\r
-       VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
-       \r
-       #define INT_MAX (((long long int)1<<(sizeof(int)*8))-1)\r
-       \r
-       // Powers of 3\r
-       for( i = 3; i < ngrp && i < INT_MAX/3; i *= 3 )\r
-               VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
-       \r
-       // Powers of 5\r
-       for( i = 5; i < ngrp && i < INT_MAX/5; i *= 5 )\r
-               VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
-       \r
-       // Powers of 7\r
-       for( i = 7; i < ngrp && i < INT_MAX/7; i *= 7 )\r
-               VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
-}\r
diff --git a/Modules/Filesystems/Ext2/ext2_common.h b/Modules/Filesystems/Ext2/ext2_common.h
deleted file mode 100644 (file)
index 6ef9d7c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file ext2_common.h
- * \brief Second Extended Filesystem Driver
- */
-#ifndef _EXT2_COMMON_H
-#define _EXT2_COMMON_H
-#include <acess.h>
-#include <vfs.h>
-#include "ext2fs.h"
-
-#define EXT2_UPDATE_WRITEBACK  1
-
-// === STRUCTURES ===
-typedef struct {
-        int    FD;
-        int    CacheID;
-       tVFS_Node       RootNode;
-       
-       tExt2_SuperBlock        SuperBlock;
-       Uint    BlockSize;
-        
-        int    GroupCount;
-       tExt2_Group             Groups[];
-} tExt2_Disk;
-
-// === FUNCTIONS ===
-// --- Common ---
-extern void    Ext2_CloseFile(tVFS_Node *Node);
-extern Uint64  Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
-extern void    Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
-extern int     Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
-extern int     Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
-// --- Dir ---
-extern char    *Ext2_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node       *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
-extern int     Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
-extern int     Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
-// --- Read ---
-extern Uint64  Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
-// --- Write ---
-extern Uint64  Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, const void *buffer);
-
-#endif
diff --git a/Modules/Filesystems/Ext2/ext2fs.h b/Modules/Filesystems/Ext2/ext2fs.h
deleted file mode 100644 (file)
index a3aa301..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/**\r
- * Acess2\r
- * \file ext2fs.h\r
- * \brief EXT2 Filesystem Driver\r
- */\r
-#ifndef _EXT2FS_H_\r
-#define _EXT2FS_H_\r
-\r
-/**\r
- \name Inode Flag Values\r
- \{\r
-*/\r
-#define EXT2_S_IFMT            0xF000  //!< Format Mask\r
-#define EXT2_S_IFSOCK  0xC000  //!< Socket\r
-#define EXT2_S_IFLNK   0xA000  //!< Symbolic Link\r
-#define EXT2_S_IFREG   0x8000  //!< Regular File\r
-#define EXT2_S_IFBLK   0x6000  //!< Block Device\r
-#define EXT2_S_IFDIR   0x4000  //!< Directory\r
-#define EXT2_S_IFCHR   0x2000  //!< Character Device\r
-#define EXT2_S_IFIFO   0x1000  //!< FIFO\r
-#define EXT2_S_ISUID   0x0800  //!< SUID\r
-#define EXT2_S_ISGID   0x0400  //!< SGID\r
-#define EXT2_S_ISVTX   0x0200  //!< sticky bit\r
-#define EXT2_S_IRWXU   0700    //!< user access rights mask\r
-#define EXT2_S_IRUSR   0400    //!< Owner Read\r
-#define EXT2_S_IWUSR   0200    //!< Owner Write\r
-#define EXT2_S_IXUSR   0100    //!< Owner Execute\r
-#define EXT2_S_IRWXG   0070    //!< Group Access rights mask\r
-#define EXT2_S_IRGRP   0040    //!< Group Read\r
-#define EXT2_S_IWGRP   0020    //!< Group Write\r
-#define EXT2_S_IXGRP   0010    //!< Group Execute\r
-#define EXT2_S_IRWXO   0007    //!< Global Access rights mask\r
-#define EXT2_S_IROTH   0004    //!< Global Read\r
-#define EXT2_S_IWOTH   0002    //!< Global Write\r
-#define EXT2_S_IXOTH   0001    //!< Global Execute\r
-//! \}\r
-\r
-#define EXT2_NAME_LEN 255      //!< Maximum Name Length\r
-\r
-// === TYPEDEFS ===\r
-typedef struct ext2_inode_s                    tExt2_Inode;    //!< Inode Type\r
-typedef struct ext2_super_block_s      tExt2_SuperBlock;       //!< Superblock Type\r
-typedef struct ext2_group_desc_s       tExt2_Group;    //!< Group Descriptor Type\r
-typedef struct ext2_dir_entry_s                tExt2_DirEnt;   //!< Directory Entry Type\r
-\r
-// === STRUCTURES ===\r
-/**\r
- * \brief EXT2 Superblock Structure\r
- */\r
-struct ext2_super_block_s {\r
-       Uint32  s_inodes_count;         //!< Inodes count\r
-       Uint32  s_blocks_count;         //!< Blocks count\r
-       Uint32  s_r_blocks_count;       //!< Reserved blocks count\r
-       Uint32  s_free_blocks_count;    //!< Free blocks count\r
-       \r
-       Uint32  s_free_inodes_count;    //!< Free inodes count\r
-       Uint32  s_first_data_block;     //!< First Data Block\r
-       Uint32  s_log_block_size;       //!< Block size\r
-       Sint32  s_log_frag_size;        //!< Fragment size\r
-       \r
-       Uint32  s_blocks_per_group;     //!< Number Blocks per group\r
-       Uint32  s_frags_per_group;      //!< Number Fragments per group\r
-       Uint32  s_inodes_per_group;     //!< Number Inodes per group\r
-       Uint32  s_mtime;                        //!< Mount time\r
-       \r
-       Uint32  s_wtime;                        //!< Write time\r
-       Uint16  s_mnt_count;            //!< Mount count\r
-       Sint16  s_max_mnt_count;        //!< Maximal mount count\r
-       Uint16  s_magic;                        //!< Magic signature\r
-       Uint16  s_state;                        //!< File system state\r
-       Uint16  s_errors;                       //!< Behaviour when detecting errors\r
-       Uint16  s_pad;                          //!< Padding\r
-       \r
-       Uint32  s_lastcheck;            //!< time of last check\r
-       Uint32  s_checkinterval;        //!< max. time between checks\r
-       Uint32  s_creator_os;           //!< Formatting OS\r
-       Uint32  s_rev_level;            //!< Revision level\r
-       \r
-       Uint16  s_def_resuid;           //!< Default uid for reserved blocks\r
-       Uint16  s_def_resgid;           //!< Default gid for reserved blocks\r
-       Uint32  s_reserved[235];        //!< Padding to the end of the block\r
-};\r
-\r
-/**\r
- * \struct ext2_inode_s\r
- * \brief EXT2 Inode Definition\r
- */\r
-struct ext2_inode_s {\r
-       Uint16 i_mode;  //!< File mode\r
-       Uint16 i_uid;   //!< Owner Uid\r
-       Uint32 i_size;  //!< Size in bytes\r
-       Uint32 i_atime; //!< Access time\r
-       Uint32 i_ctime; //!< Creation time\r
-       Uint32 i_mtime; //!< Modification time\r
-       Uint32 i_dtime; //!< Deletion Time\r
-       Uint16 i_gid;   //!< Group Id\r
-       Uint16 i_links_count;   //!< Links count\r
-       Uint32 i_blocks;        //!< Number of blocks allocated for the file\r
-       Uint32 i_flags; //!< File flags\r
-       union {\r
-               Uint32 linux_reserved1; //!< Linux: Reserved\r
-               Uint32 hurd_translator; //!< HURD: Translator\r
-               Uint32 masix_reserved1; //!< Masix: Reserved\r
-       } osd1; //!< OS dependent 1\r
-       Uint32 i_block[15];     //!< Pointers to blocks\r
-       Uint32 i_version;       //!< File version (for NFS)\r
-       Uint32 i_file_acl;      //!< File ACL\r
-       Uint32 i_dir_acl;       //!< Directory ACL / Extended File Size\r
-       Uint32 i_faddr;         //!< Fragment address\r
-       union {\r
-               struct {\r
-                       Uint8 l_i_frag; //!< Fragment number\r
-                       Uint8 l_i_fsize;        //!< Fragment size\r
-                       Uint16 i_pad1;  //!< Padding\r
-                       Uint32 l_i_reserved2[2];        //!< Reserved\r
-               } linux2;\r
-               struct {\r
-                       Uint8 h_i_frag; //!< Fragment number\r
-                       Uint8 h_i_fsize; //!< Fragment size\r
-                       Uint16 h_i_mode_high;   //!< Mode High Bits\r
-                       Uint16 h_i_uid_high;    //!< UID High Bits\r
-                       Uint16 h_i_gid_high;    //!< GID High Bits\r
-                       Uint32 h_i_author;      //!< Creator ID\r
-               } hurd2;\r
-               struct {\r
-                       Uint8 m_i_frag; //!< Fragment number\r
-                       Uint8 m_i_fsize;        //!< Fragment size\r
-                       Uint16 m_pad1;  //!< Padding\r
-                       Uint32 m_i_reserved2[2];        //!< reserved\r
-               } masix2;\r
-       } osd2; //!< OS dependent 2\r
-};\r
-\r
-/**\r
- * \struct ext2_group_desc_s\r
- * \brief EXT2 Group Descriptor\r
- */\r
-struct ext2_group_desc_s {\r
-       Uint32  bg_block_bitmap;        //!< Blocks bitmap block\r
-       Uint32  bg_inode_bitmap;        //!< Inodes bitmap block\r
-       Uint32  bg_inode_table; //!< Inodes table block\r
-       Uint16  bg_free_blocks_count;   //!< Free blocks count\r
-       Uint16  bg_free_inodes_count;   //!< Free inodes count\r
-       Uint16  bg_used_dirs_count;     //!< Directories count\r
-       Uint16  bg_pad; //!< Padding\r
-       Uint32  bg_reserved[3]; //!< Reserved\r
-};\r
-\r
-/**\r
- * \brief EXT2 Directory Entry\r
- * \note The name may take up less than 255 characters\r
- */\r
-struct ext2_dir_entry_s {\r
-       Uint32  inode;          //!< Inode number\r
-       Uint16  rec_len;        //!< Directory entry length\r
-       Uint8   name_len;       //!< Short Name Length\r
-       Uint8   type;           //!< File Type (Duplicate of ext2_inode_s.i_mode)\r
-       char    name[EXT2_NAME_LEN+1];          //!< File name\r
-};\r
-#define EXT2_DIRENT_SIZE       (sizeof(struct ext2_dir_entry_s)-EXT2_NAME_LEN+1)\r
-\r
-#endif\r
diff --git a/Modules/Filesystems/Ext2/read.c b/Modules/Filesystems/Ext2/read.c
deleted file mode 100644 (file)
index 81f5ee6..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file read.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG  1
-#define VERBOSE        0
-#include "ext2_common.h"
-
-// === PROTOTYPES ===
-Uint64         Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
-
-// === CODE ===
-/**
- * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from a file
- */
-Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tExt2_Disk      *disk = Node->ImplPtr;
-       tExt2_Inode     inode;
-       Uint64  base;
-       Uint    block;
-       Uint64  remLen;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       // Get Inode
-       Ext2_int_ReadInode(disk, Node->Inode, &inode);
-       
-       // Sanity Checks
-       if(Offset >= inode.i_size) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       if(Offset + Length > inode.i_size)
-               Length = inode.i_size - Offset;
-       
-       block = Offset / disk->BlockSize;
-       Offset = Offset / disk->BlockSize;
-       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-       if(base == 0) {
-               Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Read only block
-       if(Length <= disk->BlockSize - Offset)
-       {
-               VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);
-               LEAVE('X', Length);
-               return Length;
-       }
-       
-       // Read first block
-       remLen = Length;
-       VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);
-       remLen -= disk->BlockSize - Offset;
-       Buffer += disk->BlockSize - Offset;
-       block ++;
-       
-       // Read middle blocks
-       while(remLen > disk->BlockSize)
-       {
-               base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-               if(base == 0) {
-                       Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);
-               Buffer += disk->BlockSize;
-               remLen -= disk->BlockSize;
-               block ++;
-       }
-       
-       // Read last block
-       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-       VFS_ReadAt( disk->FD, base, remLen, Buffer);
-       
-       LEAVE('X', Length);
-       return Length;
-}
diff --git a/Modules/Filesystems/Ext2/write.c b/Modules/Filesystems/Ext2/write.c
deleted file mode 100644 (file)
index 03109e8..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file write.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG  1
-#define VERBOSE        0
-#include "ext2_common.h"
-
-// === PROTOYPES ===
-Uint32         Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
-void   Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
- int   Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
-
-// === CODE ===
-/**
- * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Write to a file
- */
-Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tExt2_Disk      *disk = Node->ImplPtr;
-       tExt2_Inode     inode;
-       Uint64  base;
-       Uint64  retLen;
-       Uint    block;
-       Uint64  allocSize;
-        int    bNewBlocks = 0;
-       
-       Debug_HexDump("Ext2_Write", Buffer, Length);
-       
-       Ext2_int_ReadInode(disk, Node->Inode, &inode);
-       
-       // Get the ammount of space already allocated
-       // - Round size up to block size
-       // - block size is a power of two, so this will work
-       allocSize = (inode.i_size + disk->BlockSize-1) & ~(disk->BlockSize-1);
-       
-       // Are we writing to inside the allocated space?
-       if( Offset > allocSize )        return 0;
-       
-       if( Offset < allocSize )
-       {
-               // Will we go out of it?
-               if(Offset + Length > allocSize) {
-                       bNewBlocks = 1;
-                       retLen = allocSize - Offset;
-               } else
-                       retLen = Length;
-               
-               // Within the allocated space
-               block = Offset / disk->BlockSize;
-               Offset %= disk->BlockSize;
-               base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-               
-               // Write only block (if only one)
-               if(Offset + retLen <= disk->BlockSize) {
-                       VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);
-                       if(!bNewBlocks) return Length;
-                       goto addBlocks; // Ugh! A goto, but it seems unavoidable
-               }
-               
-               // Write First Block
-               VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);
-               Buffer += disk->BlockSize-Offset;
-               retLen -= disk->BlockSize-Offset;
-               block ++;
-               
-               // Write middle blocks
-               while(retLen > disk->BlockSize)
-               {
-                       base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-                       VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
-                       Buffer += disk->BlockSize;
-                       retLen -= disk->BlockSize;
-                       block ++;
-               }
-               
-               // Write last block
-               base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-               VFS_WriteAt(disk->FD, base, retLen, Buffer);
-               if(!bNewBlocks) return Length;  // Writing in only allocated space
-       }
-       else
-               base = Ext2_int_GetBlockAddr(disk, inode.i_block, allocSize/disk->BlockSize-1);
-       
-addBlocks:
-       Log_Notice("EXT2", "File extending is untested");
-       
-       // Allocate blocks and copy data to them
-       retLen = Length - (allocSize-Offset);
-       while( retLen > disk->BlockSize )
-       {
-               // Allocate a block
-               block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
-               if(!block)      return Length - retLen;
-               // Add it to this inode
-               if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
-                       Ext2_int_DeallocateBlock(disk, block);
-                       goto ret;
-               }
-               // Copy data to the node
-               base = block * disk->BlockSize;
-               VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
-               // Update pointer and size remaining
-               inode.i_size += disk->BlockSize;
-               Buffer += disk->BlockSize;
-               retLen -= disk->BlockSize;
-       }
-       // Last block :D
-       block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
-       if(!block)      goto ret;
-       if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
-               Ext2_int_DeallocateBlock(disk, block);
-               goto ret;
-       }
-       base = block * disk->BlockSize;
-       VFS_WriteAt(disk->FD, base, retLen, Buffer);
-       inode.i_size += retLen;
-       retLen = 0;
-
-ret:   // Makes sure the changes to the inode are committed
-       Ext2_int_WriteInode(disk, Node->Inode, &inode);
-       return Length - retLen;
-}
-
-/**
- * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
- * \brief Allocate a block from the best possible location
- * \param Disk EXT2 Disk Information Structure
- * \param PrevBlock    Previous block ID in the file
- */
-Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
-{
-        int    bpg = Disk->SuperBlock.s_blocks_per_group;
-       Uint    blockgroup = PrevBlock / bpg;
-       Uint    bitmap[Disk->BlockSize/sizeof(Uint)];
-       Uint    bitsperblock = 8*Disk->BlockSize;
-        int    i, j = 0;
-       Uint    block;
-       
-       // Are there any free blocks?
-       if(Disk->SuperBlock.s_free_blocks_count == 0)   return 0;
-       
-       if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
-       {
-               // Search block group's bitmap
-               for(i = 0; i < bpg; i++)
-               {
-                       // Get the block in the bitmap block
-                       j = i & (bitsperblock-1);
-                       
-                       // Read in if needed
-                       if(j == 0) {
-                               VFS_ReadAt(
-                                       Disk->FD,
-                                       (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
-                                       Disk->BlockSize,
-                                       bitmap
-                                       );
-                       }
-                       
-                       // Fast Check
-                       if( bitmap[j/32] == 0xFFFFFFFF ) {
-                               j = (j + 31) & ~31;
-                               continue;
-                       }
-                       
-                       // Is the bit set?
-                       if( bitmap[j/32] & (1 << (j%32)) )
-                               continue;
-                       
-                       // Ooh! We found one
-                       break;
-               }
-               if( i < bpg ) {
-                       Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
-                       goto    checkAll;       // Search the entire filesystem for a free block
-                       // Goto needed for neatness
-               }
-               
-               // Mark as used
-               bitmap[j/32] |= (1 << (j%32));
-               VFS_WriteAt(
-                       Disk->FD,
-                       (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
-                       Disk->BlockSize,
-                       bitmap
-                       );
-               block = i;
-               Disk->Groups[blockgroup].bg_free_blocks_count --;
-               #if EXT2_UPDATE_WRITEBACK
-               //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
-               #endif
-       }
-       else
-       {
-       checkAll:
-               Log_Warning("EXT2", "TODO - Implement using blocks outside the current block group");
-               return 0;
-       }
-       
-       // Reduce global count
-       Disk->SuperBlock.s_free_blocks_count --;
-       #if EXT2_UPDATE_WRITEBACK
-       Ext2_int_UpdateSuperblock(Disk);
-       #endif
-       
-       return block;
-}
-
-/**
- * \brief Deallocates a block
- */
-void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block)
-{
-}
-
-/**
- * \brief Append a block to an inode
- */
-int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
-{
-        int    nBlocks;
-        int    dwPerBlock = Disk->BlockSize / 4;
-       Uint32  *blocks;
-       Uint32  id1, id2;
-       
-       nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize;
-       
-       // Direct Blocks
-       if( nBlocks < 12 ) {
-               Inode->i_block[nBlocks] = Block;
-               return 0;
-       }
-       
-       blocks = malloc( Disk->BlockSize );
-       if(!blocks)     return 1;
-       
-       nBlocks -= 12;
-       // Single Indirect
-       if( nBlocks < dwPerBlock)
-       {
-               // Allocate/Get Indirect block
-               if( nBlocks == 0 ) {
-                       Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
-                       if( !Inode->i_block[12] ) {
-                               free(blocks);
-                               return 1;
-                       }
-                       memset(blocks, 0, Disk->BlockSize); 
-               }
-               else
-                       VFS_ReadAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks);
-               
-               blocks[nBlocks] = Block;
-               
-               VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks);
-               free(blocks);
-               return 0;
-       }
-       
-       nBlocks += dwPerBlock;
-       // Double Indirect
-       if( nBlocks < dwPerBlock*dwPerBlock )
-       {
-               // Allocate/Get Indirect block
-               if( nBlocks == 0 ) {
-                       Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
-                       if( !Inode->i_block[13] ) {
-                               free(blocks);
-                               return 1;
-                       }
-                       memset(blocks, 0, Disk->BlockSize);
-               }
-               else
-                       VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks);
-               
-               // Allocate / Get Indirect lvl2 Block
-               if( nBlocks % dwPerBlock == 0 ) {
-                       id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
-                       if( !id1 ) {
-                               free(blocks);
-                               return 1;
-                       }
-                       blocks[nBlocks/dwPerBlock] = id1;
-                       // Write back indirect 1 block
-                       VFS_WriteAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks);
-                       memset(blocks, 0, Disk->BlockSize);
-               }
-               else {
-                       id1 = blocks[nBlocks / dwPerBlock];
-                       VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
-               }
-               
-               blocks[nBlocks % dwPerBlock] = Block;
-               
-               VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
-               free(blocks);
-               return 0;
-       }
-       
-       nBlocks -= dwPerBlock*dwPerBlock;
-       // Triple Indirect
-       if( nBlocks < dwPerBlock*dwPerBlock*dwPerBlock )
-       {
-               // Allocate/Get Indirect block
-               if( nBlocks == 0 ) {
-                       Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
-                       if( !Inode->i_block[14] ) {
-                               free(blocks);
-                               return 1;
-                       }
-                       memset(blocks, 0, Disk->BlockSize);
-               }
-               else
-                       VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks);
-               
-               // Allocate / Get Indirect lvl2 Block
-               if( (nBlocks/dwPerBlock) % dwPerBlock == 0 && nBlocks % dwPerBlock == 0 )
-               {
-                       id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
-                       if( !id1 ) {
-                               free(blocks);
-                               return 1;
-                       }
-                       blocks[nBlocks/dwPerBlock] = id1;
-                       // Write back indirect 1 block
-                       VFS_WriteAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks);
-                       memset(blocks, 0, Disk->BlockSize);
-               }
-               else {
-                       id1 = blocks[nBlocks / (dwPerBlock*dwPerBlock)];
-                       VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
-               }
-               
-               // Allocate / Get Indirect Level 3 Block
-               if( nBlocks % dwPerBlock == 0 ) {
-                       id2 = Ext2_int_AllocateBlock(Disk, id1);
-                       if( !id2 ) {
-                               free(blocks);
-                               return 1;
-                       }
-                       blocks[(nBlocks/dwPerBlock)%dwPerBlock] = id2;
-                       // Write back indirect 1 block
-                       VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
-                       memset(blocks, 0, Disk->BlockSize);
-               }
-               else {
-                       id2 = blocks[(nBlocks/dwPerBlock)%dwPerBlock];
-                       VFS_ReadAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks);
-               }
-               
-               blocks[nBlocks % dwPerBlock] = Block;
-               
-               VFS_WriteAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks);
-               free(blocks);
-               return 0;
-       }
-       
-       Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used");
-       free(blocks);
-       return 1;
-}
diff --git a/Modules/Filesystems/FAT/Makefile b/Modules/Filesystems/FAT/Makefile
deleted file mode 100644 (file)
index dfa290b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = fat.o
-NAME = FAT
-
--include ../Makefile.tpl
diff --git a/Modules/Filesystems/FAT/fat.c b/Modules/Filesystems/FAT/fat.c
deleted file mode 100644 (file)
index f5d1916..0000000
+++ /dev/null
@@ -1,1538 +0,0 @@
-/*\r
- * Acess 2\r
- * FAT12/16/32 Driver Version (Incl LFN)\r
- * \r
- * NOTE: This driver will only support _reading_ long file names, not\r
- * writing. I don't even know why I'm adding write-support. FAT sucks.\r
- * \r
- * Known Bugs:\r
- * - LFN Is buggy in FAT_ReadDir\r
- * \r
- * Notes:\r
- * - There's hard-coded 512 byte sectors everywhere, that needs to be\r
- *   cleaned.\r
- * - Thread safety is out the window with the write and LFN code\r
- */\r
-/**\r
- * \todo Implement changing of the parent directory when a file is written to\r
- * \todo Implement file creation / deletion\r
- */\r
-#define DEBUG  0\r
-#define VERBOSE        1\r
-\r
-#define CACHE_FAT      0       //!< Caches the FAT in memory\r
-#define USE_LFN                1       //!< Enables the use of Long File Names\r
-#define        SUPPORT_WRITE   0       //!< Enables write support\r
-\r
-#include <acess.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include "fs_fat.h"\r
-\r
-#define FAT_FLAG_DIRTY 0x10000\r
-#define FAT_FLAG_DELETE        0x20000\r
-\r
-// === TYPES ===\r
-#if USE_LFN\r
-/**\r
- * \brief Long-Filename cache entry\r
- */\r
-typedef struct sFAT_LFNCacheEnt\r
-{\r
-        int    ID;\r
-       // TODO: Handle UTF16 names correctly\r
-       char    Data[256];\r
-}      tFAT_LFNCacheEnt;\r
-/**\r
- * \brief Long-Filename cache\r
- */\r
-typedef struct sFAT_LFNCache\r
-{\r
-        int    NumEntries;\r
-       tFAT_LFNCacheEnt        Entries[];\r
-}      tFAT_LFNCache;\r
-#endif\r
-\r
-// === PROTOTYPES ===\r
-// --- Driver Core\r
- int   FAT_Install(char **Arguments);\r
-tVFS_Node      *FAT_InitDevice(const char *device, const char **options);\r
-void   FAT_Unmount(tVFS_Node *Node);\r
-// --- Helpers\r
- int   FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#if SUPPORT_WRITE\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#endif\r
-void   FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
-// --- File IO\r
-Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-#if SUPPORT_WRITE\r
-void   FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
-Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-#endif\r
-// --- Directory IO\r
-char   *FAT_ReadDir(tVFS_Node *Node, int ID);\r
-tVFS_Node      *FAT_FindDir(tVFS_Node *Node, const char *Name);\r
-tVFS_Node      *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);\r
-#if SUPPORT_WRITE\r
- int   FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);\r
- int   FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);\r
-#endif\r
-void   FAT_CloseFile(tVFS_Node *node);\r
-\r
-// === Options ===\r
- int   giFAT_MaxCachedClusters = 1024*512/4;\r
-\r
-// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
-tFAT_VolInfo   gFAT_Disks[8];\r
- int   giFAT_PartCount = 0;\r
-tVFS_Driver    gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
-tVFS_NodeType  gFAT_DirType = {\r
-       .TypeName = "FAT-Dir",\r
-       .ReadDir = FAT_ReadDir,\r
-       .FindDir = FAT_FindDir,\r
-       #if SUPPORT_WRITE\r
-       .MkNod = FAT_Mknod,\r
-       .Relink = FAT_Relink,\r
-       #endif\r
-       .Close = FAT_CloseFile\r
-       };\r
-tVFS_NodeType  gFAT_FileType = {\r
-       .TypeName = "FAT-File",\r
-       .Read = FAT_Read,\r
-       #if SUPPORT_WRITE\r
-       .Write = FAT_Write,\r
-       #endif\r
-       .Close = FAT_CloseFile\r
-       };\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int FAT_Install(char **Arguments)\r
- * \brief Install the FAT Driver\r
- */\r
-int FAT_Install(char **Arguments)\r
-{\r
-       VFS_AddDriver( &gFAT_FSInfo );\r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \brief Reads the boot sector of a disk and prepares the structures for it\r
- */\r
-tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)\r
-{\r
-       fat_bootsect *bs;\r
-        int    i;\r
-       Uint32  FATSz, RootDirSectors, TotSec;\r
-       tVFS_Node       *node = NULL;\r
-       tFAT_VolInfo    *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
-       \r
-       // Temporary Pointer\r
-       bs = &diskInfo->bootsect;\r
-       \r
-       // Open device and read boot sector\r
-       diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);\r
-       if(diskInfo->fileHandle == -1) {\r
-               Log_Notice("FAT", "Unable to open device '%s'", Device);\r
-               return NULL;\r
-       }\r
-       \r
-       VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
-       \r
-       if(bs->bps == 0 || bs->spc == 0) {\r
-               Log_Notice("FAT", "Error in FAT Boot Sector");\r
-               return NULL;\r
-       }\r
-       \r
-       // FAT Type Determining\r
-       // - From Microsoft FAT Specifcation\r
-       RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps;\r
-       \r
-       if(bs->fatSz16 != 0)\r
-               FATSz = bs->fatSz16;\r
-       else\r
-               FATSz = bs->spec.fat32.fatSz32;\r
-       \r
-       if(bs->totalSect16 != 0)\r
-               TotSec = bs->totalSect16;\r
-       else\r
-               TotSec = bs->totalSect32;\r
-       \r
-       diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
-       \r
-       if(diskInfo->ClusterCount < 4085)\r
-               diskInfo->type = FAT12;\r
-       else if(diskInfo->ClusterCount < 65525)\r
-               diskInfo->type = FAT16;\r
-       else\r
-               diskInfo->type = FAT32;\r
-       \r
-       #if VERBOSE\r
-       {\r
-               char    *sFatType, *sSize;\r
-               Uint    iSize = diskInfo->ClusterCount * bs->spc * bs->bps / 1024;\r
-               \r
-               switch(diskInfo->type)\r
-               {\r
-               case FAT12:     sFatType = "FAT12";     break;\r
-               case FAT16:     sFatType = "FAT16";     break;\r
-               case FAT32:     sFatType = "FAT32";     break;\r
-               default:        sFatType = "UNKNOWN";   break;\r
-               }\r
-               if(iSize <= 2*1024) {\r
-                       sSize = "KiB";\r
-               }\r
-               else if(iSize <= 2*1024*1024) {\r
-                       sSize = "MiB";\r
-                       iSize >>= 10;\r
-               }\r
-               else {\r
-                       sSize = "GiB";\r
-                       iSize >>= 20;\r
-               }\r
-               Log_Notice("FAT", "'%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
-       }\r
-       #endif\r
-       \r
-       // Get Name\r
-       if(diskInfo->type == FAT32) {\r
-               for(i=0;i<11;i++)\r
-                       diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]);\r
-       }\r
-       else {\r
-               for(i=0;i<11;i++)\r
-                       diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]);\r
-       }\r
-       diskInfo->name[11] = '\0';\r
-       \r
-       // Compute Root directory offset\r
-       if(diskInfo->type == FAT32)\r
-               diskInfo->rootOffset = bs->spec.fat32.rootClust;\r
-       else\r
-               diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc;\r
-       \r
-       diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;\r
-       \r
-       //Allow for Caching the FAT\r
-       #if CACHE_FAT\r
-       if( diskInfo->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               Uint32  Ofs;\r
-               diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
-               if(diskInfo->FATCache == NULL) {\r
-                       Log_Warning("FAT", "Heap Exhausted");\r
-                       return NULL;\r
-               }\r
-               Ofs = bs->resvSectCount*512;\r
-               if(diskInfo->type == FAT12)\r
-               {\r
-                       Uint32  val;\r
-                        int    j;\r
-                       char    buf[1536];\r
-                       for(i = 0; i < diskInfo->ClusterCount/2; i++) {\r
-                               j = i & 511;    //%512\r
-                               if( j == 0 ) {\r
-                                       VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf);\r
-                                       Ofs += 3*512;\r
-                               }\r
-                               val = *((int*)(buf+j*3));\r
-                               diskInfo->FATCache[i*2] = val & 0xFFF;\r
-                               diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF;\r
-                       }\r
-               }\r
-               else if(diskInfo->type == FAT16)\r
-               {\r
-                       Uint16  buf[256];\r
-                       for(i=0;i<diskInfo->ClusterCount;i++) {\r
-                               if( (i & 255) == 0 ) {\r
-                                       VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
-                                       Ofs += 512;\r
-                               }\r
-                               diskInfo->FATCache[i] = buf[i&255];\r
-                       }\r
-               }\r
-               else if(diskInfo->type == FAT32)\r
-               {\r
-                       Uint32  buf[128];\r
-                       for(i=0;i<diskInfo->ClusterCount;i++) {\r
-                               if( (i & 127) == 0 ) {\r
-                                       VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
-                                       Ofs += 512;\r
-                               }\r
-                               diskInfo->FATCache[i] = buf[i&127];\r
-                       }\r
-               }\r
-               LOG("FAT Fully Cached");\r
-       }\r
-       #endif /*CACHE_FAT*/\r
-       \r
-       diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
-       \r
-       // Initalise inode cache for filesystem\r
-       diskInfo->inodeHandle = Inode_GetHandle();\r
-       LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
-       \r
-       // == VFS Interface\r
-       node = &diskInfo->rootNode;\r
-       //node->Size = bs->files_in_root;\r
-       node->Size = -1;\r
-       node->Inode = diskInfo->rootOffset;     // 0:31 - Cluster, 32:63 - Parent Directory Cluster\r
-       node->ImplPtr = diskInfo;       // Disk info pointer\r
-       node->ImplInt = 0;      // 0:15 - Directory Index, 16: Dirty Flag, 17: Deletion Flag\r
-       \r
-       node->ReferenceCount = 1;\r
-       \r
-       node->UID = 0;  node->GID = 0;\r
-       node->NumACLs = 1;\r
-       node->ACLs = &gVFS_ACL_EveryoneRWX;\r
-       node->Flags = VFS_FFLAG_DIRECTORY;\r
-       node->CTime = node->MTime = node->ATime = now();\r
-\r
-       node->Type = &gFAT_DirType;     \r
-       \r
-       giFAT_PartCount ++;\r
-       return node;\r
-}\r
-\r
-/**\r
- * \brief Closes a mount and marks it as free\r
- * \param Node Mount Root\r
- * \r
- * \todo Remove FAT Cache\r
- * \todo Clear LFN Cache\r
- * \todo Check that all files are closed and flushed\r
- */\r
-void FAT_Unmount(tVFS_Node *Node)\r
-{\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       // Close Disk Handle\r
-       VFS_Close( disk->fileHandle );\r
-       // Clear Node Cache\r
-       Inode_ClearCache(disk->inodeHandle);\r
-       // Mark as unused\r
-       disk->fileHandle = -2;\r
-       return;\r
-}\r
-\r
-/**\r
- * \brief Converts an offset in a file into a disk address\r
- * \param Node File (or directory) node\r
- * \param Offset       Offset in the file\r
- * \param Addr Return Address\r
- * \param Cluster      Set to the current cluster (or the last one if \a Offset\r
- *                  is past EOC) - Not touched if the node is the root\r
- *                  directory.\r
- * \return Zero on success, non-zero on error\r
- */\r
-int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
-{\r
-       Uint32  cluster;\r
-       Uint64  addr;\r
-        int    skip;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode XOffset", Node, Offset);\r
-       \r
-       cluster = Node->Inode & 0xFFFFFFF;      // Cluster ID\r
-       LOG("cluster = 0x%07x", cluster);\r
-       \r
-       // Do Cluster Skip\r
-       // - Pre FAT32 had a reserved area for the root.\r
-       if( disk->type == FAT32 || cluster != disk->rootOffset )\r
-       {\r
-               skip = Offset / disk->BytesPerCluster;\r
-               LOG("skip = %i", skip);\r
-               // Skip previous clusters\r
-               for(; skip-- ; )\r
-               {\r
-                       if(Cluster)     *Cluster = cluster;\r
-                       cluster = FAT_int_GetFatValue(disk, cluster);\r
-                       // Check for end of cluster chain\r
-                       if(cluster == 0xFFFFFFFF) {     LEAVE('i', 1);  return 1;}\r
-               }\r
-               if(Cluster)     *Cluster = cluster;\r
-       }\r
-       else {\r
-               // Increment by clusters in offset\r
-               cluster += Offset / disk->BytesPerCluster;\r
-       }\r
-       \r
-       LOG("cluster = %08x", cluster);\r
-       \r
-       // Bounds Checking (Used to spot corruption)\r
-       if(cluster > disk->ClusterCount + 2)\r
-       {\r
-               Log_Warning("FAT", "Cluster ID is over cluster count (0x%x>0x%x)",\r
-                       cluster, disk->ClusterCount+2);\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       // Compute Offsets\r
-       // - Pre FAT32 cluster base (in sectors)\r
-       if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
-               addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
-               addr += cluster * disk->BytesPerCluster;\r
-       }\r
-       else {\r
-               addr = disk->firstDataSect * disk->bootsect.bps;\r
-               addr += (cluster - 2) * disk->BytesPerCluster;\r
-       }\r
-       // In-cluster offset\r
-       addr += Offset % disk->BytesPerCluster;\r
-       \r
-       LOG("addr = 0x%08x", addr);\r
-       *Addr = addr;\r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-\r
-/*\r
- * ====================\r
- *   FAT Manipulation\r
- * ====================\r
- */\r
-/**\r
- * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
- * \brief Fetches a value from the FAT\r
- */\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
-{\r
-       Uint32  val = 0;\r
-       Uint32  ofs;\r
-       ENTER("pDisk xCluster", Disk, cluster);\r
-       Mutex_Acquire( &Disk->lFAT );\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               val = Disk->FATCache[cluster];\r
-               if(Disk->type == FAT12 && val == EOC_FAT12)     val = -1;\r
-               if(Disk->type == FAT16 && val == EOC_FAT16)     val = -1;\r
-               if(Disk->type == FAT32 && val == EOC_FAT32)     val = -1;\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               ofs = Disk->bootsect.resvSectCount*512;\r
-               if(Disk->type == FAT12) {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);\r
-                       val = (cluster & 1 ? val>>12 : val & 0xFFF);\r
-                       if(val == EOC_FAT12)    val = -1;\r
-               } else if(Disk->type == FAT16) {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
-                       if(val == EOC_FAT16)    val = -1;\r
-               } else {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
-                       if(val == EOC_FAT32)    val = -1;\r
-               }\r
-       #if CACHE_FAT\r
-       }\r
-       #endif /*CACHE_FAT*/\r
-       Mutex_Release( &Disk->lFAT );\r
-       LEAVE('x', val);\r
-       return val;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Allocate a new cluster\r
- */\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
-{\r
-       Uint32  ret = Previous;\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               Uint32  eoc;\r
-               \r
-               LOCK(Disk->lFAT);\r
-               for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
-               {\r
-                       if(Disk->FATCache[ret] == 0)\r
-                               goto append;\r
-               }\r
-               for(ret = 0; ret < Previous; ret++)\r
-               {\r
-                       if(Disk->FATCache[ret] == 0)\r
-                               goto append;\r
-               }\r
-               \r
-               RELEASE(Disk->lFAT);\r
-               return 0;\r
-       \r
-       append:\r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:     eoc = EOC_FAT12;        break;\r
-               case FAT16:     eoc = EOC_FAT16;        break;\r
-               case FAT32:     eoc = EOC_FAT32;        break;\r
-               default:        return 0;\r
-               }\r
-               \r
-               Disk->FATCache[ret] = eoc;\r
-               Disk->FATCache[Previous] = ret;\r
-               \r
-               RELEASE(Disk->lFAT);\r
-               return ret;\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               Uint32  val;\r
-               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
-               Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
-               return 0;\r
-               \r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       if( Previous & 1 ) {\r
-                               val &= 0xFFF000;\r
-                               val |= ret;\r
-                       }\r
-                       else {\r
-                               val &= 0xFFF;\r
-                               val |= ret<<12;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       \r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
-                       if( Cluster & 1 ) {\r
-                               val &= 0xFFF000;\r
-                               val |= eoc;\r
-                       }\r
-                       else {\r
-                               val &= 0x000FFF;\r
-                               val |= eoc<<12;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
-                       break;\r
-               case FAT16:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
-                       break;\r
-               case FAT32:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
-                       break;\r
-               }\r
-               return ret;\r
-       #if CACHE_FAT\r
-       }\r
-       #endif\r
-}\r
-\r
-/**\r
- * \brief Free's a cluster\r
- * \return The original contents of the cluster\r
- */\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
-{\r
-       Uint32  ret;\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               LOCK(Disk->lFAT);\r
-               \r
-               ret = Disk->FATCache[Cluster];\r
-               Disk->FATCache[Cluster] = 0;\r
-               \r
-               RELEASE(Disk->lFAT);\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               Uint32  val;\r
-               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
-               LOCK(Disk->lFAT);\r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
-                       if( Cluster & 1 ) {\r
-                               ret = val & 0xFFF0000;\r
-                               val &= 0xFFF;\r
-                       }\r
-                       else {\r
-                               ret = val & 0xFFF;\r
-                               val &= 0xFFF000;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       break;\r
-               case FAT16:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-                       val = 0;\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
-                       break;\r
-               case FAT32:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-                       val = 0;\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
-                       break;\r
-               }\r
-               RELEASE(Disk->lFAT);\r
-       #if CACHE_FAT\r
-       }\r
-       #endif\r
-       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;\r
-       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;\r
-       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;\r
-       return ret;\r
-}\r
-#endif\r
-\r
-/*\r
- * ====================\r
- *      Cluster IO\r
- * ====================\r
- */\r
-/**\r
- * \brief Read a cluster\r
- * \param Disk Disk (Volume) to read from\r
- * \param Length       Length to read\r
- * \param Buffer       Destination for read data\r
- */\r
-void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
-{\r
-       ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
-       VFS_ReadAt(\r
-               Disk->fileHandle,\r
-               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
-                       * Disk->bootsect.bps,\r
-               Length,\r
-               Buffer\r
-               );\r
-       LEAVE('-');\r
-}\r
-\r
-/* ====================\r
- *       File IO\r
- * ====================\r
- */\r
-/**\r
- * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
- * \brief Reads data from a specified file\r
- */\r
-Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{\r
-        int    preSkip, count;\r
-       Uint64  final_bytes;\r
-        int    i, cluster, pos;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       char    tmpBuf[disk->BytesPerCluster];\r
-        int    bpc = disk->BytesPerCluster;\r
-       \r
-       ENTER("pNode Xoffset Xlength pbuffer", Node, Offset, Length, Buffer);\r
-       \r
-       // Sanity Check offset\r
-       if(Offset > Node->Size) {\r
-               LOG("Seek past EOF (%i > %i)", Offset, Node->Size);\r
-               LEAVE('i', 0);\r
-               return 0;\r
-       }\r
-       \r
-       // Cluster is stored in the low 32-bits of the Inode field\r
-       cluster = Node->Inode & 0xFFFFFFFF;\r
-       \r
-       // Clamp Size\r
-       if(Offset + Length > Node->Size) {\r
-               LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",\r
-                       Offset, Length, Node->Size, Node->Size - Offset);\r
-               Length = Node->Size - Offset;\r
-       }\r
-       \r
-       // Skip previous clusters\r
-       preSkip = Offset / bpc;\r
-       Offset %= bpc;\r
-       LOG("preSkip = %i, Offset = %i", preSkip, (int)Offset);\r
-       for(i = preSkip; i--; )\r
-       {\r
-               cluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
-                       LEAVE('i', 0);\r
-                       return 0;\r
-               }\r
-       }\r
-\r
-       // Reading from within one cluster\r
-       if((int)Offset + (int)Length <= bpc)\r
-       {\r
-               LOG("single cluster only");\r
-               FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
-               memcpy( Buffer, (void*)( tmpBuf + Offset%bpc ), Length );\r
-               LEAVE('X', Length);\r
-               return Length;\r
-       }\r
-       \r
-       // Align read to a cluster\r
-       if( Offset > 0 )\r
-       {\r
-               pos = bpc - Offset;\r
-               FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
-               memcpy( Buffer, (void*)( tmpBuf + Offset ), pos );\r
-               LOG("pos = %i, Reading the rest of the clusters");\r
-               // Get next cluster in the chain\r
-               cluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Read past End of Cluster Chain (Align)");\r
-                       LEAVE('X', pos);\r
-                       return pos;\r
-               }\r
-       }\r
-       else\r
-               pos = 0;\r
-\r
-       // Get Count of Clusters to read\r
-//     count = DivMod64U(Length - pos, bpc, &final_bytes);\r
-       count = (Length - pos) / bpc;\r
-       final_bytes = (Length - pos) % bpc;\r
-       LOG("Offset = %i, Length = %i, count = %i, final_bytes = %i", (int)Offset, (int)Length, count, final_bytes);\r
-       \r
-       // Read the rest of the cluster data\r
-       for( ; count; count -- )\r
-       {\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Read past End of Cluster Chain (Bulk)");\r
-                       LEAVE('X', pos);\r
-                       return pos;\r
-               }\r
-               // Read cluster\r
-               FAT_int_ReadCluster(disk, cluster, bpc, (void*)(Buffer+pos));\r
-               pos += bpc;\r
-               // Get next cluster in the chain\r
-               cluster = FAT_int_GetFatValue(disk, cluster);\r
-       }\r
-\r
-       if( final_bytes > 0 )\r
-       {\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Read past End of Cluster Chain (Final)");\r
-                       LEAVE('X', pos);\r
-                       return pos;\r
-               }\r
-               // Read final cluster\r
-               FAT_int_ReadCluster( disk, cluster, bpc, tmpBuf );\r
-               memcpy( (void*)(Buffer+pos), tmpBuf, Length-pos );\r
-       }\r
-               \r
-       #if DEBUG\r
-       //Debug_HexDump("FAT_Read", Buffer, Length);\r
-       #endif\r
-       \r
-       LEAVE('X', Length);\r
-       return Length;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Write a cluster to disk\r
- */\r
-void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
-{\r
-       ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
-       VFS_ReadAt(\r
-               Disk->fileHandle,\r
-               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
-                       * Disk->bootsect.bps,\r
-               Disk->BytesPerCluster,\r
-               Buffer\r
-               );\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \brief Write to a file\r
- * \param Node File Node\r
- * \param Offset       Offset within file\r
- * \param Length       Size of data to write\r
- * \param Buffer       Data source\r
- */\r
-Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       char    tmpBuf[disk->BytesPerCluster];\r
-        int    remLength = Length;\r
-       Uint32  cluster, tmpCluster;\r
-        int    bNewCluster = 0;\r
-       \r
-       if(Offset > Node->Size) return 0;\r
-       \r
-       // Seek Clusters\r
-       cluster = Node->Inode & 0xFFFFFFFF;\r
-       while( Offset > disk->BytesPerCluster )\r
-       {\r
-               cluster = FAT_int_GetFatValue( disk, cluster );\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "EOC Unexpectedly Reached");\r
-                       return 0;\r
-               }\r
-               Offset -= disk->BytesPerCluster;\r
-       }\r
-       if( Offset == disk->BytesPerCluster )\r
-       {\r
-               Uint32  tmp = FAT_int_AllocateCluster(disk, cluster);\r
-               if(!tmp)        return 0;\r
-               cluster = tmp;\r
-               Offset -= disk->BytesPerCluster;\r
-       }\r
-       \r
-       if( Offset + Length < disk->BytesPerCluster )\r
-       {\r
-               char    tmpBuf[disk->BytesPerCluster];\r
-               \r
-               // Read-Modify-Write\r
-               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
-               memcpy( tmpBuf + Offset, Buffer, Length );\r
-               FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-               \r
-               return Length;\r
-       }\r
-       \r
-       // Clean up changes within a cluster\r
-       if( Offset )\r
-       {       \r
-               // Read-Modify-Write\r
-               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
-               memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
-               FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-               \r
-               remLength -= disk->BytesPerCluster - Offset;\r
-               Buffer += disk->BytesPerCluster - Offset;\r
-               \r
-               // Get next cluster (allocating if needed)\r
-               tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(tmpCluster == -1) {\r
-                       tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
-                       if( tmpCluster == 0 ) {\r
-                               return Length - remLength;\r
-                       }\r
-               }\r
-               cluster = tmpCluster;\r
-       }\r
-       \r
-       while( remLength > disk->BytesPerCluster )\r
-       {\r
-               FAT_int_WriteCluster( disk, cluster, Buffer );\r
-               Buffer += disk->BytesPerCluster;\r
-               \r
-               // Get next cluster (allocating if needed)\r
-               tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(tmpCluster == -1) {\r
-                       bNewCluster = 1;\r
-                       tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
-                       if( tmpCluster == 0 ) {\r
-                               return Length - remLength;\r
-                       }\r
-               }\r
-               cluster = tmpCluster;\r
-       }\r
-       \r
-       // Finish off\r
-       tmpBuf = malloc( disk->BytesPerCluster );\r
-       if( bNewCluster )\r
-               memset(tmpBuf, 0, disk->BytesPerCluster);\r
-       else\r
-               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
-       memcpy( tmpBuf, Buffer, remLength );\r
-       FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-       free( tmpBuf );\r
-       \r
-       return Length;\r
-}\r
-#endif\r
-\r
-/* ====================\r
- *  File Names & Nodes\r
- * ====================\r
- */\r
-/**\r
- * \brief Converts a FAT directory entry name into a proper filename\r
- * \param dest Destination array (must be at least 13 bytes in size)\r
- * \param src  8.3 filename (concatenated, e.g 'FILE1   TXT')\r
- */\r
-void FAT_int_ProperFilename(char *dest, const char *src)\r
-{\r
-        int    inpos, outpos;\r
-       \r
-       // Name\r
-       outpos = 0;\r
-       for( inpos = 0; inpos < 8; inpos++ ) {\r
-               if(src[inpos] == ' ')   break;\r
-               dest[outpos++] = src[inpos];\r
-       }\r
-       inpos = 8;\r
-       // Check for empty extensions\r
-       if(src[8] != ' ')\r
-       {\r
-               dest[outpos++] = '.';\r
-               for( ; inpos < 11; inpos++)     {\r
-                       if(src[inpos] == ' ')   break;\r
-                       dest[outpos++] = src[inpos];\r
-               }\r
-       }\r
-       dest[outpos++] = '\0';\r
-       \r
-       //LOG("dest='%s'", dest);\r
-}\r
-\r
-/**\r
- * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
- * \brief Converts either a LFN or a 8.3 Name into a proper name\r
- * \param ft   Pointer to the file's entry in the parent directory\r
- * \param LongFileName Long file name pointer\r
- * \return Filename as a heap string\r
- */\r
-char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
-{\r
-       char    *ret;\r
-       ENTER("pft sLongFileName", ft, LongFileName);\r
-       //Log_Debug("FAT", "FAT_int_CreateName(ft=%p, LongFileName=%p'%s')", ft, LongFileName);\r
-       #if USE_LFN\r
-       if(LongFileName && LongFileName[0] != '\0')\r
-       {       \r
-               ret = strdup(LongFileName);\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               ret = (char*) malloc(13);\r
-               if( !ret ) {\r
-                       Log_Warning("FAT", "FAT_int_CreateName: malloc(13) failed");\r
-                       return NULL;\r
-               }\r
-               FAT_int_ProperFilename(ret, ft->name);\r
-       #if USE_LFN\r
-       }\r
-       #endif\r
-       LEAVE('s', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \brief Creates a tVFS_Node structure for a given file entry\r
- * \param Parent       Parent directory VFS node\r
- * \param Entry        File table entry for the new node\r
- * \param Pos  Position in the parent of the new node\r
- */\r
-tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)\r
-{\r
-       tVFS_Node       node;\r
-       tVFS_Node       *ret;\r
-       tFAT_VolInfo    *disk = Parent->ImplPtr;\r
-       \r
-       ENTER("pParent pFT", Parent, Entry);\r
-       LOG("disk = %p", disk);\r
-       \r
-       memset(&node, 0, sizeof(tVFS_Node));\r
-       \r
-       // Set Other Data\r
-       // 0-27: Cluster, 32-59: Parent Cluster\r
-       node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);\r
-       LOG("node.Inode = %llx", node.Inode);\r
-       // Position in parent directory\r
-       node.ImplInt = Pos & 0xFFFF;\r
-       // Disk Pointer\r
-       node.ImplPtr = disk;\r
-       node.Size = Entry->size;\r
-       LOG("Entry->size = %i", Entry->size);\r
-       // root:root\r
-       node.UID = 0;   node.GID = 0;\r
-       node.NumACLs = 1;\r
-       \r
-       node.Flags = 0;\r
-       if(Entry->attrib & ATTR_DIRECTORY)      node.Flags |= VFS_FFLAG_DIRECTORY;\r
-       if(Entry->attrib & ATTR_READONLY) {\r
-               node.Flags |= VFS_FFLAG_READONLY;\r
-               node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X\r
-       }\r
-       else {\r
-               node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX\r
-       }\r
-       \r
-       // Create timestamps\r
-       node.ATime = timestamp(0,0,0,\r
-                       ((Entry->adate&0x1F) - 1),      // Days\r
-                       ((Entry->adate&0x1E0) - 1),     // Months\r
-                       1980+((Entry->adate&0xFF00)>>8) // Years\r
-                       );\r
-       \r
-       node.CTime = Entry->ctimems * 10;       // Miliseconds\r
-       node.CTime += timestamp(\r
-                       ((Entry->ctime&0x1F)<<1),       // Seconds\r
-                       ((Entry->ctime&0x3F0)>>5),      // Minutes\r
-                       ((Entry->ctime&0xF800)>>11),    // Hours\r
-                       ((Entry->cdate&0x1F)-1),                // Days\r
-                       ((Entry->cdate&0x1E0)-1),               // Months\r
-                       1980+((Entry->cdate&0xFF00)>>8) // Years\r
-                       );\r
-                       \r
-       node.MTime = timestamp(\r
-                       ((Entry->mtime&0x1F)<<1),       // Seconds\r
-                       ((Entry->mtime&0x3F0)>>5),      // Minutes\r
-                       ((Entry->mtime&0xF800)>>11),    // Hours\r
-                       ((Entry->mdate&0x1F)-1),                // Days\r
-                       ((Entry->mdate&0x1E0)-1),               // Months\r
-                       1980+((Entry->mdate&0xFF00)>>8) // Years\r
-                       );\r
-       \r
-       // Set pointers\r
-       if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
-               //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
-               node.Type = &gFAT_DirType;      \r
-               node.Size = -1;\r
-       }\r
-       else {\r
-               node.Type = &gFAT_FileType;\r
-       }\r
-       \r
-       ret = Inode_CacheNode(disk->inodeHandle, &node);\r
-       LEAVE('p', ret);\r
-       return ret;\r
-}\r
-\r
-/* \r
- * ====================\r
- *     Directory IO\r
- * ====================\r
- */\r
-\r
-/**\r
- * \brief Reads a sector from the disk\r
- * \param Node Directory node to read\r
- * \param Sector       Sector number in the directory to read\r
- * \param Buffer       Destination buffer for the read data\r
- */\r
-int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
-{\r
-       Uint64  addr;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode iSector pEntry", Node, Sector, Buffer);\r
-       \r
-       // Parse address\r
-       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
-       {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       LOG("addr = 0x%llx", addr);\r
-       // Read Sector\r
-       if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)\r
-       {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Writes an entry to the disk\r
- * \todo Support expanding a directory\r
- * \param Node Directory node\r
- * \param ID   ID of entry to update\r
- * \param Entry        Entry data\r
- * \return Zero on success, non-zero on error\r
- */\r
-int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
-{\r
-       Uint64  addr = 0;\r
-        int    tmp;\r
-       Uint32  cluster = 0;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode iID pEntry", Node, ID, Entry);\r
-       \r
-       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
-       if( tmp )\r
-       {\r
-               //TODO: Allocate a cluster\r
-               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
-                       LEAVE('i', 1);\r
-                       return 1;\r
-               }\r
-               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
-       }\r
-       \r
-\r
-       LOG("addr = 0x%llx", addr);\r
-       \r
-       // Read Sector\r
-       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);      // Read Dir Data\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-#endif\r
-\r
-#if USE_LFN    \r
-/**\r
- * \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
- * \brief Return pointer to LFN cache entry\r
- * \param Node Directory node\r
- * \param ID   ID of the short name\r
- * \return Pointer to the LFN cache entry\r
- */\r
-char *FAT_int_GetLFN(tVFS_Node *Node, int ID)\r
-{\r
-       tFAT_LFNCache   *cache;\r
-        int    i, firstFree;\r
-       \r
-       Mutex_Acquire( &Node->Lock );\r
-       \r
-       // TODO: Thread Safety (Lock things)\r
-       cache = Node->Data;\r
-       \r
-       // Create a cache if it isn't there\r
-       if(!cache) {\r
-               cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );\r
-               cache->NumEntries = 1;\r
-               cache->Entries[0].ID = ID;\r
-               cache->Entries[0].Data[0] = '\0';\r
-               Mutex_Release( &Node->Lock );\r
-               //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);\r
-               return cache->Entries[0].Data;\r
-       }\r
-       \r
-       // Scan for this entry\r
-       firstFree = -1;\r
-       for( i = 0; i < cache->NumEntries; i++ )\r
-       {\r
-               if( cache->Entries[i].ID == ID ) {\r
-                       Mutex_Release( &Node->Lock );\r
-                       //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);\r
-                       return cache->Entries[i].Data;\r
-               }\r
-               if( cache->Entries[i].ID == -1 && firstFree == -1 )\r
-                       firstFree = i;\r
-       }\r
-       \r
-       if(firstFree == -1) {\r
-               // Use `i` for temp length\r
-               i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);\r
-               Node->Data = realloc( Node->Data, i );\r
-               if( !Node->Data ) {\r
-                       Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);\r
-                       Mutex_Release( &Node->Lock );\r
-                       return NULL;\r
-               }\r
-               //Log_Debug("FAT", "Realloc (%i)\n", i);\r
-               cache = Node->Data;\r
-               i = cache->NumEntries;\r
-               cache->NumEntries ++;\r
-       }\r
-       else {\r
-               i = firstFree;\r
-       }\r
-       \r
-       // Create new entry\r
-       cache->Entries[ i ].ID = ID;\r
-       cache->Entries[ i ].Data[0] = '\0';\r
-       \r
-       Mutex_Release( &Node->Lock );\r
-       //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);\r
-       return cache->Entries[ i ].Data;\r
-}\r
-\r
-/**\r
- * \fn void FAT_int_DelLFN(tVFS_Node *node)\r
- * \brief Delete a LFN cache entry\r
- * \param Node Directory node\r
- * \param ID   File Entry ID\r
- */\r
-void FAT_int_DelLFN(tVFS_Node *Node, int ID)\r
-{\r
-       tFAT_LFNCache   *cache = Node->Data;\r
-        int    i;\r
-       \r
-       // Fast return\r
-       if(!cache)      return;\r
-       \r
-       // Scan for a current entry\r
-       for( i = 0; i < cache->NumEntries; i++ )\r
-       {\r
-               if( cache->Entries[i].ID == ID )\r
-                       cache->Entries[i].ID = -1;\r
-       }\r
-       return ;\r
-}\r
-#endif\r
-\r
-/**\r
- * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
- * \param Node Node structure of directory\r
- * \param ID   Directory position\r
- * \return Filename as a heap string, NULL or VFS_SKIP\r
- */\r
-char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
-{\r
-       fat_filetable   fileinfo[16];   // sizeof(fat_filetable)=32, so 16 per sector\r
-        int    a = 0;\r
-       char    *ret;\r
-       #if USE_LFN\r
-       char    *lfn = NULL;\r
-       #endif\r
-       \r
-       ENTER("pNode iID", Node, ID);\r
-       \r
-       if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))\r
-       {\r
-               LOG("End of chain, end of dir");\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Offset in sector\r
-       a = ID % 16;\r
-\r
-       LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);\r
-       \r
-       // Check if this is the last entry\r
-       if( fileinfo[a].name[0] == '\0' ) {\r
-               Node->Size = ID;\r
-               LOG("End of list");\r
-               LEAVE('n');\r
-               return NULL;    // break\r
-       }\r
-       \r
-       // Check for empty entry\r
-       if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
-               LOG("Empty Entry");\r
-               #if 0   // Stop on empty entry?\r
-               LEAVE('n');\r
-               return NULL;    // Stop\r
-               #else\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;        // Skip\r
-               #endif\r
-       }\r
-       \r
-       #if USE_LFN\r
-       // Get Long File Name Cache\r
-       if(fileinfo[a].attrib == ATTR_LFN)\r
-       {\r
-               fat_longfilename        *lfnInfo;\r
-               \r
-               lfnInfo = (fat_longfilename *) &fileinfo[a];\r
-               \r
-               // Get cache for corresponding file\r
-               // > ID + Index gets the corresponding short node\r
-               lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );\r
-               \r
-               // Bit 6 indicates the start of an entry\r
-               if(lfnInfo->id & 0x40)  memset(lfn, 0, 256);\r
-               \r
-               a = ((lfnInfo->id & 0x3F) - 1) * 13;\r
-               //Log_Debug("FAT", "ID = 0x%02x, a = %i", lfnInfo->id, a);\r
-               \r
-               // Sanity Check (FAT implementations should not allow >255 character names)\r
-               if(a > 255)     return VFS_SKIP;\r
-               \r
-               // Append new bytes\r
-               lfn[a+ 0] = lfnInfo->name1[0];  lfn[a+ 1] = lfnInfo->name1[1];\r
-               lfn[a+ 2] = lfnInfo->name1[2];  lfn[a+ 3] = lfnInfo->name1[3];\r
-               lfn[a+ 4] = lfnInfo->name1[4];  \r
-               lfn[a+ 5] = lfnInfo->name2[0];  lfn[a+ 6] = lfnInfo->name2[1];\r
-               lfn[a+ 7] = lfnInfo->name2[2];  lfn[a+ 8] = lfnInfo->name2[3];\r
-               lfn[a+ 9] = lfnInfo->name2[4];  lfn[a+10] = lfnInfo->name2[5];\r
-               lfn[a+11] = lfnInfo->name3[0];  lfn[a+12] = lfnInfo->name3[1];\r
-               LOG("lfn = '%s'", lfn);\r
-               //Log_Debug("FAT", "lfn = '%s'", lfn);\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       #endif\r
-       \r
-       // Check if it is a volume entry\r
-       if(fileinfo[a].attrib & 0x08) {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       // Ignore .\r
-       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       // and ..\r
-       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       \r
-       LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",\r
-               fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
-               fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
-               fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
-       \r
-       #if USE_LFN\r
-       lfn = FAT_int_GetLFN(Node, ID);\r
-       //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);\r
-       ret = FAT_int_CreateName(&fileinfo[a], lfn);\r
-       #else\r
-       ret = FAT_int_CreateName(&fileinfo[a], NULL);\r
-       #endif\r
-       \r
-       LEAVE('s', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
- * \brief Finds an entry in the current directory\r
- */\r
-tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)\r
-{\r
-       fat_filetable   fileinfo[16];\r
-       char    tmpName[13];\r
-       #if USE_LFN\r
-       fat_longfilename        *lfnInfo;\r
-       char    lfn[256];\r
-        int    lfnPos=255, lfnId = -1;\r
-       #endif\r
-        int    i;\r
-       tVFS_Node       *tmpNode;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       Uint32  cluster;\r
-       \r
-       ENTER("pNode sname", Node, Name);       \r
-\r
-       // Fast Returns\r
-       if(!Name || Name[0] == '\0') {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       for( i = 0; ; i++ )\r
-       {\r
-               if((i & 0xF) == 0) {\r
-                       if(FAT_int_ReadDirSector(Node, i/16, fileinfo))\r
-                       {\r
-                               LEAVE('n');\r
-                               return NULL;\r
-                       }\r
-               }\r
-               \r
-               //Check if the files are free\r
-               if(fileinfo[i&0xF].name[0] == '\0')     break;  // End of List marker\r
-               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       // Free entry\r
-               \r
-               \r
-               #if USE_LFN\r
-               // Long File Name Entry\r
-               if(fileinfo[i & 0xF].attrib == ATTR_LFN)\r
-               {\r
-                       lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
-                       if(lfnInfo->id & 0x40) {\r
-                               memset(lfn, 0, 256);\r
-                               lfnPos = (lfnInfo->id & 0x3F) * 13 - 1;\r
-                       }\r
-                       // Sanity check the position so we don't overflow\r
-                       if( lfnPos < 12 )\r
-                               continue ;\r
-                       lfn[lfnPos--] = lfnInfo->name3[1];      lfn[lfnPos--] = lfnInfo->name3[0];\r
-                       lfn[lfnPos--] = lfnInfo->name2[5];      lfn[lfnPos--] = lfnInfo->name2[4];\r
-                       lfn[lfnPos--] = lfnInfo->name2[3];      lfn[lfnPos--] = lfnInfo->name2[2];\r
-                       lfn[lfnPos--] = lfnInfo->name2[1];      lfn[lfnPos--] = lfnInfo->name2[0];\r
-                       lfn[lfnPos--] = lfnInfo->name1[4];      lfn[lfnPos--] = lfnInfo->name1[3];\r
-                       lfn[lfnPos--] = lfnInfo->name1[2];      lfn[lfnPos--] = lfnInfo->name1[1];\r
-                       lfn[lfnPos--] = lfnInfo->name1[0];\r
-                       if((lfnInfo->id&0x3F) == 1)\r
-                       {\r
-                               lfnId = i+1;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       // Remove LFN if it does not apply\r
-                       if(lfnId != i)  lfn[0] = '\0';\r
-               #else\r
-               if(fileinfo[i&0xF].attrib == ATTR_LFN)  continue;\r
-               #endif\r
-                       // Get Real Filename\r
-                       FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
-                       LOG("tmpName = '%s'", tmpName);\r
-               \r
-                       // Only the long name is case sensitive, 8.3 is not\r
-                       #if USE_LFN\r
-                       if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0)\r
-                       #else\r
-                       if(strucmp(tmpName, Name) == 0)\r
-                       #endif\r
-                       {\r
-                               cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
-                               tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
-                               if(tmpNode == NULL)     // Node is not cached\r
-                               {\r
-                                       tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i);\r
-                               }\r
-                               LEAVE('p', tmpNode);\r
-                               return tmpNode;\r
-                       }\r
-               #if USE_LFN\r
-               }\r
-               #endif\r
-       }\r
-       \r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)\r
-{\r
-       tFAT_VolInfo    *disk = Root->ImplPtr;\r
-        int    ents_per_sector = 512 / sizeof(fat_filetable); \r
-       fat_filetable   fileinfo[ents_per_sector];\r
-        int    sector = 0, i;\r
-       tVFS_Node       stub_node;\r
-\r
-       ENTER("pRoot XInode", Root, Inode);\r
-\r
-       stub_node.ImplPtr = disk;\r
-       stub_node.Size = -1;\r
-       stub_node.Inode = Inode >> 32;\r
-\r
-       for( i = 0; ; i ++ )\r
-       {\r
-               if( i == 0 || i == ents_per_sector )\r
-               {\r
-                       if(FAT_int_ReadDirSector(&stub_node, sector, fileinfo))\r
-                       {\r
-                               LOG("ReadDirSector failed");\r
-                               LEAVE('n');\r
-                               return NULL;\r
-                       }\r
-                       i = 0;\r
-                       sector ++;\r
-               }\r
-       \r
-               // Check for free/end of list\r
-               if(fileinfo[i].name[0] == '\0') break;  // End of List marker\r
-               if(fileinfo[i].name[0] == '\xE5')       continue;       // Free entry\r
-               \r
-               if(fileinfo[i].attrib == ATTR_LFN)      continue;\r
-\r
-               LOG("fileinfo[i].cluster = %x %04x", fileinfo[i].clusterHi, fileinfo[i].cluster);\r
-               #if DEBUG\r
-               {\r
-                       char    tmpName[13];\r
-                       FAT_int_ProperFilename(tmpName, fileinfo[i].name);\r
-                       LOG("tmpName = '%s'", tmpName);\r
-               }\r
-               #endif\r
-               \r
-       \r
-               if(fileinfo[i].cluster != (Inode & 0xFFFF))     continue;\r
-               if(fileinfo[i].clusterHi != ((Inode >> 16) & 0xFFFF))   continue;\r
-\r
-               LEAVE_RET('p', FAT_int_CreateNode(&stub_node, &fileinfo[i], sector*ents_per_sector+i));\r
-       }\r
-       LOG("sector = %i, i = %i", sector, i);\r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
- * \brief Create a new node\r
- */\r
-int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
-{\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
- * \brief Rename / Delete a file\r
- */\r
-int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
-{\r
-       tVFS_Node       *child;\r
-       fat_filetable   ft = {0};\r
-        int    ret;\r
-       \r
-       child = FAT_FindDir(Node, OldName);\r
-       if(!child)      return ENOTFOUND;\r
-       \r
-       // Delete?\r
-       if( NewName == NULL )\r
-       {\r
-               child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close\r
-               \r
-               // Delete from the directory\r
-               ft.name[0] = '\xE9';\r
-               FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
-               \r
-               // Return success\r
-               ret = EOK;\r
-       }\r
-       // Rename\r
-       else\r
-       {\r
-               Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
-                       Node, OldName, NewName);\r
-               ret = ENOTIMPL;\r
-       }\r
-       \r
-       // Close child\r
-       child->Close( child );\r
-       return ret;\r
-}\r
-#endif\r
-\r
-/**\r
- * \fn void FAT_CloseFile(tVFS_Node *Node)\r
- * \brief Close an open file\r
- */\r
-void FAT_CloseFile(tVFS_Node *Node)\r
-{\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       if(Node == NULL)        return ;\r
-       \r
-       #if SUPPORT_WRITE\r
-       // Update the node if it's dirty (don't bother if it's marked for\r
-       // deletion)\r
-       if( (Node->ImplInt & FAT_FLAG_DIRTY) && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
-       {\r
-               tFAT_VolInfo    buf[16];\r
-               tFAT_VolInfo    *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
-               \r
-               FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
-               ft->size = Node->Size;\r
-               // TODO: update adate, mtime, mdate\r
-               FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
-               \r
-               Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
-       }\r
-       #endif\r
-       \r
-       // TODO: Make this more thread safe somehow, probably by moving the\r
-       // Inode_UncacheNode higher up and saving the cluster value somewhere\r
-       if( Node->ReferenceCount == 1 )\r
-       {               \r
-               #if SUPPORT_WRITE\r
-               // Delete File\r
-               if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
-                       // Since the node is marked, we only need to remove it's data\r
-                       Uint32  cluster = Node->Inode & 0xFFFFFFFF;\r
-                       while( cluster != -1 )\r
-                               cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
-               }\r
-               #endif\r
-       }\r
-       \r
-       Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
-       return ;\r
-}\r
diff --git a/Modules/Filesystems/FAT/fs_fat.h b/Modules/Filesystems/FAT/fs_fat.h
deleted file mode 100644 (file)
index 6896945..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*\r
- * Acess2\r
- * FAT12/16/32 Driver\r
- * vfs/fs/fs_fat.h\r
- */\r
-#ifndef _FS_FAT_H_\r
-#define _FS_FAT_H_\r
-\r
-// === On Disk Structures ===\r
-/**\r
- * \struct fat_bootsect_s\r
- * \brief Bootsector format\r
- */\r
-struct fat_bootsect_s\r
-{\r
-       Uint8   jmp[3]; //!< Jump Instruction\r
-       char    oemname[8];     //!< OEM Name. Typically MSDOS1.1\r
-       Uint16  bps;    //!< Bytes per Sector. Assumed to be 512\r
-       Uint8   spc;            //!< Sectors per Cluster\r
-       Uint16  resvSectCount;  //!< Number of reserved sectors at beginning of volume\r
-       // +0x10\r
-       Uint8   fatCount;       //!< Number of copies of the FAT\r
-       Uint16  files_in_root;  //!< Count of files in the root directory\r
-       Uint16  totalSect16;    //!< Total sector count (FAT12/16)\r
-       Uint8   mediaDesc;      //!< Media Desctiptor\r
-       Uint16  fatSz16;        //!< FAT Size (FAT12/16)\r
-       // +0x18\r
-       Uint16  spt;    //!< Sectors per track. Ignored (Acess uses LBA)\r
-       Uint16  heads;  //!< Heads. Ignored (Acess uses LBA)\r
-       Uint32  hiddenCount;    //!< ???\r
-       Uint32  totalSect32;    //!< Total sector count (FAT32)\r
-       union {\r
-               struct {\r
-                       Uint8   drvNum; //!< Drive Number. BIOS Drive ID (E.g. 0x80)\r
-                       Uint8   resv;   //!< Reserved byte\r
-                       Uint8   bootSig;        //!< Boot Signature. ???\r
-                       Uint32  volId;  //!< Volume ID\r
-                       char    label[11];      //!< Disk Label\r
-                       char    fsType[8];      //!< FS Type. ???\r
-               } __attribute__((packed)) fat16;        //!< FAT16 Specific information\r
-               struct {\r
-                       Uint32  fatSz32;        //!< 32-Bit FAT Size\r
-                       Uint16  extFlags;       //!< Extended flags\r
-                       Uint16  fsVer;  //!< Filesystem Version\r
-                       Uint32  rootClust;      //!< Root Cluster ID\r
-                       Uint16  fsInfo; //!< FS Info. ???\r
-                       Uint16  backupBS;       //!< Backup Bootsector Sector Offset\r
-                       char    resv[12];       //!< Reserved Data\r
-                       Uint8   drvNum; //!< Drive Number\r
-                       char    resv2;  //!< Reserved Data\r
-                       Uint8   bootSig;        //!< Boot Signature. ???\r
-                       Uint32  volId;  //!< Volume ID\r
-                       char    label[11];      //!< Disk Label\r
-                       char    fsType[8];      //!< Filesystem Type. ???\r
-               } __attribute__((packed)) fat32;        //!< FAT32 Specific Information\r
-       }__attribute__((packed)) spec;  //!< Non Shared Data\r
-       char pad[512-90];       //!< Bootsector Data (Code/Boot Signature 0xAA55)\r
-} __attribute__((packed));\r
-\r
-/**\r
- \struct fat_filetable_s\r
- \brief Format of a 8.3 file entry on disk\r
-*/\r
-struct fat_filetable_s {\r
-       char    name[11];       //!< 8.3 Name\r
-       Uint8   attrib; //!< File Attributes.\r
-       Uint8   ntres;  //!< Reserved for NT - Set to 0\r
-       Uint8   ctimems;        //!< 10ths of a second ranging from 0-199 (2 seconds)\r
-       Uint16  ctime;  //!< Creation Time\r
-       Uint16  cdate;  //!< Creation Date\r
-       Uint16  adate;  //!< Accessed Date. No Time feild though\r
-       Uint16  clusterHi;      //!< High Cluster. 0 for FAT12 and FAT16\r
-       Uint16  mtime;  //!< Last Modified Time\r
-       Uint16  mdate;  //!< Last Modified Date\r
-       Uint16  cluster;        //!< Low Word of First cluster\r
-       Uint32  size;   //!< Size of file\r
-} __attribute__((packed));\r
-\r
-/**\r
- * \struct fat_longfilename_s\r
- * \brief Format of a long file name entry on disk\r
- */\r
-struct fat_longfilename_s {\r
-       Uint8   id;     //!< ID of entry. Bit 6 is set for last entry\r
-       Uint16  name1[5];       //!< 5 characters of name\r
-       Uint8   attrib; //!< Attributes. Must be ATTR_LFN\r
-       Uint8   type;   //!< Type. ???\r
-       Uint8   checksum;       //!< Checksum\r
-       Uint16  name2[6];       //!< 6 characters of name\r
-       Uint16  firstCluster;   //!< Used for non LFN compatability. Set to 0\r
-       Uint16  name3[2];       //!< Last 2 characters of name\r
-} __attribute__((packed));\r
-\r
-/**\r
- * \name File Attributes\r
- * \brief Flag values for ::fat_filetable_s.attrib\r
- * \{\r
- */\r
-#define ATTR_READONLY  0x01    //!< Read-only file\r
-#define ATTR_HIDDEN            0x02    //!< Hidden File\r
-#define ATTR_SYSTEM            0x04    //!< System File\r
-#define ATTR_VOLUMEID  0x08    //!< Volume ID (Deprecated)\r
-#define ATTR_DIRECTORY 0x10    //!< Directory\r
-/**\r
- * \brief File needs archiving\r
- * \note User set flag, no significance to the FS driver\r
- */\r
-#define ATTR_ARCHIVE   0x20\r
-/**\r
- * \brief Meta Attribute \r
- * \r
- * If ::fat_filetable_s.attrib equals ATTR_LFN the file is a LFN entry\r
- */\r
-#define        ATTR_LFN                (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID)\r
-/**\r
- * \}\r
- */\r
-\r
-/**\r
- * \brief Internal IDs for FAT types\r
- */\r
-enum eFatType\r
-{\r
-       FAT12,  //!< FAT12 Volume\r
-       FAT16,  //!< FAT16 Volume\r
-       FAT32,  //!< FAT32 Volume\r
-};\r
-\r
-/**\r
- * \name End of Cluster marks\r
- * \brief FAT values that indicate the end of a cluster chain in\r
- *        different versions.\r
- * \{\r
- */\r
-#define        EOC_FAT12       0x0FFF  //!< FAT-12 Mark\r
-#define        EOC_FAT16       0xFFFF  //!< FAT-16 Mark\r
-#define        EOC_FAT32       0x00FFFFFF      //!< FAT-32 Mark\r
-/**\r
- * \}\r
- */\r
-\r
-typedef struct fat_bootsect_s fat_bootsect;\r
-typedef struct fat_filetable_s fat_filetable;\r
-typedef struct fat_longfilename_s fat_longfilename;\r
-\r
-// === Memory Structures ===\r
-/**\r
- * \struct drv_fat_volinfo_s\r
- * \brief Representation of a volume in memory\r
- */\r
-struct drv_fat_volinfo_s\r
-{\r
-        int    fileHandle;     //!< File Handle\r
-        int    type;   //!< FAT Type. See eFatType\r
-       char    name[12];       //!< Volume Name (With NULL Terminator)\r
-       tMutex  lFAT;   //!< Lock to prevent double-writing to the FAT\r
-       Uint32  firstDataSect;  //!< First data sector\r
-       Uint32  rootOffset;     //!< Root Offset (clusters)\r
-       Uint32  ClusterCount;   //!< Total Cluster Count\r
-       fat_bootsect    bootsect;       //!< Boot Sector\r
-       tVFS_Node       rootNode;       //!< Root Node\r
-        int    BytesPerCluster;\r
-        int    inodeHandle;    //!< Inode Cache Handle\r
-       #if CACHE_FAT\r
-       Uint32  *FATCache;      //!< FAT Cache\r
-       #endif\r
-};\r
-\r
-typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
-\r
-#endif\r
diff --git a/Modules/Filesystems/InitRD/.gitignore b/Modules/Filesystems/InitRD/.gitignore
deleted file mode 100644 (file)
index 85e33a6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-files.*.c*
diff --git a/Modules/Filesystems/InitRD/GenerateInitRD.php b/Modules/Filesystems/InitRD/GenerateInitRD.php
deleted file mode 100644 (file)
index e7cd4f7..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-<?php
-$lGenDate = date("Y-m-d H:i");
-$gOutput = <<<EOF
-/*
- * Acess2 InitRD
- * InitRD Data
- * Generated $lGenDate
- */
-#include "initrd.h"
-
-EOF;
-
-$ACESSDIR = getenv("ACESSDIR");
-$ARCH = getenv("ARCH");
-
-$gInputFile = $argv[1];
-$gOutputFile = $argv[2];
-$gOutputLDOptsFile = $argv[3];
-$gDepFile = ($argc > 4 ? $argv[4] : false);
-
-$gDependencies = array();
-
-$lines = file($argv[1]);
-
-$lDepth = 0;
-$lTree = array();
-$lStack = array( array("",array()) );
-foreach($lines as $line)
-{
-       $line = trim($line);
-       // Directory
-       if(preg_match('/^Dir\s+"([^"]+)"\s+{$/', $line, $matches))
-       {
-               $new = array($matches[1], array());
-               array_push($lStack, $new);
-               $lDepth ++;
-               continue;
-       }
-       // End of a block
-       if($line == "}")
-       {
-               $lDepth --;
-               $lStack[$lDepth][1][] = array_pop($lStack);
-               continue;
-       }
-       // File
-       if(preg_match('/^File\s+"([^"]+)"\s+"([^"]+)"$/', $line, $matches))
-       {
-               $lStack[$lDepth][1][] = array($matches[1], $matches[2]);
-               continue;
-       }
-       echo "ERROR: $line\n";
-       exit(0);
-}
-
-function hd($fp)
-{
-       //return "0x".str_pad( dechex(ord(fgetc($fp))), 8, "0", STR_PAD_LEFT );
-       $val = unpack("I", fread($fp, 4));
-       //print_r($val);        exit -1;
-       return "0x".dechex($val[1]);
-}
-
-function hd8($fp)
-{
-       return "0x".str_pad( dechex(ord(fgetc($fp))), 2, "0", STR_PAD_LEFT );
-}
-
-$inode = 0;
-$gSymFiles = array();
-function ProcessFolder($prefix, $items)
-{
-       global  $gOutput, $gDependencies;
-       global  $ACESSDIR, $ARCH;
-       global  $inode;
-       global  $gSymFiles;
-       foreach($items as $i=>$item)
-       {
-               $inode ++;
-               if(is_array($item[1]))
-               {
-                       ProcessFolder("{$prefix}_{$i}", $item[1]);
-                       
-                       $gOutput .= "tInitRD_File {$prefix}_{$i}_entries[] = {\n";
-                       foreach($item[1] as $j=>$child)
-                       {
-                               if($j)  $gOutput .= ",\n";
-                               $gOutput .= "\t{\"".addslashes($child[0])."\",&{$prefix}_{$i}_{$j}}";
-                       }
-                       $gOutput .= "\n};\n";
-                       
-                       $size = count($item[1]);
-                       $gOutput .= <<<EOF
-tVFS_Node {$prefix}_{$i} = {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Size = $size,
-       .Inode = {$inode},
-       .ImplPtr = {$prefix}_{$i}_entries,
-       .Type = &gInitRD_DirType
-};
-
-EOF;
-               }
-               else
-               {
-                       $path = $item[1];
-                       
-                       // Parse path components
-                       $path = str_replace("__BIN__", "$ACESSDIR/Usermode/Output/$ARCH", $path);
-                       $path = str_replace("__FS__", "$ACESSDIR/Usermode/Filesystem", $path);
-                       $path = str_replace("__SRC__", "$ACESSDIR", $path);
-                       echo $path,"\n";
-                       // ---
-                       
-                       $gDependencies[] = $path;
-
-                       if(!file_exists($path)) {
-                               echo "ERROR: '{$path}' does not exist\n", 
-                               exit(1);
-                       }
-                       $size = filesize($path);
-       
-/*             
-                       $_sym = $prefix."_".$i."_data";
-                       $fp = fopen($path, "rb");
-                       
-                       $gOutput .= "Uint8 $_sym[] = {\n";
-                       for( $j = 0; $j + 16 < $size; $j += 16 ) {
-                               $gOutput .= "\t";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",\n";
-                       }
-                       $gOutput .= "\t";
-                       for( ; $j < $size; $j ++ ) {
-                               if( $j & 15 )   $gOutput .= ",";
-                               $gOutput .= hd8($fp);
-                       }
-                       fclose($fp);
-                       $gOutput .= "\n};\n";
-*/
-                       
-//*
-                       $_sym = "_binary_".str_replace(array("/","-","."), "_", $path)."_start";
-                       $gOutput .= "extern Uint8 {$_sym}[];";
-                       $gSymFiles[] = $path;
-//*/
-                       $gOutput .= <<<EOF
-tVFS_Node {$prefix}_{$i} = {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = 0,
-       .Size = $size,
-       .Inode = {$inode},
-       .ImplPtr = $_sym,
-       .Type = &gInitRD_FileType
-};
-
-EOF;
-               }
-       }
-}
-
-//print_r($lStack);
-//exit(1);
-
-ProcessFolder("gInitRD_Files", $lStack[0][1]);
-
-$gOutput .= "tInitRD_File gInitRD_Root_Files[] = {\n";
-foreach($lStack[0][1] as $j=>$child)
-{
-       if($j)  $gOutput .= ",\n";
-       $gOutput .= "\t{\"".addslashes($child[0])."\",&gInitRD_Files_{$j}}";
-}
-$gOutput .= "\n};\n";
-$nRootFiles = count($lStack[0][1]);
-$gOutput .= <<<EOF
-tVFS_Node gInitRD_RootNode = {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Size = $nRootFiles,
-       .ImplPtr = gInitRD_Root_Files,
-       .Type = &gInitRD_DirType
-};
-EOF;
-
-$gOutput .= <<<EOF
-
-tVFS_Node * const gInitRD_FileList[] = {
-&gInitRD_RootNode
-EOF;
-
-function PutNodePointers($prefix, $items)
-{
-       global $gOutput;
-       foreach($items as $i=>$item)
-       {
-               $gOutput .= ",&{$prefix}_{$i}";
-               if(is_array($item[1]))
-               {
-                       PutNodePointers("{$prefix}_{$i}", $item[1]);
-               }
-       }
-}
-
-PutNodePointers("gInitRD_Files", $lStack[0][1]);
-
-$gOutput .= <<<EOF
-};
-const int giInitRD_NumFiles = sizeof(gInitRD_FileList)/sizeof(gInitRD_FileList[0]);
-
-EOF;
-
-
-$fp = fopen($gOutputFile, "w");
-fputs($fp, $gOutput);
-fclose($fp);
-
-// - Create options call
-$fp = fopen($gOutputLDOptsFile, "w");
-fputs($fp, "--format binary\n");
-foreach($gSymFiles as $sym=>$file)
-{
-       fputs($fp, "$file\n");
-//     fputs($fp, "--defsym $sym=_binary_".$sym_filename."_start\n");
-}
-fclose($fp);
-
-if($gDepFile !== false)
-{
-       $fp = fopen($gDepFile, "w");
-       $line = $gOutputFile.":\t".implode(" ", $gDependencies);
-       fputs($fp, $line);
-       fclose($fp);
-}
-
-?>
diff --git a/Modules/Filesystems/InitRD/Makefile b/Modules/Filesystems/InitRD/Makefile
deleted file mode 100644 (file)
index 5aa0e65..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# InitRD Filesystem Driver
-#
-
-OBJ = main.o files.$(ARCH).o
-EXTRA = files.c
-NAME = InitRD
-EXTRA = files.$(ARCH).c files.$(ARCH).c.dep files.$(ARCH).c.ldopts
-LDFLAGS += @files.$(ARCH).c.ldopts
-
--include ../Makefile.tpl
-
-
-files.$(ARCH).c: GenerateInitRD.php files.lst
-       ARCH=$(ARCH) ACESSDIR=$(ACESSDIR) php GenerateInitRD.php files.lst $@ [email protected] [email protected]
-
--include files.$(ARCH).c.dep
diff --git a/Modules/Filesystems/InitRD/files.lst b/Modules/Filesystems/InitRD/files.lst
deleted file mode 100644 (file)
index 16d647f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-Dir "SBin" {
-       File "init" "__BIN__/SBin/init"
-       File "login" "__BIN__/SBin/login"
-}
-Dir "Bin" {
-       File "CLIShell" "__BIN__/Bin/CLIShell"
-       File "ls" "__BIN__/Bin/ls"
-       File "cat" "__BIN__/Bin/cat"
-       File "mount" "__BIN__/Bin/mount"
-       File "ifconfig" "__BIN__/Bin/ifconfig"
-       File "telnet" "__BIN__/Bin/telnet"
-       File "irc" "__BIN__/Bin/irc"
-}
-Dir "Libs" {
-       File "ld-acess.so" "__BIN__/Libs/ld-acess.so"
-       File "libld-acess.so" "__BIN__/Libs/libld-acess.so"
-       File "libc.so" "__BIN__/Libs/libc.so"
-       File "libgcc.so" "__BIN__/Libs/libgcc.so"
-       File "libreadline.so" "__BIN__/Libs/libreadline.so"
-       File "libnet.so" "__BIN__/Libs/libnet.so"
-       File "liburi.so" "__BIN__/Libs/liburi.so"
-       File "libimage_sif.so" "__BIN__/Libs/libimage_sif.so"
-       File "libaxwin3.so" "__BIN__/Libs/libaxwin3.so"
-}
-Dir "Conf" {
-       File "BootConf.cfg" "__FS__/Conf/BootConf.cfg"
-}
-Dir "Apps" {
-       Dir "AxWin" {
-               Dir "3.0" {
-                       File "AxWinWM" "__BIN__/Apps/AxWin/3.0/AxWinWM"
-                       File "AxWinUI" "__BIN__/Apps/AxWin/3.0/AxWinUI"
-                       File "AcessLogoSmall.sif" "__SRC__/Usermode/Applications/axwin3_src/AcessLogoSmall.sif"
-               }
-       }
-}
diff --git a/Modules/Filesystems/InitRD/initrd.h b/Modules/Filesystems/InitRD/initrd.h
deleted file mode 100644 (file)
index 479a841..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- */
-#ifndef _INITRD_H_
-#define _INITRD_H_
-
-#include <acess.h>
-#include <vfs.h>
-
-typedef struct sInitRD_File
-{
-       char    *Name;
-       tVFS_Node       *Node;
-}      tInitRD_File;
-
-
-// === Functions ===
-extern Uint64  InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer);
-extern char    *InitRD_ReadDir(tVFS_Node *Node, int ID);
-extern tVFS_Node       *InitRD_FindDir(tVFS_Node *Node, const char *Name);
-
-// === Globals ===
-tVFS_NodeType  gInitRD_DirType;
-tVFS_NodeType  gInitRD_FileType;
-
-#endif
diff --git a/Modules/Filesystems/InitRD/main.c b/Modules/Filesystems/InitRD/main.c
deleted file mode 100644 (file)
index b52ab8d..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Acess OS
- * InitRD Driver Version 1
- */
-#include "initrd.h"
-#include <modules.h>
-
-#define DUMP_ON_MOUNT  1
-
-// === IMPORTS ==
-extern tVFS_Node       gInitRD_RootNode;
-extern const int       giInitRD_NumFiles;
-extern tVFS_Node * const       gInitRD_FileList[];
-
-// === PROTOTYPES ===
- int   InitRD_Install(char **Arguments);
-tVFS_Node      *InitRD_InitDevice(const char *Device, const char **Arguments);
-void   InitRD_Unmount(tVFS_Node *Node);
-tVFS_Node      *InitRD_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
-Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer);
-char   *InitRD_ReadDir(tVFS_Node *Node, int ID);
-tVFS_Node      *InitRD_FindDir(tVFS_Node *Node, const char *Name);
-void   InitRD_DumpDir(tVFS_Node *Node, int Indent);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL);
-tVFS_Driver    gInitRD_FSInfo = {
-       "initrd", 0, InitRD_InitDevice, InitRD_Unmount, InitRD_GetNodeFromINode
-       };
-tVFS_NodeType  gInitRD_DirType = {
-       .ReadDir = InitRD_ReadFile,
-       .FindDir = InitRD_FindDir
-       };
-tVFS_NodeType  gInitRD_FileType = {
-       .Read = InitRD_ReadFile
-       };
-
-/**
- * \brief Register initrd with the kernel
- */
-int InitRD_Install(char **Arguments)
-{
-       Log_Notice("InitRD", "Installed");
-       VFS_AddDriver( &gInitRD_FSInfo );
-       
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Mount the InitRD
- */
-tVFS_Node *InitRD_InitDevice(const char *Device, const char **Arguments)
-{
-       #if DUMP_ON_MOUNT
-       InitRD_DumpDir( &gInitRD_RootNode, 0 );
-       #endif
-       Log_Notice("InitRD", "Mounted (%i files)", giInitRD_NumFiles);
-       return &gInitRD_RootNode;
-}
-
-/**
- * \brief Unmount the InitRD
- */
-void InitRD_Unmount(tVFS_Node *Node)
-{
-}
-
-/**
- */
-tVFS_Node *InitRD_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)
-{
-       if( Inode >= giInitRD_NumFiles )        return NULL;
-       return gInitRD_FileList[Inode];
-}
-
-/**
- * \brief Read from a file
- */
-Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       if(Offset > Node->Size)
-               return 0;
-       if(Offset + Length > Node->Size)
-               Length = Node->Size - Offset;
-       
-       memcpy(Buffer, Node->ImplPtr+Offset, Length);
-       
-       return Length;
-}
-
-/**
- * \brief Read from a directory
- */
-char *InitRD_ReadDir(tVFS_Node *Node, int ID)
-{
-       tInitRD_File    *dir = Node->ImplPtr;
-       
-       if(ID >= Node->Size)
-               return NULL;
-       
-       return strdup(dir[ID].Name);
-}
-
-/**
- * \brief Find an element in a directory
- */
-tVFS_Node *InitRD_FindDir(tVFS_Node *Node, const char *Name)
-{
-        int    i;
-       tInitRD_File    *dir = Node->ImplPtr;
-       
-       LOG("Name = '%s'", Name);
-       
-       for( i = 0; i < Node->Size; i++ )
-       {
-               if(strcmp(Name, dir[i].Name) == 0)
-                       return dir[i].Node;
-       }
-       
-       return NULL;
-}
-
-void InitRD_DumpDir(tVFS_Node *Node, int Indent)
-{
-        int    i;
-       char    indent[Indent+1];
-       tInitRD_File    *dir = Node->ImplPtr;
-       
-       for( i = 0; i < Indent; i++ )   indent[i] = ' ';
-       indent[i] = '\0';
-       
-       for( i = 0; i < Node->Size; i++ )
-       {
-               Log_Debug("InitRD", "%s- %p %s", indent, dir[i].Node, dir[i].Name);
-               if(dir[i].Node->Flags & VFS_FFLAG_DIRECTORY)
-                       InitRD_DumpDir(dir[i].Node, Indent+1);
-       }
-}
diff --git a/Modules/Filesystems/Makefile.tpl b/Modules/Filesystems/Makefile.tpl
deleted file mode 100644 (file)
index 77dfc2c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-CATEGORY = FS
--include ../../Makefile.tpl
diff --git a/Modules/Filesystems/NFS/Makefile b/Modules/Filesystems/NFS/Makefile
deleted file mode 100644 (file)
index 0b2019f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o
-NAME = NFS
-
--include ../Makefile.tpl
diff --git a/Modules/Filesystems/NFS/common.h b/Modules/Filesystems/NFS/common.h
deleted file mode 100644 (file)
index d73592f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Acess2 - NFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * common.h - Common definitions
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-typedef struct sNFS_Connection
-{
-        int    FD;
-       tIPAddr Host;
-       char    *Base;
-       tVFS_Node       Node;
-}      tNFS_Connection;
-
-#endif
diff --git a/Modules/Filesystems/NFS/main.c b/Modules/Filesystems/NFS/main.c
deleted file mode 100644 (file)
index 459945f..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Acess2 - NFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * main.c - Driver core
- */
-#define DEBUG  1
-#define VERBOSE        0
-#include "common.h"
-#include <modules.h>
-
-// === PROTOTYPES ===
- int   NFS_Install(char **Arguments);
-tVFS_Node      *NFS_InitDevice(char *Devices, char **Options);
-void   NFS_Unmount(tVFS_Node *Node);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x32 /*v0.5*/, FS_NFS, NFS_Install, NULL);
-tVFS_Driver    gNFS_FSInfo = {"nfs", 0, NFS_InitDevice, NFS_Unmount, NULL};
-
-tNFS_Connection        *gpNFS_Connections;
-
-// === CODE ===
-/**
- * \brief Installs the NFS driver
- */
-int NFS_Install(char **Arguments)
-{
-       VFS_AddDriver( &gNFS_FSInfo );
-       return 1;
-}
-
-/**
- * \brief Mount a NFS share
- */
-tVFS_Node *NFS_InitDevice(char *Device, char **Options)
-{
-       char    *path, *host;
-       tNFS_Connection *conn;
-       
-       path = strchr( Device, ':' ) + 1;
-       host = strndup( Device, (int)(path-Device)-1 );
-       
-       conn = malloc( sizeof(tNFS_Connection) );
-       
-       if( !IPTools_GetAddress(host, &conn->IP) ) {
-               free(conn);
-               return NULL;
-       }
-       free(host);
-       
-       conn->FD = IPTools_OpenUdpClient( &conn->Host );
-       if(conn->FD == -1) {
-               free(conn);
-               return NULL;
-       }
-       
-       conn->Base = strdup( path );
-       conn->RootNode.ImplPtr = conn;
-       conn->RootNode.Flags = VFS_FFLAG_DIRECTORY;
-       
-       conn->RootNode.ReadDir = NFS_ReadDir;
-       conn->RootNode.FindDir = NFS_FindDir;
-       conn->RootNode.Close = NULL;
-       
-       return &conn->RootNode;
-}
-
-void NFS_Unmount(tVFS_Node *Node)
-{
-       
-}
diff --git a/Modules/Filesystems/NTFS/Makefile b/Modules/Filesystems/NTFS/Makefile
deleted file mode 100644 (file)
index 22c1677..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o dir.o
-NAME = NTFS
-
--include ../Makefile.tpl
diff --git a/Modules/Filesystems/NTFS/attributes.h b/Modules/Filesystems/NTFS/attributes.h
deleted file mode 100644 (file)
index 671a36e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Acess2 - NTFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * attributes.h - MFT Attribute Types
- */
-#ifndef _ATTRIBUTES_H_
-#define _ATTRIBUTES_H_
-
-typedef struct
-{
-       Uint64  ParentDirectory;        //!< Parent directory MFT entry
-       Sint64  CreationTime;   //!< Time the file was created
-       Sint64  LastDataModTime;        //!< Last change time for the data
-       Sint64  LastMtfModTime; //!< Last change time for the MFT entry
-       Sint64  LastAccessTime; //!< Last Access Time (unreliable on most systems)
-       
-       Uint64  AllocatedSize;  //!< Allocated data size for $DATA unnamed stream
-       Uint64  DataSize;       //!< Actual size of $DATA unnamed stream
-       Uint32  Flags;  //!< File attribute files
-       
-       union {
-               struct {
-                       Uint16  PackedSize;     //!< Size of buffer needed for extended attributes
-                       Uint16  _reserved;
-               } PACKED        ExtAttrib;
-               struct {
-                       Uint32  Tag;    //!< Type of reparse point
-               } PACKED        ReparsePoint;
-       } PACKED        Type;
-       
-       Uint8   FilenameType;   //!< Filename namespace (DOS, Windows, Unix)
-       WCHAR   Filename[0];
-} PACKED       tNTFS_Attrib_Filename;
-
-#endif
diff --git a/Modules/Filesystems/NTFS/common.h b/Modules/Filesystems/NTFS/common.h
deleted file mode 100644 (file)
index 598120d..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Acess2 - NTFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * common.h - Common Types and Definitions
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-#include <acess.h>
-#include <vfs.h>
-
-typedef Uint16 WCHAR;
-
-// === STRUCTURES ===
-/**
- * In-memory representation of an NTFS Disk
- */
-typedef struct sNTFS_Disk
-{
-        int    FD;
-        int    CacheHandle;
-        
-        int    ClusterSize;
-       Uint64  MFTBase;
-       Uint32  MFTRecSize;
-       
-       tVFS_Node       RootNode;
-}      tNTFS_Disk;
-
-typedef struct sNTFS_BootSector
-{
-       // 0
-       Uint8   Jump[3];
-       Uint8   SystemID[8];    // = "NTFS    "
-       Uint16  BytesPerSector;
-       Uint8   SectorsPerCluster;
-       
-       // 0xE
-       Uint8   Unused[7];
-       Uint8   MediaDescriptor;
-       Uint16  Unused2;
-       Uint16  SectorsPerTrack;
-       Uint16  Heads;
-       
-       // 0x1C
-       Uint64  Unused3;
-       Uint32  Unkown; // Usually 0x00800080 (according to Linux docs)
-       
-       // 0x28
-       Uint64  TotalSectorCount;       // Size of volume in sectors
-       Uint64  MFTStart;       // Logical Cluster Number of Cluster 0 of MFT
-       Uint64  MFTMirrorStart; // Logical Cluster Number of Cluster 0 of MFT Backup
-       
-       // 0x40
-       // If either of these are -ve, the size can be obtained via
-       // SizeInBytes = 2^(-1 * Value)
-       Sint8   ClustersPerMFTRecord;
-       Uint8   Unused4[3];
-       Sint8   ClustersPerIndexRecord;
-       Uint8   Unused5[3];
-       
-       Uint64  SerialNumber;
-       
-       Uint8   Padding[512-0x50];
-       
-} PACKED       tNTFS_BootSector;
-
-/**
- * FILE header, an entry in the MFT
- */
-typedef struct sNTFS_FILE_Header
-{
-       Uint32  Magic;  // 'FILE'
-       Uint16  UpdateSequenceOfs;
-       Uint16  UpdateSequenceSize;     // Size in words of the UpdateSequenceArray
-       
-       Uint64  LSN;    // $LogFile Sequence Number
-       
-       Uint16  SequenceNumber;
-       Uint16  HardLinkCount;  
-       Uint16  FirstAttribOfs; // Size of header?
-       Uint16  Flags;  // 0: In Use, 1: Directory
-       
-       Uint32  RecordSize;             // Real Size of FILE Record
-       Uint32  RecordSpace;    // Allocated Size for FILE Record
-       
-       /**
-        * Base address of the MFT containing this record
-        */
-       Uint64  Reference;      // "File reference to the base FILE record" ???
-       
-       Uint16  NextAttribID;
-       union
-       {
-               // Only in XP
-               struct {
-                       Uint16  AlignTo4Byte;
-                       Uint16  RecordNumber;   // Number of this MFT Record
-                       Uint16  UpdateSequenceNumber;
-                       Uint16  UpdateSequenceArray[];
-               }       XP;
-               struct {
-                       Uint16  UpdateSequenceNumber;
-                       Uint16  UpdateSequenceArray[];
-               }       All;
-       } OSDep;        
-       
-} PACKED       tNTFS_FILE_Header;
-
-/**
- * File Attribute, follows the FILE header
- */
-typedef struct sNTFS_FILE_Attrib
-{
-       Uint32  Type;   // See eNTFS_FILE_Attribs
-       Uint32  Size;   // Includes header
-       
-       Uint8   ResidentFlag;   // (What does this mean?)
-       Uint8   NameLength;
-       Uint16  NameOffset;
-       Uint16  Flags;  // 0: Compressed, 14: Encrypted, 15: Sparse
-       Uint16  AttributeID;
-       
-       union
-       {
-               struct {
-                       Uint32  AttribLen;      // In words
-                       Uint16  AttribOfs;
-                       Uint8   IndexedFlag;
-                       Uint8   Padding;
-                       
-                       Uint16  Name[]; // UTF-16
-                       // Attribute Data
-               }       Resident;
-               struct {
-                       Uint64  StartingVCN;
-                       Uint64  LastVCN;
-                       Uint16  DataRunOfs;
-                       Uint16  CompressionUnitSize;
-                       Uint32  Padding;
-                       Uint64  AllocatedSize;
-                       Uint64  RealSize;
-                       Uint64  InitiatedSize;  // One assumes, ammount of actual data stored
-                       Uint16  Name[]; // UTF-16
-                       // Data Runs
-               }       NonResident;
-       };
-} PACKED       tNTFS_FILE_Attrib;
-
-#endif
diff --git a/Modules/Filesystems/NTFS/dir.c b/Modules/Filesystems/NTFS/dir.c
deleted file mode 100644 (file)
index 37661e8..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Acess2 - NTFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * dir.c - Directory Handling
- */
-#include "common.h"
-#include "index.h"
-
-// === PROTOTYPES ===
-char   *NTFS_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *NTFS_FindDir(tVFS_Node *Node, const char *Name);
-Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str);
-
-// === CODE ===
-/**
- * \brief Get the name of an indexed directory entry
- */
-char *NTFS_ReadDir(tVFS_Node *Node, int Pos)
-{
-       return NULL;
-}
-
-/**
- * \brief Get an entry from a directory by name
- */
-tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name)
-{
-       tNTFS_Disk      *disk = Node->ImplPtr;
-       Uint64  inode = NTFS_int_IndexLookup(Node->Inode, "$I30", Name);
-       tVFS_Node       node;
-       
-       if(!inode)      return NULL;
-       
-       node.Inode = inode;
-       
-       return Inode_CacheNode(disk->CacheHandle, &node);
-}
-
-/**
- * \brief Scans an index for the requested value and returns the associated ID
- */
-Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str)
-{
-       return 0;
-}
diff --git a/Modules/Filesystems/NTFS/index.h b/Modules/Filesystems/NTFS/index.h
deleted file mode 100644 (file)
index f45d897..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Acess2 - NTFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * index.h - Index Types
- */
-#ifndef _INDEX_H_
-#define _INDEX_H_
-
-#include "attributes.h"
-
-typedef struct
-{
-       Uint32  EntryOffset;
-       Uint32  IndexLength;
-       Uint32  AllocateSize;
-       Uint8   Flags;
-       Uint8   _reserved[3];
-} PACKED       tNTFS_IndexHeader;
-
-typedef struct
-{
-       Uint32  Type;
-       Uint32  CollationRule;
-       Uint32  IndexBlockSize;
-       Uint8   ClustersPerIndexBlock;
-       Uint8   _reserved[3];
-       tNTFS_IndexHeader       Header;
-} PACKED       tNTFS_IndexRoot;
-
-typedef struct
-{
-       union {
-               struct {
-                       Uint64  File;   // MFT Index of file
-               } PACKED        Dir;
-               /**
-                * Views/Indexes
-                */
-               struct {
-                       Uint16  DataOffset;
-                       Uint16  DataLength;
-                       Uint32  _reserved;
-               } PACKED        ViewIndex;
-       } PACKED        Header;
-       
-       Uint16  Length; //!< Size of the index entry (multiple of 8 bytes)
-       Uint16  KeyLength;      //!< Size of key value
-       Uint16  Flags;  //!< Flags Bitfield
-       Uint16  _reserved;
-       
-       /**
-        * \brief Key Data
-        * \note Only valid if \a Flags does not have \a INDEX_ENTRY_END set
-        * \note In NTFS3 only \a Filename is used
-        */
-       union {
-               tNTFS_Attrib_Filename   Filename;
-               //TODO: more key types
-       } PACKED        Key;
-} PACKED       tNTFS_IndexEntry;
-
-#endif
diff --git a/Modules/Filesystems/NTFS/main.c b/Modules/Filesystems/NTFS/main.c
deleted file mode 100644 (file)
index dbda06e..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Acess2 - NTFS Driver
- * By John Hodge (thePowersGang)
- *
- * main.c - Driver core
- */
-#define DEBUG  1
-#define VERBOSE        0
-#include <acess.h>
-#include <vfs.h>
-#include "common.h"
-#include <modules.h>
-
-// === IMPORTS ===
-extern char    *NTFS_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node       *NTFS_FindDir(tVFS_Node *Node, const char *Name);
-
-// === PROTOTYPES ===
- int   NTFS_Install(char **Arguments);
-tVFS_Node      *NTFS_InitDevice(const char *Devices, const char **Options);
-void   NTFS_Unmount(tVFS_Node *Node);
-void   NTFS_DumpEntry(tNTFS_Disk *Disk, Uint32 Entry);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x0A /*v0.1*/, FS_NTFS, NTFS_Install, NULL);
-tVFS_Driver    gNTFS_FSInfo = {"ntfs", 0, NTFS_InitDevice, NTFS_Unmount, NULL};
-tVFS_NodeType  gNTFS_DirType = {
-       .TypeName = "NTFS-File",
-       .ReadDir = NTFS_ReadDir,
-       .FindDir = NTFS_FindDir,
-       .Close = NULL
-       };
-
-tNTFS_Disk     gNTFS_Disks;
-
-// === CODE ===
-/**
- * \brief Installs the NTFS driver
- */
-int NTFS_Install(char **Arguments)
-{
-       VFS_AddDriver( &gNTFS_FSInfo );
-       return 0;
-}
-
-/**
- * \brief Mount a NTFS volume
- */
-tVFS_Node *NTFS_InitDevice(const char *Device, const char **Options)
-{
-       tNTFS_Disk      *disk;
-       tNTFS_BootSector        bs;
-       
-       disk = malloc( sizeof(tNTFS_Disk) );
-       
-       disk->FD = VFS_Open(Device, VFS_OPENFLAG_READ);
-       if(!disk->FD) {
-               free(disk);
-               return NULL;
-       }
-       
-       Log_Debug("FS_NTFS", "&bs = %p", &bs);
-       VFS_ReadAt(disk->FD, 0, 512, &bs);
-       
-       Log_Debug("FS_NTFS", "Jump = %02x%02x%02x",
-               bs.Jump[0],
-               bs.Jump[1],
-               bs.Jump[2]);
-       Log_Debug("FS_NTFS", "SystemID = %02x%02x%02x%02x%02x%02x%02x%02x (%8C)",
-               bs.SystemID[0], bs.SystemID[1], bs.SystemID[2], bs.SystemID[3],
-               bs.SystemID[4], bs.SystemID[5], bs.SystemID[6], bs.SystemID[7],
-               bs.SystemID
-               );
-       Log_Debug("FS_NTFS", "BytesPerSector = %i", bs.BytesPerSector);
-       Log_Debug("FS_NTFS", "SectorsPerCluster = %i", bs.SectorsPerCluster);
-       Log_Debug("FS_NTFS", "MediaDescriptor = 0x%x", bs.MediaDescriptor);
-       Log_Debug("FS_NTFS", "SectorsPerTrack = %i", bs.SectorsPerTrack);
-       Log_Debug("FS_NTFS", "Heads = %i", bs.Heads);
-       Log_Debug("FS_NTFS", "TotalSectorCount = 0x%llx", bs.TotalSectorCount);
-       Log_Debug("FS_NTFS", "MFTStart = 0x%llx", bs.MFTStart);
-       Log_Debug("FS_NTFS", "MFTMirrorStart = 0x%llx", bs.MFTMirrorStart);
-       Log_Debug("FS_NTFS", "ClustersPerMFTRecord = %i", bs.ClustersPerMFTRecord);
-       Log_Debug("FS_NTFS", "ClustersPerIndexRecord = %i", bs.ClustersPerIndexRecord);
-       Log_Debug("FS_NTFS", "SerialNumber = 0x%llx", bs.SerialNumber);
-       
-       disk->ClusterSize = bs.BytesPerSector * bs.SectorsPerCluster;
-       Log_Debug("NTFS", "Cluster Size = %i KiB", disk->ClusterSize/1024);
-       disk->MFTBase = bs.MFTStart;
-       Log_Debug("NTFS", "MFT Base = %i", disk->MFTBase);
-       Log_Debug("NTFS", "TotalSectorCount = 0x%x", bs.TotalSectorCount);
-       
-       if( bs.ClustersPerMFTRecord < 0 ) {
-               disk->MFTRecSize = 1 << (-bs.ClustersPerMFTRecord);
-       }
-       else {
-               disk->MFTRecSize = bs.ClustersPerMFTRecord * disk->ClusterSize;
-       }
-       
-       disk->RootNode.Inode = 5;       // MFT Ent #5 is filesystem root
-       disk->RootNode.ImplPtr = disk;
-       
-       disk->RootNode.UID = 0;
-       disk->RootNode.GID = 0;
-       
-       disk->RootNode.NumACLs = 1;
-       disk->RootNode.ACLs = &gVFS_ACL_EveryoneRX;
-       
-       disk->RootNode.Type = &gNTFS_DirType;
-
-       
-       NTFS_DumpEntry(disk, 5);
-       
-       return &disk->RootNode;
-}
-
-/**
- * \brief Unmount an NTFS Disk
- */
-void NTFS_Unmount(tVFS_Node *Node)
-{
-       
-}
-
-/**
- * \brief Dumps a MFT Entry
- */
-void NTFS_DumpEntry(tNTFS_Disk *Disk, Uint32 Entry)
-{
-       void    *buf = malloc( Disk->MFTRecSize );
-       tNTFS_FILE_Header       *hdr = buf;
-       tNTFS_FILE_Attrib       *attr;
-        int    i;
-       
-       if(!buf) {
-               Log_Warning("FS_NTFS", "malloc() fail!");
-               return ;
-       }
-       
-       VFS_ReadAt( Disk->FD,
-               Disk->MFTBase * Disk->ClusterSize + Entry * Disk->MFTRecSize,
-               Disk->MFTRecSize,
-               buf);
-       
-       Log_Debug("FS_NTFS", "MFT Entry #%i", Entry);
-       Log_Debug("FS_NTFS", "- Magic = 0x%08x (%4C)", hdr->Magic, &hdr->Magic);
-       Log_Debug("FS_NTFS", "- UpdateSequenceOfs = 0x%x", hdr->UpdateSequenceOfs);
-       Log_Debug("FS_NTFS", "- UpdateSequenceSize = 0x%x", hdr->UpdateSequenceSize);
-       Log_Debug("FS_NTFS", "- LSN = 0x%x", hdr->LSN);
-       Log_Debug("FS_NTFS", "- SequenceNumber = %i", hdr->SequenceNumber);
-       Log_Debug("FS_NTFS", "- HardLinkCount = %i", hdr->HardLinkCount);
-       Log_Debug("FS_NTFS", "- FirstAttribOfs = 0x%x", hdr->FirstAttribOfs);
-       Log_Debug("FS_NTFS", "- Flags = 0x%x", hdr->Flags);
-       Log_Debug("FS_NTFS", "- RecordSize = 0x%x", hdr->RecordSize);
-       Log_Debug("FS_NTFS", "- RecordSpace = 0x%x", hdr->RecordSpace);
-       Log_Debug("FS_NTFS", "- Reference = 0x%llx", hdr->Reference);
-       Log_Debug("FS_NTFS", "- NextAttribID = 0x%04x", hdr->NextAttribID);
-       
-       attr = (void*)( (char*)hdr + hdr->FirstAttribOfs );
-       i = 0;
-       while( (tVAddr)attr < (tVAddr)hdr + hdr->RecordSize )
-       {
-               if(attr->Type == 0xFFFFFFFF)    break;
-               Log_Debug("FS_NTFS", "- Attribute %i", i ++);
-               Log_Debug("FS_NTFS", " > Type = 0x%x", attr->Type);
-               Log_Debug("FS_NTFS", " > Size = 0x%x", attr->Size);
-               Log_Debug("FS_NTFS", " > ResidentFlag = 0x%x", attr->ResidentFlag);
-               Log_Debug("FS_NTFS", " > NameLength = %i", attr->NameLength);
-               Log_Debug("FS_NTFS", " > NameOffset = 0x%x", attr->NameOffset);
-               Log_Debug("FS_NTFS", " > Flags = 0x%x", attr->Flags);
-               Log_Debug("FS_NTFS", " > AttributeID = 0x%x", attr->AttributeID);
-               if( !attr->ResidentFlag ) {
-                       Log_Debug("FS_NTFS", " > AttribLen = 0x%x", attr->Resident.AttribLen);
-                       Log_Debug("FS_NTFS", " > AttribOfs = 0x%x", attr->Resident.AttribOfs);
-                       Log_Debug("FS_NTFS", " > IndexedFlag = 0x%x", attr->Resident.IndexedFlag);
-                       Log_Debug("FS_NTFS", " > Name = '%*C'", attr->NameLength, attr->Resident.Name);
-                       Debug_HexDump("FS_NTFS",
-                               (void*)( (tVAddr)attr + attr->Resident.AttribOfs ),
-                               attr->Resident.AttribLen
-                               );
-               }
-               else {
-                       Log_Debug("FS_NTFS", " > StartingVCN = 0x%llx", attr->NonResident.StartingVCN);
-                       Log_Debug("FS_NTFS", " > LastVCN = 0x%llx", attr->NonResident.LastVCN);
-                       Log_Debug("FS_NTFS", " > DataRunOfs = 0x%x", attr->NonResident.DataRunOfs);
-                       Log_Debug("FS_NTFS", " > CompressionUnitSize = 0x%x", attr->NonResident.CompressionUnitSize);
-                       Log_Debug("FS_NTFS", " > AllocatedSize = 0x%llx", attr->NonResident.AllocatedSize);
-                       Log_Debug("FS_NTFS", " > RealSize = 0x%llx", attr->NonResident.RealSize);
-                       Log_Debug("FS_NTFS", " > InitiatedSize = 0x%llx", attr->NonResident.InitiatedSize);
-                       Log_Debug("FS_NTFS", " > Name = '%*C'", attr->NameLength, attr->NonResident.Name);
-               }
-               
-               attr = (void*)( (tVAddr)attr + attr->Size );
-       }
-       
-       free(buf);
-}
diff --git a/Modules/IPStack/Makefile b/Modules/IPStack/Makefile
deleted file mode 100644 (file)
index 0838a34..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-#
-
-OBJ := main.o interface.o
-OBJ += link.o arp.o
-OBJ += ipv4.o icmp.o
-OBJ += ipv6.o
-OBJ += firewall.o routing.o
-OBJ += udp.o tcp.o
-NAME := IPStack
-CATEGORY := 
-
--include ../Makefile.tpl
diff --git a/Modules/IPStack/arp.c b/Modules/IPStack/arp.c
deleted file mode 100644 (file)
index abaea27..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Address Resolution Protocol
- * - Part of the IPv4 protocol
- */
-#define DEBUG  0
-#include "ipstack.h"
-#include "arp.h"
-#include "link.h"
-
-#define ARPv6  0
-#define        ARP_CACHE_SIZE  64
-#define        ARP_MAX_AGE             (60*60*1000)    // 1Hr
-
-// === IMPORTS ===
-extern tInterface      *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
-#if ARPv6
-extern tInterface      *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
-#endif
-
-// === PROTOTYPES ===
- int   ARP_Initialise();
-tMacAddr       ARP_Resolve4(tInterface *Interface, tIPv4 Address);
-void   ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer);
-
-// === GLOBALS ===
-struct sARP_Cache4 {
-       tIPv4   IP;
-       tMacAddr        MAC;
-       Sint64  LastUpdate;
-       Sint64  LastUsed;
-}      *gaARP_Cache4;
- int   giARP_Cache4Space;
-tMutex glARP_Cache4;
-#if ARPv6
-struct sARP_Cache6 {
-       tIPv6   IP;
-       tMacAddr        MAC;
-       Sint64  LastUpdate;
-       Sint64  LastUsed;
-}      *gaARP_Cache6;
- int   giARP_Cache6Space;
-tMutex glARP_Cache6;
-#endif
-volatile int   giARP_LastUpdateID = 0;
-
-// === CODE ===
-/**
- * \fn int ARP_Initialise()
- * \brief Initalise the ARP section
- */
-int ARP_Initialise()
-{
-       gaARP_Cache4 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
-       memset( gaARP_Cache4, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache4) );
-       giARP_Cache4Space = ARP_CACHE_SIZE;
-       
-       #if ARPv6
-       gaARP_Cache6 = malloc( ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
-       memset( gaARP_Cache6, 0, ARP_CACHE_SIZE * sizeof(struct sARP_Cache6) );
-       giARP_Cache6Space = ARP_CACHE_SIZE;
-       #endif
-       
-       Link_RegisterType(0x0806, ARP_int_GetPacket);
-       return 1;
-}
-
-/**
- * \brief Resolves a MAC address from an IPv4 address
- */
-tMacAddr ARP_Resolve4(tInterface *Interface, tIPv4 Address)
-{
-        int    lastID;
-        int    i;
-       struct sArpRequest4     req;
-       Sint64  timeout;
-       
-       ENTER("pInterface xAddress", Interface, Address);
-       
-       // Check for broadcast
-       if( Address.L == -1 )
-       {
-               LOG("Broadcast");
-               LEAVE('-');
-               return cMAC_BROADCAST;
-       }
-
-       // Check routing tables if not on this subnet
-       if( IPStack_CompareAddress(4, &Address, Interface->Address, Interface->SubnetBits) == 0 )
-       {
-               tRoute  *route = IPStack_FindRoute(4, Interface, &Address);
-               // If the next hop is defined, use it
-               // - 0.0.0.0 as the next hop means "no next hop / direct"
-               if( route && ((tIPv4*)route->NextHop)->L != 0 )
-               {
-                       // Recursion: see /Recursion/
-                       LOG("Recursing with %s", IPStack_PrintAddress(4, route->NextHop));
-                       LEAVE('-');
-                       return ARP_Resolve4(Interface, *(tIPv4*)route->NextHop);
-               }
-               // No route, fall though
-       }
-       else
-       {
-               Uint32  netmask;
-               // Check for broadcast
-               netmask = IPv4_Netmask(Interface->SubnetBits);
-               if( (Address.L & ~netmask) == (0xFFFFFFFF & ~netmask) )
-               {
-                       LOG("Local Broadcast");
-                       LEAVE('-');
-                       return cMAC_BROADCAST;
-               }
-       }
-       
-       // Check ARP Cache
-       Mutex_Acquire( &glARP_Cache4 );
-       for( i = 0; i < giARP_Cache4Space; i++ )
-       {
-               if(gaARP_Cache4[i].IP.L != Address.L)   continue;
-               
-               // Check if the entry needs to be refreshed
-               if( now() - gaARP_Cache4[i].LastUpdate > ARP_MAX_AGE )  break;
-               
-               Mutex_Release( &glARP_Cache4 );
-               LOG("Return %x:%x:%x:%x:%x:%x",
-                       gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1],
-                       gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3],
-                       gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]
-                       );
-               LEAVE('-');
-               return gaARP_Cache4[i].MAC;
-       }
-       Mutex_Release( &glARP_Cache4 );
-       
-       lastID = giARP_LastUpdateID;
-       
-       // Create request
-       Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
-               Address.B[0], Address.B[1], Address.B[2], Address.B[3]
-               );
-       req.HWType = htons(0x0001);     // Ethernet
-       req.Type   = htons(0x0800);
-       req.HWSize = 6;
-       req.SWSize = 4;
-       req.Request = htons(1);
-       req.SourceMac = Interface->Adapter->MacAddr;
-       req.SourceIP = *(tIPv4*)Interface->Address;
-       req.DestMac = cMAC_BROADCAST;
-       req.DestIP = Address;
-       
-       // Send Request
-       Link_SendPacket(Interface->Adapter, 0x0806, req.DestMac, sizeof(struct sArpRequest4), &req);
-       
-       timeout = now() + Interface->TimeoutDelay;
-       
-       // Wait for a reply
-       for(;;)
-       {
-               while(lastID == giARP_LastUpdateID && now() < timeout) {
-                       Threads_Yield();
-               }
-               
-               if( now() >= timeout ) {
-                       Log_Log("ARP4", "Timeout");
-                       break;  // Timeout
-               }
-               
-               lastID = giARP_LastUpdateID;
-               
-               Mutex_Acquire( &glARP_Cache4 );
-               for( i = 0; i < giARP_Cache4Space; i++ )
-               {
-                       if(gaARP_Cache4[i].IP.L != Address.L)   continue;
-                       
-                       Mutex_Release( &glARP_Cache4 );
-                       Log_Debug("ARP4", "Return %02x:%02x:%02x:%02x:%02x:%02x",
-                               gaARP_Cache4[i].MAC.B[0], gaARP_Cache4[i].MAC.B[1], 
-                               gaARP_Cache4[i].MAC.B[2], gaARP_Cache4[i].MAC.B[3], 
-                               gaARP_Cache4[i].MAC.B[4], gaARP_Cache4[i].MAC.B[5]);
-                       return gaARP_Cache4[i].MAC;
-               }
-               Mutex_Release( &glARP_Cache4 );
-       }
-       {
-               tMacAddr        ret = {{0,0,0,0,0,0}};
-               return ret;
-       }
-}
-
-/**
- * \brief Updates the ARP Cache entry for an IPv4 Address
- */
-void ARP_UpdateCache4(tIPv4 SWAddr, tMacAddr HWAddr)
-{
-        int    i;
-        int    free = -1;
-        int    oldest = 0;
-       
-       // Find an entry for the IP address in the cache
-       Mutex_Acquire(&glARP_Cache4);
-       for( i = giARP_Cache4Space; i--; )
-       {
-               if(gaARP_Cache4[oldest].LastUpdate > gaARP_Cache4[i].LastUpdate) {
-                       oldest = i;
-               }
-               if( gaARP_Cache4[i].IP.L == SWAddr.L )  break;
-               if( gaARP_Cache4[i].LastUpdate == 0 && free == -1 )     free = i;
-       }
-       // If there was no match, we need to make one
-       if(i == -1) {
-               if(free != -1)
-                       i = free;
-               else
-                       i = oldest;
-       }
-       
-       Log_Log("ARP4", "Caching %i.%i.%i.%i (%02x:%02x:%02x:%02x:%02x:%02x) in %i",
-               SWAddr.B[0], SWAddr.B[1], SWAddr.B[2], SWAddr.B[3],
-               HWAddr.B[0], HWAddr.B[1], HWAddr.B[2], HWAddr.B[3], HWAddr.B[4], HWAddr.B[5],
-               i
-               );
-               
-       gaARP_Cache4[i].IP = SWAddr;
-       gaARP_Cache4[i].MAC = HWAddr;
-       gaARP_Cache4[i].LastUpdate = now();
-       giARP_LastUpdateID ++;
-       Mutex_Release(&glARP_Cache4);
-}
-
-#if ARPv6
-/**
- * \brief Updates the ARP Cache entry for an IPv6 Address
- */
-void ARP_UpdateCache6(tIPv6 SWAddr, tMacAddr HWAddr)
-{
-        int    i;
-        int    free = -1;
-        int    oldest = 0;
-       
-       // Find an entry for the MAC address in the cache
-       Mutex_Acquire(&glARP_Cache6);
-       for( i = giARP_Cache6Space; i--; )
-       {
-               if(gaARP_Cache6[oldest].LastUpdate > gaARP_Cache6[i].LastUpdate) {
-                       oldest = i;
-               }
-               if( MAC_EQU(gaARP_Cache6[i].MAC, HWAddr) )      break;
-               if( gaARP_Cache6[i].LastUpdate == 0 && free == -1 )     free = i;
-       }
-       // If there was no match, we need to make one
-       if(i == -1) {
-               if(free != -1)
-                       i = free;
-               else
-                       i = oldest;
-               gaARP_Cache6[i].MAC = HWAddr;
-       }
-       
-       gaARP_Cache6[i].IP = SWAddr;
-       gaARP_Cache6[i].LastUpdate = now();
-       giARP_LastUpdateID ++;
-       Mutex_Release(&glARP_Cache6);
-}
-#endif
-
-/**
- * \fn void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
- * \brief Called when an ARP packet is recieved
- */
-void ARP_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
-{
-       tArpRequest4    *req4 = Buffer;
-       #if ARPv6
-       tArpRequest6    *req6 = Buffer;
-       #endif
-       tInterface      *iface;
-       
-       // Sanity Check Packet
-       if( Length < (int)sizeof(tArpRequest4) ) {
-               Log_Log("ARP", "Recieved undersized packet");
-               return ;
-       }
-       if( ntohs(req4->Type) != 0x0800 ) {
-               Log_Log("ARP", "Recieved a packet with a bad type (0x%x)", ntohs(req4->Type));
-               return ;
-       }
-       if( req4->HWSize != 6 ) {
-               Log_Log("ARP", "Recieved a packet with HWSize != 6 (%i)", req4->HWSize);
-               return;
-       }
-       #if ARP_DETECT_SPOOFS
-       if( !MAC_EQU(req4->SourceMac, From) ) {
-               Log_Log("ARP", "ARP spoofing detected "
-                       "(%02x%02x:%02x%02x:%02x%02x != %02x%02x:%02x%02x:%02x%02x)",
-                       req4->SourceMac.B[0], req4->SourceMac.B[1], req4->SourceMac.B[2],
-                       req4->SourceMac.B[3], req4->SourceMac.B[4], req4->SourceMac.B[5],
-                       From.B[0], From.B[1], From.B[2],
-                       From.B[3], From.B[4], From.B[5]
-                       );
-               return;
-       }
-       #endif
-       
-       switch( ntohs(req4->Request) )
-       {
-       case 1: // You want my IP?
-               // Check what type of IP it is
-               switch( req4->SWSize )
-               {
-               case 4:
-                       Log_Debug("ARP", "ARP Request IPv4 Address %i.%i.%i.%i from %i.%i.%i.%i",
-                               req4->DestIP.B[0], req4->DestIP.B[1], req4->DestIP.B[2],
-                               req4->DestIP.B[3],
-                               req4->SourceIP.B[0], req4->SourceIP.B[1],
-                               req4->SourceIP.B[2], req4->SourceIP.B[3]);
-                       Log_Debug("ARP", " from MAC %02x:%02x:%02x:%02x:%02x:%02x",
-                               req4->SourceMac.B[0], req4->SourceMac.B[1],
-                               req4->SourceMac.B[2], req4->SourceMac.B[3],
-                               req4->SourceMac.B[4], req4->SourceMac.B[5]);
-                       iface = IPv4_GetInterface(Adapter, req4->DestIP, 0);
-                       if( iface )
-                       {
-                               ARP_UpdateCache4(req4->SourceIP, req4->SourceMac);
-                               
-                               req4->DestIP = req4->SourceIP;
-                               req4->DestMac = req4->SourceMac;
-                               req4->SourceIP = *(tIPv4*)iface->Address;;
-                               req4->SourceMac = Adapter->MacAddr;
-                               req4->Request = htons(2);
-                               Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
-                                       req4->SourceMac.B[0], req4->SourceMac.B[1],
-                                       req4->SourceMac.B[2], req4->SourceMac.B[3],
-                                       req4->SourceMac.B[4], req4->SourceMac.B[5]);
-                               Link_SendPacket(Adapter, 0x0806, req4->DestMac, sizeof(tArpRequest4), req4);
-                       }
-                       break;
-               #if ARPv6
-               case 6:
-                       if( Length < (int)sizeof(tArpRequest6) ) {
-                               Log_Log("ARP", "Recieved undersized packet (IPv6)");
-                               return ;
-                       }
-                       Log_Debug("ARP", "ARP Request IPv6 Address %08x:%08x:%08x:%08x",
-                               ntohl(req6->DestIP.L[0]), ntohl(req6->DestIP.L[1]),
-                               ntohl(req6->DestIP.L[2]), ntohl(req6->DestIP.L[3])
-                               );
-                       iface = IPv6_GetInterface(Adapter, req6->DestIP, 0);
-                       if( iface )
-                       {
-                               req6->DestIP = req6->SourceIP;
-                               req6->DestMac = req6->SourceMac;
-                               req6->SourceIP = *(tIPv6*)iface->Address;
-                               req6->SourceMac = Adapter->MacAddr;
-                               req6->Request = htons(2);
-                               Log_Debug("ARP", "Sending back us (%02x:%02x:%02x:%02x:%02x:%02x)",
-                                       req4->SourceMac.B[0], req4->SourceMac.B[1],
-                                       req4->SourceMac.B[2], req4->SourceMac.B[3],
-                                       req4->SourceMac.B[4], req4->SourceMac.B[5]);
-                               Link_SendPacket(Adapter, 0x0806, req6->DestMac, sizeof(tArpRequest6), req6);
-                       }
-                       break;
-               #endif
-               default:
-                       Log_Debug("ARP", "Unknown Protocol Address size (%i)", req4->SWSize);
-                       return ;
-               }
-               
-               break;
-       
-       case 2: // Ooh! A response!             
-               // Check what type of IP it is
-               switch( req4->SWSize )
-               {
-               case 4:
-                       ARP_UpdateCache4( req4->SourceIP, From );
-                       break;
-               #if ARPv6
-               case 6:
-                       if( Length < (int)sizeof(tArpRequest6) ) {
-                               Log_Debug("ARP", "Recieved undersized packet (IPv6)");
-                               return ;
-                       }
-                       ARP_UpdateCache6( req6->SourceIP, From );
-                       break;
-               #endif
-               default:
-                       Log_Debug("ARP", "Unknown Protocol Address size (%i)", req4->SWSize);
-                       return ;
-               }
-               
-               break;
-       
-       default:
-               Log_Warning("ARP", "Unknown Request ID %i", ntohs(req4->Request));
-               break;
-       }
-}
diff --git a/Modules/IPStack/arp.h b/Modules/IPStack/arp.h
deleted file mode 100644 (file)
index 07cdb64..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Common Header
- */
-#ifndef _ARP_H_
-#define _ARP_H_
-
-#include "ipstack.h"
-
-typedef struct sArpRequest4    tArpRequest4;
-typedef struct sArpRequest6    tArpRequest6;
-
-struct sArpRequest4 {
-       Uint16  HWType;
-       Uint16  Type;
-       Uint8   HWSize, SWSize;
-       Uint16  Request;
-       tMacAddr        SourceMac;
-       tIPv4   SourceIP;
-       tMacAddr        DestMac;
-       tIPv4   DestIP;
-} __attribute__((packed));
-
-struct sArpRequest6 {
-       Uint16  HWType;
-       Uint16  Type;
-       Uint8   HWSize, SWSize;
-       Uint16  Request;
-       tMacAddr        SourceMac;
-       tIPv6   SourceIP;
-       tMacAddr        DestMac;
-       tIPv6   DestIP;
-} __attribute__((packed));
-
-#endif
diff --git a/Modules/IPStack/firewall.c b/Modules/IPStack/firewall.c
deleted file mode 100644 (file)
index b039081..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Firewall Rules
- */
-#include "ipstack.h"
-#include "firewall.h"
-
-#define MAX_ADDRTYPE   9
-
-// === IMPORTS ===
-
-// === TYPES ===
-typedef struct sKeyValue       tKeyValue;
-typedef struct sFirewallMod    tFirewallMod;
-typedef struct sModuleRule     tModuleRule;
-typedef struct sRule   tRule;
-typedef struct sChain  tChain;
-
-// === STRUCTURES ===
-struct sKeyValue
-{
-       const char      *Key;
-       const char      *Value;
-};
-
-struct sFirewallMod
-{
-       const char      *Name;
-       
-        int    (*Match)(tModuleRule *Rule, int AddrType,
-                       const void *Src, const void *Dest,
-                       Uint8 Type, Uint32 Flags,
-                       size_t Length, const void *Data);
-       
-       tModuleRule     *(*Create)(tKeyValue *Params);
-};
-
-struct sModuleRule
-{
-       tModuleRule     *Next;
-       
-       tFirewallMod    *Mod;
-       
-       char    Data[];
-};
-
-struct sRule
-{
-       tRule   *Next;
-       
-        int    PacketCount;    // Number of packets seen
-        int    ByteCount;      // Number of bytes seen (IP Payload bytes)
-       
-        int    bInvertSource;  // Boolean NOT flag on source
-       void    *Source;        // Source address bytes
-        int    SourceMask;     // Source address mask bits
-        
-        int    bInvertDest;    // Boolean NOT flag on destination
-       void    *Dest;          // Destination address bytes
-        int    DestMask;       // Destination address mask bits
-       
-       tModuleRule     *Modules;       // Modules loaded for this rule
-       
-       char    Target[];       // Target rule name
-};
-
-struct sChain
-{
-       tChain  *Next;
-       
-       tRule   *FirstRule;
-       tRule   *LastRule;
-       
-       char    Name[];
-};
-
-// === PROTOTYPES ===
- int   IPTables_TestChain(
-       const char *RuleName,
-       const int AddressType,
-       const void *Src, const void *Dest,
-       Uint8 Type, Uint32 Flags,
-       size_t Length, const void *Data
-       );
-
-// === GLOBALS ===
-tChain *gapFirewall_Chains[MAX_ADDRTYPE+1];
-tChain gFirewall_DROP = {.Name="DROP"};
-tChain gFirewall_ACCEPT = {.Name="ACCEPT"};
-tChain gFirewall_RETURN = {.Name="RETURN"};
-
-// === CODE ===
-/**
- * \brief Apply a rule to a packet
- * \return -1 for no match, -2 for RETURN, eFirewallAction otherwise
- */
-int IPTables_DoRule(
-       tRule *Rule, int AddrType,
-       const void *Src, const void *Dest,
-       Uint8 Type, Uint32 Flags,
-       size_t Length, const void *Data)
-{
-        int    rv;
-       // Check if source doesn't match
-       if( !IPStack_CompareAddress(AddrType, Src, Rule->Source, Rule->SourceMask) == !Rule->bInvertSource )
-               return -1;
-       // Check if destination doesn't match
-       if( !IPStack_CompareAddress(AddrType, Dest, Rule->Dest, Rule->DestMask) == !Rule->bInvertDest )
-               return -1;
-       
-       // TODO: Handle modules (UDP/TCP/etc)
-       tModuleRule *modrule;
-       for( modrule = Rule->Modules; modrule; modrule = modrule->Next )
-       {
-               if( !modrule->Mod->Match )      continue;
-               rv = modrule->Mod->Match(modrule, AddrType, Src, Dest, Type, Flags, Length, Data);
-               if(rv != 0)     return rv;      // No match / action
-       }
-       
-       // Update statistics
-       Rule->PacketCount ++;
-       Rule->ByteCount += Length;
-       
-       return IPTables_TestChain(Rule->Target, AddrType, Src, Dest, Type, Flags, Length, Data);
-}
-
-/**
- * \brief Tests an IPv4 chain on a packet
- * \return Boolean Disallow (0: Packet Allowed, 1: Drop, 2: Reject, 3: Continue, -1 no match)
- */
-int IPTables_TestChain(
-       const char *RuleName,
-       const int AddressType,
-       const void *Src, const void *Dest,
-       Uint8 Type, Uint32 Flags,
-       size_t Length, const void *Data
-       )
-{
-        int    rv;
-       tChain  *chain;
-       tRule   *rule;
-       
-       if( AddressType >= MAX_ADDRTYPE )       return -1;      // Bad address type
-       
-       // Catch builtin targets
-       if(strcmp(RuleName, "") == 0)   return -1;      // No action
-       if(strcmp(RuleName, "ACCEPT") == 0)     return 0;       // Accept packet
-       if(strcmp(RuleName, "DROP") == 0)       return 1;       // Drop packet
-       if(strcmp(RuleName, "RETURN") == 0)     return -2;      // Return from rule
-       
-       // Find the rule
-       for( chain = gapFirewall_Chains[AddressType]; chain; chain = chain->Next )
-       {
-               if( strcmp(chain->Name, RuleName) == 0 )
-                       break;
-       }
-       if( !chain )    return -1;      // Bad rule name
-       
-       // Check the rules
-       for( rule = chain->FirstRule; rule; rule = rule->Next )
-       {
-               rv = IPTables_DoRule(rule, AddressType, Src, Dest, Type, Flags, Length, Data);
-               if( rv == -1 )
-                       continue ;
-               if( rv == -2 )  // -2 = Return from a chain/table, pretend no match
-                       return -1;
-               
-               return rv;
-       }
-       
-       
-       return 0;       // Accept all for now
-}
diff --git a/Modules/IPStack/firewall.h b/Modules/IPStack/firewall.h
deleted file mode 100644 (file)
index 5a62380..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-#ifndef _FIREWALL_H_
-#define _FIREWALL_H_
-
-enum eFirewallActions
-{
-       FIREWALL_ACCEPT,
-       FIREWALL_DROP
-};
-
-/**
- * \brief Tests a packet on a chain
- */
-extern int     IPTables_TestChain(
-       const char *RuleName,
-       const int AddressType,
-       const void *Src, const void *Dest,
-       Uint8 Type, Uint32 Flags,
-       size_t Length, const void *Data
-       );
-
-#endif
diff --git a/Modules/IPStack/icmp.c b/Modules/IPStack/icmp.c
deleted file mode 100644 (file)
index 1603719..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Acess2 IP Stack
- * - ICMP Handling
- */
-#include "ipstack.h"
-#include "ipv4.h"
-#include "icmp.h"
-
-// === CONSTANTS ===
-#define PING_SLOTS     64
-
-// === PROTOTYPES ===
-void   ICMP_Initialise();
-void   ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
-
-// === GLOBALS ===
-struct {
-       tInterface      *Interface;
-        int    bArrived;
-}      gICMP_PingSlots[PING_SLOTS];
-
-// === CODE ===
-/**
- * \fn void ICMP_Initialise()
- * \brief Initialise the ICMP Layer
- */
-void ICMP_Initialise()
-{
-       IPv4_RegisterCallback(IP4PROT_ICMP, ICMP_GetPacket);
-}
-
-/**
- * \fn void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
- * \brief Handles a packet from the IP Layer
- */
-void ICMP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
-{
-       tICMPHeader     *hdr = Buffer;
-       
-       //Log_Debug("ICMPv4", "Length = %i", Length);
-       Log_Debug("ICMPv4", "hdr->Type, hdr->Code = %i, %i", hdr->Type, hdr->Code);
-       //Log_Debug("ICMPv4", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
-       Log_Debug("ICMPv4", "hdr->ID = 0x%x", ntohs(hdr->ID));
-       Log_Debug("ICMPv4", "hdr->Sequence = 0x%x", ntohs(hdr->Sequence));
-       
-       switch(hdr->Type)
-       {
-       // -- 0: Echo Reply
-       case ICMP_ECHOREPLY:
-               if(hdr->Code != 0) {
-                       Log_Warning("ICMPv4", "Code == %i for ICMP Echo Reply, should be 0", hdr->Code);
-                       return ;
-               }
-               if(hdr->ID != (Uint16)~hdr->Sequence) {
-                       Log_Warning("ICMPv4", "ID and Sequence values do not match");
-                       //return ;
-               }
-               gICMP_PingSlots[hdr->ID].bArrived = 1;
-               break;
-       
-       // -- 3: Destination Unreachable
-       case ICMP_UNREACHABLE:
-               switch(hdr->Code)
-               {
-               case 3: // Port Unreachable
-                       Log_Debug("ICMPv4", "Destination Unreachable (Port Unreachable)");
-                       break;
-               default:
-                       Log_Debug("ICMPv4", "Destination Unreachable (Code %i)", hdr->Code);
-                       break;
-               }
-//             IPv4_Unreachable( Interface, hdr->Code, htons(hdr->Length)-sizeof(tICMPHeader), hdr->Data );
-               break;
-       
-       // -- 8: Echo Request
-       case ICMP_ECHOREQ:
-               if(hdr->Code != 0) {
-                       Log_Warning("ICMPv4", "Code == %i for ICMP Echo Request, should be 0", hdr->Code);
-                       return ;
-               }
-               //Log_Debug("ICMPv4", "Replying");
-               hdr->Type = ICMP_ECHOREPLY;
-               hdr->Checksum = 0;
-               hdr->Checksum = htons( IPv4_Checksum( (Uint16*)hdr, Length/2 ) );
-               //Log_Debug("ICMPv4", "Checksum = 0x%04x", hdr->Checksum);
-               IPv4_SendPacket(Interface, *(tIPv4*)Address, 1, ntohs(hdr->Sequence), Length, hdr);
-               break;
-       default:
-               break;
-       }
-       
-}
-
-/**
- * \brief Sends ICMP Echo and waits for the reply
- * \note Times out after \a Interface->TimeoutDelay has elapsed
- */
-int ICMP_Ping(tInterface *Interface, tIPv4 Addr)
-{
-       Sint64  ts;
-       Sint64  end;
-       char    buf[32] = "\x8\0\0\0\0\0\0\0Acess2 I"
-                      "P/TCP Stack 1.0\0";
-       tICMPHeader     *hdr = (void*)buf;
-        int    i;
-       
-       for(;;)
-       {
-               for(i=0;i<PING_SLOTS;i++)
-               {
-                       if(gICMP_PingSlots[i].Interface == NULL)        break;
-               }
-               if( i < PING_SLOTS )    break;
-               Threads_Yield();
-       }
-       gICMP_PingSlots[i].Interface = Interface;
-       gICMP_PingSlots[i].bArrived = 0;
-       hdr->ID = i;
-       hdr->Sequence = ~i;
-       hdr->Checksum = htons( IPv4_Checksum((Uint16*)hdr, sizeof(buf)/2) );
-       
-       ts = now();
-       
-       IPv4_SendPacket(Interface, Addr, 1, i, sizeof(buf), buf);
-       
-       end = ts + Interface->TimeoutDelay;
-       while( !gICMP_PingSlots[i].bArrived && now() < end)     Threads_Yield();
-       
-       if(now() > end)
-               return -1;
-       
-       return (int)( now() - ts );
-}
diff --git a/Modules/IPStack/icmp.h b/Modules/IPStack/icmp.h
deleted file mode 100644 (file)
index 8e78722..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Acess2 IP Stack
- * - ICMP Handling
- */
-#ifndef _ICMP_H_
-#define _ICMP_H_
-
-// === TYPEDEFS ===
-typedef struct sICMPHeader     tICMPHeader;
-
-// === STRUCTURES ===
-struct sICMPHeader
-{
-       Uint8   Type;
-       Uint8   Code;
-       Uint16  Checksum;
-       Uint16  ID;
-       Uint16  Sequence;
-       Uint8   Data[];
-};
-
-// === CONSTANTS ===
-enum eICMPTypes
-{
-       ICMP_ECHOREPLY = 0,
-       ICMP_UNREACHABLE = 3,
-       ICMP_QUENCH = 4,
-       ICMP_REDIRECT = 5,
-       ICMP_ALTADDR = 6,
-       ICMP_ECHOREQ = 8,
-       ICMP_TRACE = 30 // Information Request
-};
-
-#endif
diff --git a/Modules/IPStack/interface.c b/Modules/IPStack/interface.c
deleted file mode 100644 (file)
index b0b63b9..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Interface Control
- */
-#define DEBUG  0
-#define VERSION        VER2(0,10)
-#include "ipstack.h"
-#include "link.h"
-#include <api_drv_common.h>
-#include <api_drv_network.h>
-
-// === CONSTANTS ===
-//! Default timeout value, 30 seconds
-#define DEFAULT_TIMEOUT        (30*1000)
-
-// === IMPORTS ===
-extern int     IPv4_Ping(tInterface *Iface, tIPv4 Addr);
-//extern int   IPv6_Ping(tInterface *Iface, tIPv6 Addr);
-extern tVFS_Node       gIP_RouteNode;
-
-// === PROTOTYPES ===
-char   *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
- int   IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
-
- int   IPStack_AddFile(tSocketFile *File);
-tInterface     *IPStack_AddInterface(const char *Device, const char *Name);
-tAdapter       *IPStack_GetAdapter(const char *Path);
-
-char   *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
- int   IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
-
-// === GLOBALS ===
-tVFS_NodeType  gIP_InterfaceNodeType = {
-               .ReadDir = IPStack_Iface_ReadDir,
-               .FindDir = IPStack_Iface_FindDir,
-               .IOCtl = IPStack_Iface_IOCtl
-};
-//! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
-tInterface     gIP_LoopInterface = {
-       .Node = {
-               .ImplPtr = &gIP_LoopInterface,
-               .Flags = VFS_FFLAG_DIRECTORY,
-               .Size = -1,
-               .NumACLs = 1,
-               .ACLs = &gVFS_ACL_EveryoneRX,
-               .Type = &gIP_InterfaceNodeType
-       },
-       .Adapter = NULL,
-       .Type = 0
-};
-tShortSpinlock glIP_Interfaces;
-tInterface     *gIP_Interfaces = NULL;
-tInterface     *gIP_Interfaces_Last = NULL;
-
-tSocketFile    *gIP_FileTemplates;
-
-tAdapter       gIP_LoopAdapter = {
-       .DeviceLen = 8,
-       .Device = "LOOPBACK"
-       };
-tMutex glIP_Adapters;
-tAdapter       *gIP_Adapters = NULL;
- int   giIP_NextIfaceId = 1;
-
-// === CODE ===
-
-/**
- * \brief Read from the IP Stack's Device Directory
- */
-char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tInterface      *iface;
-       char    *name;
-       ENTER("pNode iPos", Node, Pos);
-       
-
-       // Routing Subdir
-       if( Pos == 0 ) {
-               LEAVE('s', "routes");
-               return strdup("routes");
-       }
-       // Pseudo Interfaces
-       if( Pos == 1 ) {
-               LEAVE('s', "lo");
-               return strdup("lo");
-       }
-       Pos -= 2;
-       
-       // Traverse the list
-       for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ;
-       
-       // Did we run off the end?
-       if(!iface) {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       name = malloc(4);
-       if(!name) {
-               Log_Warning("IPStack", "IPStack_Root_ReadDir - malloc error");
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Create the name
-       Pos = iface->Node.ImplInt;
-       if(Pos < 10) {
-               name[0] = '0' + Pos;
-               name[1] = '\0';
-       }
-       else if(Pos < 100) {
-               name[0] = '0' + Pos/10;
-               name[1] = '0' + Pos%10;
-               name[2] = '\0';
-       }
-       else {
-               name[0] = '0' + Pos/100;
-               name[1] = '0' + (Pos/10)%10;
-               name[2] = '0' + Pos%10;
-               name[3] = '\0';
-       }
-       
-       LEAVE('s', name);
-       // Return the pre-generated name
-       return name;
-}
-
-/**
- * \brief Get the node of an interface
- */
-tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name)
-{
-       #if 0
-        int    i, num;
-       #endif
-       tInterface      *iface;
-       
-       ENTER("pNode sName", Node, Name);
-       
-       // Routing subdir
-       if( strcmp(Name, "routes") == 0 ) {
-               LEAVE('p', &gIP_RouteNode);
-               return &gIP_RouteNode;
-       }
-       
-       // Loopback
-       if( strcmp(Name, "lo") == 0 ) {
-               LEAVE('p', &gIP_LoopInterface.Node);
-               return &gIP_LoopInterface.Node;
-       }
-       
-       for( iface = gIP_Interfaces; iface; iface = iface->Next )
-       {
-               if( strcmp(iface->Name, Name) == 0 )
-               {
-                       LEAVE('p', &iface->Node);
-                       return &iface->Node;
-               }
-       }
-       
-       LEAVE('p', NULL);
-       return NULL;
-}
-
-static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
-/**
- * \brief Handles IOCtls for the IPStack root
- */
-int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-        int    tmp;
-       ENTER("pNode iID pData", Node, ID, Data);
-       
-       switch(ID)
-       {
-       // --- Standard IOCtls (0-3) ---
-       BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Root)
-               
-       /*
-        * add_interface
-        * - Adds a new IP interface and binds it to a device
-        */
-       case 4:
-               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-               if( !CheckString( Data ) )      LEAVE_RET('i', -1);
-               LOG("New interface for '%s'", Data);
-               {
-                       char    name[4] = "";
-                       tInterface      *iface = IPStack_AddInterface(Data, name);
-                       if(iface == NULL)       LEAVE_RET('i', -1);
-                       tmp = iface->Node.ImplInt;
-               }
-               LEAVE_RET('i', tmp);
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \fn tInterface *IPStack_AddInterface(char *Device)
- * \brief Adds an interface to the list
- */
-tInterface *IPStack_AddInterface(const char *Device, const char *Name)
-{
-       tInterface      *iface;
-       tAdapter        *card;
-        int    nameLen;
-       
-       ENTER("sDevice", Device);
-       
-       card = IPStack_GetAdapter(Device);
-       if( !card ) {
-               Log_Debug("IPStack", "Unable to open card '%s'", Device);
-               LEAVE('n');
-               return NULL;    // ERR_YOURBAD
-       }
-       
-       nameLen = sprintf(NULL, "%i", giIP_NextIfaceId);
-       
-       iface = malloc(
-               sizeof(tInterface)
-               + nameLen + 1
-               + IPStack_GetAddressSize(-1)*3  // Address, Route->Network, Route->NextHop
-               );
-       if(!iface) {
-               Log_Warning("IPStack", "AddInterface - malloc() failed");
-               LEAVE('n');
-               return NULL;    // Return ERR_MYBAD
-       }
-       
-       iface->Next = NULL;
-       iface->Type = 0;        // Unset type
-       iface->Address = iface->Name + nameLen + 1;     // Address
-       iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
-       iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
-       
-       // Create Node
-       iface->Node.ImplPtr = iface;
-       iface->Node.Flags = VFS_FFLAG_DIRECTORY;
-       iface->Node.Size = -1;
-       iface->Node.NumACLs = 1;
-       iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
-       iface->Node.Type = &gIP_InterfaceNodeType;
-       
-       // Set Defaults
-       iface->TimeoutDelay = DEFAULT_TIMEOUT;
-       
-       // Get adapter handle
-       iface->Adapter = card;
-       
-       // Delay setting ImplInt until after the adapter is opened
-       // Keeps things simple
-       iface->Node.ImplInt = giIP_NextIfaceId++;
-       sprintf(iface->Name, "%i", (int)iface->Node.ImplInt);
-       
-       // Append to list
-       SHORTLOCK( &glIP_Interfaces );
-       if( gIP_Interfaces ) {
-               gIP_Interfaces_Last->Next = iface;
-               gIP_Interfaces_Last = iface;
-       }
-       else {
-               gIP_Interfaces = iface;
-               gIP_Interfaces_Last = iface;
-       }
-       SHORTREL( &glIP_Interfaces );
-
-//     gIP_DriverInfo.RootNode.Size ++;
-       
-       // Success!
-       LEAVE('p', iface);
-       return iface;
-}
-
-/**
- * \brief Adds a file to the socket list
- */
-int IPStack_AddFile(tSocketFile *File)
-{
-       Log_Log("IPStack", "Added file '%s'", File->Name);
-       File->Next = gIP_FileTemplates;
-       gIP_FileTemplates = File;
-       return 0;
-}
-
-// ---
-// VFS Functions
-// ---
-/**
- * \brief Read from an interface's directory
- */
-char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tSocketFile     *file = gIP_FileTemplates;
-       while(Pos-- && file) {
-               file = file->Next;
-       }
-       
-       if(!file)       return NULL;
-       
-       return strdup(file->Name);
-}
-
-/**
- * \brief Gets a named node from an interface directory
- */
-tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name)
-{
-       tSocketFile     *file = gIP_FileTemplates;
-       
-       // Get file definition
-       for(;file;file = file->Next)
-       {
-               if( strcmp(file->Name, Name) == 0 )     break;
-       }
-       if(!file)       return NULL;
-       
-       // Pass the buck!
-       return file->Init(Node->ImplPtr);
-}
-
-/**
- * \brief Names for interface IOCtl Calls
- */
-static const char *casIOCtls_Iface[] = {
-       DRV_IOCTLNAMES,
-       "getset_type",
-       "get_address", "set_address",
-       "getset_subnet",
-       "get_device",
-       "ping",
-       NULL
-       };
-/**
- * \brief Handles IOCtls for the IPStack interfaces
- */
-int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-        int    tmp, size;
-       tInterface      *iface = (tInterface*)Node->ImplPtr;
-       ENTER("pNode iID pData", Node, ID, Data);
-       
-       switch(ID)
-       {
-       // --- Standard IOCtls (0-3) ---
-       BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
-       
-       /*
-        * getset_type
-        * - Get/Set the interface type
-        */
-       case 4:
-               // Set Type?
-               if( Data )
-               {
-                       // Ok, it's set type
-                       if( Threads_GetUID() != 0 ) {
-                               LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-                       if( !CheckMem( Data, sizeof(int) ) ) {
-                               LOG("Invalid pointer %p", Data);
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-                       
-                       // Set type
-                       iface->Type = *(int*)Data;
-                       LOG("Interface type set to %i", iface->Type);
-                       size = IPStack_GetAddressSize(iface->Type);
-                       // Check it's actually valid
-                       if( iface->Type != 0 && size == 0 ) {
-                               iface->Type = 0;
-                               LEAVE('i', -1);
-                               return -1;
-                       }
-                       
-                       // Clear address
-                       memset(iface->Address, 0, size);
-               }
-               LEAVE('i', iface->Type);
-               return iface->Type;
-       
-       /*
-        * get_address
-        * - Get the interface's address
-        */
-       case 5:
-               size = IPStack_GetAddressSize(iface->Type);
-               if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
-               memcpy( Data, iface->Address, size );
-               LEAVE('i', 1);
-               return 1;
-       
-       /*
-        * set_address
-        * - Set the interface's address
-        */
-       case 6:
-               if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-               
-               size = IPStack_GetAddressSize(iface->Type);
-               if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
-               // TODO: Protect against trashing
-               LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
-               memcpy( iface->Address, Data, size );
-               LEAVE_RET('i', 1);
-       
-       /*
-        * getset_subnet
-        * - Get/Set the bits in the address subnet
-        */
-       case 7:
-               // Do we want to set the value?
-               if( Data )
-               {
-                       // Are we root? (TODO: Check Owner/Group)
-                       if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
-                       // Is the memory valid
-                       if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
-                       
-                       // Is the mask sane?
-                       if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
-                               LEAVE_RET('i', -1);
-                       LOG("Set subnet bits to %i", *(int*)Data);
-                       // Ok, set it
-                       iface->SubnetBits = *(int*)Data;
-               }
-               LEAVE_RET('i', iface->SubnetBits);
-       
-       /*
-        * get_device
-        * - Gets the name of the attached device
-        */
-       case 8:
-               if( iface->Adapter == NULL )
-                       LEAVE_RET('i', 0);
-               if( Data == NULL )
-                       LEAVE_RET('i', iface->Adapter->DeviceLen);
-               if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
-                       LEAVE_RET('i', -1);
-               strcpy( Data, iface->Adapter->Device );
-               LEAVE_RET('i', iface->Adapter->DeviceLen);
-       
-       /*
-        * ping
-        * - Send an ICMP Echo
-        */
-       case 9:
-               switch(iface->Type)
-               {
-               case 0:
-                       LEAVE_RET('i', 1);
-               
-               case 4:
-                       if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
-                       tmp = IPv4_Ping(iface, *(tIPv4*)Data);
-                       LEAVE_RET('i', tmp);
-                       
-               case 6:
-                       LEAVE_RET('i', 1);
-               }
-               break;
-       
-       }
-       
-       LEAVE('i', 0);
-       return 0;
-}
-
-// --- Internal ---
-/**
- * \fn tAdapter *IPStack_GetAdapter(const char *Path)
- * \brief Gets/opens an adapter given the path
- */
-tAdapter *IPStack_GetAdapter(const char *Path)
-{
-       tAdapter        *dev;
-        int    tmp;
-       
-       ENTER("sPath", Path);
-       
-       // Check for loopback
-       if( strcmp(Path, "LOOPBACK") == 0 )
-       {
-               // Initialise if required
-               if( gIP_LoopAdapter.DeviceFD == 0 )
-               {
-                       dev = &gIP_LoopAdapter;
-                       
-                       dev->NRef = 1;
-                       dev->DeviceLen = 8;
-                       
-                       dev->DeviceFD = VFS_Open( "/Devices/fifo/anon", VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
-                       if( dev->DeviceFD == -1 ) {
-                               Log_Warning("IPStack", "Unable to open FIFO '/Devices/fifo/anon' for loopback");
-                               return NULL;
-                       }
-                       
-                       dev->MacAddr.B[0] = 'A';
-                       dev->MacAddr.B[1] = 'c';
-                       dev->MacAddr.B[2] = 'e';
-                       dev->MacAddr.B[3] = 's';
-                       dev->MacAddr.B[4] = 's';
-                       dev->MacAddr.B[5] = '2';
-                       
-                       // Start watcher
-                       Link_WatchDevice( dev );
-               }
-               LEAVE('p', &gIP_LoopAdapter);
-               return &gIP_LoopAdapter;
-       }
-       
-       Mutex_Acquire( &glIP_Adapters );
-       
-       // Check if this adapter is already open
-       for( dev = gIP_Adapters; dev; dev = dev->Next )
-       {
-               if( strcmp(dev->Device, Path) == 0 ) {
-                       dev->NRef ++;
-                       Mutex_Release( &glIP_Adapters );
-                       LEAVE('p', dev);
-                       return dev;
-               }
-       }
-       
-       // Ok, so let's open it
-       dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
-       if(!dev) {
-               Log_Warning("IPStack", "GetAdapter - malloc() failed");
-               Mutex_Release( &glIP_Adapters );
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Fill Structure
-       strcpy( dev->Device, Path );
-       dev->NRef = 1;
-       dev->DeviceLen = strlen(Path);
-       
-       // Open Device
-       dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
-       if( dev->DeviceFD == -1 ) {
-               free( dev );
-               Mutex_Release( &glIP_Adapters );
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Check that it is a network interface
-       tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
-       LOG("Device type = %i", tmp);
-       if( tmp != DRV_TYPE_NETWORK ) {
-               Log_Warning("IPStack", "IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
-               VFS_Close( dev->DeviceFD );
-               free( dev );
-               Mutex_Release( &glIP_Adapters );
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Get MAC Address
-       VFS_IOCtl(dev->DeviceFD, NET_IOCTL_GETMAC, &dev->MacAddr);
-       
-       // Add to list
-       dev->Next = gIP_Adapters;
-       gIP_Adapters = dev;
-       
-       Mutex_Release( &glIP_Adapters );
-       
-       // Start watcher
-       Link_WatchDevice( dev );
-       
-       LEAVE('p', dev);
-       return dev;
-}
diff --git a/Modules/IPStack/ipstack.h b/Modules/IPStack/ipstack.h
deleted file mode 100644 (file)
index e51fded..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Common Header
- */
-#ifndef _IPSTACK_H_
-#define _IPSTACK_H_
-
-#include <acess.h>
-#include <vfs.h>
-
-typedef union uIPv4    tIPv4;
-typedef union uIPv6    tIPv6;
-typedef struct sMacAddr        tMacAddr;
-typedef struct sAdapter        tAdapter;
-typedef struct sInterface      tInterface;
-typedef struct sSocketFile     tSocketFile;
-
-typedef void   (*tIPCallback)(tInterface *Interface, void *Address, int Length, void *Buffer);
-
-enum eInterfaceTypes {
-       AF_NULL,
-       AF_INET4 = 4,   // tIPv4
-       AF_INET6 = 6    // tIPv6
-};
-
-union uIPv4 {
-       Uint32  L;
-       Uint8   B[4];
-} __attribute__((packed));
-
-union uIPv6 {
-       Uint16  W[8];
-       Uint32  L[4];
-       Uint8   B[16];
-} __attribute__((packed));
-
-struct sMacAddr {
-       Uint8   B[6];
-} __attribute__((packed));
-
-/**
- * \brief Route definition structure
- */
-typedef struct sRoute {
-       struct sRoute   *Next;
-       
-       tVFS_Node       Node;   //!< Node for route manipulation
-       
-       tInterface      *Interface;     //!< Interface for this route
-        int    AddressType;    //!< 0: Invalid, 4: IPv4, 6: IPv4
-       void    *Network;       //!< Network - Pointer to tIPv4/tIPv6/... at end of structure
-        int    SubnetBits;     //!< Number of bits in \a Network that are valid
-       void    *NextHop;       //!< Next Hop address - Pointer to tIPv4/tIPv6/... at end of structure
-        int    Metric; //!< Route priority
-}      tRoute;
-
-struct sInterface {
-       struct sInterface       *Next;  //!< Next interface in list
-       
-       tVFS_Node       Node;   //!< Node to use the interface
-       
-       tAdapter        *Adapter;       //!< Adapter the interface is associated with
-        int    TimeoutDelay;   //!< Time in miliseconds before a packet times out
-        int    Type;   //!< Interface type, see ::eInterfaceTypes
-       
-       void    *Address;       //!< IP address (stored after the Name)
-        int    SubnetBits;     //!< Number of bits that denote the address network
-       
-       tRoute  Route;  //!< Interface route
-       
-       char    Name[];
-};
-
-/**
- * \brief Represents a network adapter
- */
-struct sAdapter {
-       struct sAdapter *Next;
-       
-        int    DeviceFD;       //!< File descriptor of the device
-        int    NRef;   //!< Number of times it's been referenced
-       
-       tMacAddr        MacAddr;        //!< Physical address of the adapter
-        int    DeviceLen;      //!< Device name length
-       char    Device[];       //!< Device name
-};
-
-/**
- * \brief Describes a socket file definition
- */
-struct sSocketFile
-{
-       struct sSocketFile      *Next;
-       const char      *Name;
-       
-       tVFS_Node       *(*Init)(tInterface *Interface);
-};
-
-static const tMacAddr cMAC_BROADCAST = {{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
-static const tMacAddr cMAC_ZERO = {{0x00,0x00,0x00,0x00,0x00,0x00}};
-
-#define MAC_SET(t,v)   memcpy(&(t),&(v),sizeof(tMacAddr))
-#define IP4_SET(t,v)   (t).L = (v).L;
-#define IP6_SET(t,v)   memcpy(&(t),&(v),sizeof(tIPv6))
-
-#define MAC_EQU(a,b)   (memcmp(&(a),&(b),sizeof(tMacAddr))==0)
-#define IP4_EQU(a,b)   ((a).L==(b).L)
-#define IP6_EQU(a,b)   (memcmp(&(a),&(b),sizeof(tIPv6))==0)
-
-// === FUNCTIONS ===
-#define htonb(v)       (v)
-#define htons(v)       BigEndian16(v)
-#define htonl(v)       BigEndian32(v)
-#define ntonb(v)       (v)
-#define ntohs(v)       BigEndian16(v)
-#define ntohl(v)       BigEndian32(v)
-
-extern int     IPStack_AddFile(tSocketFile *File);
-extern int     IPStack_GetAddressSize(int AddressType);
-extern int     IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits);
-extern const char      *IPStack_PrintAddress(int AddressType, const void *Address);
-
-extern tRoute  *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
-
-#endif
diff --git a/Modules/IPStack/ipv4.c b/Modules/IPStack/ipv4.c
deleted file mode 100644 (file)
index 86301e9..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Acess2 IP Stack
- * - IPv4 Protcol Handling
- */
-#define DEBUG  1
-#include "ipstack.h"
-#include "link.h"
-#include "ipv4.h"
-#include "firewall.h"
-
-#define DEFAULT_TTL    32
-
-// === IMPORTS ===
-extern tInterface      *gIP_Interfaces;
-extern void    ICMP_Initialise();
-extern  int    ICMP_Ping(tInterface *Interface, tIPv4 Addr);
-extern tMacAddr        ARP_Resolve4(tInterface *Interface, tIPv4 Address);
-
-// === PROTOTYPES ===
- int   IPv4_Initialise();
- int   IPv4_RegisterCallback(int ID, tIPCallback Callback);
-void   IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
-tInterface     *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
-Uint32 IPv4_Netmask(int FixedBits);
-Uint16 IPv4_Checksum(const void *Buf, size_t Length);
- int   IPv4_Ping(tInterface *Iface, tIPv4 Addr);
-
-// === GLOBALS ===
-tIPCallback    gaIPv4_Callbacks[256];
-
-// === CODE ===
-/**
- * \brief Initialise the IPv4 Code
- */
-int IPv4_Initialise()
-{
-       ICMP_Initialise();
-       Link_RegisterType(IPV4_ETHERNET_ID, IPv4_int_GetPacket);
-       return 1;
-}
-
-/**
- * \brief Registers a callback
- * \param ID   8-bit packet type ID
- * \param Callback     Callback function
- */
-int IPv4_RegisterCallback(int ID, tIPCallback Callback)
-{
-       if( ID < 0 || ID > 255 )        return 0;
-       if( gaIPv4_Callbacks[ID] )      return 0;
-       gaIPv4_Callbacks[ID] = Callback;
-       return 1;
-}
-
-/**
- * \brief Creates and sends an IPv4 Packet
- * \param Iface        Interface
- * \param Address      Destination IP
- * \param Protocol     Protocol ID
- * \param ID   Some random ID number
- * \param Length       Data Length
- * \param Data Packet Data
- * \return Boolean Success
- */
-int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data)
-{
-       tMacAddr        to;
-        int    bufSize = sizeof(tIPv4Header) + Length;
-       char    buf[bufSize];
-       tIPv4Header     *hdr = (void*)buf;
-        int    ret;
-       
-       to = ARP_Resolve4(Iface, Address);
-       if( MAC_EQU(to, cMAC_ZERO) ) {
-               // No route to host
-               Log_Notice("IPv4", "No route to host %i.%i.%i.%i",
-                       Address.B[0], Address.B[1], Address.B[2], Address.B[3]);
-               return 0;
-       }
-       
-       // OUTPUT Firewall rule go here
-       ret = IPTables_TestChain("OUTPUT",
-               4, (tIPv4*)Iface->Address, &Address,
-               Protocol, 0,
-               Length, Data);
-       if(ret > 0) {
-               // Just drop it (with an error)
-               Log_Notice("IPv4", "Firewall dropped packet");
-               return 0;
-       }
-       
-       memcpy(&hdr->Options[0], Data, Length);
-       hdr->Version = 4;
-       hdr->HeaderLength = sizeof(tIPv4Header)/4;
-       hdr->DiffServices = 0;  // TODO: Check
-       
-       hdr->Reserved = 0;
-       hdr->DontFragment = 0;
-       hdr->MoreFragments = 0;
-       hdr->FragOffLow = 0;
-       hdr->FragOffHi = 0;
-       
-       hdr->TotalLength = htons( bufSize );
-       hdr->Identifcation = htons( ID );       // TODO: Check
-       hdr->TTL = DEFAULT_TTL;
-       hdr->Protocol = Protocol;
-       hdr->HeaderChecksum = 0;        // Will be set later
-       hdr->Source = *(tIPv4*)Iface->Address;
-       hdr->Destination = Address;
-       hdr->HeaderChecksum = htons( IPv4_Checksum(hdr, sizeof(tIPv4Header)) );
-       
-       Log_Log("IPv4", "Sending packet to %i.%i.%i.%i",
-               Address.B[0], Address.B[1], Address.B[2], Address.B[3]);
-       Link_SendPacket(Iface->Adapter, IPV4_ETHERNET_ID, to, bufSize, buf);
-       return 1;
-}
-
-/**
- * \fn void IPv4_int_GetPacket(tInterface *Adapter, tMacAddr From, int Length, void *Buffer)
- * \brief Process an IPv4 Packet
- */
-void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
-{
-       tIPv4Header     *hdr = Buffer;
-       tInterface      *iface;
-       Uint8   *data;
-        int    dataLength;
-        int    ret;
-       
-       if(Length < sizeof(tIPv4Header))        return;
-       
-       #if 0
-       //Log_Log("IPv4", "Version = %i", hdr->Version);
-       //Log_Log("IPv4", "HeaderLength = %i", hdr->HeaderLength);
-       //Log_Log("IPv4", "DiffServices = %i", hdr->DiffServices);
-       Log_Debug("IPv4", "TotalLength = %i", ntohs(hdr->TotalLength) );
-       //Log_Log("IPv4", "Identifcation = %i", ntohs(hdr->Identifcation) );
-       //Log_Log("IPv4", "TTL = %i", hdr->TTL );
-       Log_Debug("IPv4", "Protocol = %i", hdr->Protocol );
-       //Log_Log("IPv4", "HeaderChecksum = 0x%x", ntohs(hdr->HeaderChecksum) );
-       Log_Debug("IPv4", "Source = %i.%i.%i.%i",
-               hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3] );
-       Log_Debug("IPv4", "Destination = %i.%i.%i.%i",
-               hdr->Destination.B[0], hdr->Destination.B[1],
-               hdr->Destination.B[2], hdr->Destination.B[3] );
-       #endif  
-
-       // Check that the version IS IPv4
-       if(hdr->Version != 4) {
-               Log_Log("IPv4", "hdr->Version(%i) != 4", hdr->Version);
-               return;
-       }
-       
-       // Check Header checksum
-       {
-               Uint16  hdrVal, compVal;
-               hdrVal = ntohs(hdr->HeaderChecksum);
-               hdr->HeaderChecksum = 0;
-               compVal = IPv4_Checksum(hdr, hdr->HeaderLength * 4);
-               if(hdrVal != compVal) {
-                       Log_Log("IPv4", "Header checksum fails (%04x != %04x)", hdrVal, compVal);
-                       return ;
-               }
-               hdr->HeaderChecksum = hdrVal;
-       }
-       
-       // Check Packet length
-       if( ntohs(hdr->TotalLength) > Length) {
-               Log_Log("IPv4", "hdr->TotalLength(%i) > Length(%i)", ntohs(hdr->TotalLength), Length);
-               return;
-       }
-       
-       // TODO: Handle packet fragmentation
-       
-       
-       Log_Debug("IPv4", " From %i.%i.%i.%i to %i.%i.%i.%i",
-               hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3],
-               hdr->Destination.B[0], hdr->Destination.B[1], hdr->Destination.B[2], hdr->Destination.B[3]
-               );
-       
-       // Get Data and Data Length
-       dataLength = ntohs(hdr->TotalLength) - sizeof(tIPv4Header);
-       data = &hdr->Options[0];
-       
-       // Get Interface (allowing broadcasts)
-       iface = IPv4_GetInterface(Adapter, hdr->Destination, 1);
-       
-       // Firewall rules
-       if( iface ) {
-               // Incoming Packets
-               ret = IPTables_TestChain("INPUT",
-                       4, &hdr->Source, &hdr->Destination,
-                       hdr->Protocol, 0,
-                       dataLength, data
-                       );
-       }
-       else {
-               // Routed packets
-               ret = IPTables_TestChain("FORWARD",
-                       4, &hdr->Source, &hdr->Destination,
-                       hdr->Protocol, 0,
-                       dataLength, data
-                       );
-       }
-       switch(ret)
-       {
-       // 0 - Allow
-       case 0: break;
-       // 1 - Silent Drop
-       case 1:
-               Log_Debug("IPv4", "Silently dropping packet");
-               return ;
-       case -1:
-               // Bad rule
-               break ;
-       // Unknown, silent drop
-       default:
-               Log_Warning("IPv4", "Unknown firewall rule");
-               return ;
-       }
-       
-       // Routing
-       if(!iface)
-       {
-               tMacAddr        to;
-               tRoute  *rt;
-               
-               Log_Debug("IPv4", "Route the packet");
-               // Drop the packet if the TTL is zero
-               if( hdr->TTL == 0 ) {
-                       Log_Warning("IPv4", "TODO: Send ICMP-Timeout when TTL exceeded");
-                       return ;
-               }
-               
-               hdr->TTL --;
-               
-               rt = IPStack_FindRoute(4, NULL, &hdr->Destination);     // Get the route (gets the interface)
-               if( !rt || !rt->Interface )
-                       return ;
-               to = ARP_Resolve4(rt->Interface, hdr->Destination);     // Resolve address
-               if( MAC_EQU(to, cMAC_ZERO) )
-                       return ;
-               
-               // Send packet
-               Log_Log("IPv4", "Forwarding packet to %i.%i.%i.%i (via %i.%i.%i.%i)",
-                       hdr->Destination.B[0], hdr->Destination.B[1],
-                       hdr->Destination.B[2], hdr->Destination.B[3],
-                       ((tIPv4*)rt->NextHop)->B[0], ((tIPv4*)rt->NextHop)->B[1],
-                       ((tIPv4*)rt->NextHop)->B[2], ((tIPv4*)rt->NextHop)->B[3]);
-               Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer);
-               
-               
-               return ;
-       }
-       
-       // Send it on
-       if( !gaIPv4_Callbacks[hdr->Protocol] ) {
-               Log_Log("IPv4", "Unknown Protocol %i", hdr->Protocol);
-               return ;
-       }
-       
-       gaIPv4_Callbacks[hdr->Protocol]( iface, &hdr->Source, dataLength, data );
-}
-
-/**
- * \fn tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address)
- * \brief Searches an adapter for a matching address
- * \param Adapter      Incoming Adapter
- * \param Address      Destination Address
- * \param Broadcast    Allow broadcast packets
- */
-tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
-{
-       tInterface      *iface = NULL;
-       Uint32  netmask;
-       Uint32  addr, this;
-
-       ENTER("pAdapter xAddress bBroadcast", Adapter, Address, Broadcast);     
-
-       addr = ntohl( Address.L );
-       LOG("addr = 0x%x", addr);
-       
-       for( iface = gIP_Interfaces; iface; iface = iface->Next)
-       {
-               if( iface->Adapter != Adapter ) continue;
-               if( iface->Type != 4 )  continue;
-               if( IP4_EQU(Address, *(tIPv4*)iface->Address) ) {
-                       LOG("Exact match");
-                       LEAVE('p', iface);
-                       return iface;
-               }
-               
-               if( !Broadcast )        continue;
-               
-               // Check for broadcast
-               this = ntohl( ((tIPv4*)iface->Address)->L );
-               netmask = IPv4_Netmask(iface->SubnetBits);
-               LOG("iface addr = 0x%x, netmask = 0x%x (bits = %i)", this, netmask, iface->SubnetBits);
-
-               if( (addr & netmask) == (this & netmask) && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
-               {
-                       LOG("Broadcast match");
-                       LEAVE('p', iface);
-                       return iface;
-               }
-       }
-       LEAVE('n');
-       return NULL;
-}
-
-/**
- * \brief Convert a network prefix to a netmask
- * \param FixedBits    Netmask size (/n)
- * 
- * For example /24 will become 255.255.255.0 (0xFFFFFF00)
- */
-Uint32 IPv4_Netmask(int FixedBits)
-{
-       Uint32  ret = 0xFFFFFFFF;
-       if( FixedBits == 0 )
-               return 0;
-       if( FixedBits < 32 )
-       {
-               ret >>= (32-FixedBits);
-               ret <<= (32-FixedBits);
-       }
-       // Returns a native endian netmask
-       return ret;
-}
-
-/**
- * \brief Calculate the IPv4 Checksum
- * \param Buf  Input buffer
- * \param Size Size of input
- * 
- * One's complement sum of all 16-bit words (bitwise inverted)
- */
-Uint16 IPv4_Checksum(const void *Buf, size_t Length)
-{
-       const Uint16    *words = Buf;
-       Uint32  sum = 0;
-        int    i;
-       
-       // Sum all whole words
-       for(i = 0; i < Length/2; i++ )
-       {
-               sum += ntohs(words[i]);
-       }
-       if( Length & 1 )
-               sum += ntohs( words[i] & 0xFF );
-       
-       // Apply one's complement
-       while (sum >> 16)
-               sum = (sum & 0xFFFF) + (sum >> 16);
-       
-       return ~sum;
-}
-
-/**
- * \brief Sends an ICMP Echo and waits for a reply
- * \param IFace        Interface
- * \param Addr Destination address
- */
-int IPv4_Ping(tInterface *IFace, tIPv4 Addr)
-{
-       return ICMP_Ping(IFace, Addr);
-}
diff --git a/Modules/IPStack/ipv4.h b/Modules/IPStack/ipv4.h
deleted file mode 100644 (file)
index 2c3e1ca..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Acess2 IP Stack
- * - IPv4 Definitions
- */
-#ifndef _IPV4_H_
-#define _IPV4_H_
-
-#include "ipstack.h"
-
-typedef struct sIPv4Header     tIPv4Header;
-
-struct sIPv4Header
-{
-       struct {
-               // Spec says Version is first, but stupid bit ordering
-               unsigned HeaderLength:  4;      // in 4-byte chunks
-               unsigned Version:       4;      // = 4
-       } __attribute__((packed));
-       Uint8   DiffServices;   // Differentiated Services
-       Uint16  TotalLength;
-       Uint16  Identifcation;
-       
-       struct {
-               unsigned Reserved:      1;
-               unsigned DontFragment:  1;
-               unsigned MoreFragments: 1;
-               unsigned FragOffLow:    5;
-       } __attribute__((packed));
-       Uint8   FragOffHi;      // Number of 8-byte blocks from the original start
-       
-       Uint8   TTL;    // Max number of hops, effectively
-       Uint8   Protocol;
-       Uint16  HeaderChecksum; // One's Complement Sum of the entire header must equal zero
-       
-       tIPv4   Source;
-       tIPv4   Destination;
-       
-       Uint8   Options[];
-} __attribute__((packed));
-
-#define IP4PROT_ICMP   1
-#define IP4PROT_TCP    6
-#define IP4PROT_UDP    17
-
-#define IPV4_ETHERNET_ID       0x0800
-
-// === FUNCTIONS ===
-extern int     IPv4_RegisterCallback(int ID, tIPCallback Callback);
-extern Uint16  IPv4_Checksum(const void *Buf, size_t Length);
-extern int     IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data);
-
-#endif
diff --git a/Modules/IPStack/ipv6.c b/Modules/IPStack/ipv6.c
deleted file mode 100644 (file)
index 7cb8e0a..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Acess2 IP Stack
- * - IPv6 Protcol Handling
- */
-#include "ipstack.h"
-#include "link.h"
-#include "ipv6.h"
-#include "firewall.h"
-
-// === IMPORTS ===
-extern tInterface      *gIP_Interfaces;
-extern Uint32  IPv4_Netmask(int FixedBits);
-
-// === PROTOTYPES ===
- int   IPv6_Initialise();
- int   IPv6_RegisterCallback(int ID, tIPCallback Callback);
-void   IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
-tInterface     *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
-
-// === GLOBALS ===
-tIPCallback    gaIPv6_Callbacks[256];
-
-// === CODE ===
-/**
- * \brief Initialise the IPv6 handling code
- */
-int IPv6_Initialise()
-{
-       Link_RegisterType(IPV6_ETHERNET_ID, IPv6_int_GetPacket);
-       return 1;
-}
-
-/**
- * \brief Registers a callback
- * \param ID   8-bit packet type ID
- * \param Callback     Callback function
- */
-int IPv6_RegisterCallback(int ID, tIPCallback Callback)
-{
-       if( ID < 0 || ID > 255 )        return 0;
-       if( gaIPv6_Callbacks[ID] )      return 0;
-       gaIPv6_Callbacks[ID] = Callback;
-       return 1;
-}
-
-/**
- * \brief Creates and sends an IPv6 Packet
- * \param Iface        Interface
- * \param Destination  Destination IP
- * \param Protocol     Protocol ID
- * \param Length       Data Length
- * \param Data Packet Data
- * \return Boolean Success
- */
-int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data)
-{
-       return 0;
-}
-
-/**
- * \fn void IPv6_int_GetPacket(tInterface *Interface, tMacAddr From, int Length, void *Buffer)
- * \brief Process an IPv6 Packet
- * \param Interface    Input interface
- * \param From Source MAC address
- * \param Length       Packet length
- * \param Buffer       Packet data
- */
-void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
-{
-       tInterface      *iface;
-       tIPv6Header     *hdr = Buffer;
-        int    ret, dataLength;
-       char    *dataPtr;
-       Uint8   nextHeader;
-       
-       if(Length < sizeof(tIPv6Header))        return;
-       
-       hdr->Head = ntohl(hdr->Head);
-       
-       //if( ((hdr->Head >> (20+8)) & 0xF) != 6 )
-       if( hdr->Version != 6 )
-               return;
-       
-       #if 1
-       Log_Debug("IPv6", "hdr = {");
-       Log_Debug("IPv6", " .Version       = %i", hdr->Version );
-       Log_Debug("IPv6", " .TrafficClass  = %i", hdr->TrafficClass );
-       Log_Debug("IPv6", " .FlowLabel     = %i", hdr->FlowLabel );
-       Log_Debug("IPv6", " .PayloadLength = 0x%04x", ntohs(hdr->PayloadLength) );
-       Log_Debug("IPv6", " .NextHeader    = 0x%02x", hdr->NextHeader );
-       Log_Debug("IPv6", " .HopLimit      = 0x%02x", hdr->HopLimit );
-       Log_Debug("IPv6", " .Source        = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Source );
-       Log_Debug("IPv6", " .Destination   = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Destination );
-       Log_Debug("IPv6", "}");
-       #endif
-       
-       // No checksum in IPv6
-       
-       // Check Packet length
-       if( ntohs(hdr->PayloadLength)+sizeof(tIPv6Header) > Length) {
-               Log_Log("IPv6", "hdr->PayloadLength(%i) > Length(%i)", ntohs(hdr->PayloadLength), Length);
-               return;
-       }
-       
-       // Process Options
-       nextHeader = hdr->NextHeader;
-       dataPtr = hdr->Data;
-       dataLength = hdr->PayloadLength;
-       for( ;; )
-       {
-               struct {
-                       Uint8   NextHeader;
-                       Uint8   Length; // In 8-byte chunks, with 0 being 8 bytes long
-                       Uint8   Data[];
-               }       *optionHdr;
-               optionHdr = (void*)dataPtr;
-               // Hop-by-hop options
-               if(nextHeader == 0)
-               {
-                       // TODO: Parse the options (actually, RFC2460 doesn't specify any)
-               }
-               // Routing Options
-               else if(nextHeader == 43)
-               {
-                       // TODO: Routing Header options
-               }
-               else
-               {
-                       break;  // Unknown, pass on
-               }
-               nextHeader = optionHdr->NextHeader;
-               dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long)
-       }
-       
-       // Get Interface (allowing broadcasts)
-       iface = IPv6_GetInterface(Adapter, hdr->Destination, 1);
-       
-       // Firewall rules
-       if( iface ) {
-               // Incoming Packets
-               ret = IPTables_TestChain("INPUT",
-                       6, &hdr->Source, &hdr->Destination,
-                       hdr->NextHeader, 0,
-                       hdr->PayloadLength, hdr->Data
-                       );
-       }
-       else {
-               // Routed packets
-               ret = IPTables_TestChain("FORWARD",
-                       6, &hdr->Source, &hdr->Destination,
-                       hdr->NextHeader, 0,
-                       hdr->PayloadLength, hdr->Data
-                       );
-       }
-       
-       switch(ret)
-       {
-       // 0 - Allow
-       case 0: break;
-       // 1 - Silent Drop
-       case 1:
-               Log_Debug("IPv6", "Silently dropping packet");
-               return ;
-       // Unknown, silent drop
-       default:
-               return ;
-       }
-       
-       // Routing
-       if(!iface)
-       {
-               #if 0
-               tMacAddr        to;
-               tRoute  *rt;
-               
-               Log_Debug("IPv6", "Route the packet");
-               // Drop the packet if the TTL is zero
-               if( hdr->HopLimit == 0 ) {
-                       Log_Warning("IPv6", "TODO: Sent ICMP-Timeout when TTL exceeded");
-                       return ;
-               }
-               
-               hdr->HopLimit --;
-               
-               rt = IPStack_FindRoute(6, NULL, &hdr->Destination);     // Get the route (gets the interface)
-               to = ICMP6_ResolveHWAddr(rt->Interface, hdr->Destination);      // Resolve address
-               
-               // Send packet
-               Log_Log("IPv6", "Forwarding packet");
-               Link_SendPacket(rt->Interface->Adapter, IPV6_ETHERNET_ID, to, Length, Buffer);
-               #endif
-               
-               return ;
-       }
-       
-       // Send it on
-       if( !gaIPv6_Callbacks[hdr->NextHeader] ) {
-               Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader);
-               return ;
-       }
-       
-       gaIPv6_Callbacks[hdr->NextHeader]( iface, &hdr->Source, hdr->PayloadLength, hdr->Data );
-}
-
-/**
- * \fn tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address)
- * \brief Searches an adapter for a matching address
- * \param Adapter      Source adapter
- * \param Address      Destination Address
- * \param Broadcast    Allow broadcast?
- */
-tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
-{
-        int    i, j;
-       tInterface      *iface = NULL;
-       Uint32  netmask;
-       
-       for( iface = gIP_Interfaces; iface; iface = iface->Next)
-       {
-               tIPv6   *thisAddr;
-               
-               // Check for this adapter
-               if( iface->Adapter != Adapter ) continue;
-               
-               // Skip non-IPv6 Interfaces
-               if( iface->Type != 6 )  continue;
-               
-               thisAddr = (tIPv6*)iface->Address;
-               // If the address is a perfect match, return this interface
-               if( IP6_EQU(Address, *thisAddr) )       return iface;
-               
-               // Check if we want to match broadcast addresses
-               if( !Broadcast )        continue;
-               
-               // Check for broadcast
-               // - Check first DWORDs
-               if( iface->SubnetBits > 32 && Address.L[0] != thisAddr->L[0] )
-                       continue;
-               if( iface->SubnetBits > 64 && Address.L[1] != thisAddr->L[1] )
-                       continue;
-               if( iface->SubnetBits > 96 && Address.L[2] != thisAddr->L[2] )
-                       continue;
-               
-               // Check final DWORD
-               j = iface->SubnetBits / 32;
-               i = iface->SubnetBits % 32;
-               netmask = IPv4_Netmask( iface->SubnetBits % 32 );
-               
-               // Check the last bit of the netmask
-               if( (Address.L[j] >> i) != (thisAddr->L[j] >> i) )      continue;
-               
-               // Check that the host portion is one
-               if( (Address.L[j] & ~netmask) != (0xFFFFFFFF & ~netmask) )      continue;
-               if( j >= 2 && Address.L[3] != 0xFFFFFFFF)       continue;
-               if( j >= 1 && Address.L[2] != 0xFFFFFFFF)       continue;
-               if( j >= 0 && Address.L[1] != 0xFFFFFFFF)       continue;
-               
-               return iface;
-       }
-       return NULL;
-}
diff --git a/Modules/IPStack/ipv6.h b/Modules/IPStack/ipv6.h
deleted file mode 100644 (file)
index d2e4f28..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Acess2 IP Stack
- * - IPv6 Definitions
- */
-#ifndef _IPV6_H_
-#define _IPV6_H_
-
-#include "ipstack.h"
-
-typedef struct sIPv6Header     tIPv6Header;
-
-struct sIPv6Header
-{
-       #if 0
-       // High 4: Version
-       // Next 8: Traffic Class
-       // Low 20: Flow Label
-       Uint32  Head;
-       #else
-       union {
-               Uint32  Head;   // Allow a ntohl to happen
-               struct {
-                       unsigned Version:       4;
-                       unsigned TrafficClass:  8;
-                       unsigned FlowLabel:     20;
-               } PACKED;
-       } PACKED;
-       #endif
-       Uint16  PayloadLength;
-       Uint8   NextHeader;     // Type of payload data
-       Uint8   HopLimit;
-       tIPv6   Source;
-       tIPv6   Destination;
-       char    Data[];
-};
-
-#define IPV6_ETHERNET_ID       0x86DD
-
-extern int     IPv6_RegisterCallback(int ID, tIPCallback Callback);
-extern int     IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data);
-
-#endif
diff --git a/Modules/IPStack/link.c b/Modules/IPStack/link.c
deleted file mode 100644 (file)
index 8bca51f..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Link/Media Layer Interface
- */
-#include "ipstack.h"
-#include "link.h"
-
-// === CONSTANTS ===
-#define        MAX_PACKET_SIZE 2048
-
-// === PROTOTYPES ===
-void   Link_RegisterType(Uint16 Type, tPacketCallback Callback);
-void   Link_InitCRC();
-Uint32 Link_CalculateCRC(void *Data, int Length);
-void   Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer);
-void   Link_WatchDevice(tAdapter *Adapter);
-
-// === GLOBALS ===
- int   giRegisteredTypes = 0;
- int   giRegisteredTypeSpace = 0;
-struct {
-       Uint16  Type;
-       tPacketCallback Callback;
-}      *gaRegisteredTypes;
- int   gbLink_CRCTableGenerated = 0;
-Uint32 gaiLink_CRCTable[256];
-
-// === CODE ===
-/**
- * \fn void Link_RegisterType(Uint16 Type, tPacketCallback Callback)
- * \brief Registers a callback for a specific packet type
- * 
- * \todo Make thread safe (place a mutex on the list)
- */
-void Link_RegisterType(Uint16 Type, tPacketCallback Callback)
-{
-        int    i;
-       void    *tmp;
-       
-       for( i = giRegisteredTypes; i -- ; )
-       {
-               if(gaRegisteredTypes[i].Type == Type) {
-                       Log_Warning("Net Link", "Attempt to register 0x%x twice", Type);
-                       return ;
-               }
-               // Ooh! Free slot!
-               if(gaRegisteredTypes[i].Callback == NULL)       break;
-       }
-       
-       if(i == -1)
-       {
-               giRegisteredTypeSpace += 5;
-               tmp = realloc(gaRegisteredTypes, giRegisteredTypeSpace*sizeof(*gaRegisteredTypes));
-               if(!tmp) {
-                       Log_Warning("Net Link",
-                               "Out of heap space! (Attempted to allocate %i)",
-                               giRegisteredTypeSpace*sizeof(*gaRegisteredTypes)
-                               );
-                       return ;
-               }
-               gaRegisteredTypes = tmp;
-               i = giRegisteredTypes;
-               giRegisteredTypes ++;
-       }
-       
-       gaRegisteredTypes[i].Callback = Callback;
-       gaRegisteredTypes[i].Type = Type;
-}
-
-/**
- * \fn void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer)
- * \brief Formats and sends a packet on the specified interface
- */
-void Link_SendPacket(tAdapter *Adapter, Uint16 Type, tMacAddr To, int Length, void *Buffer)
-{
-        int    bufSize = sizeof(tEthernetHeader) + ((Length+3)&~3) + 4;
-       Uint8   buf[bufSize];   // dynamic stack arrays ftw!
-       tEthernetHeader *hdr = (void*)buf;
-       
-       Log_Log("Net Link", "Sending %i bytes to %02x:%02x:%02x:%02x:%02x:%02x (Type 0x%x)",
-               Length, To.B[0], To.B[1], To.B[2], To.B[3], To.B[4], To.B[5], Type);
-       
-       hdr->Dest = To;
-       hdr->Src = Adapter->MacAddr;
-       hdr->Type = htons(Type);
-       
-       memcpy(hdr->Data, Buffer, Length);
-       
-       *(Uint32*) &hdr->Data[bufSize-4] = 0;
-       *(Uint32*) &hdr->Data[bufSize-4] = htonl( Link_CalculateCRC(buf, bufSize) );
-       
-       VFS_Write(Adapter->DeviceFD, bufSize, buf);
-}
-
-void Link_WorkerThread(void *Ptr)
-{
-       tAdapter        *Adapter = Ptr;
-       
-       Threads_SetName(Adapter->Device);
-       Log_Log("Net Link", "Thread %i watching '%s'", Threads_GetTID(), Adapter->Device);
-
-       // Child Thread
-       while(Adapter->DeviceFD != -1)
-       {
-               Uint8   buf[MAX_PACKET_SIZE];
-               tEthernetHeader *hdr = (void*)buf;
-                int    ret, i;
-               Uint32  checksum;
-               
-               // Wait for a packet (Read on a network device is blocking)
-               //Log_Debug("NET", "Waiting on adapter FD#0x%x", Adapter->DeviceFD);
-               ret = VFS_Read(Adapter->DeviceFD, MAX_PACKET_SIZE, buf);
-               if(ret == -1)   break;
-               
-               if(ret < sizeof(tEthernetHeader)) {
-                       Log_Log("Net Link", "Recieved an undersized packet (%i < %i)",
-                               ret, sizeof(tEthernetHeader));
-                       continue;
-               }
-               
-               Log_Log("Net Link",
-                       "Packet from %02x:%02x:%02x:%02x:%02x:%02x"
-                       " to %02x:%02x:%02x:%02x:%02x:%02x (Type=%04x)",
-                       hdr->Src.B[0], hdr->Src.B[1], hdr->Src.B[2],
-                       hdr->Src.B[3], hdr->Src.B[4], hdr->Src.B[5],
-                       hdr->Dest.B[0], hdr->Dest.B[1], hdr->Dest.B[2],
-                       hdr->Dest.B[3], hdr->Dest.B[4], hdr->Dest.B[5],
-                       ntohs(hdr->Type)
-                       );
-               checksum = *(Uint32*)&hdr->Data[ret-sizeof(tEthernetHeader)-4];
-               //Log_Log("NET", "Checksum 0x%08x", checksum);
-               // TODO: Check checksum
-               
-               // Check if there is a registered callback for this packet type
-               for( i = giRegisteredTypes; i--; )
-               {
-                       if(gaRegisteredTypes[i].Type == ntohs(hdr->Type))       break;
-               }
-               // No? Ignore it
-               if( i == -1 ) {
-                       Log_Log("Net Link", "Unregistered type 0x%x", ntohs(hdr->Type));
-                       continue;
-               }
-               
-               // Call the callback
-               gaRegisteredTypes[i].Callback(
-                       Adapter,
-                       hdr->Src,
-                       ret - sizeof(tEthernetHeader),
-                       hdr->Data
-                       );
-       }
-       
-       Log_Log("Net Link", "Watcher terminated (file closed)");
-       
-       Threads_Exit(0, 0);
-}
-
-/**
- * \fn void Link_WatchDevice(tAdapter *Adapter)
- * \brief Spawns a worker thread to watch the specified adapter
- */
-void Link_WatchDevice(tAdapter *Adapter)
-{
-        int    tid;
-
-       if( !gbLink_CRCTableGenerated )
-               Link_InitCRC();
-       
-       tid = Proc_SpawnWorker(Link_WorkerThread, Adapter);     // Create a new worker thread
-       
-       if(tid < 0) {
-               Log_Warning("Net Link", "Unable to create watcher thread for '%s'", Adapter->Device);
-               return ;
-       }
-       
-       Log_Log("Net Link", "Watching '%s' using tid %i", Adapter->Device, tid);
-}
-
-// From http://www.cl.cam.ac.uk/research/srg/bluebook/21/crc/node6.html
-#define        QUOTIENT        0x04c11db7
-void Link_InitCRC(void)
-{
-     int       i, j;
-    Uint32     crc;
-
-    for (i = 0; i < 256; i++)
-    {
-        crc = i << 24;
-        for (j = 0; j < 8; j++)
-        {
-            if (crc & 0x80000000)
-                crc = (crc << 1) ^ QUOTIENT;
-            else
-                crc = crc << 1;
-        }
-        gaiLink_CRCTable[i] = crc;
-    }
-       
-       gbLink_CRCTableGenerated = 1;
-}
-
-Uint32 Link_CalculateCRC(void *Data, int Length)
-{
-       // x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
-       Uint32  result;
-     int       i;
-       Uint32  *data = Data;
-    
-    if(Length < 4)     return 0;
-
-    result = *data++ << 24;
-    result |= *data++ << 16;
-    result |= *data++ << 8;
-    result |= *data++;
-    result = ~ result;
-    Length -= 4;
-    
-    for( i = 0; i < Length; i++ )
-    {
-        result = (result << 8 | *data++) ^ gaiLink_CRCTable[result >> 24];
-    }
-    
-    return ~result;
-}
diff --git a/Modules/IPStack/link.h b/Modules/IPStack/link.h
deleted file mode 100644 (file)
index d96008d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Link/Media Layer Header
- */
-#ifndef _LINK_H_
-#define _LINK_H_
-
-// === EXTERNAL ===
-typedef void (*tPacketCallback)(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
-
-extern void    Link_RegisterType(Uint16 Type, tPacketCallback Callback);
-extern void    Link_SendPacket(tAdapter *Interface, Uint16 Type, tMacAddr To, int Length, void *Buffer);
-extern void    Link_WatchDevice(tAdapter *Adapter);
-
-// === INTERNAL ===
-typedef struct sEthernetHeader tEthernetHeader;
-typedef struct sEthernetFooter tEthernetFooter;
-struct sEthernetHeader {
-       tMacAddr        Dest;
-       tMacAddr        Src;
-       Uint16  Type;
-       Uint8   Data[];
-};
-
-struct sEthernetFooter {
-       //Uint32        CRC;
-};
-
-#endif
diff --git a/Modules/IPStack/main.c b/Modules/IPStack/main.c
deleted file mode 100644 (file)
index d5d1ebc..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Stack Initialisation
- */
-#define DEBUG  0
-#define VERSION        VER2(0,10)
-#include "ipstack.h"
-#include "link.h"
-#include <modules.h>
-#include <fs_devfs.h>
-
-// === IMPORTS ===
-extern int     ARP_Initialise();
-extern void    UDP_Initialise();
-extern void    TCP_Initialise();
-extern int     IPv4_Initialise();
-extern int     IPv6_Initialise();
-
-extern tAdapter        *IPStack_GetAdapter(const char *Path);
-extern char    *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
-extern int     IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
-extern tInterface      gIP_LoopInterface;
-extern tInterface      *IPStack_AddInterface(const char *Device, const char *Name);
-extern tRoute  *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
-
-// === PROTOTYPES ===
- int   IPStack_Install(char **Arguments);
- int   IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
-tVFS_NodeType  gIP_RootNodeType = {
-       .ReadDir = IPStack_Root_ReadDir,
-       .FindDir = IPStack_Root_FindDir,
-       .IOCtl = IPStack_Root_IOCtl
-};
-tDevFS_Driver  gIP_DriverInfo = {
-       NULL, "ip",
-       {
-       .Size = -1,     // Number of interfaces
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Type = &gIP_RootNodeType
-       }
-};
-
-// === CODE ===
-/**
- * \fn int IPStack_Install(char **Arguments)
- * \brief Intialise the relevant parts of the stack and register with DevFS
- */
-int IPStack_Install(char **Arguments)
-{
-        int    i = 0;
-       
-       // Layer 3 - Network Layer Protocols
-       ARP_Initialise();
-       IPv4_Initialise();
-       IPv6_Initialise();
-       // Layer 4 - Transport Layer Protocols
-       TCP_Initialise();
-       UDP_Initialise();
-       
-       if(Arguments)
-       {
-               // Parse module arguments
-               for( i = 0; Arguments[i]; i++ )
-               {
-                       // TODO:
-                       // Define interfaces by <Device>:<Type>:<HexStreamAddress>:<Bits>
-                       // Where:
-                       // - <Device> is the device path (E.g. /Devices/ne2k/0)
-                       // - <Type> is a number (e.g. 4) or symbol (e.g. AF_INET4)
-                       // - <HexStreamAddress> is a condensed hexadecimal stream (in big endian)
-                       //      (E.g. 0A000201 for 10.0.2.1 IPv4)
-                       // - <Bits> is the number of subnet bits (E.g. 24 for an IPv4 Class C)
-                       // Example: /Devices/ne2k/0:4:0A00020A:24
-                       //  would define an interface with the address 10.0.2.10/24
-                       if( Arguments[i][0] == '/' ) {
-                               // Define Interface
-                               char    *dev, *type, *addr, *bits;
-                               
-                               // Read definition
-                               dev = Arguments[i];
-                               type = strchr(dev, ':');
-                               if( !type ) {
-                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
-                                       continue;
-                               }
-                               *type = '\0';   type ++;
-                               
-                               addr = strchr(type, ':');
-                               if( !addr ) {
-                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
-                                       continue;
-                               }
-                               *addr = '\0';   addr ++;
-                               
-                               bits = strchr(addr, ':');
-                               if( !bits ) {
-                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
-                                       continue;
-                               }
-                               *bits = '\0';   bits ++;
-                               
-                               // Define interface
-                               {
-                                        int    iType = atoi(type);
-                                        int    size = IPStack_GetAddressSize(iType);
-                                       Uint8   addrData[size];
-                                        int    iBits = atoi(bits);
-                                       
-                                       UnHex(addrData, size, addr);
-                                       
-                                       tInterface      *iface = IPStack_AddInterface(dev, "");
-                                       if( !iface ) {
-                                               Log_Warning("IPStack", "Unable to add interface on '%s'", dev);
-                                               continue ;
-                                       }
-                                       iface->Type = iType;
-                                       memcpy(iface->Address, addrData, size);
-                                       iface->SubnetBits = iBits;
-                                       
-                                       // Route for addrData/iBits, no next hop, default metric
-                                       IPStack_AddRoute(iface->Name, iface->Address, iBits, NULL, 0);
-
-                                       Log_Notice("IPStack", "Boot interface %s/%i on %s",
-                                               IPStack_PrintAddress(iType, addrData), iBits,
-                                               dev);
-                               }
-                               
-                               continue;
-                       }
-                       
-                       // I could also define routes using <Interface>:<HexStreamNetwork>:<Bits>[:<HexStreamGateway>]
-                       // Example: 1:00000000:0:0A000201
-                       if( '0' <= Arguments[i][0] && Arguments[i][0] <= '9' )
-                       {
-                               // Define Interface
-                               char    *ifaceName, *network, *bits, *gateway;
-                               
-                               // Read definition
-                               ifaceName = Arguments[i];
-                               
-                               network = strchr(ifaceName, ':');
-                               if( !network ) {
-                                       Log_Warning("IPStack", "<iface>:<HexStreamNetwork>:<Bits>:<HexStreamGateway>");
-                                       continue;
-                               }
-                               *network = '\0';        network ++;
-                               
-                               bits = strchr(network, ':');
-                               if( !bits ) {
-                                       Log_Warning("IPStack", "<Device>:<Type>:<HexStreamAddress>:<Bits>");
-                                       continue;
-                               }
-                               *bits = '\0';   bits ++;
-                               
-                               gateway = strchr(bits, ':');
-                               if( gateway ) {
-                                       *gateway = '\0';        gateway ++;
-                               }
-                               
-                               // Define route
-                               {
-                                       tVFS_Node       *node = IPStack_Root_FindDir(NULL, ifaceName);
-                                       if( !node ) {
-                                               Log_Warning("IPStack", "Unknown interface '%s' in arg %i", ifaceName, i);
-                                               continue ;
-                                       }
-                                       tInterface      *iface = node->ImplPtr;
-                                       
-                                        int    size = IPStack_GetAddressSize(iface->Type);
-                                       Uint8   netData[size];
-                                       Uint8   gwData[size];
-                                        int    iBits = atoi(bits);
-                                       
-                                       UnHex(netData, size, network);
-                                       if( gateway )
-                                               UnHex(gwData, size, gateway);
-                                       else
-                                               memset(gwData, 0, size);
-                                       
-                                       IPStack_AddRoute(ifaceName, netData, iBits, gwData, 30);
-                               }
-                               
-                               continue;
-                       }
-               }
-       }
-       
-       // Initialise loopback interface
-       gIP_LoopInterface.Adapter = IPStack_GetAdapter("LOOPBACK");
-       
-       DevFS_AddDevice( &gIP_DriverInfo );
-       
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Gets the size (in bytes) of a specified form of address
- */
-int IPStack_GetAddressSize(int AddressType)
-{
-       switch(AddressType)
-       {
-       case -1:        // -1 = maximum
-               return sizeof(tIPv6);
-       
-       case AF_NULL:
-               return 0;
-       
-       case AF_INET4:
-               return sizeof(tIPv4);
-       case AF_INET6:
-               return sizeof(tIPv6);
-               
-       default:
-               return 0;
-       }
-}
-
-/**
- * \brief Compare two IP Addresses masked by CheckBits
- */
-int IPStack_CompareAddress(int AddressType, const void *Address1, const void *Address2, int CheckBits)
-{
-        int    size = IPStack_GetAddressSize(AddressType);
-       Uint8   mask;
-       const Uint8     *addr1 = Address1, *addr2 = Address2;
-       
-       // Sanity check size
-       if( CheckBits < 0 )     CheckBits = size*8;
-       if( CheckBits > size*8 )        CheckBits = size*8;
-       
-       if( CheckBits == 0 )    return 1;       // /0 matches anything
-       
-       // Check first bits/8 bytes
-       if( memcmp(Address1, Address2, CheckBits/8) != 0 )      return 0;
-       
-       // Check if the mask is a multiple of 8
-       if( CheckBits % 8 == 0 )        return 1;
-       
-       // Check last bits
-       mask = 0xFF << (8 - (CheckBits % 8));
-       if( (addr1[CheckBits/8] & mask) == (addr2[CheckBits/8] & mask) )
-               return 1;
-       
-       return 0;
-}
-
-const char *IPStack_PrintAddress(int AddressType, const void *Address)
-{
-       switch( AddressType )
-       {
-       case 4: {
-               static char     ret[4*3+3+1];
-               const Uint8     *addr = Address;
-               sprintf(ret, "%i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
-               return ret;
-               }
-       
-       case 6: {       // TODO: address compression
-               static char     ret[8*4+7+1];
-               const Uint16    *addr = Address;
-               sprintf(ret, "%x:%x:%x:%x:%x:%x:%x:%x",
-                       ntohs(addr[0]), ntohs(addr[1]), ntohs(addr[2]), ntohs(addr[3]),
-                       ntohs(addr[4]), ntohs(addr[5]), ntohs(addr[6]), ntohs(addr[7])
-                       );
-               return ret;
-               }
-       
-       default:
-               return "";
-       }
-}
diff --git a/Modules/IPStack/routing.c b/Modules/IPStack/routing.c
deleted file mode 100644 (file)
index 7173d1f..0000000
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * Acess2 IP Stack
- * - Routing Tables
- */
-#define DEBUG  0
-#define VERSION        VER2(0,10)
-#include <acess.h>
-#include <api_drv_common.h>
-#include "ipstack.h"
-#include "link.h"
-
-#define        DEFAUTL_METRIC  30
-
-// === IMPORTS ===
-extern tInterface      *gIP_Interfaces;
-extern tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename);
-
-// === PROTOTYPES ===
-// - Routes directory
-char   *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
- int   IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
- int   IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
-tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
- int   _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
- int   IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
-// - Route Management
-tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric);
-tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
-tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
-// - Individual Routes
- int   IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data);
-
-// === GLOBALS ===
- int   giIP_NextRouteId = 1;
-tRoute *gIP_Routes;
-tRoute *gIP_RoutesEnd;
-tVFS_NodeType  gIP_RouteNodeType = {
-       .IOCtl = IPStack_Route_IOCtl
-};
-tVFS_NodeType  gIP_RouteDirNodeType = {
-       .ReadDir = IPStack_RouteDir_ReadDir,
-       .FindDir = IPStack_RouteDir_FindDir,
-       .MkNod = IPStack_RouteDir_MkNod,
-       .Relink = IPStack_RouteDir_Relink,
-       .IOCtl = IPStack_RouteDir_IOCtl
-};
-tVFS_Node      gIP_RouteNode = {
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Size = -1,
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Type = &gIP_RouteDirNodeType
-};
-
-// === CODE ===
-/**
- * \brief ReadDir for the /Devices/ip/routes/ directory
- */
-char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tRoute  *rt;
-       
-       for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
-       if( !rt )       return NULL;
-       
-       {
-                int    addrlen = IPStack_GetAddressSize(rt->AddressType);
-                int    len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
-               char    buf[len+1];
-                int    ofs;
-               ofs = sprintf(buf, "%i:", rt->AddressType);
-               ofs += Hex(buf+ofs, addrlen, rt->Network);
-               sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
-               return strdup(buf);
-       }
-}
-
-/**
- * \brief FindDir for the /Devices/ip/routes/ directory
- */
-tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
-{
-       // Interpret the name as <type>:<addr>, returning the interface for
-       // needed to access that address.
-       //   E.g. '@4:0A02000A' - 10.2.0.10
-       // Hm... It could do with a way to have a better address type representation
-       if( Name[0] == '@' )
-       {
-               tRoute  *rt;
-                int    ofs = 1;
-                int    type;
-               
-               ofs += ParseInt(Name+ofs, &type);
-                int    addrSize = IPStack_GetAddressSize(type);
-               Uint8   addrData[addrSize];
-
-               // Separator
-               if( Name[ofs] != ':' )  return NULL;
-               ofs ++;
-
-               // Error if the size is invalid
-               if( strlen(Name+ofs) != addrSize*2 )
-                       return NULL;
-               
-               // Parse the address
-               // - Error if the address data is not fully hex
-               if( UnHex(addrData, addrSize, Name + ofs) != addrSize )
-                       return NULL;
-               
-               // Find the route
-               rt = IPStack_FindRoute(type, NULL, addrData);
-               if(!rt) return NULL;
-       
-               if( rt->Interface )
-               {       
-                       // Return the interface node
-                       // - Sure it's hijacking it from inteface.c's area, but it's
-                       //   simpler this way
-                       return &rt->Interface->Node;
-               }
-               else
-               {
-                       return NULL;
-               }
-       }
-       else if( Name[0] == '#' )
-       {
-               int num, ofs = 1;
-               
-               ofs = ParseInt(Name+ofs, &num);
-               if( ofs == 1 )  return NULL;
-               if( Name[ofs] != '\0' ) return NULL;
-               if( num < 0)    return NULL;            
-
-               for( tRoute *rt = gIP_Routes; rt; rt = rt->Next )
-               {
-                       if( rt->Node.Inode > num )      return NULL;
-                       if( rt->Node.Inode == num )     return &rt->Node;
-               }
-               return NULL;
-       }
-       else
-       {
-                int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
-               if( type <= 0 ) return NULL;
-
-                int    addrSize = IPStack_GetAddressSize(type);
-               Uint8   addrData[addrSize];
-                int    subnet_bits, metric;
-               
-               _Route_ParseRouteName(Name, addrData, &subnet_bits, &metric);
-
-               tRoute *rt = _Route_FindExactRoute(type, addrData, subnet_bits, metric);
-               if(rt)  return &rt->Node;
-               return NULL;
-       }
-}
-
-/**
- * \brief Create a new route node
- */
-int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
-{
-       if( Flags )     return -EINVAL; 
-       if( Threads_GetUID() != 0 )     return -EACCES;
-
-        int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
-       if( type <= 0 ) return -EINVAL;
-
-        int    size = IPStack_GetAddressSize(type);
-       Uint8   addrdata[size]; 
-        int    subnet, metric;
-
-       _Route_ParseRouteName(Name, addrdata, &subnet, &metric);
-
-       // Check for duplicates
-       if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
-               return -EEXIST;
-
-       IPStack_Route_Create(type, addrdata, subnet, metric);
-
-       return 0;
-}
-
-/**
- * \brief Rename / Delete a route
- */
-int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
-{
-       tRoute  *rt;
-       
-       if( Threads_GetUID() != 0 )     return -EACCES;
-
-       // Get the original route entry
-       {
-                int    type = _Route_ParseRouteName(OldName, NULL, NULL, NULL);
-               if(type <= 0)   return -EINVAL;
-               Uint8   addr[IPStack_GetAddressSize(type)];
-                int    subnet, metric;
-               _Route_ParseRouteName(OldName, addr, &subnet, &metric);
-               
-               rt = _Route_FindExactRoute(type, addr, subnet, metric);
-       }       
-
-       if( NewName == NULL )
-       {
-               // Delete the route
-               tRoute  *prev = NULL;
-               for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
-               
-               if(prev)
-                       prev->Next = rt->Next;
-               else
-                       gIP_Routes = rt->Next;
-               free(rt);
-       }
-       else
-       {
-               // Change the route
-                int    type = _Route_ParseRouteName(NewName, NULL, NULL, NULL);
-               if(type <= 0)   return -EINVAL;
-               Uint8   addr[IPStack_GetAddressSize(type)];
-                int    subnet, metric;
-               _Route_ParseRouteName(NewName, addr, &subnet, &metric);
-       
-               return -ENOTIMPL;       
-       }
-       return 0;
-}
-
-tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric)
-{
-       for(tRoute *rt = gIP_Routes; rt; rt = rt->Next)
-       {
-               if( rt->AddressType != Type )   continue;
-               if( rt->Metric != Metric )      continue;
-               if( rt->SubnetBits != Subnet )  continue;
-               if( IPStack_CompareAddress(Type, rt->Network, Network, -1) == 0 )
-                       continue ;
-               return rt;
-       }
-       return NULL;
-}
-
-int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric)
-{
-        int    type, addrlen;
-        int    ofs = 0, ilen;
-       
-       ENTER("sName pAddr pSubnetBits pMetric", Name, Addr, SubnetBits, Metric);
-
-       ilen = ParseInt(Name, &type);
-       if(ilen == 0) {
-               LOG("Type failed to parse");
-               LEAVE_RET('i', -1);
-       }
-       ofs += ilen;
-       
-       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
-       ofs ++;
-
-       addrlen = IPStack_GetAddressSize(type);
-       if( Addr )
-       {
-               if( UnHex(Addr, addrlen, Name + ofs) != addrlen )
-                       return -1;
-       }
-       ofs += addrlen*2;
-       
-       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
-       ofs ++;
-
-       ilen = ParseInt(Name+ofs, SubnetBits);
-       if(ilen == 0) {
-               LOG("Subnet failed to parse");
-               LEAVE_RET('i', -1);
-       }
-       ofs += ilen;
-       
-       if(Name[ofs] != ':')    LEAVE_RET('i', -1);
-       ofs ++;
-
-       ilen = ParseInt(Name+ofs, Metric);
-       if(ilen == 0) {
-               LOG("Metric failed to parse");
-               LEAVE_RET('i', -1);
-       }
-       ofs += ilen;
-       
-       if(Name[ofs] != '\0')   LEAVE_RET('i', -1);
-
-       LEAVE('i', type);
-       return type;
-}
-
-/**
- * \brief Names for the route list IOCtl Calls
- */
-static const char *casIOCtls_RouteDir[] = {
-       DRV_IOCTLNAMES,
-       "locate_route", // Find the best route for an address - struct {int Type, char Address[]} *
-       NULL
-       };
-
-/**
- * \brief IOCtl for /Devices/ip/routes/
- */
-int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tRoute  *rt;
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       // --- Standard IOCtls (0-3) ---
-       BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir)
-       
-       case 4: // Locate Route
-               {
-                       struct {
-                                int    Type;
-                               Uint8   Addr[];
-                       }       *data = Data;
-                       
-                       if( !CheckMem(Data, sizeof(int)) )
-                               LEAVE_RET('i', -1);
-                       if( !CheckMem(Data, sizeof(int) + IPStack_GetAddressSize(data->Type)) )
-                               LEAVE_RET('i', -1);
-                       
-                       Log_Debug("IPStack", "Route_RouteDir_IOCtl - FindRoute %i, %s",
-                               data->Type, IPStack_PrintAddress(data->Type, data->Addr) );
-                       rt = IPStack_FindRoute(data->Type, NULL, data->Addr);
-                       
-                       if( !rt )
-                               LEAVE_RET('i', 0);
-                       
-                       LEAVE('i', rt->Node.Inode);
-                       return rt->Node.Inode;
-               }
-               break;
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \brief Create a new route entry
- * \param InterfaceName        Name of the interface using this route
- */
-tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric)
-{
-       tRoute  *rt;
-        int    size;
-       
-       // Get the size of the specified address type
-       size = IPStack_GetAddressSize(AddrType);
-       if( size == 0 ) {
-               return NULL;
-       }
-       
-       // Allocate space
-       rt = calloc(1, sizeof(tRoute) + size*2 );
-       
-       // Set up node
-       rt->Node.ImplPtr = rt;
-       rt->Node.Inode = giIP_NextRouteId ++;
-       rt->Node.Size = 0;
-       rt->Node.NumACLs = 1,
-       rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
-       rt->Node.Type = &gIP_RouteNodeType;
-       
-       // Set up state
-       rt->AddressType = AddrType;
-       rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
-       rt->SubnetBits = SubnetBits;
-       rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
-       rt->Interface = NULL;
-       rt->Metric = Metric;
-       memcpy(rt->Network, Network, size);
-       memset(rt->NextHop, 0, size);
-       
-       // Clear non-fixed bits
-       {
-               Uint8   *data = rt->Network;
-                int    i;
-               i = SubnetBits / 8;
-               if( SubnetBits % 8 ) {
-                       data[i] &= ~((1 << (8 - SubnetBits % 8)) - 1);
-                       i ++;
-               }
-               memset(data + i, 0, size - i);
-       }       
-
-
-       // Add to list
-       if( gIP_RoutesEnd ) {
-               gIP_RoutesEnd->Next = rt;
-               gIP_RoutesEnd = rt;
-       }
-       else {
-               gIP_Routes = gIP_RoutesEnd = rt;
-       }
-       
-//     Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
-       
-       return rt;
-}
-
-/**
- * \brief Add and fill a route
- */
-tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
-{
-       tInterface      *iface;
-       tRoute  *rt;
-        int    addrSize;
-       
-       {
-               tVFS_Node       *tmp;
-               tmp = IPStack_Root_FindDir(NULL, Interface);
-               if(!tmp)        return NULL;
-               iface = tmp->ImplPtr;
-               if(tmp->Type->Close)    tmp->Type->Close(tmp);
-       }
-
-       rt = IPStack_Route_Create(iface->Type, Network, SubnetBits, Metric);
-       if( !rt )       return NULL;
-       
-       addrSize = IPStack_GetAddressSize(iface->Type);
-       rt->Interface = iface;
-       
-       if( NextHop )
-               memcpy(rt->NextHop, NextHop, addrSize);
-       
-       return rt;
-}
-
-/**
- */
-tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address)
-{
-       tRoute  *rt;
-       tRoute  *best = NULL;
-       tInterface      *iface;
-        int    addrSize;
-       
-       ENTER("iAddressType pInterface sAddress",
-               AddressType, Interface, IPStack_PrintAddress(AddressType, Address));
-       
-       if( Interface && AddressType != Interface->Type ) {
-               LOG("Interface->Type (%i) != AddressType", Interface->Type);
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Get address size
-       addrSize = IPStack_GetAddressSize(AddressType);
-       
-       // Check against explicit routes
-       for( rt = gIP_Routes; rt; rt = rt->Next )
-       {
-               // Check interface
-               if( Interface && rt->Interface != Interface )   continue;
-               // Check address type
-               if( rt->AddressType != AddressType )    continue;
-               
-               LOG("Checking network %s/%i", IPStack_PrintAddress(AddressType, rt->Network), rt->SubnetBits);
-               
-               // Check if the address matches
-               if( !IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
-                       continue;
-               
-               if( best ) {
-                       // More direct routes are preferred
-                       if( best->SubnetBits > rt->SubnetBits ) {
-                               LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
-                               continue;
-                       }
-                       // If equally direct, choose the best metric
-                       if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
-                               LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
-                               continue;
-                       }
-               }
-               
-               best = rt;
-       }
-       
-       // Check against implicit routes
-       if( !best && !Interface )
-       {
-               for( iface = gIP_Interfaces; iface; iface = iface->Next )
-               {
-                       if( Interface && iface != Interface )   continue;
-                       if( iface->Type != AddressType )        continue;
-                       
-                       
-                       // Check if the address matches
-                       if( !IPStack_CompareAddress(AddressType, iface->Address, Address, iface->SubnetBits) )
-                               continue;
-                       
-                       if( best ) {
-                               // More direct routes are preferred
-                               if( best->SubnetBits > rt->SubnetBits ) {
-                                       LOG("Skipped - less direct (%i < %i)", rt->SubnetBits, best->SubnetBits);
-                                       continue;
-                               }
-                               // If equally direct, choose the best metric
-                               if( best->SubnetBits == rt->SubnetBits && best->Metric < rt->Metric ) {
-                                       LOG("Skipped - higher metric (%i > %i)", rt->Metric, best->Metric);
-                                       continue;
-                               }
-                       }
-                       
-                       rt = &iface->Route;
-                       memcpy(rt->Network, iface->Address, addrSize);
-                       memset(rt->NextHop, 0, addrSize);
-                       rt->Metric = DEFAUTL_METRIC;
-                       rt->SubnetBits = iface->SubnetBits;
-                       
-                       best = rt;
-               }
-       }
-       if( !best && Interface )
-       {
-               rt = &Interface->Route;
-               // Make sure route is up to date
-               memcpy(rt->Network, Interface->Address, addrSize);
-               memset(rt->NextHop, 0, addrSize);
-               rt->Metric = DEFAUTL_METRIC;
-               rt->SubnetBits = Interface->SubnetBits;
-               
-               if( IPStack_CompareAddress(AddressType, rt->Network, Address, rt->SubnetBits) )
-               {
-                       best = rt;
-               }
-       }
-       
-       LEAVE('p', best);
-       return best;
-}
-
-/**
- * \brief Names for route IOCtl Calls
- */
-static const char *casIOCtls_Route[] = {
-       DRV_IOCTLNAMES,
-       "get_nexthop",  // Get next hop - (void *Data), returns boolean success
-       "set_nexthop",  // Set next hop - (void *Data), returns boolean success
-       "get_interface",        // Get interface name - (char *Name), returns name length, NULL OK
-       "set_interface",        // Set interface - (const char *Name)
-       NULL
-       };
-
-/**
- * \brief IOCtl for /Devices/ip/routes/#
- */
-int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tRoute  *rt = Node->ImplPtr;
-        int    addrSize = IPStack_GetAddressSize(rt->AddressType);
-       
-       switch(ID)
-       {
-       // --- Standard IOCtls (0-3) ---
-       BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route)
-       
-       // Get Next Hop
-       case 4:
-               if( !CheckMem(Data, addrSize) ) return -1;
-               memcpy(Data, rt->NextHop, addrSize);
-               return 1;
-       // Set Next Hop
-       case 5:
-               if( Threads_GetUID() != 0 )     return -1;
-               if( !CheckMem(Data, addrSize) ) return -1;
-               memcpy(rt->NextHop, Data, addrSize);
-               return 1;
-
-       // Get interface name
-       case 6:
-               if( !rt->Interface ) {
-                       if(Data && !CheckMem(Data, 1) )
-                               return -1;
-                       if(Data)
-                               *(char*)Data = 0;
-                       return 0;
-               }
-               if( Data ) {
-                       if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
-                               return -1;
-                       strcpy(Data, rt->Interface->Name);
-               }
-               return strlen(rt->Interface->Name);
-       // Set interface name
-       case 7:
-               if( Threads_GetUID() != 0 )
-                       return -1;
-               if( !CheckString(Data) )
-                       return -1;
-               else
-               {
-                       tInterface      *iface;
-                       tVFS_Node       *tmp;
-                       tmp = IPStack_Root_FindDir(NULL, Data);
-                       if(!tmp)
-                               return -1;
-                       iface = tmp->ImplPtr;
-                       if(tmp->Type->Close)    tmp->Type->Close(tmp);
-                       
-                       if( iface->Type != rt->AddressType )
-                               return -1;
-
-                       // TODO: Other checks?          
-       
-                       rt->Interface = iface;
-               }
-               return 0;
-
-       default:
-               return -1;
-       }
-}
diff --git a/Modules/IPStack/sctp.c b/Modules/IPStack/sctp.c
deleted file mode 100644 (file)
index d130933..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Acess2 IP Stack
- * - SCTP (Stream Control Transmission Protocol) Handling
- */
-#include "ipstack.h"
-#include <api_drv_common.h>
-#include "sctp.h"
-
-#define SCTP_ALLOC_BASE        0xC000
-
-// === PROTOTYPES ===
-void   SCTP_Initialise();
-void   SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
-void   SCTP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
-void   SCTP_SendPacket(tSCTPChannel *Channel, void *Data, size_t Length);
-// --- Listening Server
-tVFS_Node      *SCTP_Server_Init(tInterface *Interface);
-char   *SCTP_Server_ReadDir(tVFS_Node *Node, int ID);
-tVFS_Node      *SCTP_Server_FindDir(tVFS_Node *Node, const char *Name);
- int   SCTP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
-void   SCTP_Server_Close(tVFS_Node *Node);
-// --- Client Channels
-tVFS_Node      *SCTP_Channel_Init(tInterface *Interface);
-Uint64 SCTP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 SCTP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
- int   SCTP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
-void   SCTP_Channel_Close(tVFS_Node *Node);
-// --- Helpers
-Uint16 SCTP_int_AllocatePort();
- int   SCTP_int_MarkPortAsUsed(Uint16 Port);
-void   SCTP_int_FreePort(Uint16 Port);
-
-// === GLOBALS ===
-tMutex glSCTP_Servers;
-tSCTPServer    *gpSCTP_Servers;
-
-tMutex glSCTP_Channels;
-tSCTPChannel   *gpSCTP_Channels;
-
-tMutex glSCTP_Ports;
-Uint32 gSCTP_Ports[0x10000/32];
-
-tSocketFile    gSCTP_ServerFile = {NULL, "sctps", SCTP_Server_Init};
-tSocketFile    gSCTP_ClientFile = {NULL, "sctpc", SCTP_Channel_Init};
-
-// === CODE ===
-/**
- * \fn void TCP_Initialise()
- * \brief Initialise the TCP Layer
- */
-void SCTP_Initialise()
-{
-       IPStack_AddFile(&gSCTP_ServerFile);
-       IPStack_AddFile(&gSCTP_ClientFile);
-       //IPv4_RegisterCallback(IP4PROT_SCTP, SCTP_GetPacket, SCTP_Unreachable);
-       IPv4_RegisterCallback(IP4PROT_SCTP, SCTP_GetPacket);
-}
-
-/**
- * \brief Scan a list of tSCTPChannels and find process the first match
- * \return 0 if no match was found, -1 on error and 1 if a match was found
- */
-int SCTP_int_ScanList(tSCTPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
-{
-       tSCTPHeader     *hdr = Buffer;
-       tSCTPChannel    *chan;
-       tSCTPPacket     *pack;
-        int    len;
-       
-       for(chan = List;
-               chan;
-               chan = chan->Next)
-       {
-               if(chan->Interface != Interface)        continue;
-               if(chan->LocalPort != ntohs(hdr->DestPort))     continue;
-               if(chan->RemotePort != ntohs(hdr->SourcePort))  continue;
-               
-               if(Interface->Type == 4) {
-                       if(!IP4_EQU(chan->RemoteAddr.v4, *(tIPv4*)Address))     continue;
-               }
-               else if(Interface->Type == 6) {
-                       if(!IP6_EQU(chan->RemoteAddr.v6, *(tIPv6*)Address))     continue;
-               }
-               else {
-                       Log_Warning("SCTP", "Address type %i unknown", Interface->Type);
-                       Mutex_Release(&glSCTP_Channels);
-                       return -1;
-               }
-               
-               Log_Log("SCTP", "Recieved packet for %p", chan);
-               // Create the cached packet
-               len = ntohs(hdr->Length);
-               pack = malloc(sizeof(tSCTPPacket) + len);
-               pack->Next = NULL;
-               pack->Length = len;
-               memcpy(pack->Data, hdr->Data, len);
-               
-               // Add the packet to the channel's queue
-               SHORTLOCK(&chan->lQueue);
-               if(chan->Queue)
-                       chan->QueueEnd->Next = pack;
-               else
-                       chan->QueueEnd = chan->Queue = pack;
-               SHORTREL(&chan->lQueue);
-               Mutex_Release(&glSCTP_Channels);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * \fn void SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
- * \brief Handles a packet from the IP Layer
- */
-void SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
-{
-       tSCTPHeader     *hdr = Buffer;
-       tSCTPServer     *srv;
-        int    ret;
-       
-       Log_Log("SCTP", "hdr->SourcePort = %i", ntohs(hdr->SourcePort));
-       Log_Log("SCTP", "hdr->DestPort = %i", ntohs(hdr->DestPort));
-       Log_Log("SCTP", "hdr->VerifcationTag = %i", ntohs(hdr->VerifcationTag));
-       Log_Log("SCTP", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
-       
-       // Check registered connections
-       Mutex_Acquire(&glSCTP_Channels);
-       ret = SCTP_int_ScanList(gpSCTP_Channels, Interface, Address, Length, Buffer);
-       Mutex_Release(&glSCTP_Channels);
-       if(ret != 0)    return ;
-       
-       
-       // TODO: Server/Listener
-       Mutex_Acquire(&glSCTP_Servers);
-       for(srv = gpSCTP_Servers;
-               srv;
-               srv = srv->Next)
-       {
-               if(srv->Interface != Interface) continue;
-               if(srv->ListenPort != ntohs(hdr->DestPort))     continue;
-               ret = SCTP_int_ScanList(srv->Channels, Interface, Address, Length, Buffer);
-               if(ret != 0)    break;
-               
-               // Add connection
-               Log_Warning("SCTP", "TODO - Add channel on connection");
-               //TODO
-       }
-       Mutex_Release(&glSCTP_Servers);
-       
-}
-
-/**
- * \brief Handle an ICMP Unrechable Error
- */
-void SCTP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
-{
-       
-}
-
-/**
- * \brief Send a packet
- * \param Channel      Channel to send the packet from
- * \param Data Packet data
- * \param Length       Length in bytes of packet data
- */
-void SCTP_SendPacket(tSCTPChannel *Channel, void *Data, size_t Length)
-{
-       tSCTPHeader     *hdr;
-       
-       switch(Channel->Interface->Type)
-       {
-       case 4:
-               // Create the packet
-               hdr = malloc(sizeof(tSCTPHeader)+Length);
-               hdr->SourcePort = htons( Channel->LocalPort );
-               hdr->DestPort = htons( Channel->RemotePort );
-               hdr->Length = htons( sizeof(tSCTPHeader) + Length );
-               hdr->Checksum = 0;      // Checksum can be zero on IPv4
-               memcpy(hdr->Data, Data, Length);
-               // Pass on the the IPv4 Layer
-               IPv4_SendPacket(Channel->Interface, Channel->RemoteAddr.v4, IP4PROT_SCTP, 0, sizeof(tSCTPHeader)+Length, hdr);
-               // Free allocated packet
-               free(hdr);
-               break;
-       }
-}
-
-// --- Listening Server
-tVFS_Node *SCTP_Server_Init(tInterface *Interface)
-{
-       tSCTPServer     *new;
-       new = calloc( sizeof(tSCTPServer), 1 );
-       if(!new)        return NULL;
-       
-       new->Node.ImplPtr = new;
-       new->Node.Flags = VFS_FFLAG_DIRECTORY;
-       new->Node.NumACLs = 1;
-       new->Node.ACLs = &gVFS_ACL_EveryoneRX;
-       new->Node.ReadDir = SCTP_Server_ReadDir;
-       new->Node.FindDir = SCTP_Server_FindDir;
-       new->Node.IOCtl = SCTP_Server_IOCtl;
-       new->Node.Close = SCTP_Server_Close;
-       
-       Mutex_Acquire(&glSCTP_Servers);
-       new->Next = gpSCTP_Servers;
-       gpSCTP_Servers = new;
-       Mutex_Release(&glSCTP_Servers);
-       
-       return &new->Node;
-}
-
-/**
- * \brief Wait for a connection and return its ID in a string
- */
-char *SCTP_Server_ReadDir(tVFS_Node *Node, int ID)
-{
-       tSCTPServer     *srv = Node->ImplPtr;
-       tSCTPChannel    *chan;
-       char    *ret;
-       
-       if( srv->ListenPort == 0 )      return NULL;
-       
-       // Lock (so another thread can't collide with us here) and wait for a connection
-       Mutex_Acquire( &srv->Lock );
-       while( srv->NewChannels == NULL )       Threads_Yield();
-       // Pop the connection off the new list
-       chan = srv->NewChannels;
-       srv->NewChannels = chan->Next;
-       // Release the lock
-       Mutex_Release( &srv->Lock );
-       
-       // Create the ID string and return it
-       ret = malloc(11+1);
-       sprintf(ret, "%i", chan->Node.ImplInt);
-       
-       return ret;
-}
-
-/**
- * \brief Take a string and find the channel
- */
-tVFS_Node *SCTP_Server_FindDir(tVFS_Node *Node, const char *Name)
-{
-       tSCTPServer     *srv = Node->ImplPtr;
-       tSCTPChannel    *chan;
-        int    id = atoi(Name);
-       
-       for(chan = srv->Channels;
-               chan;
-               chan = chan->Next)
-       {
-               if( chan->Node.ImplInt < id )   continue;
-               if( chan->Node.ImplInt > id )   break;  // Go sorted lists!
-               
-               return &chan->Node;
-       }
-       
-       return NULL;
-}
-
-/**
- * \brief Names for server IOCtl Calls
- */
-static const char *casIOCtls_Server[] = {
-       DRV_IOCTLNAMES,
-       "getset_listenport",
-       NULL
-       };
-/**
- * \brief Channel IOCtls
- */
-int SCTP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tSCTPServer     *srv = Node->ImplPtr;
-       
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_MISC, "SCTP Server", 0x100, casIOCtls_Server);
-       
-       case 4: // getset_localport (returns bool success)
-               if(!Data)       LEAVE_RET('i', srv->ListenPort);
-               if(!CheckMem( Data, sizeof(Uint16) ) ) {
-                       LOG("Invalid pointer %p", Data);
-                       LEAVE_RET('i', -1);
-               }
-               // Set port
-               srv->ListenPort = *(Uint16*)Data;
-               // Permissions check (Ports lower than 1024 are root-only)
-               if(srv->ListenPort != 0 && srv->ListenPort < 1024) {
-                       if( Threads_GetUID() != 0 ) {
-                               LOG("Attempt by non-superuser to listen on port %i", srv->ListenPort);
-                               srv->ListenPort = 0;
-                               LEAVE_RET('i', -1);
-                       }
-               }
-               // Allocate a random port if requested
-               if( srv->ListenPort == 0 )
-                       srv->ListenPort = SCTP_int_AllocatePort();
-               else
-               {
-                       // Else, mark the requested port as used
-                       if( SCTP_int_MarkPortAsUsed(srv->ListenPort) == 0 ) {
-                               LOG("Port %i us currently in use", srv->ListenPort);
-                               srv->ListenPort = 0;
-                               LEAVE_RET('i', -1);
-                       }
-                       LEAVE_RET('i', 1);
-               }
-               LEAVE_RET('i', 1);
-       
-       default:
-               LEAVE_RET('i', -1);
-       }
-       LEAVE_RET('i', 0);
-}
-
-void SCTP_Server_Close(tVFS_Node *Node)
-{
-       tSCTPServer     *srv = Node->ImplPtr;
-       tSCTPServer     *prev;
-       tSCTPChannel    *chan;
-       tSCTPPacket     *tmp;
-       
-       
-       // Remove from the main list first
-       Mutex_Acquire(&glSCTP_Servers);
-       if(gpSCTP_Servers == srv)
-               gpSCTP_Servers = gpSCTP_Servers->Next;
-       else
-       {
-               for(prev = gpSCTP_Servers;
-                       prev->Next && prev->Next != srv;
-                       prev = prev->Next);
-               if(!prev->Next)
-                       Log_Warning("SCTP", "Bookeeping Fail, server %p is not in main list", srv);
-               else
-                       prev->Next = prev->Next->Next;
-       }
-       Mutex_Release(&glSCTP_Servers);
-       
-       
-       Mutex_Acquire(&srv->Lock);
-       for(chan = srv->Channels;
-               chan;
-               chan = chan->Next)
-       {
-               // Clear Queue
-               SHORTLOCK(&chan->lQueue);
-               while(chan->Queue)
-               {
-                       tmp = chan->Queue;
-                       chan->Queue = tmp->Next;
-                       free(tmp);
-               }
-               SHORTREL(&chan->lQueue);
-               
-               // Free channel structure
-               free(chan);
-       }
-       Mutex_Release(&srv->Lock);
-       
-       free(srv);
-}
-
-// --- Client Channels
-tVFS_Node *SCTP_Channel_Init(tInterface *Interface)
-{
-       tSCTPChannel    *new;
-       new = calloc( sizeof(tSCTPChannel), 1 );
-       new->Interface = Interface;
-       new->Node.ImplPtr = new;
-       new->Node.NumACLs = 1;
-       new->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       new->Node.Read = SCTP_Channel_Read;
-       new->Node.Write = SCTP_Channel_Write;
-       new->Node.IOCtl = SCTP_Channel_IOCtl;
-       new->Node.Close = SCTP_Channel_Close;
-       
-       Mutex_Acquire(&glSCTP_Channels);
-       new->Next = gpSCTP_Channels;
-       gpSCTP_Channels = new;
-       Mutex_Release(&glSCTP_Channels);
-       
-       return &new->Node;
-}
-
-/**
- * \brief Read from the channel file (wait for a packet)
- */
-Uint64 SCTP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tSCTPChannel    *chan = Node->ImplPtr;
-       tSCTPPacket     *pack;
-       
-       if(chan->LocalPort == 0)        return 0;
-       if(chan->RemotePort == 0)       return 0;
-       
-       while(chan->Queue == NULL)      Threads_Yield();
-       
-       for(;;)
-       {
-               SHORTLOCK(&chan->lQueue);
-               if(chan->Queue == NULL) {
-                       SHORTREL(&chan->lQueue);
-                       continue;
-               }
-               pack = chan->Queue;
-               chan->Queue = pack->Next;
-               if(!chan->Queue)        chan->QueueEnd = NULL;
-               SHORTREL(&chan->lQueue);
-               break;
-       }
-       
-       // Clip length to packet length
-       if(Length > pack->Length)       Length = pack->Length;
-       // Copy packet data from cache
-       memcpy(Buffer, pack->Data, Length);
-       // Free cached packet
-       free(pack);     
-       
-       return Length;
-}
-
-/**
- * \brief Write to the channel file (send a packet)
- */
-Uint64 SCTP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tSCTPChannel    *chan = Node->ImplPtr;
-       if(chan->RemotePort == 0)       return 0;
-       
-       SCTP_SendPacket(chan, Buffer, (size_t)Length);
-       
-       return 0;
-}
-
-/**
- * \brief Names for channel IOCtl Calls
- */
-static const char *casIOCtls_Channel[] = {
-       DRV_IOCTLNAMES,
-       "getset_localport",
-       "getset_remoteport",
-       "set_remoteaddr",
-       NULL
-       };
-/**
- * \brief Channel IOCtls
- */
-int SCTP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tSCTPChannel    *chan = Node->ImplPtr;
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_MISC, "SCTP Channel", 0x100, casIOCtls_Channel);
-       
-       case 4: // getset_localport (returns bool success)
-               if(!Data)       LEAVE_RET('i', chan->LocalPort);
-               if(!CheckMem( Data, sizeof(Uint16) ) ) {
-                       LOG("Invalid pointer %p", Data);
-                       LEAVE_RET('i', -1);
-               }
-               // Set port
-               chan->LocalPort = *(Uint16*)Data;
-               // Permissions check (Ports lower than 1024 are root-only)
-               if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
-                       if( Threads_GetUID() != 0 ) {
-                               LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
-                               chan->LocalPort = 0;
-                               LEAVE_RET('i', -1);
-                       }
-               }
-               // Allocate a random port if requested
-               if( chan->LocalPort == 0 )
-                       chan->LocalPort = SCTP_int_AllocatePort();
-               else
-               {
-                       // Else, mark the requested port as used
-                       if( SCTP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
-                               LOG("Port %i us currently in use", chan->LocalPort);
-                               chan->LocalPort = 0;
-                               LEAVE_RET('i', 0);
-                       }
-                       LEAVE_RET('i', 1);
-               }
-               LEAVE_RET('i', 1);
-       
-       case 5: // getset_remoteport (returns bool success)
-               if(!Data)       LEAVE_RET('i', chan->RemotePort);
-               if(!CheckMem( Data, sizeof(Uint16) ) ) {
-                       LOG("Invalid pointer %p", Data);
-                       LEAVE_RET('i', -1);
-               }
-               chan->RemotePort = *(Uint16*)Data;
-               return 1;
-       
-       case 6: // set_remoteaddr (returns bool success)
-               switch(chan->Interface->Type)
-               {
-               case 4:
-                       if(!CheckMem(Data, sizeof(tIPv4))) {
-                               LOG("Invalid pointer %p", Data);
-                               LEAVE_RET('i', -1);
-                       }
-                       chan->RemoteAddr.v4 = *(tIPv4*)Data;
-                       break;
-               }
-               break;
-       }
-       LEAVE_RET('i', 0);
-}
-
-/**
- * \brief Close and destroy an open channel
- */
-void SCTP_Channel_Close(tVFS_Node *Node)
-{
-       tSCTPChannel    *chan = Node->ImplPtr;
-       tSCTPChannel    *prev;
-       
-       // Remove from the main list first
-       Mutex_Acquire(&glSCTP_Channels);
-       if(gpSCTP_Channels == chan)
-               gpSCTP_Channels = gpSCTP_Channels->Next;
-       else
-       {
-               for(prev = gpSCTP_Channels;
-                       prev->Next && prev->Next != chan;
-                       prev = prev->Next);
-               if(!prev->Next)
-                       Log_Warning("SCTP", "Bookeeping Fail, channel %p is not in main list", chan);
-               else
-                       prev->Next = prev->Next->Next;
-       }
-       Mutex_Release(&glSCTP_Channels);
-       
-       // Clear Queue
-       SHORTLOCK(&chan->lQueue);
-       while(chan->Queue)
-       {
-               tSCTPPacket     *tmp;
-               tmp = chan->Queue;
-               chan->Queue = tmp->Next;
-               free(tmp);
-       }
-       SHORTREL(&chan->lQueue);
-       
-       // Free channel structure
-       free(chan);
-}
-
-/**
- * \return Port Number on success, or zero on failure
- */
-Uint16 SCTP_int_AllocatePort()
-{
-        int    i;
-       Mutex_Acquire(&glSCTP_Ports);
-       // Fast Search
-       for( i = SCTP_ALLOC_BASE; i < 0x10000; i += 32 )
-               if( gSCTP_Ports[i/32] != 0xFFFFFFFF )
-                       break;
-       if(i == 0x10000)        return 0;
-       for( ;; i++ )
-       {
-               if( !(gSCTP_Ports[i/32] & (1 << (i%32))) )
-                       return i;
-       }
-       Mutex_Release(&glSCTP_Ports);
-}
-
-/**
- * \brief Allocate a specific port
- * \return Boolean Success
- */
-int SCTP_int_MarkPortAsUsed(Uint16 Port)
-{
-       Mutex_Acquire(&glSCTP_Ports);
-       if( gSCTP_Ports[Port/32] & (1 << (Port%32)) ) {
-               return 0;
-               Mutex_Release(&glSCTP_Ports);
-       }
-       gSCTP_Ports[Port/32] |= 1 << (Port%32);
-       Mutex_Release(&glSCTP_Ports);
-       return 1;
-}
-
-/**
- * \brief Free an allocated port
- */
-void SCTP_int_FreePort(Uint16 Port)
-{
-       Mutex_Acquire(&glSCTP_Ports);
-       gSCTP_Ports[Port/32] &= ~(1 << (Port%32));
-       Mutex_Release(&glSCTP_Ports);
-}
diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c
deleted file mode 100644 (file)
index e9c3de9..0000000
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*
- * Acess2 IP Stack
- * - TCP Handling
- */
-#define DEBUG  1
-#include "ipstack.h"
-#include "ipv4.h"
-#include "ipv6.h"
-#include "tcp.h"
-
-#define USE_SELECT     1
-#define HEXDUMP_INCOMING       0
-#define HEXDUMP_OUTGOING       0
-#define        CACHE_FUTURE_PACKETS_IN_BYTES   1       // Use a ring buffer to cache out of order packets
-
-#define TCP_MIN_DYNPORT        0xC000
-#define TCP_MAX_HALFOPEN       1024    // Should be enough
-
-#define TCP_MAX_PACKET_SIZE    1024
-#define TCP_WINDOW_SIZE        0x2000
-#define TCP_RECIEVE_BUFFER_SIZE        0x4000
-
-// === PROTOTYPES ===
-void   TCP_Initialise(void);
-void   TCP_StartConnection(tTCPConnection *Conn);
-void   TCP_SendPacket(tTCPConnection *Conn, size_t Length, tTCPHeader *Data);
-void   TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
-void   TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length);
-int    TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length);
-void   TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection);
-Uint16 TCP_GetUnusedPort();
- int   TCP_AllocatePort(Uint16 Port);
- int   TCP_DeallocatePort(Uint16 Port);
-// --- Server
-tVFS_Node      *TCP_Server_Init(tInterface *Interface);
-char   *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *TCP_Server_FindDir(tVFS_Node *Node, const char *Name);
- int   TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
-void   TCP_Server_Close(tVFS_Node *Node);
-// --- Client
-tVFS_Node      *TCP_Client_Init(tInterface *Interface);
-Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
- int   TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
-void   TCP_Client_Close(tVFS_Node *Node);
-// --- Helpers
- int   WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue);
-
-// === TEMPLATES ===
-tSocketFile    gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
-tSocketFile    gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
-tVFS_NodeType  gTCP_ServerNodeType = {
-       .TypeName = "TCP Server",
-       .ReadDir = TCP_Server_ReadDir,
-       .FindDir = TCP_Server_FindDir,
-       .IOCtl   = TCP_Server_IOCtl,
-       .Close   = TCP_Server_Close
-       };
-tVFS_NodeType  gTCP_ClientNodeType = {
-       .TypeName = "TCP Client/Connection",
-       .Read  = TCP_Client_Read,
-       .Write = TCP_Client_Write,
-       .IOCtl = TCP_Client_IOCtl,
-       .Close = TCP_Client_Close
-       };
-
-// === GLOBALS ===
- int   giTCP_NumHalfopen = 0;
-tShortSpinlock glTCP_Listeners;
-tTCPListener   *gTCP_Listeners;
-tShortSpinlock glTCP_OutbountCons;
-tTCPConnection *gTCP_OutbountCons;
-Uint32 gaTCP_PortBitmap[0x800];
- int   giTCP_NextOutPort = TCP_MIN_DYNPORT;
-
-// === CODE ===
-/**
- * \brief Initialise the TCP Layer
- * 
- * Registers the client and server files and the GetPacket callback
- */
-void TCP_Initialise(void)
-{
-       giTCP_NextOutPort += rand()%32;
-       IPStack_AddFile(&gTCP_ServerFile);
-       IPStack_AddFile(&gTCP_ClientFile);
-       IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
-       IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
-}
-
-/**
- * \brief Sends a packet from the specified connection, calculating the checksums
- * \param Conn Connection
- * \param Length       Length of data
- * \param Data Packet data (cast as a TCP Header)
- */
-void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data )
-{
-       Uint16  checksum[2];
-       
-       Data->Checksum = 0;
-       checksum[1] = htons( ~IPv4_Checksum( (void*)Data, Length ) );   // Partial checksum
-       if(Length & 1)
-               ((Uint8*)Data)[Length] = 0;
-       
-       // TODO: Fragment packet
-       
-       switch( Conn->Interface->Type )
-       {
-       case 4:
-               // Append IPv4 Pseudo Header
-               {
-                       Uint32  buf[3];
-                       buf[0] = ((tIPv4*)Conn->Interface->Address)->L;
-                       buf[1] = Conn->RemoteIP.v4.L;
-                       buf[2] = (htons(Length)<<16) | (6<<8) | 0;
-                       checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) );        // Partial checksum
-               }
-               Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two
-               IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, Length, Data);
-               break;
-               
-       case 6:
-               // Append IPv6 Pseudo Header
-               {
-                       Uint32  buf[4+4+1+1];
-                       memcpy(buf, Conn->Interface->Address, 16);
-                       memcpy(&buf[4], &Conn->RemoteIP, 16);
-                       buf[8] = htonl(Length);
-                       buf[9] = htonl(6);
-                       checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) );        // Partial checksum
-               }
-               Data->Checksum = htons( IPv4_Checksum(checksum, 2*2) ); // Combine the two
-               IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data);
-               break;
-       }
-}
-
-/**
- * \brief Handles a packet from the IP Layer
- * \param Interface    Interface the packet arrived from
- * \param Address      Pointer to the addres structure
- * \param Length       Size of packet in bytes
- * \param Buffer       Packet data
- */
-void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
-{
-       tTCPHeader      *hdr = Buffer;
-       tTCPListener    *srv;
-       tTCPConnection  *conn;
-
-       Log_Log("TCP", "TCP_GetPacket: <Local>:%i from [%s]:%i, Flags= %s%s%s%s%s%s%s%s",
-               ntohs(hdr->DestPort),
-               IPStack_PrintAddress(Interface->Type, Address),
-               ntohs(hdr->SourcePort),
-               (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "",
-               (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "",
-               (hdr->Flags & TCP_FLAG_URG) ? "URG " : "",
-               (hdr->Flags & TCP_FLAG_ACK) ? "ACK " : "",
-               (hdr->Flags & TCP_FLAG_PSH) ? "PSH " : "",
-               (hdr->Flags & TCP_FLAG_RST) ? "RST " : "",
-               (hdr->Flags & TCP_FLAG_SYN) ? "SYN " : "",
-               (hdr->Flags & TCP_FLAG_FIN) ? "FIN " : ""
-               );
-
-       if( Length > (hdr->DataOffset >> 4)*4 )
-       {
-               Log_Log("TCP", "TCP_GetPacket: SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
-#if HEXDUMP_INCOMING
-               Debug_HexDump(
-                       "TCP_GetPacket: Packet Data = ",
-                       (Uint8*)hdr + (hdr->DataOffset >> 4)*4,
-                       Length - (hdr->DataOffset >> 4)*4
-                       );
-#endif
-       }
-
-       // Check Servers
-       {
-               for( srv = gTCP_Listeners; srv; srv = srv->Next )
-               {
-                       // Check if the server is active
-                       if(srv->Port == 0)      continue;
-                       // Check the interface
-                       if(srv->Interface && srv->Interface != Interface)       continue;
-                       // Check the destination port
-                       if(srv->Port != htons(hdr->DestPort))   continue;
-                       
-                       Log_Log("TCP", "TCP_GetPacket: Matches server %p", srv);
-                       // Is this in an established connection?
-                       for( conn = srv->Connections; conn; conn = conn->Next )
-                       {
-                               // Check that it is coming in on the same interface
-                               if(conn->Interface != Interface)        continue;
-
-                               // Check Source Port
-                               Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)",
-                                       conn->RemotePort, ntohs(hdr->SourcePort));
-                               if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
-
-                               // Check Source IP
-                               Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)",
-                                       IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP));
-                               Log_Debug("TCP", "                == Address(%s)",
-                                       IPStack_PrintAddress(conn->Interface->Type, Address));
-                               if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
-                                       continue ;
-
-                               Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn);
-                               // We have a response!
-                               TCP_INT_HandleConnectionPacket(conn, hdr, Length);
-
-                               return;
-                       }
-
-                       Log_Log("TCP", "TCP_GetPacket: Opening Connection");
-                       // Open a new connection (well, check that it's a SYN)
-                       if(hdr->Flags != TCP_FLAG_SYN) {
-                               Log_Log("TCP", "TCP_GetPacket: Packet is not a SYN");
-                               return ;
-                       }
-                       
-                       // TODO: Check for halfopen max
-                       
-                       conn = calloc(1, sizeof(tTCPConnection));
-                       conn->State = TCP_ST_SYN_RCVD;
-                       conn->LocalPort = srv->Port;
-                       conn->RemotePort = ntohs(hdr->SourcePort);
-                       conn->Interface = Interface;
-                       
-                       switch(Interface->Type)
-                       {
-                       case 4: conn->RemoteIP.v4 = *(tIPv4*)Address;   break;
-                       case 6: conn->RemoteIP.v6 = *(tIPv6*)Address;   break;
-                       }
-                       
-                       conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
-                       
-                       conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1;
-                       conn->NextSequenceSend = rand();
-                       
-                       // Create node
-                       conn->Node.NumACLs = 1;
-                       conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
-                       conn->Node.ImplPtr = conn;
-                       conn->Node.ImplInt = srv->NextID ++;
-                       conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end?
-                       
-                       // Hmm... Theoretically, this lock will never have to wait,
-                       // as the interface is locked to the watching thread, and this
-                       // runs in the watching thread. But, it's a good idea to have
-                       // it, just in case
-                       // Oh, wait, there is a case where a wildcard can be used
-                       // (srv->Interface == NULL) so having the lock is a good idea
-                       SHORTLOCK(&srv->lConnections);
-                       if( !srv->Connections )
-                               srv->Connections = conn;
-                       else
-                               srv->ConnectionsTail->Next = conn;
-                       srv->ConnectionsTail = conn;
-                       if(!srv->NewConnections)
-                               srv->NewConnections = conn;
-                       VFS_MarkAvaliable( &srv->Node, 1 );
-                       SHORTREL(&srv->lConnections);
-
-                       // Send the SYN ACK
-                       hdr->Flags |= TCP_FLAG_ACK;
-                       hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv);
-                       hdr->SequenceNumber = htonl(conn->NextSequenceSend);
-                       hdr->DestPort = hdr->SourcePort;
-                       hdr->SourcePort = htons(srv->Port);
-                       hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4;
-                       TCP_SendPacket( conn, sizeof(tTCPHeader), hdr );
-                       conn->NextSequenceSend ++;
-                       return ;
-               }
-       }
-
-
-       // Check Open Connections
-       {
-               for( conn = gTCP_OutbountCons; conn; conn = conn->Next )
-               {
-                       // Check that it is coming in on the same interface
-                       if(conn->Interface != Interface)        continue;
-
-                       // Check Source Port
-                       if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
-
-                       // Check Source IP
-                       if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
-                               continue;
-                       if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
-                               continue;
-
-                       TCP_INT_HandleConnectionPacket(conn, hdr, Length);
-                       return ;
-               }
-       }
-       
-       Log_Log("TCP", "TCP_GetPacket: No Match");
-}
-
-/**
- * \brief Handles a packet sent to a specific connection
- * \param Connection   TCP Connection pointer
- * \param Header       TCP Packet pointer
- * \param Length       Length of the packet
- */
-void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length)
-{
-        int    dataLen;
-       Uint32  sequence_num;
-       
-       // Silently drop once finished
-       // TODO: Check if this needs to be here
-       if( Connection->State == TCP_ST_FINISHED ) {
-               Log_Log("TCP", "Packet ignored - connection finnished");
-               return ;
-       }
-       
-       // Syncronise sequence values
-       if(Header->Flags & TCP_FLAG_SYN) {
-               // TODO: What if the packet also has data?
-               Connection->NextSequenceRcv = ntohl(Header->SequenceNumber);
-       }
-       
-       // Ackowledge a sent packet
-       if(Header->Flags & TCP_FLAG_ACK) {
-               // TODO: Process an ACKed Packet
-               Log_Log("TCP", "Conn %p, Sent packet 0x%x ACKed", Connection, Header->AcknowlegementNumber);
-       }
-       
-       // Get length of data
-       dataLen = Length - (Header->DataOffset>>4)*4;
-       Log_Log("TCP", "HandleConnectionPacket - dataLen = %i", dataLen);
-       
-       // 
-       // State Machine
-       //
-       switch( Connection->State )
-       {
-       // Pre-init connection?
-       case TCP_ST_CLOSED:
-               Log_Log("TCP", "Packets to a closed connection?!");
-               break;
-       
-       // --- Init States ---
-       // SYN sent, expecting SYN-ACK Connection Opening
-       case TCP_ST_SYN_SENT:
-               if( Header->Flags & TCP_FLAG_SYN )
-               {
-                       Connection->NextSequenceRcv ++;
-                       Header->DestPort = Header->SourcePort;
-                       Header->SourcePort = htons(Connection->LocalPort);
-                       Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
-                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
-                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
-                       Header->Flags = TCP_FLAG_ACK;
-                       Header->DataOffset = (sizeof(tTCPHeader)/4) << 4;
-                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
-                       
-                       if( Header->Flags & TCP_FLAG_ACK )
-                       {       
-                               Log_Log("TCP", "ACKing SYN-ACK");
-                               Connection->State = TCP_ST_OPEN;
-                       }
-                       else
-                       {
-                               Log_Log("TCP", "ACKing SYN");
-                               Connection->State = TCP_ST_SYN_RCVD;
-                       }
-               }
-               break;
-       
-       // SYN-ACK sent, expecting ACK
-       case TCP_ST_SYN_RCVD:
-               if( Header->Flags & TCP_FLAG_ACK )
-               {
-                       // TODO: Handle max half-open limit
-                       Connection->State = TCP_ST_OPEN;
-                       Log_Log("TCP", "Connection fully opened");
-               }
-               break;
-               
-       // --- Established State ---
-       case TCP_ST_OPEN:
-               // - Handle State changes
-               //
-               if( Header->Flags & TCP_FLAG_FIN ) {
-                       Log_Log("TCP", "Conn %p closed, recieved FIN", Connection);
-                       VFS_MarkError(&Connection->Node, 1);
-                       Connection->State = TCP_ST_CLOSE_WAIT;
-//                     Header->Flags &= ~TCP_FLAG_FIN;
-                       // CLOSE WAIT requires the client to close (or does it?)
-                       #if 0
-                       
-                       #endif
-               }
-       
-               // Check for an empty packet
-               if(dataLen == 0) {
-                       if( Header->Flags == TCP_FLAG_ACK )
-                       {
-                               Log_Log("TCP", "ACK only packet");
-                               return ;
-                       }
-                       Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte)
-                       Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
-                       Header->DestPort = Header->SourcePort;
-                       Header->SourcePort = htons(Connection->LocalPort);
-                       Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
-                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
-                       Header->Flags |= TCP_FLAG_ACK;
-                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
-                       return ;
-               }
-               
-               // NOTES:
-               // Flags
-               //    PSH - Has Data?
-               // /NOTES
-               
-               sequence_num = ntohl(Header->SequenceNumber);
-               
-               Log_Log("TCP", "0x%08x <= 0x%08x < 0x%08x",
-                       Connection->NextSequenceRcv,
-                       ntohl(Header->SequenceNumber),
-                       Connection->NextSequenceRcv + TCP_WINDOW_SIZE
-                       );
-               
-               // Is this packet the next expected packet?
-               if( sequence_num == Connection->NextSequenceRcv )
-               {
-                        int    rv;
-                       // Ooh, Goodie! Add it to the recieved list
-                       rv = TCP_INT_AppendRecieved(Connection,
-                               (Uint8*)Header + (Header->DataOffset>>4)*4,
-                               dataLen
-                               );
-                       if(rv != 0) {
-                               break;
-                       }
-                       Log_Log("TCP", "0x%08x += %i", Connection->NextSequenceRcv, dataLen);
-                       Connection->NextSequenceRcv += dataLen;
-                       
-                       // TODO: This should be moved out of the watcher thread,
-                       // so that a single lost packet on one connection doesn't cause
-                       // all connections on the interface to lag.
-                       // - Meh, no real issue, as the cache shouldn't be that large
-                       TCP_INT_UpdateRecievedFromFuture(Connection);
-               
-                       // ACK Packet
-                       Header->DestPort = Header->SourcePort;
-                       Header->SourcePort = htons(Connection->LocalPort);
-                       Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
-                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
-                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
-                       Header->Flags &= TCP_FLAG_SYN;  // Eliminate all flags save for SYN
-                       Header->Flags |= TCP_FLAG_ACK;  // Add ACK
-                       Log_Log("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv);
-                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
-                       //Connection->NextSequenceSend ++;
-               }
-               // Check if the packet is in window
-               else if( WrapBetween(Connection->NextSequenceRcv, sequence_num,
-                               Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) )
-               {
-                       Uint8   *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4;
-                       #if CACHE_FUTURE_PACKETS_IN_BYTES
-                       Uint32  index;
-                        int    i;
-                       
-                       index = sequence_num % TCP_WINDOW_SIZE;
-                       for( i = 0; i < dataLen; i ++ )
-                       {
-                               Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8);
-                               Connection->FuturePacketData[index] = dataptr[i];
-                               // Do a wrap increment
-                               index ++;
-                               if(index == TCP_WINDOW_SIZE)    index = 0;
-                       }
-                       #else
-                       tTCPStoredPacket        *pkt, *tmp, *prev = NULL;
-                       
-                       // Allocate and fill cached packet
-                       pkt = malloc( sizeof(tTCPStoredPacket) + dataLen );
-                       pkt->Next = NULL;
-                       pkt->Sequence = ntohl(Header->SequenceNumber);
-                       pkt->Length = dataLen;
-                       memcpy(pkt->Data, dataptr, dataLen);
-                       
-                       Log_Log("TCP", "We missed a packet, caching",
-                               pkt->Sequence, Connection->NextSequenceRcv);
-                       
-                       // No? Well, let's cache it and look at it later
-                       SHORTLOCK( &Connection->lFuturePackets );
-                       for(tmp = Connection->FuturePackets;
-                               tmp;
-                               prev = tmp, tmp = tmp->Next)
-                       {
-                               if(tmp->Sequence >= pkt->Sequence)      break;
-                       }
-                       
-                       // Add if before first, or sequences don't match 
-                       if( !tmp || tmp->Sequence != pkt->Sequence )
-                       {
-                               if(prev)
-                                       prev->Next = pkt;
-                               else
-                                       Connection->FuturePackets = pkt;
-                               pkt->Next = tmp;
-                       }
-                       // Replace if larger
-                       else if(pkt->Length > tmp->Length)
-                       {
-                               if(prev)
-                                       prev->Next = pkt;
-                               pkt->Next = tmp->Next;
-                               free(tmp);
-                       }
-                       else
-                       {
-                               free(pkt);      // TODO: Find some way to remove this
-                       }
-                       SHORTREL( &Connection->lFuturePackets );
-                       #endif
-               }
-               // Badly out of sequence packet
-               else
-               {
-                       Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped",
-                               sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE);
-                       // TODO: Spec says we should send an empty ACK with the current state
-               }
-               break;
-       
-       // --- Remote close states
-       case TCP_ST_CLOSE_WAIT:
-               
-               // Ignore everything, CLOSE_WAIT is terminated by the client
-               Log_Debug("TCP", "CLOSE WAIT - Ignoring packets");
-               
-               break;
-       
-       // LAST-ACK - Waiting for the ACK of FIN (from CLOSE WAIT)
-       case TCP_ST_LAST_ACK:
-               if( Header->Flags & TCP_FLAG_ACK )
-               {
-                       Connection->State = TCP_ST_FINISHED;    // Connection completed
-                       Log_Log("TCP", "LAST-ACK to CLOSED - Connection remote closed");
-                       // TODO: Destrory the TCB
-               }
-               break;
-       
-       // --- Local close States
-       case TCP_ST_FIN_WAIT1:
-               if( Header->Flags & TCP_FLAG_FIN )
-               {
-                       Connection->State = TCP_ST_CLOSING;
-                       Log_Debug("TCP", "Conn %p closed, sent FIN and recieved FIN", Connection);
-                       VFS_MarkError(&Connection->Node, 1);
-                       
-                       // ACK Packet
-                       Header->DestPort = Header->SourcePort;
-                       Header->SourcePort = htons(Connection->LocalPort);
-                       Header->AcknowlegementNumber = Header->SequenceNumber;
-                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
-                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
-                       Header->Flags = TCP_FLAG_ACK;
-                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
-                       break ;
-               }
-               
-               // TODO: Make sure that the packet is actually ACKing the FIN
-               if( Header->Flags & TCP_FLAG_ACK )
-               {
-                       Connection->State = TCP_ST_FIN_WAIT2;
-                       Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection);
-                       VFS_MarkError(&Connection->Node, 1);
-                       return ;
-               }
-               break;
-       
-       case TCP_ST_FIN_WAIT2:
-               if( Header->Flags & TCP_FLAG_FIN )
-               {
-                       Connection->State = TCP_ST_TIME_WAIT;
-                       Log_Debug("TCP", "FIN sent and recieved, ACKing and going into TIME WAIT %p FINWAIT-2 -> TIME WAIT", Connection);
-                       // Send ACK
-                       Header->DestPort = Header->SourcePort;
-                       Header->SourcePort = htons(Connection->LocalPort);
-                       Header->AcknowlegementNumber = Header->SequenceNumber;
-                       Header->SequenceNumber = htonl(Connection->NextSequenceSend);
-                       Header->WindowSize = htons(TCP_WINDOW_SIZE);
-                       Header->Flags = TCP_FLAG_ACK;
-                       TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
-               }
-               break;
-       
-       case TCP_ST_CLOSING:
-               // TODO: Make sure that the packet is actually ACKing the FIN
-               if( Header->Flags & TCP_FLAG_ACK )
-               {
-                       Connection->State = TCP_ST_TIME_WAIT;
-                       Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection);
-                       VFS_MarkError(&Connection->Node, 1);
-                       return ;
-               }
-               break;
-       
-       // --- Closed (or near closed) states) ---
-       case TCP_ST_TIME_WAIT:
-               Log_Log("TCP", "Packets on Time-Wait, ignored");
-               break;
-       
-       case TCP_ST_FINISHED:
-               Log_Log("TCP", "Packets when CLOSED, ignoring");
-               break;
-       
-       //default:
-       //      Log_Warning("TCP", "Unhandled TCP state %i", Connection->State);
-       //      break;
-       }
-       
-}
-
-/**
- * \brief Appends a packet to the recieved list
- * \param Connection   Connection structure
- * \param Data Packet contents
- * \param Length       Length of \a Data
- */
-int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length)
-{
-       Mutex_Acquire( &Connection->lRecievedPackets );
-
-       if(Connection->RecievedBuffer->Length + Length > Connection->RecievedBuffer->Space )
-       {
-               VFS_MarkAvaliable(&Connection->Node, 1);
-               Log_Error("TCP", "Buffer filled, packet dropped (:%i) - %i + %i > %i",
-                       Connection->LocalPort, Connection->RecievedBuffer->Length, Length,
-                       Connection->RecievedBuffer->Space
-                       );
-               Mutex_Release( &Connection->lRecievedPackets );
-               return 1;
-       }
-       
-       RingBuffer_Write( Connection->RecievedBuffer, Data, Length );
-
-       VFS_MarkAvaliable(&Connection->Node, 1);
-       
-       Mutex_Release( &Connection->lRecievedPackets );
-       return 0;
-}
-
-/**
- * \brief Updates the connections recieved list from the future list
- * \param Connection   Connection structure
- * 
- * Updates the recieved packets list with packets from the future (out 
- * of order) packets list that are now able to be added in direct
- * sequence.
- */
-void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
-{
-       #if CACHE_FUTURE_PACKETS_IN_BYTES
-        int    i, length = 0;
-       Uint32  index;
-       
-       // Calculate length of contiguous bytes
-       length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
-       index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
-       for( i = 0; i < length; i ++ )
-       {
-               if( Connection->FuturePacketValidBytes[i / 8] == 0xFF ) {
-                       i += 7; index += 7;
-                       continue;
-               }
-               else if( !(Connection->FuturePacketValidBytes[i / 8] & (1 << (i%8))) )
-                       break;
-               
-               index ++;
-               if(index > TCP_WINDOW_SIZE)
-                       index -= TCP_WINDOW_SIZE;
-       }
-       length = i;
-       
-       index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
-       
-       // Write data to to the ring buffer
-       if( TCP_WINDOW_SIZE - index > length )
-       {
-               // Simple case
-               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length );
-       }
-       else
-       {
-                int    endLen = TCP_WINDOW_SIZE - index;
-               // 2-part case
-               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, endLen );
-               RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - length );
-       }
-       
-       // Mark (now saved) bytes as invalid
-       // - Align index
-       while(index % 8 && length)
-       {
-               Connection->FuturePacketData[index] = 0;
-               Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
-               index ++;
-               if(index > TCP_WINDOW_SIZE)
-                       index -= TCP_WINDOW_SIZE;
-               length --;
-       }
-       while( length > 7 )
-       {
-               Connection->FuturePacketData[index] = 0;
-               Connection->FuturePacketValidBytes[index/8] = 0;
-               length -= 8;
-               index += 8;
-               if(index > TCP_WINDOW_SIZE)
-                       index -= TCP_WINDOW_SIZE;
-       }
-       while(length)
-       {
-               Connection->FuturePacketData[index] = 0;
-               Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
-               index ++;
-               if(index > TCP_WINDOW_SIZE)
-                       index -= TCP_WINDOW_SIZE;
-               length --;
-       }
-       
-       #else
-       tTCPStoredPacket        *pkt;
-       for(;;)
-       {
-               SHORTLOCK( &Connection->lFuturePackets );
-               
-               // Clear out duplicates from cache
-               // - If a packet has just been recieved, and it is expected, then
-               //   (since NextSequenceRcv = rcvd->Sequence + rcvd->Length) all
-               //   packets in cache that are smaller than the next expected
-               //   are now defunct.
-               pkt = Connection->FuturePackets;
-               while(pkt && pkt->Sequence < Connection->NextSequenceRcv)
-               {
-                       tTCPStoredPacket        *next = pkt->Next;
-                       free(pkt);
-                       pkt = next;
-               }
-               
-               // If there's no packets left in cache, stop looking
-               if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) {
-                       SHORTREL( &Connection->lFuturePackets );
-                       return;
-               }
-               
-               // Delete packet from future list
-               Connection->FuturePackets = pkt->Next;
-               
-               // Release list
-               SHORTREL( &Connection->lFuturePackets );
-               
-               // Looks like we found one
-               TCP_INT_AppendRecieved(Connection, pkt);
-               Connection->NextSequenceRcv += pkt->Length;
-               free(pkt);
-       }
-       #endif
-}
-
-/**
- * \fn Uint16 TCP_GetUnusedPort()
- * \brief Gets an unused port and allocates it
- */
-Uint16 TCP_GetUnusedPort()
-{
-       Uint16  ret;
-
-       // Get Next outbound port
-       ret = giTCP_NextOutPort++;
-       while( gaTCP_PortBitmap[ret/32] & (1UL << (ret%32)) )
-       {
-               ret ++;
-               giTCP_NextOutPort++;
-               if(giTCP_NextOutPort == 0x10000) {
-                       ret = giTCP_NextOutPort = TCP_MIN_DYNPORT;
-               }
-       }
-
-       // Mark the new port as used
-       gaTCP_PortBitmap[ret/32] |= 1 << (ret%32);
-
-       return ret;
-}
-
-/**
- * \fn int TCP_AllocatePort(Uint16 Port)
- * \brief Marks a port as used
- */
-int TCP_AllocatePort(Uint16 Port)
-{
-       // Check if the port has already been allocated
-       if( gaTCP_PortBitmap[Port/32] & (1 << (Port%32)) )
-               return 0;
-
-       // Allocate
-       gaTCP_PortBitmap[Port/32] |= 1 << (Port%32);
-
-       return 1;
-}
-
-/**
- * \fn int TCP_DeallocatePort(Uint16 Port)
- * \brief Marks a port as unused
- */
-int TCP_DeallocatePort(Uint16 Port)
-{
-       // Check if the port has already been allocated
-       if( !(gaTCP_PortBitmap[Port/32] & (1 << (Port%32))) )
-               return 0;
-
-       // Allocate
-       gaTCP_PortBitmap[Port/32] &= ~(1 << (Port%32));
-
-       return 1;
-}
-
-// --- Server
-tVFS_Node *TCP_Server_Init(tInterface *Interface)
-{
-       tTCPListener    *srv;
-       
-       srv = calloc( 1, sizeof(tTCPListener) );
-
-       if( srv == NULL ) {
-               Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
-               return NULL;
-       }
-
-       srv->Interface = Interface;
-       srv->Port = 0;
-       srv->NextID = 0;
-       srv->Connections = NULL;
-       srv->ConnectionsTail = NULL;
-       srv->NewConnections = NULL;
-       srv->Next = NULL;
-       srv->Node.Flags = VFS_FFLAG_DIRECTORY;
-       srv->Node.Size = -1;
-       srv->Node.ImplPtr = srv;
-       srv->Node.NumACLs = 1;
-       srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       srv->Node.Type = &gTCP_ServerNodeType;
-
-       SHORTLOCK(&glTCP_Listeners);
-       srv->Next = gTCP_Listeners;
-       gTCP_Listeners = srv;
-       SHORTREL(&glTCP_Listeners);
-
-       return &srv->Node;
-}
-
-/**
- * \brief Wait for a new connection and return the connection ID
- * \note Blocks until a new connection is made
- * \param Node Server node
- * \param Pos  Position (ignored)
- */
-char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tTCPListener    *srv = Node->ImplPtr;
-       tTCPConnection  *conn;
-       char    *ret;
-       
-       ENTER("pNode iPos", Node, Pos);
-
-       Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID());
-       for(;;)
-       {
-               SHORTLOCK( &srv->lConnections );
-               if( srv->NewConnections != NULL )       break;
-               SHORTREL( &srv->lConnections );
-               Threads_Yield();        // TODO: Sleep until poked
-       }
-       
-
-       // Increment the new list (the current connection is still on the 
-       // normal list)
-       conn = srv->NewConnections;
-       srv->NewConnections = conn->Next;
-
-       if( srv->NewConnections == NULL )
-               VFS_MarkAvaliable( Node, 0 );
-       
-       SHORTREL( &srv->lConnections );
-       
-       LOG("conn = %p", conn);
-       LOG("srv->Connections = %p", srv->Connections);
-       LOG("srv->NewConnections = %p", srv->NewConnections);
-       LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail);
-
-       ret = malloc(9);
-       itoa(ret, conn->Node.ImplInt, 16, 8, '0');
-       Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret);
-       LEAVE('s', ret);
-       return ret;
-}
-
-/**
- * \brief Gets a client connection node
- * \param Node Server node
- * \param Name Hexadecimal ID of the node
- */
-tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name)
-{
-       tTCPConnection  *conn;
-       tTCPListener    *srv = Node->ImplPtr;
-       char    tmp[9];
-        int    id = atoi(Name);
-       
-       ENTER("pNode sName", Node, Name);
-
-       // Check for a non-empty name
-       if( Name[0] ) 
-       {       
-               // Sanity Check
-               itoa(tmp, id, 16, 8, '0');
-               if(strcmp(tmp, Name) != 0) {
-                       LOG("'%s' != '%s' (%08x)", Name, tmp, id);
-                       LEAVE('n');
-                       return NULL;
-               }
-               
-               Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
-               Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
-               Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
-               
-               // Search
-               SHORTLOCK( &srv->lConnections );
-               for(conn = srv->Connections;
-                       conn;
-                       conn = conn->Next)
-               {
-                       LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
-                       if(conn->Node.ImplInt == id)    break;
-               }
-               SHORTREL( &srv->lConnections );
-
-               // If not found, ret NULL
-               if(!conn) {
-                       LOG("Connection %i not found", id);
-                       LEAVE('n');
-                       return NULL;
-               }
-       }
-       // Empty Name - Check for a new connection and if it's there, open it
-       else
-       {
-               SHORTLOCK( &srv->lConnections );
-               conn = srv->NewConnections;
-               if( conn != NULL )
-                       srv->NewConnections = conn->Next;
-               VFS_MarkAvaliable( Node, srv->NewConnections != NULL );
-               SHORTREL( &srv->lConnections );
-               if( !conn ) {
-                       LOG("No new connections");
-                       LEAVE('n');
-                       return NULL;
-               }
-       }
-               
-       // Return node
-       LEAVE('p', &conn->Node);
-       return &conn->Node;
-}
-
-/**
- * \brief Handle IOCtl calls
- */
-int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tTCPListener    *srv = Node->ImplPtr;
-
-       switch(ID)
-       {
-       case 4: // Get/Set Port
-               if(!Data)       // Get Port
-                       return srv->Port;
-
-               if(srv->Port)   // Wait, you can't CHANGE the port
-                       return -1;
-
-               if(!CheckMem(Data, sizeof(Uint16)))     // Sanity check
-                       return -1;
-
-               // Permissions check
-               if(Threads_GetUID() != 0
-               && *(Uint16*)Data != 0
-               && *(Uint16*)Data < 1024)
-                       return -1;
-
-               // TODO: Check if a port is in use
-
-               // Set Port
-               srv->Port = *(Uint16*)Data;
-               if(srv->Port == 0)      // Allocate a random port
-                       srv->Port = TCP_GetUnusedPort();
-               else    // Else, mark this as used
-                       TCP_AllocatePort(srv->Port);
-               
-               Log_Log("TCP", "Server %p listening on port %i", srv, srv->Port);
-               
-               return srv->Port;
-       }
-       return 0;
-}
-
-void TCP_Server_Close(tVFS_Node *Node)
-{
-       free(Node->ImplPtr);
-}
-
-// --- Client
-/**
- * \brief Create a client node
- */
-tVFS_Node *TCP_Client_Init(tInterface *Interface)
-{
-       tTCPConnection  *conn = calloc( sizeof(tTCPConnection) + TCP_WINDOW_SIZE + TCP_WINDOW_SIZE/8, 1 );
-
-       conn->State = TCP_ST_CLOSED;
-       conn->Interface = Interface;
-       conn->LocalPort = -1;
-       conn->RemotePort = -1;
-
-       conn->Node.ImplPtr = conn;
-       conn->Node.NumACLs = 1;
-       conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       conn->Node.Type = &gTCP_ClientNodeType;
-
-       conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
-       #if 0
-       conn->SentBuffer = RingBuffer_Create( TCP_SEND_BUFFER_SIZE );
-       Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name);
-       #endif
-       
-       #if CACHE_FUTURE_PACKETS_IN_BYTES
-       // Future recieved data (ahead of the expected sequence number)
-       conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection);
-       conn->FuturePacketValidBytes = conn->FuturePacketData + TCP_WINDOW_SIZE;
-       #endif
-
-       SHORTLOCK(&glTCP_OutbountCons);
-       conn->Next = gTCP_OutbountCons;
-       gTCP_OutbountCons = conn;
-       SHORTREL(&glTCP_OutbountCons);
-
-       return &conn->Node;
-}
-
-/**
- * \brief Wait for a packet and return it
- * \note If \a Length is smaller than the size of the packet, the rest
- *       of the packet's data will be discarded.
- */
-Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tTCPConnection  *conn = Node->ImplPtr;
-       size_t  len;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       LOG("conn = %p {State:%i}", conn, conn->State);
-       
-       // Check if connection is estabilishing
-       // - TODO: Sleep instead (maybe using VFS_SelectNode to wait for the
-       //   data to be availiable
-       while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
-               Threads_Yield();
-       
-       // If the conneciton is not open, then clean out the recieved buffer
-       if( conn->State != TCP_ST_OPEN )
-       {
-               Mutex_Acquire( &conn->lRecievedPackets );
-               len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
-               Mutex_Release( &conn->lRecievedPackets );
-               
-               if( len == 0 ) {
-                       VFS_MarkAvaliable(Node, 0);
-                       LEAVE('i', -1);
-                       return -1;
-               }
-               
-               LEAVE('i', len);
-               return len;
-       }
-       
-       // Wait
-       VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, NULL, "TCP_Client_Read");
-       
-       // Lock list and read as much as possible (up to `Length`)
-       Mutex_Acquire( &conn->lRecievedPackets );
-       len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
-       
-       if( len == 0 || conn->RecievedBuffer->Length == 0 ) {
-               LOG("Marking as none avaliable (len = %i)", len);
-               VFS_MarkAvaliable(Node, 0);
-       }
-               
-       // Release the lock (we don't need it any more)
-       Mutex_Release( &conn->lRecievedPackets );
-
-       LEAVE('i', len);
-       return len;
-}
-
-/**
- * \brief Send a data packet on a connection
- */
-void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const void *Data)
-{
-       char    buf[sizeof(tTCPHeader)+Length];
-       tTCPHeader      *packet = (void*)buf;
-       
-       packet->SourcePort = htons(Connection->LocalPort);
-       packet->DestPort = htons(Connection->RemotePort);
-       packet->DataOffset = (sizeof(tTCPHeader)/4)*16;
-       packet->WindowSize = htons(TCP_WINDOW_SIZE);
-       
-       packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
-       packet->SequenceNumber = htonl(Connection->NextSequenceSend);
-       packet->Flags = TCP_FLAG_PSH|TCP_FLAG_ACK;      // Hey, ACK if you can!
-       
-       memcpy(packet->Options, Data, Length);
-       
-       Log_Debug("TCP", "Send sequence 0x%08x", Connection->NextSequenceSend);
-#if HEXDUMP_OUTGOING
-       Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length);
-#endif
-       
-       TCP_SendPacket( Connection, sizeof(tTCPHeader)+Length, packet );
-       
-       Connection->NextSequenceSend += Length;
-}
-
-/**
- * \brief Send some bytes on a connection
- */
-Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tTCPConnection  *conn = Node->ImplPtr;
-       size_t  rem = Length;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-//     #if DEBUG
-//     Debug_HexDump("TCP_Client_Write: Buffer = ",
-//             Buffer, Length);
-//     #endif
-       
-       // Check if connection is open
-       while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
-               Threads_Yield();
-       
-       if( conn->State != TCP_ST_OPEN ) {
-               VFS_MarkError(Node, 1);
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       do
-       {
-                int    len = (rem < TCP_MAX_PACKET_SIZE) ? rem : TCP_MAX_PACKET_SIZE;
-               
-               #if 0
-               // Wait for space in the buffer
-               Semaphore_Signal( &Connection->SentBufferSpace, len );
-               
-               // Save data to buffer (and update the length read by the ammount written)
-               len = RingBuffer_Write( &Connection->SentBuffer, Buffer, len);
-               #endif
-               
-               // Send packet
-               TCP_INT_SendDataPacket(conn, len, Buffer);
-               
-               Buffer += len;
-               rem -= len;
-       } while( rem > 0 );
-       
-       LEAVE('i', Length);
-       return Length;
-}
-
-/**
- * \brief Open a connection to another host using TCP
- * \param Conn Connection structure
- */
-void TCP_StartConnection(tTCPConnection *Conn)
-{
-       tTCPHeader      hdr = {0};
-
-       Conn->State = TCP_ST_SYN_SENT;
-
-       hdr.SourcePort = htons(Conn->LocalPort);
-       hdr.DestPort = htons(Conn->RemotePort);
-       Conn->NextSequenceSend = rand();
-       hdr.SequenceNumber = htonl(Conn->NextSequenceSend);
-       hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4;
-       hdr.Flags = TCP_FLAG_SYN;
-       hdr.WindowSize = htons(TCP_WINDOW_SIZE);        // Max
-       hdr.Checksum = 0;       // TODO
-       
-       TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr );
-       
-       Conn->NextSequenceSend ++;
-       Conn->State = TCP_ST_SYN_SENT;
-
-       return ;
-}
-
-/**
- * \brief Control a client socket
- */
-int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tTCPConnection  *conn = Node->ImplPtr;
-       
-       ENTER("pNode iID pData", Node, ID, Data);
-
-       switch(ID)
-       {
-       case 4: // Get/Set local port
-               if(!Data)
-                       LEAVE_RET('i', conn->LocalPort);
-               if(conn->State != TCP_ST_CLOSED)
-                       LEAVE_RET('i', -1);
-               if(!CheckMem(Data, sizeof(Uint16)))
-                       LEAVE_RET('i', -1);
-
-               if(Threads_GetUID() != 0 && *(Uint16*)Data < 1024)
-                       LEAVE_RET('i', -1);
-
-               conn->LocalPort = *(Uint16*)Data;
-               LEAVE_RET('i', conn->LocalPort);
-
-       case 5: // Get/Set remote port
-               if(!Data)       LEAVE_RET('i', conn->RemotePort);
-               if(conn->State != TCP_ST_CLOSED)        LEAVE_RET('i', -1);
-               if(!CheckMem(Data, sizeof(Uint16)))     LEAVE_RET('i', -1);
-               conn->RemotePort = *(Uint16*)Data;
-               LEAVE_RET('i', conn->RemotePort);
-
-       case 6: // Set Remote IP
-               if( conn->State != TCP_ST_CLOSED )
-                       LEAVE_RET('i', -1);
-               if( conn->Interface->Type == 4 )
-               {
-                       if(!CheckMem(Data, sizeof(tIPv4)))      LEAVE_RET('i', -1);
-                       conn->RemoteIP.v4 = *(tIPv4*)Data;
-               }
-               else if( conn->Interface->Type == 6 )
-               {
-                       if(!CheckMem(Data, sizeof(tIPv6)))      LEAVE_RET('i', -1);
-                       conn->RemoteIP.v6 = *(tIPv6*)Data;
-               }
-               LEAVE_RET('i', 0);
-
-       case 7: // Connect
-               if(conn->LocalPort == 0xFFFF)
-                       conn->LocalPort = TCP_GetUnusedPort();
-               if(conn->RemotePort == -1)
-                       LEAVE_RET('i', 0);
-
-               {
-                       tTime   timeout_end = now() + conn->Interface->TimeoutDelay;
-       
-                       TCP_StartConnection(conn);
-                       // TODO: Wait for connection to open
-                       while( conn->State == TCP_ST_SYN_SENT && timeout_end > now() ) {
-                               Threads_Yield();
-                       }
-                       if( conn->State == TCP_ST_SYN_SENT )
-                               LEAVE_RET('i', 0);
-               }
-
-               LEAVE_RET('i', 1);
-       
-       // Get recieve buffer length
-       case 8:
-               LEAVE_RET('i', conn->RecievedBuffer->Length);
-       }
-
-       return 0;
-}
-
-void TCP_Client_Close(tVFS_Node *Node)
-{
-       tTCPConnection  *conn = Node->ImplPtr;
-       tTCPHeader      packet;
-       
-       ENTER("pNode", Node);
-       
-       if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_OPEN )
-       {
-               packet.SourcePort = htons(conn->LocalPort);
-               packet.DestPort = htons(conn->RemotePort);
-               packet.DataOffset = (sizeof(tTCPHeader)/4)*16;
-               packet.WindowSize = TCP_WINDOW_SIZE;
-               
-               packet.AcknowlegementNumber = 0;
-               packet.SequenceNumber = htonl(conn->NextSequenceSend);
-               packet.Flags = TCP_FLAG_FIN;
-               
-               TCP_SendPacket( conn, sizeof(tTCPHeader), &packet );
-       }
-       
-       switch( conn->State )
-       {
-       case TCP_ST_CLOSE_WAIT:
-               conn->State = TCP_ST_LAST_ACK;
-               break;
-       case TCP_ST_OPEN:
-               conn->State = TCP_ST_FIN_WAIT1;
-               while( conn->State == TCP_ST_FIN_WAIT1 )        Threads_Yield();
-               break;
-       default:
-               Log_Warning("TCP", "Unhandled connection state in TCP_Client_Close");
-               break;
-       }
-       
-       free(conn);
-       
-       LEAVE('-');
-}
-
-/**
- * \brief Checks if a value is between two others (after taking into account wrapping)
- */
-int WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue)
-{
-       if( MaxValue < 0xFFFFFFFF )
-       {
-               Lower %= MaxValue + 1;
-               Value %= MaxValue + 1;
-               Higher %= MaxValue + 1;
-       }
-       
-       // Simple Case, no wrap ?
-       //       Lower Value Higher
-       // | ... + ... + ... + ... |
-
-       if( Lower < Higher ) {
-               return Lower < Value && Value < Higher;
-       }
-       // Higher has wrapped below lower
-       
-       // Value > Lower ?
-       //       Higher Lower Value
-       // | ... +  ... + ... + ... |
-       if( Value > Lower ) {
-               return 1;
-       }
-       
-       // Value < Higher ?
-       //       Value Higher Lower
-       // | ... + ... +  ... + ... |
-       if( Value < Higher ) {
-               return 1;
-       }
-       
-       return 0;
-}
diff --git a/Modules/IPStack/tcp.h b/Modules/IPStack/tcp.h
deleted file mode 100644 (file)
index 6aa404f..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Acess2 IP Stack
- * - TCP Definitions
- */
-#ifndef _TCP_H_
-#define _TCP_H_
-
-#include "ipstack.h"
-#include <adt.h>       // tRingBuffer
-
-typedef struct sTCPHeader      tTCPHeader;
-typedef struct sTCPListener    tTCPListener;
-typedef struct sTCPStoredPacket        tTCPStoredPacket;
-typedef struct sTCPConnection  tTCPConnection;
-
-struct sTCPHeader
-{
-       Uint16  SourcePort;
-       Uint16  DestPort;
-       Uint32  SequenceNumber;
-       Uint32  AcknowlegementNumber;
-       #if 0
-       struct {        // Lowest to highest
-               unsigned Reserved:      4;
-               unsigned DataOffset: 4; // Size of the header in 32-bit words
-       } __attribute__ ((packed));
-       #else
-       Uint8   DataOffset;
-       #endif
-       #if 0
-       struct {        // Lowest to Highest
-               unsigned FIN:   1;      // Last packet
-               unsigned SYN:   1;      // Synchronise Sequence Numbers
-               unsigned RST:   1;      // Reset Connection
-               unsigned PSH:   1;      // Push Function
-               unsigned ACK:   1;      // Acknowlegement field is significant
-               unsigned URG:   1;      // Urgent pointer is significant
-               unsigned ECE:   1;      // ECN-Echo
-               unsigned CWR:   1;      // Congestion Window Reduced
-       } __attribute__ ((packed)) Flags;
-       #else
-       Uint8   Flags;
-       #endif
-       Uint16  WindowSize;
-       
-       Uint16  Checksum;
-       Uint16  UrgentPointer;
-       
-       Uint8   Options[];
-} __attribute__ ((packed));
-
-enum eTCPFlags
-{
-       TCP_FLAG_FIN    = 0x01,
-       TCP_FLAG_SYN    = 0x02,
-       TCP_FLAG_RST    = 0x04,
-       TCP_FLAG_PSH    = 0x08,
-       TCP_FLAG_ACK    = 0x10,
-       TCP_FLAG_URG    = 0x20,
-       TCP_FLAG_ECE    = 0x40,
-       TCP_FLAG_CWR    = 0x80
-};
-
-struct sTCPListener
-{
-       struct sTCPListener     *Next;  //!< Next server in the list
-       Uint16  Port;           //!< Listening port (0 disables the server)
-       tInterface      *Interface;     //!< Listening Interface
-       tVFS_Node       Node;   //!< Server Directory node
-        int    NextID;         //!< Name of the next connection
-       tShortSpinlock  lConnections;   //!< Spinlock for connections
-       tTCPConnection  *Connections;   //!< Connections (linked list)
-       tTCPConnection  *volatile NewConnections;
-       tTCPConnection  *ConnectionsTail;
-};
-
-struct sTCPStoredPacket
-{
-       struct sTCPStoredPacket *Next;
-       size_t  Length;
-       Uint32  Sequence;
-       Uint8   Data[];
-};
-
-enum eTCPConnectionState
-{
-       TCP_ST_CLOSED,          // 0 - Connection invalid
-       
-       TCP_ST_SYN_SENT,        // 1 - SYN sent by local, waiting for SYN-ACK
-       TCP_ST_SYN_RCVD,        // 2 - SYN recieved, SYN-ACK sent
-       
-       TCP_ST_OPEN,            // 3 - Connection open
-       
-       // Local Close
-       TCP_ST_FIN_WAIT1,       // 4 - FIN sent, waiting for reply (ACK or FIN)
-       TCP_ST_FIN_WAIT2,       // 5 - sent FIN acked, waiting for FIN from peer
-       TCP_ST_CLOSING,         // 6 - Waiting for ACK of FIN (FIN sent and recieved)
-       TCP_ST_TIME_WAIT,       // 7 - Waiting for timeout after local close
-       // Remote close
-       TCP_ST_CLOSE_WAIT,      // 8 - FIN recieved, waiting for user to close (error set, wait for node close)
-       TCP_ST_LAST_ACK,        // 9 - FIN sent and recieved, waiting for ACK
-       TCP_ST_FINISHED         // 10 - Essentially closed, all packets are invalid
-};
-
-struct sTCPConnection
-{
-       struct sTCPConnection   *Next;
-       enum eTCPConnectionState        State;  //!< Connection state (see ::eTCPConnectionState)
-       Uint16  LocalPort;      //!< Local port
-       Uint16  RemotePort;     //!< Remote port
-       tInterface      *Interface;     //!< Listening Interface
-       tVFS_Node       Node;   //!< Node
-       
-       Uint32  NextSequenceSend;       //!< Next sequence value for outbound packets
-       Uint32  NextSequenceRcv;        //!< Next expected sequence value for inbound
-       
-       #if 0
-       /**
-        * \brief Non-ACKed packets
-        * \note Ring buffer
-        * \{
-        */
-       tMutex  lNonACKedPackets;
-       tTCPStoredPacket        *SentPackets;   //!< Non-acknowleged packets
-       /**
-        * \}
-        */
-       #endif
-       
-       /**
-        * \brief Unread Packets
-        * \note Ring buffer
-        * \{
-        */
-       tMutex  lRecievedPackets;
-       tRingBuffer     *RecievedBuffer;
-       /**
-        * \}
-        */
-       
-       /**
-        * \brief Out of sequence packets
-        * \note Sorted list to improve times
-        * \todo Convert this to a ring buffer and a bitmap of valid bytes
-        * \{
-        */
-       #if CACHE_FUTURE_PACKETS_OR_BYTES == bytes
-       Uint32  HighestSequenceRcvd;    //!< Highest sequence number (within window) recieved
-       Uint8   *FuturePacketData;      //!< Future packet data (indexed by sequence number)
-       Uint8   *FuturePacketValidBytes;        //!< Valid byte bitmap (WINDOW_SIZE/8 bytes)
-       #else
-       tShortSpinlock  lFuturePackets; //!< Future packets spinlock
-       tTCPStoredPacket        *FuturePackets; //!< Out of sequence packets
-       #endif
-       /**
-        * \}
-        */
-       
-       union {
-               tIPv4   v4;
-               tIPv6   v6;
-       } RemoteIP;     //!< Remote IP Address
-       // Type is determined by LocalInterface->Type
-};
-
-#endif
diff --git a/Modules/IPStack/udp.c b/Modules/IPStack/udp.c
deleted file mode 100644 (file)
index cbdcd56..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Acess2 IP Stack
- * - UDP Handling
- */
-#include "ipstack.h"
-#include <api_drv_common.h>
-#include "udp.h"
-
-#define UDP_ALLOC_BASE 0xC000
-
-// === PROTOTYPES ===
-void   UDP_Initialise();
-void   UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
-void   UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
-void   UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length);
-// --- Client Channels
-tVFS_Node      *UDP_Channel_Init(tInterface *Interface);
-Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
- int   UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
-void   UDP_Channel_Close(tVFS_Node *Node);
-// --- Helpers
-Uint16 UDP_int_AllocatePort();
- int   UDP_int_MarkPortAsUsed(Uint16 Port);
-void   UDP_int_FreePort(Uint16 Port);
-
-// === GLOBALS ===
-tVFS_NodeType  gUDP_NodeType = {
-       .Read = UDP_Channel_Read,
-       .Write = UDP_Channel_Write,
-       .IOCtl = UDP_Channel_IOCtl,
-       .Close = UDP_Channel_Close
-};
-tMutex glUDP_Channels;
-tUDPChannel    *gpUDP_Channels;
-
-tMutex glUDP_Ports;
-Uint32 gUDP_Ports[0x10000/32];
-
-tSocketFile    gUDP_SocketFile = {NULL, "udp", UDP_Channel_Init};
-
-// === CODE ===
-/**
- * \fn void TCP_Initialise()
- * \brief Initialise the TCP Layer
- */
-void UDP_Initialise()
-{
-       IPStack_AddFile(&gUDP_SocketFile);
-       //IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_Unreachable);
-       IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket);
-}
-
-/**
- * \brief Scan a list of tUDPChannels and find process the first match
- * \return 0 if no match was found, -1 on error and 1 if a match was found
- */
-int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
-{
-       tUDPHeader      *hdr = Buffer;
-       tUDPChannel     *chan;
-       tUDPPacket      *pack;
-        int    len;
-       
-       for(chan = List;
-               chan;
-               chan = chan->Next)
-       {
-               // Match local endpoint
-               if(chan->Interface && chan->Interface != Interface)     continue;
-               if(chan->LocalPort != ntohs(hdr->DestPort))     continue;
-               
-               // Check for remote port restriction
-               if(chan->Remote.Port && chan->Remote.Port != ntohs(hdr->SourcePort))
-                       continue;
-               // Check for remote address restriction
-               if(chan->RemoteMask)
-               {
-                       if(chan->Remote.AddrType != Interface->Type)
-                               continue;
-                       if(!IPStack_CompareAddress(Interface->Type, Address,
-                               &chan->Remote.Addr, chan->RemoteMask)
-                               )
-                               continue;
-               }
-               
-               Log_Log("UDP", "Recieved packet for %p", chan);
-               // Create the cached packet
-               len = ntohs(hdr->Length);
-               pack = malloc(sizeof(tUDPPacket) + len);
-               pack->Next = NULL;
-               memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type));
-               pack->Remote.Port = ntohs(hdr->SourcePort);
-               pack->Remote.AddrType = Interface->Type;
-               pack->Length = len;
-               memcpy(pack->Data, hdr->Data, len);
-               
-               // Add the packet to the channel's queue
-               SHORTLOCK(&chan->lQueue);
-               if(chan->Queue)
-                       chan->QueueEnd->Next = pack;
-               else
-                       chan->QueueEnd = chan->Queue = pack;
-               SHORTREL(&chan->lQueue);
-               VFS_MarkAvaliable(&chan->Node, 1);
-               Mutex_Release(&glUDP_Channels);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
- * \brief Handles a packet from the IP Layer
- */
-void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
-{
-       tUDPHeader      *hdr = Buffer;
-       
-       Log_Debug("UDP", "hdr->SourcePort = %i", ntohs(hdr->SourcePort));
-       Log_Debug("UDP", "hdr->DestPort = %i", ntohs(hdr->DestPort));
-       Log_Debug("UDP", "hdr->Length = %i", ntohs(hdr->Length));
-       Log_Debug("UDP", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
-       
-       // Check registered connections
-       Mutex_Acquire(&glUDP_Channels);
-       UDP_int_ScanList(gpUDP_Channels, Interface, Address, Length, Buffer);
-       Mutex_Release(&glUDP_Channels);
-}
-
-/**
- * \brief Handle an ICMP Unrechable Error
- */
-void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
-{
-       
-}
-
-/**
- * \brief Send a packet
- * \param Channel      Channel to send the packet from
- * \param Data Packet data
- * \param Length       Length in bytes of packet data
- */
-void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length)
-{
-       tUDPHeader      *hdr;
-
-       if(Channel->Interface && Channel->Interface->Type != AddrType)  return ;
-       
-       switch(AddrType)
-       {
-       case 4:
-               // Create the packet
-               hdr = malloc(sizeof(tUDPHeader)+Length);
-               hdr->SourcePort = htons( Channel->LocalPort );
-               hdr->DestPort = htons( Port );
-               hdr->Length = htons( sizeof(tUDPHeader) + Length );
-               hdr->Checksum = 0;      // Checksum can be zero on IPv4
-               memcpy(hdr->Data, Data, Length);
-               // Pass on the the IPv4 Layer
-               // TODO: What if Channel->Interface is NULL here?
-               IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, sizeof(tUDPHeader)+Length, hdr);
-               // Free allocated packet
-               free(hdr);
-               break;
-       }
-}
-
-// --- Client Channels
-tVFS_Node *UDP_Channel_Init(tInterface *Interface)
-{
-       tUDPChannel     *new;
-       new = calloc( sizeof(tUDPChannel), 1 );
-       new->Interface = Interface;
-       new->Node.ImplPtr = new;
-       new->Node.NumACLs = 1;
-       new->Node.ACLs = &gVFS_ACL_EveryoneRW;
-       new->Node.Type = &gUDP_NodeType;
-       
-       Mutex_Acquire(&glUDP_Channels);
-       new->Next = gpUDP_Channels;
-       gpUDP_Channels = new;
-       Mutex_Release(&glUDP_Channels);
-       
-       return &new->Node;
-}
-
-/**
- * \brief Read from the channel file (wait for a packet)
- */
-Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tUDPChannel     *chan = Node->ImplPtr;
-       tUDPPacket      *pack;
-       tUDPEndpoint    *ep;
-        int    ofs, addrlen;
-       
-       if(chan->LocalPort == 0) {
-               Log_Notice("UDP", "Channel %p sent with no local port", chan);
-               return 0;
-       }
-       
-       while(chan->Queue == NULL)      Threads_Yield();
-       
-       for(;;)
-       {
-               VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "UDP_Channel_Read");
-               SHORTLOCK(&chan->lQueue);
-               if(chan->Queue == NULL) {
-                       SHORTREL(&chan->lQueue);
-                       continue;
-               }
-               pack = chan->Queue;
-               chan->Queue = pack->Next;
-               if(!chan->Queue) {
-                       chan->QueueEnd = NULL;
-                       VFS_MarkAvaliable(Node, 0);     // Nothing left
-               }
-               SHORTREL(&chan->lQueue);
-               break;
-       }
-
-       // Check that the header fits
-       addrlen = IPStack_GetAddressSize(pack->Remote.AddrType);
-       ep = Buffer;
-       ofs = 4 + addrlen;
-       if(Length < ofs) {
-               free(pack);
-               Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs);
-               return 0;
-       }
-       
-       // Fill header
-       ep->Port = pack->Remote.Port;
-       ep->AddrType = pack->Remote.AddrType;
-       memcpy(&ep->Addr, &pack->Remote.Addr, addrlen);
-       
-       // Copy packet data
-       if(Length > ofs + pack->Length) Length = ofs + pack->Length;
-       memcpy((char*)Buffer + ofs, pack->Data, Length - ofs);
-
-       // Free cached packet
-       free(pack);
-       
-       return Length;
-}
-
-/**
- * \brief Write to the channel file (send a packet)
- */
-Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tUDPChannel     *chan = Node->ImplPtr;
-       const tUDPEndpoint      *ep;
-       const void      *data;
-        int    ofs;
-       if(chan->LocalPort == 0)        return 0;
-       
-       ep = Buffer;    
-       ofs = 2 + 2 + IPStack_GetAddressSize( ep->AddrType );
-
-       data = (const char *)Buffer + ofs;
-
-       UDP_SendPacketTo(chan, ep->AddrType, &ep->Addr, ep->Port, data, (size_t)Length - ofs);
-       
-       return 0;
-}
-
-/**
- * \brief Names for channel IOCtl Calls
- */
-static const char *casIOCtls_Channel[] = {
-       DRV_IOCTLNAMES,
-       "getset_localport",
-       "getset_remoteport",
-       "getset_remotemask",
-       "set_remoteaddr",
-       NULL
-       };
-/**
- * \brief Channel IOCtls
- */
-int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tUDPChannel     *chan = Node->ImplPtr;
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_MISC, "UDP Channel", 0x100, casIOCtls_Channel);
-       
-       case 4: // getset_localport (returns bool success)
-               if(!Data)       LEAVE_RET('i', chan->LocalPort);
-               if(!CheckMem( Data, sizeof(Uint16) ) ) {
-                       LOG("Invalid pointer %p", Data);
-                       LEAVE_RET('i', -1);
-               }
-               // Set port
-               chan->LocalPort = *(Uint16*)Data;
-               // Permissions check (Ports lower than 1024 are root-only)
-               if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
-                       if( Threads_GetUID() != 0 ) {
-                               LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
-                               chan->LocalPort = 0;
-                               LEAVE_RET('i', -1);
-                       }
-               }
-               // Allocate a random port if requested
-               if( chan->LocalPort == 0 )
-                       chan->LocalPort = UDP_int_AllocatePort();
-               else
-               {
-                       // Else, mark the requested port as used
-                       if( UDP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
-                               LOG("Port %i us currently in use", chan->LocalPort);
-                               chan->LocalPort = 0;
-                               LEAVE_RET('i', 0);
-                       }
-                       LEAVE_RET('i', 1);
-               }
-               LEAVE_RET('i', 1);
-       
-       case 5: // getset_remoteport (returns bool success)
-               if(!Data)       LEAVE_RET('i', chan->Remote.Port);
-               if(!CheckMem( Data, sizeof(Uint16) ) ) {
-                       LOG("Invalid pointer %p", Data);
-                       LEAVE_RET('i', -1);
-               }
-               chan->Remote.Port = *(Uint16*)Data;
-               return 1;
-       
-       case 6: // getset_remotemask (returns bool success)
-               if(!Data)       LEAVE_RET('i', chan->RemoteMask);
-               if(!CheckMem(Data, sizeof(int)))        LEAVE_RET('i', -1);
-               if( !chan->Interface ) {
-                       LOG("Can't set remote mask on NULL interface");
-                       LEAVE_RET('i', -1);
-               }
-               if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) )
-                       LEAVE_RET('i', -1);
-               chan->RemoteMask = *(int*)Data;
-               return 1;       
-
-       case 7: // set_remoteaddr (returns bool success)
-               if( !chan->Interface ) {
-                       LOG("Can't set remote address on NULL interface");
-                       LEAVE_RET('i', -1);
-               }
-               if(!CheckMem(Data, IPStack_GetAddressSize(chan->Interface->Type))) {
-                       LOG("Invalid pointer");
-                       LEAVE_RET('i', -1);
-               }
-               memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type));
-               return 0;
-       }
-       LEAVE_RET('i', 0);
-}
-
-/**
- * \brief Close and destroy an open channel
- */
-void UDP_Channel_Close(tVFS_Node *Node)
-{
-       tUDPChannel     *chan = Node->ImplPtr;
-       tUDPChannel     *prev;
-       
-       // Remove from the main list first
-       Mutex_Acquire(&glUDP_Channels);
-       if(gpUDP_Channels == chan)
-               gpUDP_Channels = gpUDP_Channels->Next;
-       else
-       {
-               for(prev = gpUDP_Channels;
-                       prev->Next && prev->Next != chan;
-                       prev = prev->Next);
-               if(!prev->Next)
-                       Log_Warning("UDP", "Bookeeping Fail, channel %p is not in main list", chan);
-               else
-                       prev->Next = prev->Next->Next;
-       }
-       Mutex_Release(&glUDP_Channels);
-       
-       // Clear Queue
-       SHORTLOCK(&chan->lQueue);
-       while(chan->Queue)
-       {
-               tUDPPacket      *tmp;
-               tmp = chan->Queue;
-               chan->Queue = tmp->Next;
-               free(tmp);
-       }
-       SHORTREL(&chan->lQueue);
-       
-       // Free channel structure
-       free(chan);
-}
-
-/**
- * \return Port Number on success, or zero on failure
- */
-Uint16 UDP_int_AllocatePort()
-{
-        int    i;
-       Mutex_Acquire(&glUDP_Ports);
-       // Fast Search
-       for( i = UDP_ALLOC_BASE; i < 0x10000; i += 32 )
-               if( gUDP_Ports[i/32] != 0xFFFFFFFF )
-                       break;
-       if(i == 0x10000)        return 0;
-       for( ;; i++ )
-       {
-               if( !(gUDP_Ports[i/32] & (1 << (i%32))) )
-                       return i;
-       }
-       Mutex_Release(&glUDP_Ports);
-}
-
-/**
- * \brief Allocate a specific port
- * \return Boolean Success
- */
-int UDP_int_MarkPortAsUsed(Uint16 Port)
-{
-       Mutex_Acquire(&glUDP_Ports);
-       if( gUDP_Ports[Port/32] & (1 << (Port%32)) ) {
-               return 0;
-               Mutex_Release(&glUDP_Ports);
-       }
-       gUDP_Ports[Port/32] |= 1 << (Port%32);
-       Mutex_Release(&glUDP_Ports);
-       return 1;
-}
-
-/**
- * \brief Free an allocated port
- */
-void UDP_int_FreePort(Uint16 Port)
-{
-       Mutex_Acquire(&glUDP_Ports);
-       gUDP_Ports[Port/32] &= ~(1 << (Port%32));
-       Mutex_Release(&glUDP_Ports);
-}
diff --git a/Modules/IPStack/udp.h b/Modules/IPStack/udp.h
deleted file mode 100644 (file)
index 3914789..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Acess2 IP Stack
- * - UDP Definitions
- */
-#ifndef _UDP_H_
-#define _UDP_H_
-
-#include "ipstack.h"
-#include "ipv4.h"
-
-typedef struct sUDPHeader      tUDPHeader;
-typedef struct sUDPEndpoint    tUDPEndpoint;
-typedef struct sUDPPacket      tUDPPacket;
-typedef struct sUDPChannel     tUDPChannel;
-
-struct sUDPHeader
-{
-       Uint16  SourcePort;
-       Uint16  DestPort;
-       Uint16  Length;
-       Uint16  Checksum;
-       Uint8   Data[];
-};
-
-struct sUDPEndpoint
-{
-       Uint16  Port;
-       Uint16  AddrType;
-       union {
-               tIPv4   v4;
-               tIPv6   v6;
-       }       Addr;
-};
-
-struct sUDPPacket
-{
-       struct sUDPPacket       *Next;
-       tUDPEndpoint    Remote;
-       size_t  Length;
-       Uint8   Data[];
-};
-
-struct sUDPChannel
-{
-       struct sUDPChannel      *Next;
-       tInterface      *Interface;
-       Uint16  LocalPort;
-
-       tUDPEndpoint    Remote; // Only accept packets form this address/port pair
-        int    RemoteMask;     // Mask on the address
-       
-       tVFS_Node       Node;
-       tShortSpinlock  lQueue;
-       tUDPPacket      * volatile Queue;
-       tUDPPacket      *QueueEnd;
-};
-
-#endif
-
diff --git a/Modules/Input/Makefile.tpl b/Modules/Input/Makefile.tpl
deleted file mode 100644 (file)
index c36c928..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = Input
-
--include ../../Makefile.tpl
diff --git a/Modules/Input/PS2KbMouse/8042.c b/Modules/Input/PS2KbMouse/8042.c
deleted file mode 100644 (file)
index e11bc74..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Acess2
- * - By thePowersGang (John Hodge)
- *
- * 8042 (or comaptible) Driver
- */
-#include <acess.h>
-#include "common.h"
-
-// === PROTOTYPES ===
-void   KBC8042_Init(void);
-void   KBC8042_KeyboardHandler(int IRQ, void *Ptr);
-void   KBC8042_MouseHandler(int IRQ, void *Ptr);
-void   KBC8042_EnableMouse(void);
-static inline void     KBC8042_SendDataAlt(Uint8 data);
-static inline void     KBC8042_SendData(Uint8 data);
-static inline Uint8    KBC8042_ReadData(void);
-static void    KBC8042_SendMouseCommand(Uint8 cmd);
-
-// === CODE ===
-void KBC8042_Init(void)
-{
-       IRQ_AddHandler(1, KBC8042_KeyboardHandler, NULL);
-       IRQ_AddHandler(12, KBC8042_MouseHandler, NULL); // Set IRQ
-       
-       {
-               Uint8   temp;
-               // Attempt to get around a strange bug in Bochs/Qemu by toggling
-               // the controller on and off
-               temp = inb(0x61);
-               outb(0x61, temp | 0x80);
-               outb(0x61, temp & 0x7F);
-               inb(0x60);      // Clear keyboard buffer
-       }
-}
-
-void KBC8042_KeyboardHandler(int IRQ, void *Ptr)
-{
-       Uint8   scancode;
-
-//     Log("KBC8042_KeyboardHandler: (IRQ=%i, Ptr=%p)", IRQ, Ptr);
-
-       scancode = inb(0x60);
-       KB_HandleScancode( scancode );
-}
-
-void KBC8042_MouseHandler(int IRQ, void *Ptr)
-{
-       PS2Mouse_HandleInterrupt( inb(0x60) );
-}
-
-void KBC8042_SetLEDs(Uint8 leds)
-{
-       while( inb(0x64) & 2 ); // Wait for bit 2 to unset
-       outb(0x60, 0xED);       // Send update command
-
-       while( inb(0x64) & 2 ); // Wait for bit 2 to unset
-       outb(0x60, leds);
-}
-
-void KBC8042_EnableMouse(void)
-{
-       Uint8   status;
-       Log_Log("8042", "Enabling Mouse...");
-       
-       // Enable AUX PS/2
-       KBC8042_SendDataAlt(0xA8);
-       
-       // Enable AUX PS/2 (Compaq Status Byte)
-       KBC8042_SendDataAlt(0x20);      // Send Command
-       status = KBC8042_ReadData();    // Get Status
-       status &= ~0x20;        // Clear "Disable Mouse Clock"
-       status |= 0x02;         // Set IRQ12 Enable
-       KBC8042_SendDataAlt(0x60);      // Send Command
-       KBC8042_SendData(status);       // Set Status
-       
-       //mouseSendCommand(0xF6);       // Set Default Settings
-       KBC8042_SendMouseCommand(0xF4); // Enable Packets
-}
-
-static inline void KBC8042_SendDataAlt(Uint8 data)
-{
-       int timeout=100000;
-       while( timeout-- && inb(0x64) & 2 );    // Wait for Flag to clear
-       outb(0x64, data);       // Send Command
-}
-static inline void KBC8042_SendData(Uint8 data)
-{
-       int timeout=100000;
-       while( timeout-- && inb(0x64) & 2 );    // Wait for Flag to clear
-       outb(0x60, data);       // Send Command
-}
-static inline Uint8 KBC8042_ReadData(void)
-{
-       int timeout=100000;
-       while( timeout-- && (inb(0x64) & 1) == 0);      // Wait for Flag to set
-       return inb(0x60);
-}
-static inline void KBC8042_SendMouseCommand(Uint8 cmd)
-{
-       KBC8042_SendDataAlt(0xD4);
-       KBC8042_SendData(cmd);
-}
-
diff --git a/Modules/Input/PS2KbMouse/Makefile b/Modules/Input/PS2KbMouse/Makefile
deleted file mode 100644 (file)
index 306e2b4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#
-
-OBJ = main.o kb.o ps2mouse.o
-OBJ += 8042.o pl050.o
-NAME = PS2KbMouse
-
--include ../Makefile.tpl
diff --git a/Modules/Input/PS2KbMouse/common.h b/Modules/Input/PS2KbMouse/common.h
deleted file mode 100644 (file)
index 7cbffe9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Acess2
- * 
- * PS2 Keyboard/Mouse Driver
- *
- * common.h
- * - Shared definitions
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-extern int     KB_Install(char **Arguments);
-extern int     PS2Mouse_Install(char **Arguments);
-
-extern void    KBC8042_Init(void);
-extern void    KBC8042_EnableMouse(void);
-
-extern void    PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ);
-extern void    PL050_EnableMouse(void);
-
-extern void    KB_HandleScancode(Uint8 scancode);
-extern void    PS2Mouse_HandleInterrupt(Uint8 InputByte);
-
-extern void    (*gpMouse_EnableFcn)(void);
-
-#endif
diff --git a/Modules/Input/PS2KbMouse/kb.c b/Modules/Input/PS2KbMouse/kb.c
deleted file mode 100644 (file)
index a121b61..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Acess2
- * PS2 Keyboard Driver
- */
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <api_drv_common.h>
-#include <api_drv_keyboard.h>
-#include "kb_kbdus.h"
-
-// === CONSTANTS ===
-#define        KB_BUFFER_SIZE  1024
-#define        USE_KERNEL_MAGIC        1
-
-// === IMPORTS ===
-extern void    Threads_ToggleTrace(int TID);
-extern void    Threads_Dump(void);
-extern void    Heap_Stats(void);
-
-// === PROTOTYPES ===
- int   KB_Install(char **Arguments);
-void   KB_HandleScancode(Uint8 scancode);
-void   KB_UpdateLEDs(void);
- int   KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
-
-// === GLOBALS ===
-tVFS_NodeType  gKB_NodeType = {
-       .IOCtl = KB_IOCtl
-};
-tDevFS_Driver  gKB_DevInfo = {
-       NULL, "PS2Keyboard",
-       { .Type = &gKB_NodeType }
-};
-tKeybardCallback       gKB_Callback = NULL;
-Uint32 **gpKB_Map = gpKBDUS;
-Uint8  gbaKB_States[3][256];
- int   gbKB_ShiftState = 0;
- int   gbKB_CapsState = 0;
- int   gbKB_KeyUp = 0;
- int   giKB_KeyLayer = 0;
-#if USE_KERNEL_MAGIC
- int   gbKB_MagicState = 0;
- int   giKB_MagicAddress = 0;
- int   giKB_MagicAddressPos = 0;
-#endif
-
-// === CODE ===
-/**
- * \brief Install the keyboard driver
- */
-int KB_Install(char **Arguments)
-{
-       DevFS_AddDevice( &gKB_DevInfo );
-       //Log("KB_Install: Installed");
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Called on a keyboard IRQ
- * \param IRQNum       IRQ number (unused)
- */
-void KB_HandleScancode(Uint8 scancode)
-{
-       Uint32  ch;
-        int    bCaseSwitch = (gbKB_ShiftState != 0) != (gbKB_CapsState != 0);
-
-       //Log_Debug("Keyboard", "scancode = %02x", scancode);
-
-       // Ignore ACKs
-       if(scancode == 0xFA) {
-               // Oh man! This is anarchic (I'm leaving it here to represent
-               // the mess that Acess once was)
-               //kb_lastChar = KB_ACK;
-               return;
-       }
-
-       // Layer +1
-       if(scancode == 0xE0) {
-               giKB_KeyLayer = 1;
-               return;
-       }
-       // Layer +2
-       if(scancode == 0xE1) {
-               giKB_KeyLayer = 2;
-               return;
-       }
-
-       #if KB_ALT_SCANCODES
-       if(scancode == 0xF0)
-       {
-               gbKB_KeyUp = 1;
-               return;
-       }
-       #else
-       if(scancode & 0x80)
-       {
-               scancode &= 0x7F;
-               gbKB_KeyUp = 1;
-       }
-       #endif
-       
-       if( gKB_Callback )
-               gKB_Callback( (giKB_KeyLayer << 8) | scancode | KEY_ACTION_RAWSYM );
-
-       // Translate
-       ch = gpKB_Map[giKB_KeyLayer*2+bCaseSwitch][scancode];
-       // - Unknown characters in the shift layer fall through to lower
-       if(bCaseSwitch && ch == 0)
-               ch = gpKB_Map[giKB_KeyLayer*2][scancode];
-       // Check for unknown key
-       if(!ch)
-       {
-               if(!gbKB_KeyUp)
-                       Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
-//             return ;
-               // Can pass through to ensure each raw message has a up/down with it
-       }
-
-       // Key Up?
-       if (gbKB_KeyUp)
-       {
-               gbKB_KeyUp = 0;
-               gbaKB_States[giKB_KeyLayer][scancode] = 0;      // Unset key state flag
-
-               #if USE_KERNEL_MAGIC
-               if(ch == KEY_LCTRL)     gbKB_MagicState &= ~1;
-               if(ch == KEY_LALT)      gbKB_MagicState &= ~2;
-               #endif
-
-               if(ch == KEY_LSHIFT)    gbKB_ShiftState &= ~1;
-               if(ch == KEY_RSHIFT)    gbKB_ShiftState &= ~2;
-
-               // Call callback
-               if(gKB_Callback)        gKB_Callback( ch | KEY_ACTION_RELEASE );
-
-               // Reset Layer
-               giKB_KeyLayer = 0;
-               return;
-       }
-
-       // Refire?
-       if( gbaKB_States[giKB_KeyLayer][scancode] == 1 )
-       {
-               if(gKB_Callback)        gKB_Callback(ch | KEY_ACTION_REFIRE);
-               giKB_KeyLayer = 0;
-               return ;
-       }
-
-       // Set the bit relating to the key
-       gbaKB_States[giKB_KeyLayer][scancode] = 1;
-       // Set shift key bits
-       if(ch == KEY_LSHIFT)    gbKB_ShiftState |= 1;
-       if(ch == KEY_RSHIFT)    gbKB_ShiftState |= 2;
-
-       // Check for Caps Lock
-       if(ch == KEY_CAPSLOCK) {
-               gbKB_CapsState = !gbKB_CapsState;
-               KB_UpdateLEDs();
-       }
-
-       // --- Check for Kernel Magic Combos
-       #if USE_KERNEL_MAGIC
-       if(ch == KEY_LCTRL) {
-               gbKB_MagicState |= 1;
-               //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
-       }
-       if(ch == KEY_LALT) {
-               gbKB_MagicState |= 2;
-               //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
-       }
-       if(gbKB_MagicState == 3)
-       {
-               switch(ch)
-               {
-               case '0':       case '1':       case '2':       case '3':
-               case '4':       case '5':       case '6':       case '7':
-               case '8':       case '9':       case 'a':       case 'b':
-               case 'c':       case 'd':       case 'e':       case 'f':
-                       {
-                       char    str[4] = {'0', 'x', ch, 0};
-                       if(giKB_MagicAddressPos == BITS/4)      return;
-                       giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
-                       giKB_MagicAddressPos ++;
-                       }
-                       return;
-               
-               // Instruction Tracing
-               case 't':
-                       Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
-                       Threads_ToggleTrace( giKB_MagicAddress );
-                       giKB_MagicAddress = 0;  giKB_MagicAddressPos = 0;
-                       return;
-               
-               // Thread List Dump
-               case 'p':       Threads_Dump(); return;
-               // Heap Statistics
-               case 'h':       Heap_Stats();   return;
-               // Dump Structure
-               case 's':       return;
-               }
-       }
-       #endif
-
-       if(gKB_Callback)
-               gKB_Callback(ch | KEY_ACTION_PRESS);
-
-       // Reset Layer
-       giKB_KeyLayer = 0;
-}
-
-/**
- * \fn void KB_UpdateLEDs(void)
- * \brief Updates the status of the keyboard LEDs
- */
-void KB_UpdateLEDs(void)
-{
-       Uint8   leds;
-
-       leds = (gbKB_CapsState ? 4 : 0);
-
-       // TODO: Update LEDS
-       Log_Warning("Keyboard", "TODO: Update LEDs");
-}
-
-static const char      *csaIOCTL_NAMES[] = {DRV_IOCTLNAMES, DRV_KEYBAORD_IOCTLNAMES, NULL};
-
-/**
- * \fn int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief Calls an IOCtl Command
- */
-int KB_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
-       switch(Id)
-       {
-       BASE_IOCTLS(DRV_TYPE_KEYBOARD, "KB", 0x100, csaIOCTL_NAMES);
-       
-       // Sets the Keyboard Callback
-       case KB_IOCTL_SETCALLBACK:
-               // Sanity Check
-               if((Uint)Data < KERNEL_BASE)    return 0;
-               // Can only be set once
-               if(gKB_Callback != NULL)        return 0;
-               // Set Callback
-               gKB_Callback = Data;
-               return 1;
-
-       default:
-               return 0;
-       }
-}
diff --git a/Modules/Input/PS2KbMouse/kb_kbdus.h b/Modules/Input/PS2KbMouse/kb_kbdus.h
deleted file mode 100644 (file)
index 5df3257..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-\r
-#ifndef _KBDUS_H\r
-#define _KBDUS_H\r
-\r
-// - Base (NO PREFIX)\r
-Uint32 gpKBDUS1[256] = {\r
-       0,\r
-       KEY_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',      // 0x01 - 0x0e\r
-       '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', // 0x0f - 0x1c\r
-       KEY_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'',       // 0x1d - 0x28\r
-       '`', KEY_LSHIFT,'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT,     // 0x29 - 0x3e\r
-       KEY_KPSTAR,\r
-       KEY_LALT, ' ', KEY_CAPSLOCK,\r
-       KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,\r
-       KEY_NUMLOCK, KEY_SCROLLLOCK,\r
-       KEY_KPHOME, KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS,\r
-       KEY_KPLEFT, KEY_KP5, KEY_KPRIGHT, KEY_KPPLUS,\r
-       KEY_KPEND, KEY_KPDOWN, KEY_KPPGDN,\r
-       KEY_KPINS, KEY_KPDEL,\r
-       0, 0, 0, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0,\r
-/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-};\r
-// Shift Key pressed\r
-Uint32 gpKBDUS1s[256] = {\r
-       0,\r
-       KEY_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',      // 0x01 - 0x0e\r
-       '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', // 0x0f - 0x1c\r
-       KEY_LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':','"',        // 0x1d - 0x28\r
-       '~', KEY_LSHIFT,'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', KEY_RSHIFT,      // 0x29 - 0x3e\r
-       0\r
-       };\r
-// - 0xE0 Prefixed\r
-Uint32 gpKBDUS2[256] = {\r
-//     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\r
-/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-F\r
-/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_KPENTER, KEY_RCTRL, 0, 0,\r
-/*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*30*/ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, 0, KEY_RALT, 0, 0, 0, 0, 0, 0, 0,\r
-/*40*/ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, KEY_UP, KEY_PGUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END,\r
-/*50*/ KEY_DOWN, KEY_PGDOWN, KEY_INS, KEY_DEL, 0, 0, 0, 0, 0, 0, 0, KEY_LWIN, KEY_RWIN, KEY_MENU, 0, 0,\r
-/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-};\r
-// - 0xE1 Prefixed\r
-Uint32 gpKBDUS3[256] = {\r
-//     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\r
-/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0-F\r
-/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PAUSE, 0, 0,\r
-/*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-};\r
-\r
-\r
-Uint32 *gpKBDUS[6] = { gpKBDUS1, gpKBDUS1s, gpKBDUS2, gpKBDUS2, gpKBDUS3, gpKBDUS3 };\r
-\r
-#endif\r
diff --git a/Modules/Input/PS2KbMouse/main.c b/Modules/Input/PS2KbMouse/main.c
deleted file mode 100644 (file)
index c5ad4e8..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Acess2
- *
- * PS/2 Keboard / Mouse Driver
- */
-#include <acess.h>
-#include <modules.h>
-#include "common.h"
-
-// === IMPORTS ===
-// TODO: Allow runtime/compile-time switching
-//       Maybe PCI will have it?
-// Integrator-CP
-#if 0
-#define KEYBOARD_IRQ   3
-#define KEYBOARD_BASE  0x18000000
-#define MOUSE_IRQ      4
-#define MOUSE_BASE     0x19000000
-#endif
-// Realview
-#if 1
-#define KEYBOARD_IRQ   20
-#define KEYBOARD_BASE  0x10006000
-#define MOUSE_IRQ      21
-#define MOUSE_BASE     0x10007000
-#endif
-
-// === PROTOTYPES ===
- int   PS2_Install(char **Arguments);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x0100, Input_PS2KbMouse, PS2_Install, NULL, NULL);   // Shuts the makefile up
-MODULE_DEFINE(0, 0x0100, PS2Keyboard, KB_Install, NULL, "Input_PS2KbMouse", NULL);
-MODULE_DEFINE(0, 0x0100, PS2Mouse, PS2Mouse_Install, NULL, "Input_PS2KbMouse", NULL);
-
-// === CODE ===
-int PS2_Install(char **Arguments)
-{
-       #if ARCHDIR_is_x86 || ARCHDIR_is_x86_64
-       KBC8042_Init();
-       gpMouse_EnableFcn = KBC8042_EnableMouse;
-       #elif ARCHDIR_is_armv7
-       PL050_Init(KEYBOARD_BASE, KEYBOARD_IRQ, MOUSE_BASE, MOUSE_IRQ);
-       gpMouse_EnableFcn = PL050_EnableMouse;
-       #endif
-
-       return MODULE_ERR_OK;
-}
diff --git a/Modules/Input/PS2KbMouse/pl050.c b/Modules/Input/PS2KbMouse/pl050.c
deleted file mode 100644 (file)
index 839c0bd..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Acess2
- * - By thePowersGang (John Hodge)
- *
- * PL050 (or comaptible) Driver
- */
-#define DEBUG  1
-
-#include <acess.h>
-#include "common.h"
-
-// === CONSTANTS ===
-#define PL050_TXBUSY   0x20
-
-// === PROTOTYPES ===
-void   PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ);
-void   PL050_KeyboardHandler(int IRQ, void *Ptr);
-void   PL050_MouseHandler(int IRQ, void *Ptr);
-void   PL050_EnableMouse(void);
-static inline void     PL050_WriteMouseData(Uint8 data);
-static inline void     PL050_WriteKeyboardData(Uint8 data);
-static inline Uint8    PL050_ReadMouseData(void);
-static inline Uint8    PL050_ReadKeyboardData(void);
-
-// === GLOBALS ===
-Uint32 *gpPL050_KeyboardBase;
-Uint32 *gpPL050_MouseBase;
-
-// === CODE ===
-void PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ)
-{
-       if( KeyboardBase ) {
-               LOG("KeyboardBase = 0x%x", KeyboardBase);
-               gpPL050_KeyboardBase = (void*)MM_MapHWPages(KeyboardBase, 1);
-               LOG("gpPL050_KeyboardBase = %p", gpPL050_KeyboardBase);
-               IRQ_AddHandler(KeyboardIRQ, PL050_KeyboardHandler, NULL);
-
-               gpPL050_KeyboardBase[0] = 0x10;
-       }
-       if( MouseBase ) {
-               gpPL050_MouseBase = (void*)MM_MapHWPages(MouseBase, 1);
-               IRQ_AddHandler(MouseIRQ, PL050_MouseHandler, NULL);
-
-               gpPL050_MouseBase[0] = 0x10;
-       }
-}
-
-void PL050_KeyboardHandler(int IRQ, void *Ptr)
-{
-       Uint8   scancode;
-
-       scancode = PL050_ReadKeyboardData();
-       KB_HandleScancode( scancode );
-}
-
-void PL050_MouseHandler(int IRQ, void *Ptr)
-{
-       PS2Mouse_HandleInterrupt( PL050_ReadMouseData() );
-}
-
-void PL050_SetLEDs(Uint8 leds)
-{
-       PL050_WriteKeyboardData(0xED);
-       PL050_WriteKeyboardData(leds);
-}
-
-void PL050_EnableMouse(void)
-{
-       Log_Log("PL050", "Enabling Mouse...");
-       
-       //PL050_WriteMouseData(0xD4);
-       //PL050_WriteMouseData(0xF6);   // Set Default Settings
-       PL050_WriteMouseData(0xD4);
-       PL050_WriteMouseData(0xF4);     // Enable Packets
-       LOG("Done");
-}
-
-static inline void PL050_WriteMouseData(Uint8 Data)
-{
-        int    timeout = 10000;
-
-       if( !gpPL050_MouseBase ) {
-               Log_Error("PL050", "Mouse disabled (gpPL050_MouseBase = NULL)");
-               return ;
-       }
-
-       ENTER("xData", Data);
-
-       while( --timeout && (gpPL050_MouseBase[1] & PL050_TXBUSY) );
-       if(timeout)
-               gpPL050_MouseBase[2] = Data;
-       else
-               Log_Error("PL050", "Write to mouse timed out");
-       LEAVE('-');
-}
-
-static inline Uint8 PL050_ReadMouseData(void)
-{
-       if( !gpPL050_MouseBase ) {
-               Log_Error("PL050", "Mouse disabled (gpPL050_MouseBase = NULL)");
-               return 0;
-       }
-       return gpPL050_MouseBase[2];
-}
-static inline void PL050_WriteKeyboardData(Uint8 Data)
-{
-        int    timeout = 10000;
-
-       if( !gpPL050_KeyboardBase ) {
-               Log_Error("PL050", "Keyboard disabled (gpPL050_KeyboardBase = NULL)");
-               return ;
-       }
-
-       while( --timeout && gpPL050_KeyboardBase[1] & PL050_TXBUSY );
-       if(timeout)
-               gpPL050_KeyboardBase[2] = Data;
-       else
-               Log_Error("PL050", "Write to keyboard timed out");
-}
-static inline Uint8 PL050_ReadKeyboardData(void)
-{
-       if( !gpPL050_KeyboardBase ) {
-               Log_Error("PL050", "Keyboard disabled (gpPL050_KeyboardBase = NULL)");
-               return 0;
-       }
-
-       return gpPL050_KeyboardBase[2];
-}
-
diff --git a/Modules/Input/PS2KbMouse/ps2mouse.c b/Modules/Input/PS2KbMouse/ps2mouse.c
deleted file mode 100644 (file)
index 44be3b7..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*\r
- * Acess2 Mouse Driver\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include <fs_devfs.h>\r
-#include <api_drv_common.h>\r
-#include <api_drv_joystick.h>\r
-#include "common.h"\r
-\r
-// == CONSTANTS ==\r
-#define NUM_AXIES      2       // X+Y\r
-#define NUM_BUTTONS    5       // Left, Right, Scroll Click, Scroll Up, Scroll Down\r
-\r
-// == PROTOTYPES ==\r
-// - Internal -\r
- int   PS2Mouse_Install(char **Arguments);\r
-void   PS2Mouse_HandleInterrupt(Uint8 InputByte);\r
-// - Filesystem -\r
-Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-int    PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
-\r
-// == GLOBALS ==\r
-void   (*gpMouse_EnableFcn)(void);\r
-// - Settings\r
- int   giMouse_Sensitivity = 1;\r
- int   giMouse_MaxX = 640, giMouse_MaxY = 480;\r
-// - File Data\r
-Uint8  gMouse_FileData[sizeof(tJoystick_FileHeader) + NUM_AXIES*sizeof(tJoystick_Axis) + NUM_BUTTONS];\r
-tJoystick_FileHeader   *gMouse_FileHeader = (void *)gMouse_FileData;\r
-tJoystick_Axis *gMouse_Axies;\r
-Uint8  *gMouse_Buttons;\r
-tJoystick_Callback     gMouse_Callback;\r
- int   gMouse_CallbackArg;\r
- int   giMouse_AxisLimits[2];\r
-// - Internal State\r
- int   giMouse_Cycle = 0;      // IRQ Position\r
-Uint8  gaMouse_Bytes[4] = {0,0,0,0};\r
-// - Driver definition\r
-tVFS_NodeType  gMouse_NodeType = {\r
-       .Read = PS2Mouse_Read,\r
-       .IOCtl = PS2Mouse_IOCtl\r
-};\r
-tDevFS_Driver  gMouse_DriverStruct = {\r
-       NULL, "PS2Mouse",\r
-       {\r
-       .NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
-       .Type = &gMouse_NodeType\r
-       }\r
-};\r
-\r
-// == CODE ==\r
-int PS2Mouse_Install(char **Arguments)\r
-{\r
-       \r
-\r
-       // Set up variables\r
-       gMouse_Axies = (void*)&gMouse_FileData[4];\r
-       gMouse_Buttons = (void*)&gMouse_Axies[NUM_AXIES];\r
-\r
-       gMouse_FileHeader->NAxies = 2;  gMouse_FileHeader->NButtons = 3;\r
-       gMouse_Axies[0].MinValue = -10; gMouse_Axies[0].MaxValue = 10;\r
-       gMouse_Axies[1].MinValue = -10; gMouse_Axies[1].MaxValue = 10;\r
-       \r
-       // Initialise Mouse Controller\r
-       giMouse_Cycle = 0;      // Set Current Cycle position\r
-       gpMouse_EnableFcn();\r
-       \r
-       DevFS_AddDevice(&gMouse_DriverStruct);\r
-       \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/* Handle Mouse Interrupt\r
- */\r
-void PS2Mouse_HandleInterrupt(Uint8 InputByte)\r
-{\r
-       Uint8   flags;\r
-        int    d[2], d_accel[2];\r
-        int    i;\r
-       \r
-       // Gather mouse data\r
-       gaMouse_Bytes[giMouse_Cycle] = InputByte;\r
-       LOG("gaMouse_Bytes[%i] = 0x%02x", gMouse_Axies[0].MaxValue);\r
-       // - If bit 3 of the first byte is not set, it's not a valid packet?\r
-       if(giMouse_Cycle == 0 && !(gaMouse_Bytes[0] & 0x08) )\r
-               return ;\r
-       giMouse_Cycle++;\r
-       if(giMouse_Cycle < 3)\r
-               return ;\r
-\r
-       giMouse_Cycle = 0;\r
-\r
-       // Actual Processing (once we have all bytes)   \r
-       flags = gaMouse_Bytes[0];\r
-\r
-       LOG("flags = 0x%x", flags);\r
-       \r
-       // Check for X/Y Overflow\r
-       if(flags & 0xC0)        return;\r
-               \r
-       // Calculate dX and dY\r
-       d[0] = gaMouse_Bytes[1];        if(flags & 0x10) d[0] = -(256-d[0]);    // x\r
-       d[1] = gaMouse_Bytes[2];        if(flags & 0x20) d[1] = -(256-d[1]);    // y\r
-       d[1] = -d[1];   // Y is negated\r
-       LOG("RAW dx=%i, dy=%i\n", d[0], d[1]);\r
-       // Apply scaling\r
-       // TODO: Apply a form of curve to the mouse movement (dx*log(dx), dx^k?)\r
-       // TODO: Independent sensitivities?\r
-       // TODO: Disable acceleration via a flag?\r
-       d_accel[0] = d[0]*giMouse_Sensitivity;\r
-       d_accel[1] = d[1]*giMouse_Sensitivity;\r
-       \r
-       // Set Buttons (Primary)\r
-       for( i = 0; i < 3; i ++ )\r
-       {\r
-               Uint8   newVal = (flags & (1 << i)) ? 0xFF : 0;\r
-               if(newVal != gMouse_Buttons[i]) {\r
-                       if( gMouse_Callback )\r
-                               gMouse_Callback(gMouse_CallbackArg, 0, i, newVal - gMouse_Buttons[i]);\r
-                       gMouse_Buttons[i] = newVal;\r
-               }\r
-       }\r
-       \r
-       // Update X and Y Positions\r
-       for( i = 0; i < 2; i ++ )\r
-       {\r
-               Sint16  newCursor = 0;\r
-               if( giMouse_AxisLimits[i] )\r
-                       newCursor = MIN( MAX(0, gMouse_Axies[i].CursorPos + d_accel[i]), giMouse_AxisLimits[i] );;\r
-               \r
-               if( gMouse_Callback )\r
-               {\r
-                       if(giMouse_AxisLimits[i] && gMouse_Axies[i].CursorPos != newCursor)\r
-                               gMouse_Callback(gMouse_CallbackArg, 1, i, newCursor - gMouse_Axies[i].CursorPos);\r
-                       if(!giMouse_AxisLimits[i] && gMouse_Axies[i].CurValue != d_accel[i])\r
-                               gMouse_Callback(gMouse_CallbackArg, 1, i, d_accel[i] - gMouse_Axies[i].CurValue);\r
-               }\r
-               \r
-               gMouse_Axies[i].CurValue = d_accel[i];\r
-               gMouse_Axies[i].CursorPos = newCursor;\r
-       }\r
-\r
-//     Log("Mouse at %ix%i", gMouse_Axies[0].CursorPos, gMouse_Axies[1].CursorPos);\r
-               \r
-       VFS_MarkAvaliable(&gMouse_DriverStruct.RootNode, 1);\r
-}\r
-\r
-/* Read mouse state (coordinates)\r
- */\r
-Uint64 PS2Mouse_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{\r
-       if(Offset > sizeof(gMouse_FileData))    return 0;\r
-       if(Length > sizeof(gMouse_FileData))    Length = sizeof(gMouse_FileData);\r
-       if(Offset + Length > sizeof(gMouse_FileData))   Length = sizeof(gMouse_FileData) - Offset;\r
-\r
-       memcpy(Buffer, &gMouse_FileData[Offset], Length);\r
-       \r
-       VFS_MarkAvaliable(Node, 0);\r
-       return Length;\r
-}\r
-\r
-static const char *csaIOCtls[] = {DRV_IOCTLNAMES, DRV_JOY_IOCTLNAMES, NULL};\r
-/* Handle messages to the device\r
- */\r
-int PS2Mouse_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-       tJoystick_NumValue      *info = Data;\r
-\r
-       switch(ID)\r
-       {\r
-       BASE_IOCTLS(DRV_TYPE_JOYSTICK, "PS2Mouse", 0x100, csaIOCtls);\r
-\r
-       case JOY_IOCTL_SETCALLBACK:     // TODO: Implement\r
-               return -1;\r
-       \r
-       case JOY_IOCTL_SETCALLBACKARG:  // TODO: Implement\r
-               return -1;\r
-       \r
-       case JOY_IOCTL_GETSETAXISLIMIT:\r
-               if(!info)       return 0;\r
-               if(info->Num < 0 || info->Num >= 2)     return 0;\r
-               if(info->Value != -1)\r
-                       giMouse_AxisLimits[info->Num] = info->Value;\r
-               return giMouse_AxisLimits[info->Num];\r
-       \r
-       case JOY_IOCTL_GETSETAXISPOSITION:\r
-               if(!info)       return 0;\r
-               if(info->Num < 0 || info->Num >= 2)     return 0;\r
-               if(info->Value != -1)\r
-                       gMouse_Axies[info->Num].CursorPos = info->Value;\r
-               return gMouse_Axies[info->Num].CursorPos;\r
-\r
-       case JOY_IOCTL_GETSETAXISFLAGS:\r
-               return -1;\r
-       \r
-       case JOY_IOCTL_GETSETBUTTONFLAGS:\r
-               return -1;\r
-\r
-       default:\r
-               return 0;\r
-       }\r
-}\r
-\r
diff --git a/Modules/Interfaces/EDI/Makefile b/Modules/Interfaces/EDI/Makefile
deleted file mode 100644 (file)
index a93a8b7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# 
-# EDI - Extensible Driver Interface
-# 
-# Acess Interface
-
-
-OBJ = main.o edi.o
-NAME = EDI
-
--include ../Makefile.tpl
diff --git a/Modules/Interfaces/EDI/edi/acess-edi.h b/Modules/Interfaces/EDI/edi/acess-edi.h
deleted file mode 100644 (file)
index 4071388..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*! \file acess-edi.h
- * \brief Acess Specific EDI Objects
- * 
- * Contains documentation and information for
- * - Timers
- */
-
-/* Copyright (c)  2006  John Hodge
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#ifndef ACESS_EDI_H
-#define ACESS_EDI_H
-
-#include "edi_objects.h"
-
-/// \brief Name of Acess EDI Time Class
-#define        ACESS_TIMER_CLASS       "ACESSEDI-TIMER"
-
-#ifndef IMPLEMENTING_EDI
-/*! \brief int32_t ACESSEDI-TIMER.init_timer(uint32_t Delay, void (*Callback)(int), int Arg);
- *
- * Takes a timer pointer and intialises the timer object to fire after \a Delay ms
- * When the timer fires, \a Callback is called with \a Arg passed to it.
- */
-EDI_DEFVAR int32_t (*init_timer)(object_pointer port_object, uint32_t Delay, void (*fcn)(int), int arg);
-
-/*! \brief void ACESSEDI-TIMER.disable_timer();
- * 
- * Disables the timer and prevents it from firing
- * After this has been called, the timer can then be initialised again.
- */
-EDI_DEFVAR void (*disable_timer)(object_pointer port_object);
-
-
-#endif // defined(IMPLEMENTING_EDI)
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi.h b/Modules/Interfaces/EDI/edi/edi.h
deleted file mode 100644 (file)
index 273f7a3..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef EDI_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#define EDI_H
-/*! \file edi.h
- * \brief The unitive EDI header to include others, start EDI, and stop EDI.
- *
- * Data structures and algorithms this header represents:
- *     DATA STRUCTURE: CLASS QUOTAS - The runtime and the driver have the right to set a quota on how many objects of a given class
- * owned by that party the other may construct.  These quotas are kept internally by the driver or runtime, are optional and are
- * exposed to the other party via the quota() function (for quotas of runtime-owned classes) and the k_quota() function pointer given
- * to the runtime by the driver.
- *
- *     ALGORITHMS: INITIALIZATION AND SHUTDOWN - On initialization of the runtime's EDI environment for this driver it calls the
- * driver's driver_init() routine (which must match driver_init_t) to initialize the driver with a list of EDI objects the runtime
- * thinks the driver should run with.  The driver then initializes.  This can include calling edi_negotiate_resources() to try and
- * obtain more or different objects.  Eventually driver_init() returns an edi_initialization_t structure containing its quota
- * function and the list of classes belonging to the driver which the runtime can construct.  Either the driver or the runtime can
- * shut down EDI by calling edi_shutdown(), which in turn calls the driver's driver_finish() routine.  On shutdown all objects, of
- * classes belonging to both the runtime and driver, are destroyed. */
-
-#include "edi_objects.h"
-#include "edi_dma_streams.h"
-#include "edi_pthreads.h"
-#include "edi_port_io.h"
-#include "edi_memory_mapping.h"
-#include "edi_devices.h"
-#include "edi_interrupts.h"
-
-/*! \brief A pointer to a function the runtime can call if it fails to construct one of the driver's classes to find out what the
- * runtime's quota is for that class.
- *
- * A pointer to a function which takes an edi_string_t as a parameter and returns in int32_t.  This function follows the same
- * semantics as the quota() function, returning the number of objects of the given class that can be constructed, -1 for infinity or
- * -2 for an erroneous class name.  It is used to tell the runtime the location of such a function in the driver so that the runtime
- * can check quotas on driver-owned classes. */
-typedef int32_t (*k_quota_t)(edi_string_t resource_class);
-/*!\struct edi_initialization_t
- * \brief Structure containing driver classes available to the runtime and the driver's quota function after the driver has initialized. 
- *
- * Structure containing driver classes available to runtime, the driver's quota function and the driver's name provided to the runtime
- * after the driver has initialized.  driver_bus, vendor_id, and device_id are all optional fields which coders should consider
- * supplementary information.  Kernels can require these fields if they so please, but doing so for devices which don't run on a Vendor
- * ID/Product ID supporting bus is rather unwise. */
-typedef struct {
-       /*!\brief The number of driver classes in the driver_classes array. */
-       int32_t num_driver_classes;
-       /*!\brief An array of declarations of driver classes available to the runtime. 
-        *
-        * This array should not necessarily contain the entire list of EDI classes implemented by the driver.  Instead, it should
-        * contain a list of those classes which the driver has correctly initialized itself to provide instances of with full
-        * functionality. */
-       edi_class_declaration_t *driver_classes;
-       /*!\brief The driver's quota function. */
-       k_quota_t k_quota;
-       /*!\brief The driver's name. */
-       edi_string_t driver_name;
-       /*!\brief The bus of the device this driver wants to drive, if applicable.
-        *
-        * The driver does not have to supply this field, and can also supply "MULTIPLE BUSES" here to indicate that it drives devices
-        * on multiple buses. */
-       edi_string_t driver_bus;
-       /*!\brief The driver's vendor ID, if applicable.
-        *
-        * The driver does not need to supply this field, and should supply -1 to indicate that it does not wish to. */
-       int16_t vendor_id;
-       /*!\brief The driver's device ID, if applicable.
-        *
-        * The driver does not need to supply this field, but can supply it along with vendor_id.  If either vendor_id or this field are
-        * set to -1 the runtime should consider this field not supplied. */
-       int16_t driver_id;
-} edi_initialization_t;        
-/*!\brief A pointer to a driver's initialization function.
- *
- * The protocol for the driver's initialization function.  The runtime gives the driver a set of EDI objects representing the
- * resources it thinks the driver should run with.  This function returns an edi_initialization_t structure containing declarations
- * of the EDI classes the driver can make available to the runtime after initialization.  If any member of that structure contains 0
- * or NULL, it is considered invalid and the runtime should destroy the driver without calling its driver_finish() routine. */
-typedef edi_initialization_t (*driver_init_t)(int32_t num_resources,edi_object_metadata_t *resources);
-/*!\brief Requests more resources from the runtime.  Can be called during driver initialization.
- *
- * Called to negotiate with the runtime for the right to create further EDI objects/obtain further resources owned by the runtime.
- * When the driver calls this routine, the runtime decides whether to grant more resources.  If yes, this call returns true, and the
- * driver can proceed to try and create the objects it desires, in addition to destroying EDI objects it doesn't want.  Otherwise,
- * it returns false.
- * The driver must deal with whatever value this routine returns. */
-bool edi_negotiate_resources();
-
-/*! \brief Returns the driver's quota of objects for a given runtime-owned class. 
- *
- * This function takes an edi_string_t with the name of a runtime-owned class in it and returns the number of objects of that class
- * which drivers can construct, -1 for infinity, or -2 for an erroneous class name. */
-int32_t quota(edi_string_t resource_class);
-/*! \brief Sends a string to the operating systems debug output or logging facilities. */
-void edi_debug_write(uint32_t debug_string_length, char *debug_string);
-/*! \brief This call destroys all objects and shuts down the entire EDI environment of the driver. 
- *
- * This function shuts down EDI as described in INITIALIZATION AND SHUTDOWN above.  All objects are destroyed, EDI functions can no
- * longer be successfully called, etc.  This function only succeeds when EDI has already been initialized, so it returns -1 when EDI
- * hasn't been, 1 on success, or 0 for all other errors. */
-int32_t shutdown_edi(void);
-
-/*!\brief A pointer to the driver's finishing/shutdown function.
- *
- * The protocol for the driver's shutting down.  This function should do anything the driver wants done before it dies. */
-typedef void (*driver_finish_t)();
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi_devices.h b/Modules/Interfaces/EDI/edi/edi_devices.h
deleted file mode 100644 (file)
index 245e01f..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef EDI_DEVICES_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-/* Edited by thePowersGang (John Hodge) June 2009
- * - Add #ifdef EDI_MAIN_FILE
- */
-
-#define EDI_DEVICES_H
-
-/*! \file edi_devices.h
- * \brief Declaration and description of simple classes for implementation by EDI drivers to represent hardware devices.
- *
- * Data structures and algorithms this header represents:
- *
- *     DATA STRUCTURE AND ALGORITHM: BASIC DEVICES - There are two functions, select() for waiting on devices and ioctl() for
- * controlling them, common to many POSIX devices.  Implementations of EDI-CHARACTER-DEVICE or EDI-BLOCK-DEVICE may implement either of
- * these or both, and users of such objects much query for the methods to see if they're supported.  Obviously, runtime or driver
- * developers don't *need* to support these.
- *
- *     DATA STRUCTURE AND ALGORITHM: CHARACTER DEVICES - The class EDI-CHARACTER-DEVICE provides a very basic interface to character
- * devices, which read and write streams of characters.  As such, this class only provides read() and write().  The calls attempt a
- * likeness to POSIX.
- *
- *     DATA STRUCTURE AND ALGORITHM: BLOCK DEVICES - The class EDI-BLOCK-DEVICE provides a very basic interface to block devices, which
- * can read(), write() and seek() to blocks of a specific size in an array of blocks with a specific size.  Its declarations and
- * semantics should behave like those of most POSIX operating systems.
- *
- * Note that EDI runtimes should not implement these classes.  Their declarations are provided for drivers to implement. */
-
-#include "edi_objects.h"
-
-/* Methods common to all EDI device classes specified in this header. */
-
-/*!\brief EAGAIN returned by functions for block and character devices.
- *
- * Means that the amount of data the device has ready is less than count. */
-#define EAGAIN -1
-/*!\brief EBADOBJ returned by functions for block and character devices.
- *
- * Means that the object passed as the method's this point was not a valid object of the needed class. */
-#define EBADOBJ -2
-/*!\brief EINVAL returned by functions for block and character devices.
- *
- * Means that the method got passed invalid parameters. */
-#ifdef EINVAL
-# undef EINVAL
-#endif
-#define EINVAL -3
-
-/*!\brief select() type to wait until device is writable. */
-#define EDI_SELECT_WRITABLE 0
-/*!\brief select() type to wait until device is readable. */
-#define EDI_SELECT_READABLE 1
-
-/*!\brief Argument to seek().  Sets the block offset (ie: the "current block" index) to the given whence value. */
-#define EDI_SEEK_SET 0
-/*!\brief Argument to seek().  Sets the block offset (ie: the "current block" index) to its current value + whence. */
-#define EDI_SEEK_CURRENT 1
-
-#ifdef EDI_MAIN_FILE
-/*!\brief Arguments to EDI's basic select() function. */
-edi_variable_declaration_t select_arguments[2] = {{"pointer void","device",1},
-                                                {"unsigned int32_t","select_type",1}};
-/*!\brief Declaration of EDI's basic select() function. 
- *
- * Contrary to the POSIX version, this select() puts its error codes in its return value. */
-edi_function_declaration_t select_declaration = {"int32_t","edi_device_select",0,2,select_arguments,NULL};
-#else
-extern edi_function_declaration_t select_declaration;  // Declare for non main files
-#endif
-
-#ifdef EDI_MAIN_FILE
-/*!\brief Arguments to EDI's basic ioctl() function. */
-edi_variable_declaration_t ioctl_arguments[3] = {{"pointer void","device",1},{"int32_t","request",1},{"pointer void","argp",1}};
-/*!\brief Declaration of EDI's basic ioctl() function. 
- *
- * Contrary to the POSIX version, this ioctl() puts its error codes in its return value. */
-edi_function_declaration_t ioctl_declaration = {"int32_t","edi_device_ioctl",0,3,ioctl_arguments,NULL};
-#else
-extern edi_class_declaration_t ioctl_declaration;      // Declare for non main files
-#endif
-
-#ifdef EDI_MAIN_FILE
-/*!\brief Declaration of the arguments EDI-CHARACTER-DEVICE's read() and write() methods. */
-edi_variable_declaration_t chardev_read_write_arguments[3] = {{"pointer void","chardev",1},
-                                                             {"pointer void","buffer",1},
-                                                             {"unsigned int32_t","char_count",1}};
-/*!\brief Declarations of the methods of EDI-CHARACTER-DEVICE, read() and write().
- *
- * The code pointers of these function declarations are all given as NULL.  Driver developers implementing EDI-CHARACTER-DEVICE should
- * fill in these entries with pointers to their own functions. */
-EDI_DEFVAR edi_function_declaration_t chardev_methods[2]= {{"int32_t","edi_chardev_read",0,3,chardev_read_write_arguments,NULL},
-                                               {"int32_t","edi_chardev_write",0,3,chardev_read_write_arguments,NULL}};
-/*!\brief Declaration of the EDI-CHARACTER-DEVICE class.
- *
- * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
- * before passing the filled-in structure to the EDI runtime. */
-EDI_DEFVAR edi_class_declaration_t chardev_class = {"EDI-CHARACTER-DEVICE",0,2,chardev_methods,NULL,NULL,NULL};
-#else
-extern edi_class_declaration_t chardev_class;  // Declare for non main files
-#endif
-
-#ifdef EDI_MAIN_FILE
-/*!\brief Arguments to EDI-BLOCK-DEVICE's read() and write() methods. */
-edi_variable_declaration_t blockdev_read_write_arguments[3] = {{"pointer void","blockdev",1},
-                                                              {"pointer void","buffer",1},
-                                                              {"unsigned int32_t","blocks",1}};
-/*!\brief Arguments to EDI-BLOCK-DEVICE's seek() method. */
-edi_variable_declaration_t blockdev_seek_arguments[3] = {{"pointer void","blockdev",1},
-                                                        {"int32_t","offset",1},
-                                                        {"int32_t","whence",1}};
-/*!\brief Declaration of the methods of EDI-BLOCK-DEVICE, read(), write(), seek(), and get_block_size(). 
- *
- * The code pointers of these function declarations are all given as NULL.  Driver developers implementing EDI-BLOCK-DEVICE should fill
- * these entries in with pointers to their own functions. */
-edi_function_declaration_t blockdev_methods[4] = {{"int32_t","edi_blockdev_read",0,3,blockdev_read_write_arguments,NULL},
-                                                 {"int32_t","edi_blockdev_write",0,3,blockdev_read_write_arguments,NULL},
-                                                 {"int32_t","edi_blockdev_seek",0,3,blockdev_seek_arguments,NULL},
-                                                 {"unsigned int32_t","edi_blockdev_get_block_size",0,0,NULL,NULL}};
-/*!\brief Declaration of the EDI-BLOCK-DEVICE class.
- *
- * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
- * before passing the filled-in structure to the EDI runtime. */
-edi_class_declaration_t blockdev_class = {"EDI-BLOCK-DEVICE",0,4,blockdev_methods,NULL,NULL,NULL};
-#else
-extern edi_class_declaration_t blockdev_class; // Declare for non main files
-#endif
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi_dma_streams.h b/Modules/Interfaces/EDI/edi/edi_dma_streams.h
deleted file mode 100644 (file)
index 8ab80cc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef EDI_DMA_STREAMS_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#define EDI_DMA_STREAMS_H
-
-/*! \file edi_dma_streams.h 
- * \brief EDI's stream subclass for handling Direct Memory Access hardware.
- *
- * Data structures and algorithms this header represents:
- *
- *     DATA STRUCTURE: DMA STREAMS - DMA streams are objects of the class EDI-STREAM-DMA used to pass data between a buffer of
- * memory and the computer's DMA hardware.  It is the responsibility of the object to allocate memory for its stream memory buffer
- * which can be used with DMA hardware and to program the DMA hardware for transmissions.  DMA streams can be bidirectional if the
- * correct DMA mode is used. */
-
-#include "edi_objects.h"
-
-#define DMA_STREAM_CLASS       "EDI-STREAM-DMA"
-
-/*! \brief The name of the EDI DMA stream class.
- *
- * An edi_string_t with the class name "EDI-STREAM-DMA" in it. */
-#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
-const edi_string_t dma_stream_class = DMA_STREAM_CLASS;
-#else
-extern const edi_string_t dma_stream_class;
-#endif
-
-#ifndef IMPLEMENTING_EDI
-/*! \brief int32_t EDI-STREAM-DMA.init_dma_stream(unsigned int32_t channel,unsigned int32_t mode,unsigned int32_t buffer_pages);
- *
- * Pointer to the init_dma_stream() method of class EDI-STREAM-DMA, which initializes a DMA stream with a DMA channel, DMA mode, and
- * the number of DMA-accessible memory pages to keep as a buffer.  It will only work once per stream object.  It's possible return
- * values are 1 for sucess, -1 for invalid DMA channel, -2 for invalid DMA mode, -3 for inability to allocate enough buffer pages and
- * 0 for all other errors. */
-EDI_DEFVAR  int32_t (*init_dma_stream)(object_pointer stream, uint32_t channel, uint32_t mode, uint32_t buffer_pages);
-/*! \brief int32_t EDI-STREAM-DMA.transmit(data_pointer *anchor,unsigned int32 num_bytes,bool sending);
- *
- * Pointer to the dma_stream_transmit() method of class EDI-STREAM-DMA, which transmits the given number of bytes of data through
- * the DMA stream to/from the given anchor (either source or destination), in the given direction.  It returns 1 on success, -1 on
- * an uninitialized or invalid DMA stream object, -2 when the anchor was NULL or otherwise invalid, -3 if the DMA stream can't
- * transmit in the given direction, and 0 for all other errors. */
-EDI_DEFVAR int32_t (*dma_stream_transmit)(object_pointer stream, data_pointer anchor, uint32_t num_bytes, bool sending);
-#endif
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi_interrupts.h b/Modules/Interfaces/EDI/edi/edi_interrupts.h
deleted file mode 100644 (file)
index ef2ffc9..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef EDI_INTERRUPTS_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#define EDI_INTERRUPTS_H
-
-/*! \file edi_interrupts.h
- * \brief Declaration and description of EDI's interrupt handling class.
- *
- * Data structures and algorithms this header represents:
- *     DATA STRUCTURE AND ALGORITHM: INTERRUPT OBJECTS - The class EDI-INTERRUPT encapsulates the handling of machine interrupts.
- * It is initialized with an interrupt number to handle and a handler routine to call when that interrupt occurs.  Only a couple of
- * guarantees are made to the driver regarding the runtime's implementation of interrupt handling: 1) That the driver's handler is
- * called for every time the interrupt associated with a valid and initialized interrupt object occurs, in the order of the
- * occurences, 2) That the runtime handle the architecture-specific (general to the entire machine, not just this device)
- * end-of-interrupt code when the driver is called without first returning from the machine interrupt.  Note that the runtime hands
- * out interrupt numbers at its own discretion and policy. */
-
-#include "edi_objects.h"
-
-/*! \brief Macro constant containing the name of the interrupt class
- */
-#define INTERRUPTS_CLASS       "EDI-INTERRUPT"
-/*! \brief The name of EDI's interrupt-handling class.
- *
- * An edi_string_t holding the name of the runtime-implemented interrupt object class.  It's value is "EDI-INTERRUPT". */
-#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
-const edi_string_t interrupts_class = INTERRUPTS_CLASS;
-#else
-extern const edi_string_t interrupts_class;
-#endif
-
-/*! \brief A pointer to an interrupt handling function.
- *
- * A pointer to a function called to handle interrupts.  Its unsigned int32_t parameter is the interrupt number that is being
- * handled. */
-typedef void (*interrupt_handler_t)(uint32_t interrupt_number);
-
-#ifndef IMPLEMENTING_EDI
-/*! \brief Initializes an interrupt object with an interrupt number and a pointer to a handler function.
- *
- * A pointer to the init_interrupt() method of class EDI-INTERRUPT.  This method initializes a newly-created interrupt object with an
- * interrupt number and a pointer to the driver's handler of type interrupt_handler_t.  It can only be called once per object, and
- * returns 1 on success, fails with -1 when the interrupt number is invalid or unacceptable to the runtime, fails with -2 when the
- * pointer to the driver's interrupt handler is invalid, and fails with -3 for all other errors. */
-EDI_DEFVAR int32_t (*init_interrupt)(object_pointer interrupt, uint32_t interrupt_number, interrupt_handler_t handler);
-/*! \brief Get this interrupt object's interrupt number. */
-EDI_DEFVAR uint32_t (*interrupt_get_irq)(object_pointer interrupt);
-/*! \brief Set a new handler for this interrupt object. */
-EDI_DEFVAR void (*interrupt_set_handler)(object_pointer interrupt, interrupt_handler_t handler);
-/*! \brief Return from this interrupt, letting the runtime run any necessary End-Of-Interrupt code.
- *
- * A pointer to the interrupt_return() method of class EDI-INTERRUPT.  This method returns from the interrupt designated by the
- * calling interrupt object.  If there is a machine-wide end-of-interrupt procedure and the driver was called during the handling of
- * the machine interrupt (as opposed to delaying the handling and letting the runtime EOI), the runtime runs it during this method.
- * This method has no return value, since once it's called control leaves the calling thread. */
-EDI_DEFVAR void (*interrupt_return)(object_pointer interrupt);
-#endif
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi_memory_mapping.h b/Modules/Interfaces/EDI/edi/edi_memory_mapping.h
deleted file mode 100644 (file)
index ba8dff3..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef EDI_MEMORY_MAPPING_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#define EDI_MEMORY_MAPPING_H
-
-/*! \file edi_memory_mapping.h
- * \brief Declaration and description of EDI's class for mapping physical pages into the driver's address space.
- *
- * Data structures and algorithms this header represents:
- *     ALGORITHM: MEMORY MAPPINGS - Memory mapping objects of the class EDI-MEMORY-MAPPING are used to give virtual (driver-visible)
- * addresses to sections of physical memory.  These can either be memory mappings belonging to hardware devices or plain RAM which
- * the driver wants page-aligned.  A memory mapping object is initialized with the physical address for the memory mapping and the
- * number of pages the mapping takes up, or simply the desired length of the a physically contiguous buffer in pages.  The class's
- * two methods map the section of memory into and out of the driver's virtual address space. */
-
-#include "edi_objects.h"
-
-/*! \brief The name of EDI's memory mapping class.
- *
- * An edi_string_t with the name of the memory mapping class, "EDI-MEMORY-MAPPING". */
-#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
-const edi_string_t memory_mapping_class = "EDI-MEMORY-MAPPING";
-#else
-extern const edi_string_t memory_mapping_class;
-#endif
-
-/*! \brief Flag representing Strong Uncacheable caching method. */
-#define CACHING_STRONG_UNCACHEABLE 0
-/*! \brief Flag representing Uncacheable caching method. */
-#define CACHING_UNCACHEABLE 1
-/*! \brief Flag representing Write combining caching method. */
-#define CACHING_WRITE_COMBINING 2
-/*! \brief Flag representing Write Through caching method. */
-#define CACHING_WRITE_THROUGH 3
-/*! \brief Flag representing Write Back caching method. */
-#define CACHING_WRITE_BACK 3
-/*! \brief Flag representing Write Protected caching method. */
-#define CACHING_WRITE_PROTECTED 3
-
-#ifndef IMPLEMENTING_EDI
-/*! \brief Initialize an EDI-MEMORY-MAPPING object with a physical address range.
- *
- * This method takes the start_physical_address of a memory mapping and the number of pages in that mapping and uses these arguments
- * to initialize an EDI-MEMORY-MAPPING object.  It can only be called once per object.  It returns 1 when successful, -1 when an
- * invalid physical address is given (one that the runtime knows is neither a physical memory mapping belonging to a device nor
- * normal RAM), -2 when the number of pages requested is bad (for the same reasons as the starting address can be bad), and 0 for
- * all other errors. 
- *
- * Note that this method can't be invoked on an object which has already initialized via init_memory_mapping_with_pages(). */
-EDI_DEFVAR int32_t (*init_memory_mapping_with_address)(object_pointer mapping, data_pointer start_physical_address, uint32_t pages);
-/*! \brief Initialize an EDI-MEMORY-MAPPING object by requesting a number of new physical pages.
- *
- * This method takes a desired number of physical pages for a memory mapping, and uses that number to initialize an
- * EDI-MEMORY-MAPPING object by creating a buffer of contiguous physical pages.  It can only be called once per object.  It returns
- * 1 when successful, -1 when the request for pages cannot be fulfilled, and 0 for all other errors.
- *
- * Note that this method cannot be called if init_memory_mapping_with_address() has already been used on the given object. */
-EDI_DEFVAR int32_t (*init_memory_mapping_with_pages)(object_pointer mapping, uint32_t pages);
-/*! \brief Map the memory-mapping into this driver's visible address space.
- *
- * This asks the runtime to map a given memory mapping into the driver's virtual address space.  Its parameter is the address of a
- * data_pointer to place the virtual address of the mapping into.  This method returns 1 on success, -1 on an invalid argument, -2
- * for an uninitialized object, and 0 for all other errors. */
-EDI_DEFVAR int32_t (*map_in_mapping)(object_pointer mapping, data_pointer *address_mapped_to);
-/*! \brief Unmap the memory mapping from this driver's visible address space.
- *
- * This method tries to map the given memory mapping out of the driver's virtual address space.  It returns 1 for success, -1
- * for an uninitialized memory mapping object, -2 if the mapping isn't mapped into the driver's address space already, and 0
- * for all other errors. */
-EDI_DEFVAR int32_t (*map_out_mapping)(object_pointer mapping);
-
-/*! \brief Set the caching flags for a memory mapping. */
-EDI_DEFVAR void (*mapping_set_caching_method)(object_pointer mapping, uint32_t caching_method);
-/*! \brief Get the current caching method for a memory mapping. */
-EDI_DEFVAR uint32_t (*mapping_get_caching_method)(object_pointer mapping);
-/*! \brief Flush write-combining buffers on CPU to make sure changes to memory mapping actually get written.  Only applies to a Write Combining caching method (I think.).*/
-EDI_DEFVAR void (*flush_write_combining_mapping)(object_pointer mapping);
-#endif
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi_objects.h b/Modules/Interfaces/EDI/edi/edi_objects.h
deleted file mode 100644 (file)
index 0e47951..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-#ifndef EDI_OBJECTS_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#define EDI_OBJECTS_H
-
-/*! \file edi_objects.h
- * \brief The header file for basic EDI types and the object system.
- *
- * This file contains declarations of EDI's primitive data types, as well as structures and functions for with the object system.
- * It represents these data structures and algorithms:
- * 
- *     DATA STRUCTURE: THE CLASS LIST - EDI implementing runtime's must keep an internal list of classes implemented by the runtime
- *     and separate lists of classes implemented by each driver.  Whoever implements a class is said to "own" that class.  The
- *     internal format of this list is up to the runtime coders, but it must be possible to recreate the original list of
- *     edi_class_declaration structures the driver declared to the runtime from it.  This list is declared to the runtime in an
- *     initialization function in the header edi.h.  The object_class member of an edi_object_metadata structure must point to that
- *     object's class's entry in this list.
- *     
- *     ALGORITHM AND DATA STRUCTURE: CLASSES AND INHERITANCE - Classes are described using edi_class_declaration_t structures and
- *     follow very simple rules.  All data is private and EDI provides no way to access instance data, so there are no member
- *     variable declarations.  However, if the data isn't memory-protected (for example, driver data on the driver heap) EDI allows
- *     the possibility of pointer access to data, since runtime and driver coders could make use of that behavior.  Classes may have
- *     one ancestor by declaring so in their class declaration structure, and if child methods are different then parent methods
- *     the children always override their parents.  An EDI runtime must also be able to check the existence and ownership of a given
- *     class given its name in an edi_string_t.
- *     
- *     ALGORITHM: OBJECT CREATION AND DESTRUCTION - An EDI runtime should be able to call the constructor of a named class, put the
- *     resulting object_pointer into an edi_object_metadata_t and return that structure.  The runtime should also be able to call an
- *     object's class's destructor when given a pointer to a valid edi_metadata_t for an already-existing object.  Data equivalent
- *     to an edi_object_metadata_t should also be tracked by the runtime for every object in existence in case of sudden EDI shutdown
- *     (see edi.h).
- *
- *     ALGORITHM: RUNTIME TYPE INFORMATION - When passed the data_pointer member of an edi_object_metadata_t to a valid object, an
- *     EDI runtime must be able to return an edi_string_t containing the name of that object's class and to return function_pointers
- *     to methods when the required information to find the correct method is given by calling a class's method getting function.*/
-
-/* If the EDI headers are linked with the standard C library, they use its type definitions.  Otherwise, equivalent definitions are
- * made.*/
-#if __STDC_VERSION__ == 199901L
-# include <stdbool.h>
-# include <stdint.h>
-#else
-# ifndef NULL
-#  define      NULL    ((void*)0)
-# endif
-typedef unsigned char bool;
-# define true 1
-# define false 0
-typedef char int8_t;
-typedef short int16_t;
-typedef long int32_t;
-typedef long long int64_t;
-typedef unsigned char  uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned long  uint32_t;
-typedef unsigned long long     uint64_t;
-#endif
-
-/*! \brief Define a variable in the header
- */
-#ifdef EDI_MAIN_FILE
-# define EDI_DEFVAR
-#else
-# define EDI_DEFVAR    extern
-#endif
-
-/*! \brief A pointer to the in-memory instance of an object.
- *
- * This type is sized just like a general C pointer type (whatever*) for the target architecture.  It's passed as a first parameter
- * to all methods, thus allowing EDI classes to be implemented as C++ classes and providing some protection from confusing objects
- * with normal pointers.  Equivalent to a C++ this pointer or an Object Pascal Self argument. */
-typedef void *object_pointer;
-/*! \brief A basic pointer type pointing to arbitrary data in an arbitrary location. */
-typedef void *data_pointer;
-/*! \brief A basic function pointer type.
- *
- * A pointer to a piece of code which can be called and return to its caller, used to distinguish between pointers to code and
- * pointers to data.  Its size is hardware-dependent. */
-typedef void (*function_pointer)(void);
-/*! \brief The length of an EDI string without its null character. */
-#define EDI_STRING_LENGTH 31
-/*! \brief A type representing a 31-character long string with a terminating NULL character at the end.  All of EDI uses this type
- * for strings.
- *
- * A null-terminated string type which stores characters in int8s.  It allows for 31 characters in each string, with the final
- * character being the NULL terminator.  Functions which use this type must check that its final character is NULL, a string which
- * doesn't not have this property is invalid and insecure.  I (the author of EDI) know and understand that this form of a string
- * suffers from C programmer's disease, but I can't use anything else without either making string use far buggier or dragging
- * everyone onto a better language than C.  */
-typedef int8_t edi_string_t[0x20];
-/*! \brief A type representing a pointer form of #edi_string_t suitable for function returns
- */
-typedef int8_t *edi_string_ptr_t;
-
-/*! \var EDI_BASE_TYPES
- * \brief A constant array of edi_string_t's holding every available EDI primitive type. */
-/*! \var EDI_TYPE_MODIFIERS
- * \brief A constant array of edi_string_t's holding available modifiers for EDI primitive types. */
-#ifdef IMPLEMENTING_EDI
- const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg","edi_string_t"};
- const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
-#else
- //extern const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg", "edi_string_t"};
- //extern const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
- extern const edi_string_t EDI_BASE_TYPES[9];
- extern const edi_string_t EDI_TYPE_MODIFIERS[2];
-#endif
-
-/*! \struct edi_object_metadata_t
- * \brief A packed structure holding all data to identify an object to the EDI object system. */
-typedef struct {
-       /*! \brief Points to the instance data of the object represented by this structure.
-        *
-        * An object_pointer to the object this structure refers to.  The this pointer, so to speak. */
-       object_pointer object;
-       /*! \brief Points the internal record kept by the runtime describing the object's class.
-        *
-        * Points to wherever the runtime has stored the class data this object was built from.  The class data doesn't need to be
-        * readable to the driver, and so this pointer can point to an arbitrary runtime-reachable location. */
-       data_pointer object_class;
-} edi_object_metadata_t;
-
-/*! \struct edi_variable_declaration_t
- * \brief The data structure used to describe a variable declaration to the EDI object system.
- *
- * The data structure used to describe a variable declaration to the EDI object system.  The context of the declaration depends on
- * where the data structure appears, ie: alone, in a class declaration, in a parameter list, etc. */
-typedef struct {
-       /*! \brief The type of the declared variable. 
-        *
-        * The type of the variable, which must be a valid EDI primitive type as specified in the constant EDI_BASE_TYPES and
-        * possibly modified by a modifier specified in the constant EDI_TYPE_MODIFIERS. */
-       edi_string_t type;
-       /*! \brief The name of the declared variable. */
-       edi_string_t name;
-       /*! \brief Number of array entries if this variable is an array declaration. 
-        *
-        * An int32_t specifying the number of variables of 'type' in the array 'name'.  For a single variable this value should
-        * simply be set to 1, for values greater than 1 a packed array of contiguous variables is being declared, and a value of 0
-        * is invalid. */
-       int32_t array_length;
-} edi_variable_declaration_t;
-
-/*! \struct edi_function_declaration_t
- * \brief The data structure used to declare a function to the EDI object system. */
-typedef struct {
-       /*! \brief The return type of the function.  The same type rules which govern variable definitions apply here. */
-       edi_string_t return_type;
-       /*! \brief The name of the declared function. */
-       edi_string_t name;
-       /*! \brief The version number of the function, used to tell different implementations of the same function apart. */
-       uint32_t version;
-       /*! \brief The number of arguments passed to the function.
-        *
-        * The number of entries in the member arguments that the object system should care about.  Caring about less misses
-        * parameters to functions, caring about more results in buffer overflows. */
-       uint32_t num_arguments;
-       /*! \brief An array of the declared function's arguments.
-        *
-        * A pointer to an array num_arguments long containing edi_variable_declaration_t's for each argument to the declared
-        * function.*/
-       edi_variable_declaration_t *arguments;
-       /*!\brief A pointer to the declared function's code in memory. */
-       function_pointer code;
-} edi_function_declaration_t;
-
-/*! \brief A pointer to a function for constructing instances of a class.
- *
- * A pointer to a function which takes no parameters and returns an object_pointer pointing to the newly made instance of a class.
- * It is the constructor's responsibility to allocate memory for the new object.  Each EDI class needs one of these. */
-typedef object_pointer (*edi_constructor_t)(void);
-/*! \brief A pointer to a function for destroying instances of a class.
- *
- * A pointer to a function which takes an object_pointer as a parameter and returns void.  This is the destructor counterpart to a
- * class's edi_constructor_t, it destroys the object pointed to by its parameter and frees the object's memory.  Every class must
- * have one */
-typedef void (*edi_destructor_t)(object_pointer);
-
-/*! \brief Information the driver must give the runtime about its classes so EDI can construct them and call their methods.
- *
- * A structure used to declare a class to an EDI runtime so instances of it can be constructed by the EDI object system. */
-typedef struct {
-       /*! \brief The name of the class declared by the structure. */
-       edi_string_t name;
-       /*! \brief The version of the class.  This number is used to tell identically named but differently
-        * implemented classes apart.*/
-       uint32_t version;
-       /*! \brief The number of methods in the 'methods' function declaration array. */
-       uint32_t num_methods;
-       /*! \brief An array of edi_function_declaration_t declaring the methods of this class. */
-       edi_function_declaration_t *methods;
-       /*! \brief Allocates the memory for a new object of the declared class and constructs the object.  Absolutely required.*/
-       edi_constructor_t constructor;
-       /*! \brief Destroys the given object of the declared class and frees its memory. Absolutely required. */
-       edi_destructor_t destructor;
-       /*! \brief A pointer to another EDI class declaration structure specifying the declared class's parent class. 
-        *
-        * Points to a parent class declared in another class declaration.  It can be NULL to mean this class has no parent. */
-       struct edi_class_declaration_t *parent;
-} edi_class_declaration_t;
-
-/*! \brief Checks the existence of the named class.
- *
- * This checks for the existence on THE CLASS LIST of the class named by its edi_string_t parameter and returns a signed int32_t.  If
- * the class isn't found (ie: it doesn't exist as far as EDI is concerned) -1 is returned, if the class is owned by the driver
- * (implemented by the driver and declared to the runtime by the driver) 0, and if the class is owned by the runtime (implemented by
- * the runtime) 1. */
-int32_t check_class_existence(edi_string_t class_name);
-/*! \brief Constructs an object of the named class and returns its object_pointer and a data_pointer to its class data.
- *
- * Given a valid class name in an edi_string_t this function constructs the specified class and returns an edi_metadata_t describing
- * the new object as detailed in OBJECT CREATION AND DESTRUCTION.  If the construction fails it returns a structure full of NULL
- * pointers. */
-edi_object_metadata_t construct_object(edi_string_t class_name);
-/*! \brief Destroys the given object using its class data.
- *
- * As specified in OBJECT CREATION AND DESTRUCTION this function should destroy an object when given its valid edi_metadata_t.  The
- * destruction is accomplished by calling the class's destructor. */
-void destroy_object(edi_object_metadata_t object);
-/*! \brief Obtains a function pointer to a named method of a given class. 
- *
- * When given a valid data_pointer object_class from an edi_object_metadata_t and an edi_string_t representing the name of the
- * desired method retrieves a function_pointer to the method's machine code in memory.  If the desired method isn't found, NULL is
- * returned. */
-function_pointer get_method_by_name(data_pointer object_class,edi_string_t method_name);
-/*! \brief Obtains a function pointer to a method given by a declaration of the given class if the class's method matches the
- * declaration. 
- *
- * Works just like get_method_by_name(), but by giving an edi_function_declaration_t for the desired method instead of just its name.
- * Performs detailed checking against THE CLASS LIST to make sure that the method returned exactly matches the declaration passed
- * in. */
-function_pointer get_method_by_declaration(data_pointer object_class,edi_function_declaration_t declaration);
-
-/* Runtime typing information. */
-/*! \brief Returns the name of the class specified by a pointer to class data. 
- *
- * Given the data_pointer to an object's class data as stored in an edi_object_metadata_t retrieves the name of the object's class
- * and returns it in an edi_string_t. */
-edi_string_ptr_t get_object_class(data_pointer object_class);
-/*! \brief Returns the name of a class's parent class.
- *
- * When given an edi_string_t with a class name in it, returns another edi_string_t containing the name of the class's parent, or an
- * empty string. */
-edi_string_ptr_t get_class_parent(edi_string_t some_class);
-/*! \brief Returns the internal class data of a named class (if it exists) or NULL.
- *
- * When given an edi_string_t with a valid class name in it, returns a pointer to the runtime's internal class data for that class.
- * Otherwise, it returns NULL. */
-data_pointer get_internal_class(edi_string_t some_class);
-
-#endif 
diff --git a/Modules/Interfaces/EDI/edi/edi_port_io.h b/Modules/Interfaces/EDI/edi/edi_port_io.h
deleted file mode 100644 (file)
index a2a1773..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef EDI_PORT_IO_H
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-/* Modified by thePowersGang (John Hodge)
- * - Surround variable definitions with an #ifdef IMPLEMENTING_EDI
- */
-
-#define EDI_PORT_IO_H
-
-/*! \file edi_port_io.h
- * \brief Declaration and description of EDI's port I/O class.
- *
- * Data structures and algorithms this header represents:
- *
- *     DATA STRUCTURE AND ALGORITHM: PORT I/O OBJECTS - A class named "EDI-IO-PORT" is defined as an encapsulation of the port I/O
- * used on some machine architectures.  Each object of this class represents a single I/O port which can be read from and written to
- * in various sizes.  Each port can be held by one object only at a time. */
-
-#include "edi_objects.h"
-
-/*! \brief Macro to create methods for reading from ports.
- *
- * This macro creates four similar methods, differing in the size of the type they read from the I/O port held by the object.  Their
- * parameter is a pointer to the output type, which is filled with the value read from the I/O port.  They return 1 for success, -1
- * for an uninitialized I/O port object, and 0 for other errors. */
-#define port_read_method(type,name) int32_t (*name)(object_pointer port_object, type *out)
-/*! \brief Macro to create methods for writing to ports.
- *
- * This macro creates four more similar methods, differing in the size of the type they write to the I/O port held by the object.
- * Their parameter is the value to write to the port.  They return 1 for success, -1 for an uninitialized I/O port object and 0 for
- * other errors. */
-#define port_write_method(type,name) int32_t (*name)(object_pointer port_object, type in)
-
-/*! \brief Name of EDI I/O port class. (Constant)
- *
- * A CPP constant with the value of #io_port_class */
-#define        IO_PORT_CLASS   "EDI-IO-PORT"
-/*! \brief Name of EDI I/O port class.
- *
- * An edi_string_t containing the class name "EDI-IO-PORT". */
-#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
-const edi_string_t io_port_class = IO_PORT_CLASS;
-#else
-extern const edi_string_t io_port_class;
-#endif
-
-#ifndef IMPLEMENTING_EDI
-/*! \brief int32_t EDI-IO-PORT.init_io_port(unsigned int16_t port);
- *
- * This method takes an unsigned int16_t representing a particular I/O port and initializes the invoked EDI-IO-PORT object with it.
- * The method returns 1 if successful, -1 if the I/O port could not be obtained for the object, and 0 for all other errors. */
-EDI_DEFVAR int32_t (*init_io_port)(object_pointer port_object, uint16_t port);
-/*! \brief Get the port number from a port object. */
-EDI_DEFVAR uint16_t (*get_port_number)(object_pointer port);
-/*! \brief Method created by port_read_method() in order to read bytes (int8s) from I/O ports. */
-EDI_DEFVAR int32_t (*read_byte_io_port)(object_pointer port_object, int8_t *out);
-/*! \brief Method created by port_read_method() in order to read words (int16s) from I/O ports. */
-EDI_DEFVAR int32_t (*read_word_io_port)(object_pointer port_object, int16_t *out);
-/*! \brief Method created by port_read_method() in order to read longwords (int32s) from I/O ports. */
-EDI_DEFVAR int32_t (*read_long_io_port)(object_pointer port_object, int32_t *out);
-/*! \brief Method created by port_read_method() in order to read long longwords (int64s) from I/O ports. */
-EDI_DEFVAR int32_t (*read_longlong_io_port)(object_pointer port_object,int64_t *out);
-/*! \brief Method of EDI-IO-PORT to read long strings of data from I/O ports.
- *
- * Reads arbitrarily long strings of data from the given I/O port.  Returns 1 for success, -1 for an uninitialized port object, -2
- * for a bad pointer to the destination buffer, and 0 for all other errors. */
-EDI_DEFVAR int32_t (*read_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *out);
-/*! \brief Method created by port_write_method() in order to write bytes (int8s) to I/O ports. */
-EDI_DEFVAR int32_t (*write_byte_io_port)(object_pointer port_object, int8_t in);
-/*! \brief Method created by port_write_method() in order to write words (int16s) to I/O ports. */
-EDI_DEFVAR int32_t (*write_word_io_port)(object_pointer port_object, int16_t in);
-/*! \brief Method created by port_write_method() in order to write longwords (int32s) to I/O ports. */
-EDI_DEFVAR int32_t (*write_long_io_port)(object_pointer port_object, int32_t in);
-/*! \brief Method created by port_write_method() in order to write long longwords (int64s) to I/O ports. */
-EDI_DEFVAR int32_t (*write_longlong_io_port)(object_pointer port_object, int64_t in);
-/*! \brief Method of EDI-IO-PORT to write long strings of data to I/O ports.
- *
- * Writes arbitrarily long strings of data to the given I/O port.  Returns 1 for success, -1 for an uninitialized port object, -2
- * for a bad pointer to the source buffer, and 0 for all other errors. */
-EDI_DEFVAR int32_t (*write_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *in);
-
-#endif // defined(IMPLEMENTING_EDI)
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/edi_pthreads.h b/Modules/Interfaces/EDI/edi/edi_pthreads.h
deleted file mode 100644 (file)
index c21fa75..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef EDI_PTHREADS
-
-/* Copyright (c)  2006  Eli Gottlieb.
- * Permission is granted to copy, distribute and/or modify this document
- * under the terms of the GNU Free Documentation License, Version 1.2
- * or any later version published by the Free Software Foundation;
- * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
- * Texts.  A copy of the license is included in the file entitled "COPYING". */
-
-#define EDI_PTHREADS
-/*!\file edi_pthreads.h
- * \brief A basic subset of POSIX Threads functionality, providing threading and thread synchronization.
- *
- * A very basic POSIX Threads interface.  Note that pthreads are not a class, because none of these calls really gels with
- * object-oriented programming.  Also, if drivers aren't processes or threads under the implementing operating system a small
- * threading system must be implemented in-runtime just to multiplex the pthreads of EDI drivers.  Sorry about that.
- *
- * Data structures and algorithms this header represents:
- *
- *     ALGORITHM AND DATA STRUCTURE: POSIX Threading - The runtime must provide enough of a POSIX threading interface to implement
- * the calls described here.  The actual multithreading must be performed by the runtime, and the runtime can implement that
- * multithreading however it likes as long as the given POSIX Threads subset works.  There is, however, a caveat: since the runtime
- * calls the driver like it would a library, the driver must perceive all calls made to it by the runtime as running under one thread.
- * From this thread the driver can create others.  Such behavior is a quirk of EDI, and does not come from the POSIX standard.
- * However, it is necessary to provide the driver with a thread for its own main codepaths.  For further details on a given POSIX
- * Threading routine, consult its Unix manual page. */
-
-#include "edi_objects.h"
-
-/* Placeholder type definitions.  Users of the PThreads interface only ever need to define pointers to these types. */
-/*!\brief Opaque POSIX Threading thread attribute type. */
-typedef void pthread_attr_t;
-/*!\brief Opaque POSIX Threading mutex (mutual exclusion semaphore) type. */
-typedef void pthread_mutex_t;
-/*!\brief Opaque POSIX Threading mutex attribute type. */
-typedef void pthread_mutex_attr_t;
-
-/*!\struct sched_param
- * \brief POSIX Threading scheduler parameters for a thread. */
-typedef struct {
-       /*!\brief The priority of the thread. */
-       int32_t sched_priority;
-} sched_param;
-
-/*!\brief POSIX Threading thread identifier. */
-typedef uint32_t pthread_t;
-/*!\brief POSIX Threading thread function type.
- *
- * A function pointer to a thread function, with the required signature of a thread function.  A thread function takes one untyped
- * pointer as an argument and returns an untyped pointer.  Such a function is a thread's main routine: it's started with the thread,
- * and the thread exits if it returns. */
-typedef void *(*pthread_function_t)(void*);
-
-/*!\brief Insufficient resources. */
-#define EAGAIN -1
-/*!\brief Invalid parameter. */
-#define EINVAL -2
-/*!\brief Permission denied. */
-#define EPERM -3
-/*!\brief Operation not supported. */
-#define ENOTSUP -4
-/*!\brief Priority scheduling for POSIX/multiple schedulers is not implemented. */
-#define ENOSYS -5
-/*!\brief Out of memory. */
-#define ENOMEM -6
-/*!\brief Deadlock.  Crap. */
-#define EDEADLK -7
-/*!\brief Busy.  Mutex already locked. */
-#define EBUSY -8
-
-/*!\brief Scheduling policy for regular, non-realtime scheduling.  The default. */
-#define SCHED_OTHER 0
-/*!\brief Real-time, first-in first-out scheduling policy.  Requires special (superuser, where such a thing exists) permissions. */
-#define SCHED_FIFO 1
-/*!\brief Real-time, round-robin scheduling policy.  Requires special (superuser, where such a thing exists) permissions. */
-#define SCHED_RR 0
-
-/*!\brief Creates a new thread with the given attributes, thread function and arguments, giving back the thread ID of the new
- * thread.
- *
- * pthread_create() creates a new thread of control that executes concurrently with the calling thread.  The new thread applies the
- * function start_routine, passing it arg as its argument.  The attr argument specifies thread attributes to apply to the new thread;
- * it can also be NULL for the default thread attributes (joinable with default scheduling policy).  On success this function returns
- * 0 and places the identifier of the new thread into thread_id.  On an error, pthread_create() can return EAGAIN if insufficient
- * runtime resources are available to create the requested thread, EINVAL a value specified by attributes is invalid, or EPERM if the
- * caller doesn't have permissions to set the given attributes.
- *
- * For further information: man 3 pthread_create */
-int32_t pthread_create(pthread_t *thread_id, const pthread_attr_t *attributes, pthread_function_t thread_function, void *arguments);
-/*!\brief Terminates the execution of the calling thread.  The thread's exit code with by status, and this routine never returns. */
-void pthread_exit(void *status);
-/*!\brief Returns the thread identifier of the calling thread. */
-pthread_t pthread_self();
-/*!\brief Compares two thread identifiers.
- *
- * Determines of the given two thread identifiers refer to the same thread.  If so, returns non-zero.  Otherwise, 0 is returned. */
-int32_t pthread_equal(pthread_t thread1, pthread_t thread2);
-/*!\brief Used by the calling thread to relinquish use of the processor.  The thread then waits in the run queue to be scheduled
- * again. */
-void pthread_yield();
-
-/*!\brief Gets the scheduling policy of the given attributes.
- *
- * Places the scheduling policy for attributes into policy.  Returns 0 on success, EINVAL if attributes was invalid, and ENOSYS if
- * priority scheduling/multiple scheduler support is not implemented. */
-int32_t pthread_attr_getschedpolicy(const pthread_attr_t *attributes, int32_t *policy);
-/*!\brief Sets the scheduling policy of the given attributes.
- *
- * Requests a switch of scheduling policy to policy for the given attributes.  Can return 0 for success, EINVAL if the given policy
- * is not one of SCHED_OTHER, SCHED_FIFO or SCHED_RR or ENOTSUP if policy is either SCHED_FIFO or SCHED_RR and the driver is not
- * running with correct privileges. */
-int32_t pthread_attr_setschedpolicy(pthread_attr_t *attributes, int32_t policy);
-
-/*!\brief Gets the scheduling paramaters (priority) from the given attributes.
- *
- * On success, stores scheduling parameters in param from attributes, and returns 0.  Otherwise, returns non-zero error code, such
- * as EINVAL if the attributes object is invalid. */
-int32_t pthread_attr_getschedparam(const pthread_attr_t *attributes, sched_param *param);
-/*!\brief Sets the scheduling parameters (priority) of the given attributes.
- *
- * Requests that the runtime set the scheduling parameters (priority) of attributes from param. Returns 0 for success, EINVAL for an
- * invalid attributes object, ENOSYS when multiple schedulers/priority scheduling is not implemented, and ENOTSUP when the value of
- * param isn't supported/allowed. */
-int32_t pthread_attr_setschedparam(pthread_attr_t *attributes, const sched_param *param);
-
-/*!\brief The thread obtains its scheduling properties explicitly from its attributes structure. */
-#define PTHREAD_EXPLICIT_SCHED 1
-/*!\brief The thread inherits its scheduling properties from its parent thread. */
-#define PTHREAD_INHERIT_SCHED 0
-
-/*!\brief Returns the inheritsched attribute of the given attributes.
- *
- * On success, returns 0 and places the inheritsched attribute from attributes into inherit.  This attribute specifies where the
- * thread's scheduling properites shall come from, and can be set to PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED.  On failure it
- * returns EINVAL if attributes was invalid or ENOSYS if multiple schedulers/priority scheduling isn't implemented. */
-int32_t pthread_attr_getinheritsched(const pthread_attr_t *attributes, int32_t *inherit);
-/*!\brief Sets the inheritsched attribute of the given attributes.
- *
- * On success, places inherit into the inheritsched attribute of attributes and returns 0.  inherit must either contain
- * PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED.  On failure, this routine returns EINVAL if attributes is invalid, ENOSYS when
- * multiple schedulers/priority scheduling isn't implemented, and ENOSUP if the inheritsched attribute isn't supported. */
-int32_t pthread_attr_setinheritsched(pthread_attr_t *attributes, int32_t inherit);
-
-/*!\brief Creates a new POSIX Threads mutex, which will initially be unlocked.
- *
- * Creates a new mutex with the given attributes.  If attributes is NULL, the default attributes will be used.  The mutex starts out
- * unlocked.  On success, the new mutex resides in the mutex structure pointed to by mutex, and this routine routines 0.  On failure,
- * it returns EAGAIN if the system lacked sufficient non-memory resources to initialize the mutex, EBUSY if the given mutex is
- * already initialized and in use, EINVAL if either parameter is invalid, and ENOMEM if the system lacks the memory for a new
- * mutex.  Note: All EDI mutexes are created with the default attributes, and are of type PTHREAD_MUTEX_ERRORCHECK.  This means
- * undefined behavior can never result from an badly placed function call. */
-int32_t pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *attributes);
-/*!\brief Locks the given mutex.
- *
- * Locks the given mutex.  If the mutex is already locked, blocks the calling thread until it can acquire the lock.  When this
- * routine returns successfully, it will return 0 and the calling thread will own the lock of the mutex.  If the call fails, it can
- * return EINVAL when mutex is invalid or EDEADLK if the calling thread already owns the mutex. */
-int32_t pthread_mutex_lock(pthread_mutex_t *mutex);
-/*!\brief Unlocks the given mutex.
- *
- * Unlocks the given mutex, returning 0 on success.  On failure, it can return EINVAL when mutex is invalid or EPERM when the
- * calling thread doesn't own the mutex. */
-int32_t pthread_mutex_unlock(pthread_mutex_t *mutex);
-/*!\brief Tries to lock the given mutex, returning immediately even if the mutex is already locked.
- *
- * Attempts to lock the given mutex, but returns immediately if it can't acquire a lock.  Returns 0 when it has acquired a lock,
- * EBUSY if the mutex is already locked, or EINVAL if mutex is invalid. */
-int32_t pthread_mutex_trylock(pthread_mutex_t *mutex);
-/*!\brief Destroys the given mutex, or at least the internal structure of it. 
- *
- * Deletes the given mutex, making mutex invalid until it should be initialized by pthread_mutex_init().  Returns 0 on success,
- * EINVAL when mutex is invalid, or EBUSY when mutex is locked or referenced by another thread. */
-int32_t pthread_mutex_destroy (pthread_mutex_t *mutex);
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi/helpers.h b/Modules/Interfaces/EDI/edi/helpers.h
deleted file mode 100644 (file)
index d7bc138..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef HELPERS_H
-
-#define HELPERS_H
-
-#include <edi.h>
-
-// Locally Defined
-bool edi_string_equal(edi_string_t x,edi_string_t y);
-bool descends_from(data_pointer object_class,edi_string_t desired_class);
-data_pointer get_actual_class(edi_string_t ancestor,int32_t num_objects,edi_object_metadata_t *objects);
-
-// Local Copy/set
-void *memcpyd(void *dest, void *src, unsigned int count);
-
-// Implementation Defined Common functions
-void *memcpy(void *dest, void *src, unsigned int count);
-void *memmove(void *dest, void *src, unsigned int count);
-void *realloc(void *ptr, unsigned int size);
-
-#endif
diff --git a/Modules/Interfaces/EDI/edi_int.inc.c b/Modules/Interfaces/EDI/edi_int.inc.c
deleted file mode 100644 (file)
index 0ab3359..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * AcessOS EDI Interface
- * - IRQ Class
- * 
- * By John Hodge (thePowersGang)
- * 
- * This file has been released into the public domain.
- * You are free to use it as you wish.
- */
-#include "edi/edi.h"
-
-// === TYPES ===
-typedef struct {
-       uint16_t        State;  // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
-       uint16_t        Num;
-       interrupt_handler_t     Handler;
-} tEdiIRQ;
-
-// === PROTOTYPES ===
-void EDI_Int_IRQ_Handler(tRegs *Regs);
-
-// === GLOBALS ===
-tEdiIRQ        gEdi_IRQObjects[16];
-
-// === FUNCTIONS ===
-/**
- * \fn object_pointer Edi_Int_IRQ_Construct(void)
- * \brief Creates a new IRQ Object
- * \return     Pointer to object
- */
-object_pointer Edi_Int_IRQ_Construct(void)
-{
-        int    i;
-       // Search for a free irq
-       for( i = 0; i < 16; i ++ )
-       {
-               if(gEdi_IRQObjects[i].State)    continue;
-               gEdi_IRQObjects[i].State = 1;
-               gEdi_IRQObjects[i].Num = 0;
-               gEdi_IRQObjects[i].Handler = NULL;
-               return &gEdi_IRQObjects[i];
-       }
-       return NULL;
-}
-
-/**
- * \fn void Edi_Int_IRQ_Destruct(object_pointer Object)
- * \brief Destruct an IRQ Object
- * \param Object       Object to destroy
- */
-void Edi_Int_IRQ_Destruct(object_pointer Object)
-{
-       tEdiIRQ *obj;
-       
-       VALIDATE_PTR(Object,);
-       obj = GET_DATA(Object);
-       
-       if( !obj->State )       return;
-       
-       if( obj->Handler )
-               irq_uninstall_handler( obj->Num );
-       
-       if( obj->State & 0x8000 ) {     // If in heap, free
-               free(Object);
-       } else {        // Otherwise, mark as unallocated
-               obj->State = 0;
-       }
-}
-
-/**
- * \fn int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
- * \brief Initialises an IRQ
- * \param Object       Object Pointer (this)
- * \param Num  IRQ Number to use
- * \param Handler      Callback for IRQ
- */
-int32_t        Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
-{
-       tEdiIRQ *obj;
-       
-       //LogF("Edi_Int_IRQ_InitInt: (Object=0x%x, Num=%i, Handler=0x%x)\n", Object, Num, Handler);
-       
-       VALIDATE_PTR(Object,0);
-       obj = GET_DATA(Object);
-       
-       if( !obj->State )       return 0;
-       
-       if(Num > 15)    return 0;
-       
-       // Install the IRQ if a handler is passed
-       if(Handler) {
-               if( !irq_install_handler(Num, Edi_Int_IRQ_Handler) )
-                       return 0;
-               obj->Handler = Handler;
-       }
-       
-       obj->Num = Num;
-       obj->State &= ~0x3FFF;
-       obj->State |= 2;        // Set initialised flag
-       return 1;
-}
-
-/**
- * \fn uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
- * \brief Returns the irq number associated with the object
- * \param Object       IRQ Object to get number from
- * \return IRQ Number
- */
-uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
-{
-       tEdiIRQ *obj;
-       
-       VALIDATE_PTR(Object,0);
-       obj = GET_DATA(Object);
-       
-       if( !obj->State )       return 0;
-       return obj->Num;
-}
-
-/**
- * \fn void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
- * \brief Set the IRQ handler for an IRQ object
- * \param Object       IRQ Object to alter
- * \param Handler      Function to use as handler
- */
-void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
-{
-       tEdiIRQ *obj;
-       
-       // Get Data Pointer
-       VALIDATE_PTR(Object,);
-       obj = GET_DATA(Object);
-       
-       // Sanity Check arguments
-       if( !obj->State )       return ;
-       
-       // Only register the mediator if it is not already
-       if( Handler && !obj->Handler )
-               if( !irq_install_handler(obj->Num, Edi_Int_IRQ_Handler) )
-                       return ;
-       obj->Handler = Handler;
-}
-
-/**
- * \fn void EDI_Int_IRQ_Return(object_pointer Object)
- * \brief Return from interrupt
- * \param Object       IRQ Object
- * \note Due to the structure of acess interrupts, this is a dummy
- */
-void EDI_Int_IRQ_Return(object_pointer Object)
-{
-}
-
-/**
- * \fn void Edi_Int_IRQ_Handler(struct regs *Regs)
- * \brief EDI IRQ Handler - Calls the handler 
- * \param Regs Register state at IRQ call
- */
-void Edi_Int_IRQ_Handler(struct regs *Regs)
-{
-        int    i;
-       for( i = 0; i < 16; i ++ )
-       {
-               if(!gEdi_IRQObjects[i].State)   continue;       // Unused, Skip
-               if(gEdi_IRQObjects[i].Num != Regs->int_no)      continue;       // Another IRQ, Skip
-               if(!gEdi_IRQObjects[i].Handler) continue;       // No Handler, Skip
-               gEdi_IRQObjects[i].Handler( Regs->int_no );     // Call Handler
-               return;
-       }
-}
-
-
-// === CLASS DECLARATION ===
-static edi_function_declaration_t      scEdi_Int_Functions_IRQ[] = {
-               {"int32_t", "init_interrupt", 1, 3, NULL, //scEdi_Int_Variables_IO[0],
-                       (function_pointer)Edi_Int_IRQ_InitInt
-                       },
-               {"uint32_t", "interrupt_get_irq", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
-                       (function_pointer)Edi_Int_IRQ_GetInt
-                       },
-               {"void", "interrupt_set_handler", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
-                       (function_pointer)Edi_Int_IRQ_GetInt
-                       },
-               {"void", "interrupt_return", 1, 1, NULL, //scEdi_Int_Variables_IO[3],
-                       (function_pointer)Edi_Int_IRQ_GetInt
-                       }
-       };
-static edi_class_declaration_t scEdi_Int_Class_IRQ = 
-       {
-               INTERRUPTS_CLASS, 1, 12,
-               scEdi_Int_Functions_IRQ,
-               Edi_Int_IRQ_Construct,
-               Edi_Int_IRQ_Destruct,
-               NULL
-       };
diff --git a/Modules/Interfaces/EDI/edi_io.inc.c b/Modules/Interfaces/EDI/edi_io.inc.c
deleted file mode 100644 (file)
index 8a6ef22..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * AcessOS EDI Interface
- * - IO Port Class
- * 
- * By John Hodge (thePowersGang)
- * 
- * This file has been released into the public domain.
- * You are free to use it as you wish.
- */
-#include "edi/edi.h"
-
-// === TYPES ===
-typedef struct {
-       uint16_t        State;  // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
-       uint16_t        Num;
-} tEdiPort;
-
-// === GLOBALS ===
-#define        NUM_PREALLOC_PORTS      128
-tEdiPort       gEdi_PortObjects[NUM_PREALLOC_PORTS];
-
-// === FUNCTIONS ===
-/**
- * \fn object_pointer Edi_Int_IO_Construct(void)
- * \brief Creates a new IO Port Object
- * \return     Pointer to object
- */
-object_pointer Edi_Int_IO_Construct(void)
-{
-       tEdiPort        *ret;
-        int    i;
-       // Search for a free preallocated port
-       for( i = 0; i < NUM_PREALLOC_PORTS; i ++ )
-       {
-               if(gEdi_PortObjects[i].State)   continue;
-               gEdi_PortObjects[i].State = 1;
-               gEdi_PortObjects[i].Num = 0;
-               return &gEdi_PortObjects[i];
-       }
-       // Else, use heap space
-       ret = malloc( sizeof(tEdiPort) );
-       ret->State = 0x8001;
-       ret->Num = 0;
-       return ret;
-}
-
-/**
- * \fn void Edi_Int_IO_Destruct(object_pointer Object)
- * \brief Destruct an IO Port Object
- * \param Object       Object to destroy
- */
-void Edi_Int_IO_Destruct(object_pointer Object)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object,);
-       obj = GET_DATA(Object);
-       
-       if(obj->State & 0x8000) {       // If in heap, free
-               free(Object);
-       } else {        // Otherwise, mark as unallocated
-               obj->State = 0;
-       }
-}
-
-/**
- * \fn int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
- * \brief Initialises an IO Port
- * \param Object       Object Pointer (this)
- * \param Port Port Number to use
- */
-int32_t        Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       
-       if( !obj->State )       return 0;
-       obj->Num = Port;
-       obj->State &= ~0x3FFF;
-       obj->State |= 2;        // Set initialised flag
-       return 1;
-}
-
-/**
- * \fn uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
- * \brief Returns the port number associated with the object
- * \param Object       Port Object to get number from
- * \return Port Number
- */
-uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       // Check if valid
-       if( !obj->State )       return 0;
-       // Return Port No
-       return obj->Num;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
- * \brief Read a byte from an IO port
- * \param Object       Port Object
- * \param out  Pointer to put read data
- */
-int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "inb %%dx, %%al" : "=a" (*out) : "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
- * \brief Read a word from an IO port
- * \param Object       Port Object
- * \param out  Pointer to put read data
- */
-int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
-{
-       
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "inw %%dx, %%ax" : "=a" (*out) : "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
- * \brief Read a double word from an IO port
- * \param Object       Port Object
- * \param out  Pointer to put read data
- */
-int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
-{
-       
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out) : "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
- * \brief Read a quad word from an IO port
- * \param Object       Port Object
- * \param out  Pointer to put read data
- */
-int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
-{
-       uint32_t        *out32 = (uint32_t*)out;
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out32) : "d" ( obj->Num ) );
-       __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*(out32+1)) : "d" ( obj->Num+4 ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
- * \brief Read a byte from an IO port
- * \param Object       Port Object
- * \param Length       Number of bytes to read
- * \param out  Pointer to put read data
- */
-int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "rep insb" : : "c" (Length), "D" (out), "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
- * \brief Write a byte from an IO port
- * \param Object       Port Object
- * \param in   Data to write
- */
-int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "outb %%al, %%dx" : : "a" (in), "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
- * \brief Write a word from an IO port
- * \param Object       Port Object
- * \param in   Data to write
- */
-int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "outw %%ax, %%dx" : : "a" (in), "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
- * \brief Write a double word from an IO port
- * \param Object       Port Object
- * \param in   Data to write
- */
-int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (in), "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
- * \brief Write a quad word from an IO port
- * \param Object       Port Object
- * \param in   Data to write
- */
-int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
-{
-       uint32_t        *in32 = (uint32_t*)&in;
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*in32), "d" ( obj->Num ) );
-       __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*(in32+1)), "d" ( obj->Num+4 ) );
-       
-       return 1;
-}
-
-/**
- * \fn int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
- * \brief Read a byte from an IO port
- * \param Object       Port Object
- * \param Length       Number of bytes to write
- * \param in   Pointer to of data to write
- */
-int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
-{
-       tEdiPort        *obj;
-       // Get Data Pointer
-       VALIDATE_PTR(Object, 0);
-       obj = GET_DATA(Object);
-       if( !obj->State )       return 0;
-       if( obj->State & 1 )    return -1;      // Unintialised
-       
-       __asm__ __volatile__ ( "rep outsb" : : "c" (Length), "D" (in), "d" ( obj->Num ) );
-       
-       return 1;
-}
-
-// === CLASS DECLARATION ===
-/*static edi_variable_declaration_t    *scEdi_Int_Variables_IO[] = {
-       {
-               {"pointer", "port_object", 0},
-               {"uint16_t", "port", 0}
-       },
-       {
-               {"pointer", "port_object", 0}
-       },
-       {
-               {"pointer", "port_object", 0},
-               {"pointer int8_t", "out", 0}
-       }
-};*/
-static edi_function_declaration_t      scEdi_Int_Functions_IO[] = {
-               {"int32_t", "init_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[0],
-                       (function_pointer)Edi_Int_IO_InitPort
-                       },
-               {"uint16_t", "get_port_number", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
-                       (function_pointer)Edi_Int_IO_GetPortNum
-                       },
-               {"int32_t", "read_byte_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
-                       (function_pointer)Edi_Int_IO_ReadByte
-                       },
-               {"int32_t", "read_word_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"pointer int16_t", "out", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_ReadWord
-                       },
-               {"int32_t", "read_long_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"pointer int32_t", "out", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_ReadDWord
-                       },
-               {"int32_t", "read_longlong_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"pointer int64_t", "out", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_ReadQWord
-                       },
-               {"int32_t", "read_string_io_port", 1, 3, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"int32_T", "data_length", 0},
-                               {"pointer int64_t", "out", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_ReadString
-                       },
-                       
-               {"int32_t", "write_byte_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"int8_t", "in", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_WriteByte},
-               {"int32_t", "write_word_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"int16_t", "in", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_WriteWord},
-               {"int32_t", "write_long_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"int32_t", "in", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_WriteDWord},
-               {"int32_t", "write_longlong_io_port", 1, 2, NULL/*{
-                               {"pointer", "port_object", 0},
-                               {"int64_t", "in", 0}
-                       }*/,
-                       (function_pointer)Edi_Int_IO_WriteQWord}
-       };
-static edi_class_declaration_t scEdi_Int_Class_IO = 
-       {
-               IO_PORT_CLASS, 1, 12,
-               scEdi_Int_Functions_IO,
-               Edi_Int_IO_Construct,
-               Edi_Int_IO_Destruct,
-               NULL
-       };
diff --git a/Modules/Interfaces/EDI/main.c b/Modules/Interfaces/EDI/main.c
deleted file mode 100644 (file)
index c3d0272..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Acess2 EDI Layer
- */
-#define DEBUG  0
-#define VERSION        ((0<<8)|1)
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#define        IMPLEMENTING_EDI        1
-#include "edi/edi.h"
-
-#define        VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0)
-#define        GET_DATA(_ptr)  (Object)
-
-#include "edi_io.inc.c"
-#include "edi_int.inc.c"
-
-// === STRUCTURES ===
-typedef struct sAcessEdiDriver {
-       struct sAcessEdiDriver  *Next;
-       tDevFS_Driver   Driver;
-        int    FileCount;
-       struct {
-               char    *Name;
-               tVFS_Node       Node;
-       }       *Files;
-       edi_object_metadata_t   *Objects;
-       edi_initialization_t    Init;
-       driver_finish_t Finish;
-} tAcessEdiDriver;
-
-// === PROTOTYPES ===
- int   EDI_Install(char **Arguments);
- int   EDI_DetectDriver(void *Base);
- int   EDI_LoadDriver(void *Base);
-vfs_node *EDI_FS_ReadDir(vfs_node *Node, int Pos);
-vfs_node *EDI_FS_FindDir(vfs_node *Node, char *Name);
- int   EDI_FS_CharRead(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
- int   EDI_FS_CharWrite(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
- int   EDI_FS_IOCtl(vfs_node *Node, int Id, void *Data);
-data_pointer EDI_GetInternalClass(edi_string_t ClassName);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL);
-tModuleLoader  gEDI_Loader = {
-       NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL
-};
-tSpinlock      glEDI_Drivers;
-tAcessEdiDriver        *gEdi_Drivers = NULL;
-edi_class_declaration_t        *gcEdi_IntClasses[] = {
-       &scEdi_Int_Class_IO, &scEdi_Int_Class_IRQ
-};
-#define        NUM_INT_CLASSES (sizeof(gcEdi_IntClasses)/sizeof(gcEdi_IntClasses[0]))
-char *csCharNumbers[] = {"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"};
-char *csBlockNumbers[] = {"blk0", "blk1", "blk2", "blk3", "blk4", "blk5", "blk6", "blk7", "blk8", "blk9"};
-
-// === CODE ===
-/**
- * \fn int EDI_Install(char **Arguments)
- * \brief Stub intialisation routine
- */
-int EDI_Install(char **Arguments)
-{
-       Module_RegisterLoader( &gEDI_Loader );
-       return 1;
-}
-
-/**
- * \brief Detects if a driver should be loaded by the EDI subsystem
- */
-int EDI_DetectDriver(void *Base)
-{
-       if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 )
-               return 0;
-       
-       return 1;
-}
-
-/**
- * \fn int Edi_LoadDriver(void *Base)
- * \brief Load an EDI Driver from a loaded binary
- * \param Base Binary Handle
- * \return 0 on success, non zero on error
- */
-int EDI_LoadDriver(void *Base)
-{
-       driver_init_t   init;
-       driver_finish_t finish;
-       tAcessEdiDriver *info;
-        int    i, j;
-        int    devfsId;
-       edi_class_declaration_t *classes;
-
-       ENTER("pBase", Base);
-       
-       // Get Functions
-       if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init)
-       ||      !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) )
-       {
-               Warning("[EDI  ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base);
-               Binary_Unload(Base);
-               return 0;
-       }
-       
-       // Allocate Driver Information
-       info = malloc( sizeof(tAcessEdiDriver) );
-       info->Finish = finish;
-       
-       // Initialise Driver
-       info->Init = init( 0, NULL );   // TODO: Implement Resources
-       
-       LOG("info->Init.driver_name = '%s'", info->Init.driver_name);
-       LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes);
-       
-       // Count mappable classes
-       classes = info->Init.driver_classes;
-       info->FileCount = 0;
-       info->Objects = NULL;
-       for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ )
-       {
-               if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 )
-               {
-                       data_pointer    *obj;
-                       // Initialise Object Instances
-                       for( ; (obj = classes[i].constructor()); j++ ) {
-                               LOG("%i - Constructed '%s'", j, classes[i].name);
-                               info->FileCount ++;
-                               info->Objects = realloc(info->Objects, sizeof(*info->Objects)*info->FileCount);
-                               info->Objects[j].object = obj;
-                               info->Objects[j].object_class = &classes[i];
-                       }
-               }
-               else
-                       LOG("%i - %s", i, classes[i].name);
-       }
-       
-       if(info->FileCount)
-       {
-                int    iNumChar = 0;
-               // Create VFS Nodes
-               info->Files = malloc( info->FileCount * sizeof(*info->Files) );
-               memset(info->Files, 0, info->FileCount * sizeof(*info->Files));
-               j = 0;
-               for( j = 0; j < info->FileCount; j++ )
-               {
-                       classes = info->Objects[j].object_class;
-                       if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 )
-                       {
-                               LOG("%i - %s", j, csCharNumbers[iNumChar]);
-                               info->Files[j].Name = csCharNumbers[iNumChar];
-                               info->Files[j].Node.NumACLs = 1;
-                               info->Files[j].Node.ACLs = &gVFS_ACL_EveryoneRW;
-                               info->Files[j].Node.ImplPtr = &info->Objects[j];
-                               info->Files[j].Node.Read = EDI_FS_CharRead;
-                               info->Files[j].Node.Write = EDI_FS_CharWrite;
-                               info->Files[j].Node.IOCtl = EDI_FS_IOCtl;
-                               info->Files[j].Node.CTime =
-                                       info->Files[j].Node.MTime =
-                                       info->Files[j].Node.ATime = now();
-                               
-                               iNumChar ++;
-                               continue;
-                       }
-               }
-               
-               // Create DevFS Driver
-               info->Driver.ioctl = EDI_FS_IOCtl;
-               memsetda(&info->Driver.rootNode, 0, sizeof(vfs_node) / 4);
-               info->Driver.Name = info->Init.driver_name;
-               info->Driver.RootNode.Flags = VFS_FFLAG_DIRECTORY;
-               info->Driver.RootNode.NumACLs = 1;
-               info->Driver.RootNode.ACLs = &gVFS_ACL_EveryoneRX;
-               info->Driver.RootNode.Length = info->FileCount;
-               info->Driver.RootNode.ImplPtr = info;
-               info->Driver.RootNode.ReadDir = EDI_FS_ReadDir;
-               info->Driver.RootNode.FindDir = EDI_FS_FindDir;
-               info->Driver.RootNode.IOCtl = EDI_FS_IOCtl;
-               
-               // Register
-               devfsId = dev_addDevice( &info->Driver );
-               if(devfsId == -1) {
-                       free(info->Files);      // Free Files
-                       info->Finish(); // Clean up driver
-                       free(info);             // Free info structure
-                       Binary_Unload(iDriverBase);     // Unload library
-                       return -3;      // Return error
-               }
-       }
-       
-       // Append to loaded list;
-       LOCK(&glEDI_Drivers);
-       info->Next = gEDI_Drivers;
-       gEDI_Drivers = info;
-       RELEASE(&glEDI_Drivers);
-       
-       LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path);
-       LEAVE('i', 1);
-       return 1;
-}
-
-// --- Filesystem Interaction ---
-/**
- * \brief Read from a drivers class list
- * \param Node Driver's Root Node
- * \param Pos  Index of file to get
- */
-char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos)
-{
-       tAcessEdiDriver *info;
-       
-       // Sanity Check
-       if(!Node)       return NULL;
-       
-       // Get Information Structure
-       info = (void *) Node->ImplPtr;
-       if(!info)       return NULL;
-       
-       // Check Position
-       if(Pos < 0)     return NULL;
-       if(Pos >= info->FileCount)      return NULL;
-       
-       return strdup( info->Files[Pos].Name );
-}
-
-/**
- * \fn tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
- * \brief Find a named file in a driver
- * \param Node Driver's Root Node
- * \param Name Name of file to find
- */
-tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
-{
-       tAcessEdiDriver *info;
-        int    i;
-       
-       // Sanity Check
-       if(!Node)       return NULL;
-       if(!Name)       return NULL;
-       
-       // Get Information Structure
-       info = (void *) Node->ImplPtr;
-       if(!info)       return NULL;
-       
-       for( i = 0; i < info->FileCount; i++ )
-       {
-               if(strcmp(info->Files[i].name, Name) == 0)
-                       return &info->Files[i].Node;
-       }
-       
-       return NULL;
-}
-
-/**
- * \fn Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from an EDI Character Device
- * \param Node File Node
- * \param Offset       Offset into file (ignored)
- * \param Length       Number of characters to read
- * \param Buffer       Destination for data
- * \return     Number of characters read
- */
-Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       edi_object_metadata_t   *meta;
-       edi_class_declaration_t *class;
-       
-       // Sanity Check
-       if(!Node || !Buffer)    return 0;
-       if(Length <= 0) return 0;
-       // Get Object Metadata
-       meta = (void *) Node->ImplPtr;
-       if(!meta)       return 0;
-       
-       // Get Class
-       class = meta->object_class;
-       if(!class)      return 0;
-       
-       // Read from object
-       if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length ))
-               return Length;
-
-       return 0;
-}
-
-/**
- * \fn Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Write to an EDI Character Device
- * \param Node File Node
- * \param Offset       Offset into file (ignored)
- * \param Length       Number of characters to write
- * \param Buffer       Source for data
- * \return     Number of characters written
- */
-Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       edi_object_metadata_t   *meta;
-       edi_class_declaration_t *class;
-       
-       // Sanity Check
-       if(!Node || !Buffer)    return 0;
-       if(Length <= 0) return 0;
-       // Get Object Metadata
-       meta = (void *) Node->ImplPtr;
-       if(!meta)       return 0;
-       
-       // Get Class
-       class = meta->object_class;
-       if(!class)      return 0;
-       
-       // Write to object
-       if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length ))
-               return Length;
-
-       return 0;
-}
-
-/**
- * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief Perfom an IOCtl call on the object
- */
-int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
-       return 0;
-}
-
-// --- EDI Functions ---
-/**
- * \fn data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
- * \brief Gets the structure of a driver defined class
- * \param ClassName    Name of class to find
- * \return Class definition or NULL
- */
-data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
-{
-        int    i;
-       tAcessEdiDriver *drv;
-       edi_class_declaration_t *classes;
-       
-       for(drv = gEdi_Drivers;
-               drv;
-               drv = drv->Next )
-       {
-               classes = drv->Init.driver_classes;
-               for( i = 0; i < drv->Init.num_driver_classes; i++ )
-               {
-                       if( strncmp(classes[i].name, ClassName, 32) == 0 )
-                               return &classes[i];
-               }
-       }
-       return NULL;
-}
-
-/**
- * \fn int32_t EDI_CheckClassExistence(edi_string_t ClassName)
- * \brief Checks if a class exists
- * \param ClassName    Name of class
- * \return 1 if the class exists, -1 otherwise
- */
-int32_t EDI_CheckClassExistence(edi_string_t ClassName)
-{
-       //LogF("check_class_existence: (ClassName='%s')\n", ClassName);
-       if(EDI_GetInternalClass(ClassName))
-               return 1;
-               
-       if(EDI_GetDefinedClass(ClassName))      // Driver Defined
-               return 1;
-       
-       return -1;
-}
-
-/**
- * \fn edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
- * \brief Construct an instance of an class (an object)
- * \param ClassName    Name of the class to construct
- */
-edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
-{
-       edi_object_metadata_t   ret = {0, 0};
-       edi_class_declaration_t *class;
-       
-       //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName);
-       
-       // Get class definition
-       if( !(class = EDI_GetInternalClass(ClassName)) )        // Internal
-               if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined
-                       return ret;             // Return ERROR
-       
-       // Initialise
-       ret.object = class->constructor();
-       if( !ret.object )
-               return ret;     // Return ERROR
-       
-       // Set declaration pointer
-       ret.object_class = class;
-       
-       //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class);
-       return ret;
-}
-
-/**
- * \fn void EDI_DestroyObject(edi_object_metadata_t Object)
- * \brief Destroy an instance of a class
- * \param Object       Object to destroy
- */
-void EDI_DestroyObject(edi_object_metadata_t Object)
-{
-       if( !Object.object )    return;
-       if( !Object.object_class )      return;
-       
-       ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object );
-}
-
-/**
- * \fn function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
- * \brief Get a method of a class by it's name
- * \param ObjectClass  Pointer to a ::edi_object_metadata_t of the object
- * \param MethodName   Name of the desired method
- * \return Function address or NULL
- */
-function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
-{
-       edi_class_declaration_t *dec = ObjectClass;
-        int    i;
-       
-       //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName);
-       
-       if(!ObjectClass)        return NULL;
-       
-       for(i = 0; i < dec->num_methods; i++)
-       {
-               if(strncmp(MethodName, dec->methods[i].name, 32) == 0)
-                       return dec->methods[i].code;
-       }
-       return NULL;
-}
-
-#if 0
-function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration);
-#endif
-
-/**
- * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
- * \brief Get the parent of the named class
- * \todo Implement
- */
-edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
-{
-       WarningEx("EDI", "`get_class_parent` is unimplemented");
-       return NULL;
-}
-
-/**
- * \fn data_pointer EDI_GetInternalClass(edi_string_t ClassName)
- * \brief Get a builtin class
- * \param ClassName    Name of class to find
- * \return Pointer to the ::edi_class_declaration_t of the class
- */
-data_pointer EDI_GetInternalClass(edi_string_t ClassName)
-{
-        int    i;
-       //LogF("get_internal_class: (ClassName='%s')\n", ClassName);
-       for( i = 0; i < NUM_INT_CLASSES; i++ )
-       {
-               if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) {
-                       return gcEdi_IntClasses[i];
-               }
-       }
-       //LogF("get_internal_class: RETURN NULL\n");
-       return NULL;
-}
-
-/**
- * \fn edi_string_ptr_t EDI_GetObjectClass(data_pointer Object)
- * \brief Get the name of the object of \a Object
- * \param Object       Object to get name of
- * \return Pointer to the class name
- */
-edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass)
-{
-       edi_object_metadata_t   *Metadata = ObjectClass;
-       // Sanity Check
-       if(!ObjectClass)        return NULL;
-       if(!(edi_class_declaration_t*) Metadata->object_class)  return NULL;
-       
-       // Return Class Name
-       return ((edi_class_declaration_t*) Metadata->object_class)->name;
-}
-
-// === EXPORTS ===
-EXPORTAS(EDI_CheckClassExistence, check_class_existence);
-EXPORTAS(EDI_ConstructObject, construct_object);
-EXPORTAS(EDI_DestroyObject, destroy_object);
-EXPORTAS(EDI_GetMethodByName, get_method_by_name);
-EXPORTAS(EDI_GetClassParent, get_class_parent);
-EXPORTAS(EDI_GetInternalClass, get_internal_class);
-EXPORTAS(EDI_GetObjectClass, get_object_class);
diff --git a/Modules/Interfaces/Makefile.tpl b/Modules/Interfaces/Makefile.tpl
deleted file mode 100644 (file)
index 80c6d4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
--include ../../Makefile.tpl
diff --git a/Modules/Interfaces/UDI/Makefile b/Modules/Interfaces/UDI/Makefile
deleted file mode 100644 (file)
index 4c199f1..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-#
-
-CPPFLAGS = -I./include
-OBJ  = main.o logging.o strmem.o imc.o mem.o buf.o cb.o
-OBJ += meta_mgmt.o meta_gio.o
-OBJ += physio.o physio/meta_bus.o physio/meta_intr.o
-NAME = UDI
-
--include ../Makefile.tpl
diff --git a/Modules/Interfaces/UDI/Notes.txt b/Modules/Interfaces/UDI/Notes.txt
deleted file mode 100644 (file)
index 1e2e9d4..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-
-<Love4Boobies> logical volume metalanguage - for file system drivers to use, network protocol 
-               metalanguage and audio support
-<Love4Boobies> madeofstaples expressed his interest in reviewing the OpenUSBDI specification to update 
-               it for USB 3.0
-
-
-=== Initialisation ===
-udi_init_t
- > udi_init_info
- > This is the only defined symbol in a UDI driver
-
-udi_primary_init_t
-- UDI_MAX_SCRATCH
-- UDI_OP_LONG_EXEC
-
-udi_secondary_init_t
-
-udi_ops_init_t
-
-udi_cb_init_t
-
-udi_cb_select_t
-
-udi_gcb_init_t
-
-udi_init_context_t
-
-udi_limits_t
-- UDI_MIN_ALLOC_LIMIT
-- UDI_MIN_TRACE_LOG_LIMIT
-- UDI_MIN_INSTANCE_ATTR_LIMIT
-
-udi_chan_context_t
-
-udi_child_chan_context_t
diff --git a/Modules/Interfaces/UDI/buf.c b/Modules/Interfaces/UDI/buf.c
deleted file mode 100644 (file)
index 5327cc8..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * \file buf.c
- * \author John Hodge (thePowersGang)
- * 
- * Buffer Manipulation
- */
-#include <acess.h>
-#include <udi.h>
-
-// === EXPORTS ===
-EXPORT(udi_buf_copy);
-EXPORT(udi_buf_write);
-EXPORT(udi_buf_read);
-EXPORT(udi_buf_free);
-
-// === CODE ===
-void udi_buf_copy(
-       udi_buf_copy_call_t *callback,
-       udi_cb_t        *gcb,
-       udi_buf_t       *src_buf,
-       udi_size_t      src_off,
-       udi_size_t      src_len,
-       udi_buf_t       *dst_buf,
-       udi_size_t      dst_off,
-       udi_size_t      dst_len,
-       udi_buf_path_t path_handle
-       )
-{
-       UNIMPLEMENTED();
-}
-
-/**
- * \brief Write to a buffer
- * \param callback     Function to call once the write has completed
- * \param gcb  Control Block
- * \param src_mem      Source Data
- * \param src_len      Length of source data
- * \param dst_buf      Destination buffer
- * \param dst_off      Destination offset in the buffer
- * \param dst_len      Length of destination area (What the?, Redundant
- *                     Department of redundacny department)
- * \param path_handle  ???
- */
-void udi_buf_write(
-       udi_buf_write_call_t *callback,
-       udi_cb_t        *gcb,
-       const void      *src_mem,
-       udi_size_t      src_len,
-       udi_buf_t       *dst_buf,
-       udi_size_t      dst_off,
-       udi_size_t      dst_len,
-       udi_buf_path_t path_handle
-       )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_buf_read(
-       udi_buf_t       *src_buf,
-       udi_size_t      src_off,
-       udi_size_t      src_len,
-       void    *dst_mem )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_buf_free(udi_buf_t *buf)
-{
-       UNIMPLEMENTED();
-}
diff --git a/Modules/Interfaces/UDI/cb.c b/Modules/Interfaces/UDI/cb.c
deleted file mode 100644 (file)
index b615dfe..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * \file cb.c
- * \author John Hodge (thePowersGang)
- * \brief Control block code
- */
-#include <acess.h>
-#include <udi.h>
-
-// === CODE ===
-void udi_cb_alloc (
-       udi_cb_alloc_call_t     *callback,      //!< Function to be called when the CB is allocated
-       udi_cb_t        *gcb,   //!< Parent Control Block
-       udi_index_t     cb_idx,
-       udi_channel_t   default_channel
-       )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_cb_alloc_dynamic(
-       udi_cb_alloc_call_t     *callback,
-       udi_cb_t        *gcb,
-       udi_index_t     cb_idx,
-       udi_channel_t   default_channel,
-       udi_size_t      inline_size,
-       udi_layout_t    *inline_layout
-       )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_cb_alloc_batch(
-       udi_cb_alloc_batch_call_t       *callback,      //!< 
-       udi_cb_t        *gcb,   //!< 
-       udi_index_t     cb_idx,
-       udi_index_t     count,
-       udi_boolean_t   with_buf,
-       udi_size_t      buf_size,
-       udi_buf_path_t  path_handle
-       )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_cb_free(udi_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_cancel(udi_cancel_call_t *callback, udi_cb_t *gcb)
-{
-       UNIMPLEMENTED();
-}
-
-// === EXPORTS ===
-EXPORT(udi_cb_alloc);
-EXPORT(udi_cb_alloc_dynamic);
-EXPORT(udi_cb_alloc_batch);
-EXPORT(udi_cb_free);
-EXPORT(udi_cancel);
diff --git a/Modules/Interfaces/UDI/imc.c b/Modules/Interfaces/UDI/imc.c
deleted file mode 100644 (file)
index cd15e07..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * \file imc.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-
-// === EXPORTS ===
-EXPORT(udi_channel_anchor);
-EXPORT(udi_channel_spawn);
-EXPORT(udi_channel_set_context);
-EXPORT(udi_channel_op_abort);
-EXPORT(udi_channel_close);
-EXPORT(udi_channel_event_ind);
-EXPORT(udi_channel_event_complete);
-
-// === CODE ===
-/**
- */
-void udi_channel_anchor(
-       udi_channel_anchor_call_t *callback, udi_cb_t *gcb,
-       udi_channel_t channel, udi_index_t ops_idx, void *channel_context
-       )
-{
-       Warning("%s Unimplemented", __func__);
-}
-
-/**
- */
-extern void udi_channel_spawn(
-       udi_channel_spawn_call_t *callback, udi_cb_t *gcb,
-       udi_channel_t channel, udi_index_t spawn_idx,
-       udi_index_t ops_idx, void *channel_context
-       )
-{
-       Warning("%s Unimplemented", __func__);
-}
-
-/**
- * 
- */
-void udi_channel_set_context(
-       udi_channel_t target_channel, void *channel_context
-       )
-{
-       Warning("%s Unimplemented", __func__);
-}
-
-void udi_channel_op_abort(
-       udi_channel_t target_channel, udi_cb_t *orig_cb
-       )
-{
-       Warning("%s Unimplemented", __func__);
-}
-
-void udi_channel_close(udi_channel_t channel)
-{
-       Warning("%s Unimplemented", __func__);
-}
-
-void udi_channel_event_ind(udi_channel_event_cb_t *cb)
-{
-       udi_channel_event_complete(cb, UDI_OK);
-}
-
-void udi_channel_event_complete(udi_channel_event_cb_t *cb, udi_status_t status)
-{
-       Warning("%s Unimplemented", __func__);
-}
diff --git a/Modules/Interfaces/UDI/include/physio/meta_bus.h b/Modules/Interfaces/UDI/include/physio/meta_bus.h
deleted file mode 100644 (file)
index 7b88ece..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * \file physio/meta_bus.h
- */
-#ifndef _PHYSIO_META_BUS_H_
-#define _PHYSIO_META_BUS_H_
-
-#include <udi.h>
-#include <udi_physio.h>
-
-typedef const struct udi_bus_device_ops_s      udi_bus_device_ops_t;
-typedef const struct udi_bus_bridge_ops_s      udi_bus_bridge_ops_t;
-typedef struct udi_bus_bind_cb_s       udi_bus_bind_cb_t;
-typedef void   udi_bus_unbind_req_op_t(udi_bus_bind_cb_t *cb);
-typedef void   udi_bus_unbind_ack_op_t(udi_bus_bind_cb_t *cb);
-typedef void   udi_bus_bind_req_op_t(udi_bus_bind_cb_t *cb);
-typedef void   udi_bus_bind_ack_op_t(
-       udi_bus_bind_cb_t       *cb,
-       udi_dma_constraints_t   dma_constraints,
-       udi_ubit8_t     preferred_endianness,
-       udi_status_t    status
-       );
-
-
-struct udi_bus_device_ops_s
-{
-       udi_channel_event_ind_op_t      *channel_event_ind_op;
-       udi_bus_bind_ack_op_t   *bus_bind_ack_op;
-       udi_bus_unbind_ack_op_t *bus_unbind_ack_op;
-       udi_intr_attach_ack_op_t        *intr_attach_ack_op;
-       udi_intr_detach_ack_op_t        *intr_detach_ack_op;
-};
-/* Bus Device Ops Vector Number */
-#define UDI_BUS_DEVICE_OPS_NUM            1
-
-struct udi_bus_bridge_ops_s
-{
-     udi_channel_event_ind_op_t        *channel_event_ind_op;
-     udi_bus_bind_req_op_t     *bus_bind_req_op;
-     udi_bus_unbind_req_op_t   *bus_unbind_req_op;
-     udi_intr_attach_req_op_t  *intr_attach_req_op;
-     udi_intr_detach_req_op_t  *intr_detach_req_op;
-};
-/* Bus Bridge Ops Vector Number */
-#define UDI_BUS_BRIDGE_OPS_NUM
-
-struct udi_bus_bind_cb_s
-{
-     udi_cb_t gcb;
-};
-/* Bus Bind Control Block Group Number */
-#define UDI_BUS_BIND_CB_NUM              1
-
-
-extern void udi_bus_bind_req(udi_bus_bind_cb_t *cb);
-
-extern void udi_bus_bind_ack(
-       udi_bus_bind_cb_t       *cb,
-       udi_dma_constraints_t   dma_constraints,
-       udi_ubit8_t     preferred_endianness,
-       udi_status_t    status
-       );
-/* Values for preferred_endianness */
-#define UDI_DMA_BIG_ENDIAN                (1U<<5)
-#define UDI_DMA_LITTLE_ENDIAN             (1U<<6)
-#define UDI_DMA_ANY_ENDIAN                (1U<<0)
-
-extern void udi_bus_unbind_req(udi_bus_bind_cb_t *cb);
-extern void udi_bus_unbind_ack(udi_bus_bind_cb_t *cb);
-
-
-
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/physio/meta_intr.h b/Modules/Interfaces/UDI/include/physio/meta_intr.h
deleted file mode 100644 (file)
index d5dd394..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * \file physio/meta_intr.h
- */
-#ifndef _PHYSIO_META_INTR_H_
-#define _PHYSIO_META_INTR_H_
-
-#include <udi.h>
-#include <udi_physio.h>
-#include "pio.h"
-
-typedef struct udi_intr_attach_cb_s    udi_intr_attach_cb_t;
-typedef void   udi_intr_attach_req_op_t(udi_intr_attach_cb_t *intr_attach_cb);
-typedef void   udi_intr_attach_ack_op_t(
-       udi_intr_attach_cb_t *intr_attach_cb,
-       udi_status_t status
-       );
-typedef struct udi_intr_detach_cb_s    udi_intr_detach_cb_t;
-typedef void   udi_intr_detach_req_op_t(udi_intr_detach_cb_t *intr_detach_cb);
-typedef void   udi_intr_detach_ack_op_t(udi_intr_detach_cb_t *intr_detach_cb);
-typedef const struct udi_intr_handler_ops_s    udi_intr_handler_ops_t;
-typedef const struct udi_intr_dispatcher_ops_s udi_intr_dispatcher_ops_t;
-typedef struct udi_intr_event_cb_s     udi_intr_event_cb_t;
-typedef void   udi_intr_event_ind_op_t(udi_intr_event_cb_t *intr_event_cb, udi_ubit8_t flags);
-typedef void   udi_intr_event_rdy_op_t(udi_intr_event_cb_t *intr_event_cb);
-
-
-struct udi_intr_attach_cb_s
-{
-       udi_cb_t        gcb;
-       udi_index_t     interrupt_idx;
-       udi_ubit8_t     min_event_pend;
-       udi_pio_handle_t        preprocessing_handle;
-};
-/* Bridge Attach Control Block Group Number */
-#define UDI_BUS_INTR_ATTACH_CB_NUM        2
-
-struct udi_intr_detach_cb_s
-{
-       udi_cb_t        gcb;
-       udi_index_t     interrupt_idx;
-};
-/* Bridge Detach Control Block Group Number */
-#define UDI_BUS_INTR_DETACH_CB_NUM       3
-
-struct udi_intr_handler_ops_s
-{
-       udi_channel_event_ind_op_t      *channel_event_ind_op;
-       udi_intr_event_ind_op_t *intr_event_ind_op;
-};
-/* Interrupt Handler Ops Vector Number */
-#define UDI_BUS_INTR_HANDLER_OPS_NUM      3
-
-struct udi_intr_dispatcher_ops_s
-{
-       udi_channel_event_ind_op_t      *channel_event_ind_op;
-       udi_intr_event_rdy_op_t *intr_event_rdy_op;
-};
-/* Interrupt Dispatcher Ops Vector Number */
-#define UDI_BUS_INTR_DISPATCH_OPS_NUM     4
-
-struct udi_intr_event_cb_s
-{
-       udi_cb_t        gcb;
-       udi_buf_t       *event_buf;
-       udi_ubit16_t    intr_result;
-};
-/* Flag values for interrupt handling */
-#define UDI_INTR_UNCLAIMED               (1U<<0)
-#define UDI_INTR_NO_EVENT                (1U<<1)
-/* Bus Interrupt Event Control Block Group Number */
-#define UDI_BUS_INTR_EVENT_CB_NUM        4
-
-
-
-extern void udi_intr_attach_req(udi_intr_attach_cb_t *intr_attach_cb);
-extern void udi_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status);
-extern void udi_intr_attach_ack_unused(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status);
-
-extern void udi_intr_detach_req(udi_intr_detach_cb_t *intr_detach_cb);
-extern void udi_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb);
-extern void udi_intr_detach_ack_unused(udi_intr_detach_cb_t *intr_detach_cb);
-
-
-extern void udi_intr_event_ind(udi_intr_event_cb_t *intr_event_cb, udi_ubit8_t flags);
-/**
- * \brief Values for ::udi_intr_event_ind \a flags
- * \{
- */
-#define UDI_INTR_MASKING_NOT_REQUIRED    (1U<<0)
-#define UDI_INTR_OVERRUN_OCCURRED        (1U<<1)
-#define UDI_INTR_PREPROCESSED            (1U<<2)
-/**
- * \}
- */
-
-extern void udi_intr_event_rdy(udi_intr_event_cb_t *intr_event_cb);
-
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/physio/pio.h b/Modules/Interfaces/UDI/include/physio/pio.h
deleted file mode 100644 (file)
index 1ce305f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * \file physio/pio.h
- */
-#ifndef _PHYSIO_PIO_H_
-#define _PHYSIO_PIO_H_
-
-#include <udi.h>
-#include <udi_physio.h>
-
-
-typedef _udi_handle_t  udi_pio_handle_t;
-/* Null handle value for udi_pio_handle_t */
-#define UDI_NULL_PIO_HANDLE    _NULL_HANDLE
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi.h b/Modules/Interfaces/UDI/include/udi.h
deleted file mode 100644 (file)
index 53953c0..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * \file udi.h
- */
-#ifndef _UDI_H_
-#define _UDI_H_
-
-// Use the core acess file to use the specific size types (plus va_arg)
-#include <acess.h>
-
-#include "udi/arch/x86.h"
-
-/**
- * \name Values and Flags for udi_status_t
- * \{
- */
-#define UDI_STATUS_CODE_MASK           0x0000FFFF
-#define UDI_STAT_META_SPECIFIC         0x00008000
-#define UDI_SPECIFIC_STATUS_MASK       0x00007FFF
-#define UDI_CORRELATE_OFFSET           16
-#define UDI_CORRELATE_MASK                     0xFFFF0000
-/* Common Status Values */
-#define UDI_OK                                         0
-#define UDI_STAT_NOT_SUPPORTED         1
-#define UDI_STAT_NOT_UNDERSTOOD                2
-#define UDI_STAT_INVALID_STATE         3
-#define UDI_STAT_MISTAKEN_IDENTITY     4
-#define UDI_STAT_ABORTED                       5
-#define UDI_STAT_TIMEOUT                       6
-#define UDI_STAT_BUSY                          7
-#define UDI_STAT_RESOURCE_UNAVAIL      8
-#define UDI_STAT_HW_PROBLEM                    9
-#define UDI_STAT_NOT_RESPONDING                10
-#define UDI_STAT_DATA_UNDERRUN         11
-#define UDI_STAT_DATA_OVERRUN          12
-#define UDI_STAT_DATA_ERROR                    13
-#define UDI_STAT_PARENT_DRV_ERROR      14
-#define UDI_STAT_CANNOT_BIND           15
-#define UDI_STAT_CANNOT_BIND_EXCL      16
-#define UDI_STAT_TOO_MANY_PARENTS      17
-#define UDI_STAT_BAD_PARENT_TYPE       18
-#define UDI_STAT_TERMINATED                    19
-#define UDI_STAT_ATTR_MISMATCH         20
-/**
- * \}
- */
-
-/**
- * \name Data Layout Specifiers
- * \{
- */
-typedef const udi_ubit8_t      udi_layout_t;
-/* Specific-Length Layout Type Codes */
-#define UDI_DL_UBIT8_T                   1
-#define UDI_DL_SBIT8_T                   2
-#define UDI_DL_UBIT16_T                  3
-#define UDI_DL_SBIT16_T                  4
-#define UDI_DL_UBIT32_T                  5
-#define UDI_DL_SBIT32_T                  6
-#define UDI_DL_BOOLEAN_T                 7
-#define UDI_DL_STATUS_T                  8
-/* Abstract Element Layout Type Codes */
-#define UDI_DL_INDEX_T                   20
-/* Opaque Handle Element Layout Type Codes */
-#define UDI_DL_CHANNEL_T                 30
-#define UDI_DL_ORIGIN_T                  32
-/* Indirect Element Layout Type Codes */
-#define UDI_DL_BUF                       40
-#define UDI_DL_CB                        41
-#define UDI_DL_INLINE_UNTYPED            42
-#define UDI_DL_INLINE_DRIVER_TYPED       43
-#define UDI_DL_MOVABLE_UNTYPED           44
-/* Nested Element Layout Type Codes */
-#define UDI_DL_INLINE_TYPED              50
-#define UDI_DL_MOVABLE_TYPED             51
-#define UDI_DL_ARRAY                     52
-#define UDI_DL_END                       0
-/**
- * \}
- */
-
-
-// === INCLUDE SUB-SECTIONS ===
-#include "udi/cb.h"    // Control Blocks
-#include "udi/log.h"   // Logging
-#include "udi/attr.h"  // Attributes
-#include "udi/strmem.h"        // String/Memory
-#include "udi/buf.h"   // Buffers
-#include "udi/mem.h"   // Memory Management
-#include "udi/imc.h"   // Inter-module Communication
-#include "udi/meta_mgmt.h"     // Management Metalanguage
-#include "udi/meta_gio.h"      // General IO Metalanguage
-#include "udi/init.h"  // Init
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/arch/x86.h b/Modules/Interfaces/UDI/include/udi/arch/x86.h
deleted file mode 100644 (file)
index 9c505d3..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-
-#ifndef _UDI_ARCH_x86_H_
-#define _UDI_ARCH_x86_H_
-
-typedef Sint8  udi_sbit8_t;    /* signed 8-bit: -2^7..2^7-1 */
-typedef Sint16 udi_sbit16_t;   /* signed 16-bit: -2^15..2^15-1 */
-typedef Sint32 udi_sbit32_t;   /* signed 32-bit: -2^31..2^31-1 */
-typedef Uint8  udi_ubit8_t;    /* unsigned 8-bit: 0..28-1 */
-typedef Uint16 udi_ubit16_t;   /* unsigned 16-bit: 0..216-1 */
-typedef Uint32 udi_ubit32_t;   /* unsigned 32-bit: 0..232-1 */
-
-typedef udi_ubit8_t    udi_boolean_t;  /* 0=False; 1..28-1=True */
-#define FALSE  0
-#define TRUE   1
-
-typedef size_t udi_size_t;     /* buffer size */
-typedef size_t udi_index_t;    /* zero-based index type */
-
-typedef void   *_udi_handle_t;
-#define        _NULL_HANDLE    NULL
-
-/* Channel Handle */
-typedef _udi_handle_t  *udi_channel_t;
-#define UDI_NULL_CHANNEL       _NULL_HANDLE
-
-/**
- * \brief Buffer Path
- */
-typedef _udi_handle_t  udi_buf_path_t;
-#define UDI_NULL_BUF_PATH      _NULL_HANDLE
-
-typedef _udi_handle_t  udi_origin_t;
-#define UDI_NULL_ORIGIN        _NULL_HANDLE
-
-typedef Sint64 udi_timestamp_t;
-
-#define UDI_HANDLE_IS_NULL(handle, handle_type)        (handle == NULL)
-#define UDI_HANDLE_ID(handle, handle_type)     ((Uint32)handle)
-
-/**
- * \name va_arg wrapper
- * \{
- */
-#define UDI_VA_ARG(pvar, type, va_code)        va_arg(pvar,type)
-#define UDI_VA_UBIT8_T
-#define UDI_VA_SBIT8_T
-#define UDI_VA_UBIT16_T
-#define UDI_VA_SBIT16_T
-#define UDI_VA_UBIT32_T
-#define UDI_VA_SBIT32_T
-#define UDI_VA_BOOLEAN_T
-#define UDI_VA_INDEX_T
-#define UDI_VA_SIZE_T
-#define UDI_VA_STATUS_T
-#define UDI_VA_CHANNEL_T
-#define UDI_VA_ORIGIN_T
-#define UDI_VA_POINTER
-/**
- * \}
- */
-
-/**
- * \brief Status Type
- */
-typedef udi_ubit32_t   udi_status_t;
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/attr.h b/Modules/Interfaces/UDI/include/udi/attr.h
deleted file mode 100644 (file)
index a63ce8a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * \file udi_attr.h
- */
-#ifndef _UDI_ATTR_H_
-#define _UDI_ATTR_H_
-
-typedef struct udi_instance_attr_list_s        udi_instance_attr_list_t;
-typedef udi_ubit8_t    udi_instance_attr_type_t;
-
-/* Instance attribute limits */
-#define UDI_MAX_ATTR_NAMELEN   32
-#define UDI_MAX_ATTR_SIZE              64
-
-/**
- * \brief Instance Attribute
- */
-struct udi_instance_attr_list_s
-{
-     char      attr_name[UDI_MAX_ATTR_NAMELEN];
-     udi_ubit8_t       attr_value[UDI_MAX_ATTR_SIZE];
-     udi_ubit8_t       attr_length;
-     udi_instance_attr_type_t  attr_type;
-};
-
-
-/**
- * \brief Instance Attribute Types
- * \see ::udi_instance_attr_type_t
- */
-enum
-{
-       UDI_ATTR_NONE,
-       UDI_ATTR_STRING,
-       UDI_ATTR_ARRAY8,
-       UDI_ATTR_UBIT32,
-       UDI_ATTR_BOOLEAN,
-       UDI_ATTR_FILE
-};
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/buf.h b/Modules/Interfaces/UDI/include/udi/buf.h
deleted file mode 100644 (file)
index fa2428b..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * \file udi_buf.h
- */
-#ifndef _UDI_BUF_H_
-#define _UDI_BUF_H_
-
-
-typedef struct udi_buf_s       udi_buf_t;
-typedef struct udi_xfer_constraints_s  udi_xfer_constraints_t;
-typedef void udi_buf_copy_call_t(udi_cb_t *gcb, udi_buf_t *new_dst_buf);
-typedef void udi_buf_write_call_t(udi_cb_t *gcb, udi_buf_t *new_dst_buf);
-
-/**
- * \brief Describes a buffer
- * \note Semi-Opaque
- */
-struct udi_buf_s
-{
-       udi_size_t      buf_size;
-       Uint8   Data[]; //!< ENVIRONMENT ONLY
-};
-
-/**
- * \brief 
- */
-struct udi_xfer_constraints_s
-{
-       udi_ubit32_t    udi_xfer_max;
-       udi_ubit32_t    udi_xfer_typical;
-       udi_ubit32_t    udi_xfer_granularity;
-       udi_boolean_t   udi_xfer_one_piece;
-       udi_boolean_t   udi_xfer_exact_size;
-       udi_boolean_t   udi_xfer_no_reorder;
-};
-
-// --- MACROS ---
-/**
- * \brief Allocates a buffer
- */
-#define UDI_BUF_ALLOC(callback, gcb, init_data, size, path_handle) \
-       udi_buf_write(callback, gcb, init_data, size, NULL, 0, 0, path_handle)
-
-/**
- * \brief Inserts data into a buffer
- */
-#define UDI_BUF_INSERT(callback, gcb, new_data, size, dst_buf, dst_off) \
-       udi_buf_write(callback, gcb, new_data, size, dst_buf, dst_off, 0, UDI_NULL_BUF_PATH)
-
-/**
- * \brief Removes data from a buffer (data afterwards will be moved forewards)
- */
-#define UDI_BUF_DELETE(callback, gcb, size, dst_buf, dst_off) \
-       udi_buf_write(callback, gcb, NULL, 0, dst_buf, dst_off, size, UDI_NULL_BUF_PATH)
-
-/**
- * \brief Duplicates \a src_buf
- */
-#define UDI_BUF_DUP(callback, gcb, src_buf, path_handle) \
-       udi_buf_copy(callback, gcb, src_buf, 0, (src_buf)->buf_size, NULL, 0, 0, path_handle)
-
-
-/**
- * \brief Copies data from one buffer to another
- */
-extern void udi_buf_copy(
-       udi_buf_copy_call_t *callback,
-       udi_cb_t        *gcb,
-       udi_buf_t       *src_buf,
-       udi_size_t      src_off,
-       udi_size_t      src_len,
-       udi_buf_t       *dst_buf,
-       udi_size_t      dst_off,
-       udi_size_t      dst_len,
-       udi_buf_path_t path_handle );
-
-/**
- * \brief Copies data from driver space to a buffer
- */
-extern void udi_buf_write(
-       udi_buf_write_call_t *callback,
-       udi_cb_t        *gcb,
-       const void      *src_mem,
-       udi_size_t      src_len,
-       udi_buf_t       *dst_buf,
-       udi_size_t      dst_off,
-       udi_size_t      dst_len,
-       udi_buf_path_t path_handle
-       );
-
-/**
- * \brief Reads data from a buffer into driver space
- */
-extern void udi_buf_read(
-       udi_buf_t       *src_buf,
-       udi_size_t      src_off,
-       udi_size_t      src_len,
-       void    *dst_mem );
-
-/**
- * \brief Frees a buffer
- */
-extern void udi_buf_free(udi_buf_t *buf);
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/cb.h b/Modules/Interfaces/UDI/include/udi/cb.h
deleted file mode 100644 (file)
index 76db5c6..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * \file udi_cb.h
- */
-#ifndef _UDI_CB_H_
-#define _UDI_CB_H_
-
-typedef struct udi_cb_s        udi_cb_t;
-typedef void udi_cb_alloc_call_t(udi_cb_t *gcb, udi_cb_t *new_cb);
-typedef void udi_cb_alloc_batch_call_t(udi_cb_t *gcb, udi_cb_t *first_new_cb);
-typedef void udi_cancel_call_t(udi_cb_t *gcb);
-
-#define UDI_GCB(mcb)   (&(mcb)->gcb)
-#define UDI_MCB(gcb, cb_type)  ((cb_type *)(gcb))
-
-/**
- * \brief Describes a generic control block
- * \note Semi-opaque
- */
-struct udi_cb_s
-{
-       /**
-        * \brief Channel associated with the control block
-        */
-       udi_channel_t   channel;
-       /**
-        * \brief Current state
-        * \note Driver changable
-        */
-       void    *context;
-       /**
-        * \brief CB's scratch area
-        */
-       void    *scratch;
-       /**
-        * \brief ???
-        */
-       void    *initiator_context;
-       /**
-        * \brief Request Handle?
-        */
-       udi_origin_t    origin;
-};
-
-extern void udi_cb_alloc (
-       udi_cb_alloc_call_t     *callback,
-       udi_cb_t        *gcb,
-       udi_index_t     cb_idx,
-       udi_channel_t   default_channel
-       );
-
-extern void udi_cb_alloc_dynamic(
-       udi_cb_alloc_call_t     *callback,
-       udi_cb_t        *gcb,
-       udi_index_t     cb_idx,
-       udi_channel_t   default_channel,
-       udi_size_t      inline_size,
-       udi_layout_t    *inline_layout
-       );
-
-extern void udi_cb_alloc_batch(
-       udi_cb_alloc_batch_call_t       *callback,
-       udi_cb_t        *gcb,
-       udi_index_t     cb_idx,
-       udi_index_t     count,
-       udi_boolean_t   with_buf,
-       udi_size_t      buf_size,
-       udi_buf_path_t  path_handle
-       );
-
-extern void udi_cb_free(udi_cb_t *cb);
-
-extern void udi_cancel(udi_cancel_call_t *callback, udi_cb_t *gcb);
-
-
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/imc.h b/Modules/Interfaces/UDI/include/udi/imc.h
deleted file mode 100644 (file)
index e5b3f3b..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * \file udi_imc.h
- * \brief Inter-Module Communication
- */
-#ifndef _UDI_IMC_H_
-#define _UDI_IMC_H_
-
-typedef void udi_channel_anchor_call_t(udi_cb_t *gcb, udi_channel_t anchored_channel);
-typedef void udi_channel_spawn_call_t(udi_cb_t *gcb, udi_channel_t new_channel);
-
-typedef struct udi_channel_event_cb_s  udi_channel_event_cb_t;
-
-typedef void udi_channel_event_ind_op_t(udi_channel_event_cb_t *cb);
-
-/**
- * \brief Anchors a channel end to the current region
- */
-extern void udi_channel_anchor(
-       udi_channel_anchor_call_t *callback, udi_cb_t *gcb,
-       udi_channel_t channel, udi_index_t ops_idx, void *channel_context
-       );
-
-/**
- * \brief Created a new channel between two regions
- */
-extern void udi_channel_spawn(
-       udi_channel_spawn_call_t *callback,
-       udi_cb_t *gcb,
-       udi_channel_t channel,
-       udi_index_t spawn_idx,
-       udi_index_t ops_idx,
-       void *channel_context
-       );
-
-/**
- * \brief Attaches a new context pointer to the current channel
- */
-extern void udi_channel_set_context(
-       udi_channel_t target_channel,
-       void *channel_context
-       );
-/**
- * \brief 
- */
-extern void udi_channel_op_abort(
-       udi_channel_t target_channel,
-       udi_cb_t *orig_cb
-       );
-
-/**
- * \brief Closes an open channel
- */
-extern void udi_channel_close(udi_channel_t channel);
-
-/**
- * \brief Describes a channel event
- */
-struct udi_channel_event_cb_s
-{
-       udi_cb_t gcb;
-       udi_ubit8_t event;
-       union {
-               struct {
-                       udi_cb_t *bind_cb;
-               } internal_bound;
-               struct {
-                       udi_cb_t *bind_cb;
-                       udi_ubit8_t parent_ID;
-                       udi_buf_path_t *path_handles;
-               } parent_bound;
-               udi_cb_t *orig_cb;
-       }       params;
-};
-/* Channel event types */
-#define UDI_CHANNEL_CLOSED                0
-#define UDI_CHANNEL_BOUND                 1
-#define UDI_CHANNEL_OP_ABORTED            2
-
-/**
- * \brief Proxy function 
- */
-extern void udi_channel_event_ind(udi_channel_event_cb_t *cb);
-
-/**
- * \brief Called when channel event is completed
- */
-extern void udi_channel_event_complete(
-       udi_channel_event_cb_t *cb, udi_status_t status
-       );
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/init.h b/Modules/Interfaces/UDI/include/udi/init.h
deleted file mode 100644 (file)
index a6d5bb4..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/**
- * \file udi_init.h
- */
-#ifndef _UDI_INIT_H_
-#define _UDI_INIT_H_
-
-typedef struct udi_init_s              udi_init_t;
-typedef struct udi_primary_init_s      udi_primary_init_t;
-typedef struct udi_secondary_init_s    udi_secondary_init_t;
-typedef struct udi_ops_init_s  udi_ops_init_t;
-typedef struct udi_cb_init_s   udi_cb_init_t;
-typedef struct udi_cb_select_s udi_cb_select_t;
-typedef struct udi_gcb_init_s  udi_gcb_init_t;
-
-typedef struct udi_init_context_s      udi_init_context_t;
-typedef struct udi_limits_s            udi_limits_t;
-typedef struct udi_chan_context_s      udi_chan_context_t;
-typedef struct udi_child_chan_context_s        udi_child_chan_context_t;
-
-typedef void   udi_op_t(void);
-typedef udi_op_t * const       udi_ops_vector_t;
-
-/**
- * \brief UDI Initialisation Structure
- * 
- * Defines how to initialise and use a UDI driver
- */
-struct udi_init_s
-{
-       /**
-        * \brief Defines the primary region
-        * \note For secondary modules this must be NULL
-        */
-       udi_primary_init_t      *primary_init_info;
-       
-       /**
-        * \brief Defines all secondary regions
-        * Pointer to a list (so, essentially an array) of ::udi_secondary_init_t
-        * It is terminated by an entry with ::udi_secondary_init_t.region_idx
-        * set to zero.
-        * \note If NULL, it is to be treated as an empty list
-        */
-       udi_secondary_init_t    *secondary_init_list;
-       
-       /**
-        * \brief Channel operations
-        * Pointer to a ::udi_ops_init_t.ops_idx == 0  terminated list that
-        * defines the channel opterations usage for each ops vector implemented
-        * in this module.
-        * \note Must contain at least one entry for each metalanguage used
-        */
-       udi_ops_init_t  *ops_init_list;
-       
-       /**
-        * \brief Control Blocks
-        */
-       udi_cb_init_t   *cb_init_list;
-       
-       /**
-        * \brief Generic Control Blocks
-        */
-       udi_gcb_init_t  *gcb_init_list;
-       
-       /**
-        * \brief Overrides for control blocks
-        * Allows a control block to override the ammount of scratch space it
-        * gets for a specific ops vector.
-        */
-       udi_cb_select_t *cb_select_list;
-};
-
-
-/**
- * \name Flags for ::udi_primary_init_t.mgmt_op_flags
- * \{
- */
-
-/**
- * \brief Tells the environment that this operation may take some time
- * Used as a hint in scheduling tasks
- */
-#define UDI_OP_LONG_EXEC       0x01
-
-/**
- * \}
- */
-
-/**
- * \brief Describes the Primary Region
- * Tells the environment how to set up the driver's primary region.
- */
-struct udi_primary_init_s
-{
-       /**
-        * \brief Management Ops Vector
-        * Pointer to a list of functions for the Management Metalanguage
-        */
-       udi_mgmt_ops_t  *mgmt_ops;
-       
-       /**
-        * \brief Flags for \a mgmt_ops
-        * Each entry in \a mgmt_ops is acommanied by an entry in this array.
-        * Each entry contains the flags that apply to the specified ops vector.
-        * \see UDI_OP_LONG_EXEC
-        */
-       const udi_ubit8_t       *mgmt_op_flags;
-       
-       /**
-        * \brief Scratch space size
-        * Specifies the number of bytes to allocate for each control block
-        * passed by the environment.
-        * \note must not exceed ::UDI_MAX_SCRATCH
-        */
-       udi_size_t      mgmt_scratch_requirement;
-       
-       /**
-        * \todo What is this?
-        */
-       udi_ubit8_t     enumeration_attr_list_length;
-       
-       /**
-        * \brief Size in bytes to allocate to each instance of the primary
-        *        region
-        * Essentially the size of the driver's instance state
-        * \note Must be at least sizeof(udi_init_context_t) and not more
-        *       than UDI_MIN_ALLOC_LIMIT
-        */
-       udi_size_t      rdata_size;
-       
-       /**
-        * \brief Size in bytes to allocate for each call to ::udi_enumerate_req
-        * \note Must not exceed UDI_MIN_ALLOC_LIMIT
-        */
-       udi_size_t      child_data_size;
-       
-       /**
-        * \brief Number of path handles for each parent bound to this driver
-        * \todo What the hell are path handles?
-        */
-       udi_ubit8_t     per_parent_paths;
-};
-
-/**
- * \brief Tells the environment how to create a secondary region
- */
-struct udi_secondary_init_s
-{
-       /**
-        * \brief Region Index
-        * Non-zero driver-dependent index value that identifies the region
-        * \note This corresponds to a "region" declaration in the udiprops.txt
-        *       file.
-        */
-       udi_index_t     region_idx;
-       /**
-        * \brief Number of bytes to allocate
-        * 
-        * \note Again, must be between sizeof(udi_init_context_t) and
-        *       UDI_MIN_ALLOC_LIMIT
-        */
-       udi_size_t      rdata_size;
-};
-
-/**
- * \brief Defines channel endpoints (ways of communicating with the driver)
- * 
- */
-struct udi_ops_init_s
-{
-       /**
-        * \brief ops index number
-        * Used to uniquely this entry
-        * \note If this is zero, it marks the end of the list
-        */
-       udi_index_t     ops_idx;
-       /**
-        * \brief Metalanguage Index
-        * Defines what metalanguage is used
-        */
-       udi_index_t     meta_idx;
-       /**
-        * \brief Metalanguage Operation
-        * Defines what metalanguage operation is used
-        */
-       udi_index_t     meta_ops_num;
-       /**
-        * \brief Size of the context area
-        * \note If non-zero, must be at least 
-        */
-       udi_size_t      chan_context_size;
-       /**
-        * \brief Pointer to the operations
-        * Pointer to a <<meta>>_<<role>>_ops_t structure
-        */
-       udi_ops_vector_t        *ops_vector;
-       /**
-        * \brief Flags for each entry in \a ops_vector
-        */
-       //const udi_ubit8_t     *op_flags;
-};
-
-/**
- * \brief Defines control blocks
- * Much the same as ::udi_ops_init_t
- */
-struct udi_cb_init_s
-{
-       udi_index_t     cb_idx;
-       udi_index_t     meta_idx;
-       udi_index_t     meta_cb_num;
-       udi_size_t      scratch_requirement;
-       /**
-        * \brief Size of inline memory
-        */
-       udi_size_t      inline_size;
-       /**
-        * \brief Layout of inline memory
-        */
-       udi_layout_t    *inline_layout;
-};
-
-/**
- * \brief Overrides the scratch size for an operation
- */
-struct udi_cb_select_s
-{
-       udi_index_t     ops_idx;
-       udi_index_t     cb_idx;
-};
-
-/**
- * \brief General Control Blocks
- * These control blocks can only be used as general data storage, not
- * for any channel operations.
- */
-struct udi_gcb_init_s
-{
-       udi_index_t     cb_idx;
-       udi_size_t      scratch_requirement;
-};
-
-
-// ===
-// ===
-/**
- * \brief Environement Imposed Limits
- */
-struct udi_limits_s
-{
-       /**
-        * \brief Maximum legal ammount of memory that can be allocated
-        */
-       udi_size_t      max_legal_alloc;
-       
-       /**
-        * \brief Maximum ammount of guaranteed memory
-        */
-       udi_size_t      max_safe_alloc;
-       /**
-        * \brief Maximum size of the final string from ::udi_trace_write
-        *        or ::udi_log_write
-        */
-       udi_size_t      max_trace_log_formatted_len;
-       /**
-        * \brief Maximum legal size of an instanct attribute value
-        */
-       udi_size_t      max_instance_attr_len;
-       /**
-        * \brief Minumum time difference (in nanoseconds between unique values
-        *        returned by ::udi_time_current
-        */
-       udi_ubit32_t    min_curtime_res;
-       /**
-        * \brief Minimum resolution of timers
-        * \see ::udi_timer_start_repeating, ::udi_timer_start
-        */
-       udi_ubit32_t    min_timer_res;
-} PACKED;
-
-/**
- * \brief Primary Region Context data
- */
-struct udi_init_context_s
-{
-       udi_index_t     region_idx;
-       udi_limits_t    limits;
-};
-
-/**
- * \brief Channel context data
- */
-struct udi_chan_context_s
-{
-       /**
-        * \brief Pointer to the driver instance's initial region data
-        */
-       void    *rdata;
-} PACKED;
-
-/**
- * \brief Child Channel context
- */
-struct udi_child_chan_context_s
-{
-       /**
-        * \brief Pointer to the driver instance's initial region data
-        */
-       void    *rdata;
-       /**
-        * \brief Some sort of unique ID number
-        */
-       udi_ubit32_t    child_ID;
-};
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/log.h b/Modules/Interfaces/UDI/include/udi/log.h
deleted file mode 100644 (file)
index dccb124..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * \file udi_log.h
- */
-#ifndef _UDI_LOG_H_
-#define _UDI_LOG_H_
-
-/**
- * \brief Trace Event
- */
-typedef udi_ubit32_t   udi_trevent_t;
-
-/**
- * \brief Log Callback
- */
-typedef void udi_log_write_call_t(udi_cb_t *gcb, udi_status_t correlated_status);
-
-/**
- * \name Log Severities
- * \brief Values for severity
- * \{
- */
-#define UDI_LOG_DISASTER       1
-#define UDI_LOG_ERROR          2
-#define UDI_LOG_WARNING                3
-#define UDI_LOG_INFORMATION    4
-/**
- * \}
- */
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/mem.h b/Modules/Interfaces/UDI/include/udi/mem.h
deleted file mode 100644 (file)
index d29f25e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * \file udi_mem.h
- */
-#ifndef _UDI_MEM_H_
-#define _UDI_MEM_H_
-
-/**
- * \brief Callback type for ::udi_mem_alloc
- */
-typedef void udi_mem_alloc_call_t(udi_cb_t *gcb, void *new_mem);
-
-/**
- * \brief Allocate memory
- */
-extern void udi_mem_alloc(
-       udi_mem_alloc_call_t *callback,
-       udi_cb_t        *gcb,
-       udi_size_t      size,
-       udi_ubit8_t     flags
-       );
-
-/**
- * \brief Values for ::udi_mem_alloc \a flags
- * \{
- */
-#define UDI_MEM_NOZERO               (1U<<0)   //!< No need to zero the memory
-#define UDI_MEM_MOVABLE              (1U<<1)   //!< Globally accessable memory?
-/**
- * \}
- */
-
-/**
- * \brief Free allocated memory
- */
-extern void udi_mem_free(void *target_mem);
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/meta_gio.h b/Modules/Interfaces/UDI/include/udi/meta_gio.h
deleted file mode 100644 (file)
index d1cf86f..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * \file udi_meta_gio.h
- */
-#ifndef _UDI_META_GIO_H_
-#define _UDI_META_GIO_H_
-
-typedef const struct udi_gio_provider_ops_s    udi_gio_provider_ops_t;
-typedef const struct udi_gio_client_ops_s      udi_gio_client_ops_t;
-typedef struct udi_gio_bind_cb_s       udi_gio_bind_cb_t;
-typedef struct udi_gio_xfer_cb_s       udi_gio_xfer_cb_t;
-typedef struct udi_gio_rw_params_s     udi_gio_rw_params_t;
-typedef struct udi_gio_event_cb_s      udi_gio_event_cb_t;
-
-typedef void   udi_gio_bind_req_op_t(udi_gio_bind_cb_t *cb);
-typedef void   udi_gio_unbind_req_op_t(udi_gio_bind_cb_t *cb);
-typedef void   udi_gio_xfer_req_op_t(udi_gio_bind_cb_t *cb);
-typedef void   udi_gio_event_res_op_t(udi_gio_bind_cb_t *cb);
-
-typedef void   udi_gio_bind_ack_op_t(
-       udi_gio_bind_cb_t *cb,
-       udi_ubit32_t    device_size_lo,
-       udi_ubit32_t    device_size_hi,
-       udi_status_t    status
-       );
-typedef void   udi_gio_unbind_ack_op_t(udi_gio_bind_cb_t *cb);
-typedef void   udi_gio_xfer_ack_op_t(udi_gio_bind_cb_t *cb);
-typedef void   udi_gio_xfer_nak_op_t(udi_gio_bind_cb_t *cb, udi_status_t status);
-typedef void   udi_gio_event_ind_op_t(udi_gio_bind_cb_t *cb);
-
-typedef udi_ubit8_t    udi_gio_op_t;
-/* Limit values for udi_gio_op_t */
-#define UDI_GIO_OP_CUSTOM                 16
-#define UDI_GIO_OP_MAX                    64
-/* Direction flag values for op */
-#define UDI_GIO_DIR_READ                  (1U<<6)
-#define UDI_GIO_DIR_WRITE                 (1U<<7)
-/* Standard Operation Codes */
-#define UDI_GIO_OP_READ       UDI_GIO_DIR_READ
-#define UDI_GIO_OP_WRITE      UDI_GIO_DIR_WRITE
-
-
-
-struct udi_gio_provider_ops_s
-{
-       udi_channel_event_ind_op_t      *channel_event_ind_op;
-       udi_gio_bind_req_op_t   *gio_bind_req_op;
-       udi_gio_unbind_req_op_t *gio_unbind_req_op;
-       udi_gio_xfer_req_op_t   *gio_xfer_req_op;
-       udi_gio_event_res_op_t  *gio_event_res_op;
-};
-/* Ops Vector Number */
-#define UDI_GIO_PROVIDER_OPS_NUM          1
-
-struct udi_gio_client_ops_s
-{
-       udi_channel_event_ind_op_t      *channel_event_ind_op;
-       udi_gio_bind_ack_op_t   *gio_bind_ack_op;
-       udi_gio_unbind_ack_op_t *gio_unbind_ack_op;
-       udi_gio_xfer_ack_op_t   *gio_xfer_ack_op;
-       udi_gio_xfer_nak_op_t   *gio_xfer_nak_op;
-       udi_gio_event_ind_op_t  *gio_event_ind_op;
-};
-/* Ops Vector Number */
-#define UDI_GIO_CLIENT_OPS_NUM            2
-
-struct udi_gio_bind_cb_s
-{
-       udi_cb_t        gcb;
-       udi_xfer_constraints_t  xfer_constraints;
-};
-/* Control Block Group Number */
-#define UDI_GIO_BIND_CB_NUM      1
-
-
-struct udi_gio_xfer_cb_s
-{
-       udi_cb_t        gcb;
-       udi_gio_op_t    op;
-       void    *tr_params;
-       udi_buf_t       *data_buf;
-};
-/* Control Block Group Number */
-#define UDI_GIO_XFER_CB_NUM      2
-
-struct udi_gio_rw_params_s
-{
-       udi_ubit32_t offset_lo;
-       udi_ubit32_t offset_hi;
-};
-
-struct udi_gio_event_cb_s
-{
-       udi_cb_t        gcb;
-       udi_ubit8_t     event_code;
-       void    *event_params;
-};
-/* Control Block Group Number */
-#define UDI_GIO_EVENT_CB_NUM     3
-
-
-extern void udi_gio_bind_req(udi_gio_bind_cb_t *cb);
-extern void udi_gio_bind_ack(
-       udi_gio_bind_cb_t       *cb,
-       udi_ubit32_t    device_size_lo,
-       udi_ubit32_t    device_size_hi,
-       udi_status_t    status
-       );
-
-extern void udi_gio_unbind_req(udi_gio_bind_cb_t *cb);
-extern void udi_gio_unbind_ack(udi_gio_bind_cb_t *cb);
-
-extern void udi_gio_xfer_req(udi_gio_xfer_cb_t *cb);
-extern void udi_gio_xfer_ack(udi_gio_xfer_cb_t *cb);
-extern void udi_gio_xfer_nak(udi_gio_xfer_cb_t *cb, udi_status_t status);
-
-extern void udi_gio_event_res(udi_gio_event_cb_t *cb);
-extern void udi_gio_event_ind(udi_gio_event_cb_t *cb);
-extern void udi_gio_event_res_unused(udi_gio_event_cb_t *cb);
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/meta_mgmt.h b/Modules/Interfaces/UDI/include/udi/meta_mgmt.h
deleted file mode 100644 (file)
index 97eccf2..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * \file udi_meta_mgmt.h
- */
-#ifndef _UDI_META_MGMT_H_
-#define _UDI_META_MGMT_H_
-
-typedef struct udi_mgmt_ops_s  udi_mgmt_ops_t;
-typedef struct udi_mgmt_cb_s   udi_mgmt_cb_t;
-typedef struct udi_usage_cb_s  udi_usage_cb_t;
-typedef struct udi_filter_element_s    udi_filter_element_t;
-typedef struct udi_enumerate_cb_s      udi_enumerate_cb_t;
-
-/**
- * \name Specify Usage
- * \{
- */
-typedef void udi_usage_ind_op_t(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
-/* Values for resource_level */
-#define UDI_RESOURCES_CRITICAL     1
-#define UDI_RESOURCES_LOW          2
-#define UDI_RESOURCES_NORMAL       3
-#define UDI_RESOURCES_PLENTIFUL    4
-/* Proxy */
-extern void    udi_static_usage(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
-/**
- * \}
- */
-
-typedef void udi_usage_res_op_t(udi_usage_cb_t *cb);
-
-/**
- * \name Enumerate this driver
- * \{
- */
-typedef void udi_enumerate_req_op_t(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
-/* Values for enumeration_level */
-#define UDI_ENUMERATE_START           1
-#define UDI_ENUMERATE_START_RESCAN    2
-#define UDI_ENUMERATE_NEXT            3
-#define UDI_ENUMERATE_NEW             4
-#define UDI_ENUMERATE_DIRECTED        5
-#define UDI_ENUMERATE_RELEASE         6
-/* Proxy */
-extern void udi_enumerate_no_children(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
-/**
- * \}
- */
-
-/**
- * \name Enumeration Acknowlagement
- * \{
- */
-typedef void udi_enumerate_ack_op_t(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_result, udi_index_t ops_idx);
-/* Values for enumeration_result */
-#define UDI_ENUMERATE_OK             0
-#define UDI_ENUMERATE_LEAF           1
-#define UDI_ENUMERATE_DONE           2
-#define UDI_ENUMERATE_RESCAN         3
-#define UDI_ENUMERATE_REMOVED        4
-#define UDI_ENUMERATE_REMOVED_SELF   5
-#define UDI_ENUMERATE_RELEASED       6
-#define UDI_ENUMERATE_FAILED         255
-/**
- * \}
- */
-
-/**
- * \name 
- * \{
- */
-typedef void udi_devmgmt_req_op_t(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
-
-typedef void udi_devmgmt_ack_op_t(udi_mgmt_cb_t *cb, udi_ubit8_t flags, udi_status_t status);
-/**
- * \}
- */
-typedef void udi_final_cleanup_req_op_t(udi_mgmt_cb_t *cb);
-typedef void udi_final_cleanup_ack_op_t(udi_mgmt_cb_t *cb);
-
-
-
-
-
-struct udi_mgmt_ops_s
-{
-       udi_usage_ind_op_t      *usage_ind_op;
-       udi_enumerate_req_op_t  *enumerate_req_op;
-       udi_devmgmt_req_op_t    *devmgmt_req_op;
-       udi_final_cleanup_req_op_t      *final_cleanup_req_op;
-};
-
-struct udi_mgmt_cb_s
-{
-       udi_cb_t        gcb;
-};
-
-struct udi_usage_cb_s
-{
-       udi_cb_t        gcb;
-       udi_trevent_t   trace_mask;
-       udi_index_t     meta_idx;
-};
-
-
-struct udi_filter_element_s
-{
-     char      attr_name[UDI_MAX_ATTR_NAMELEN];
-     udi_ubit8_t       attr_min[UDI_MAX_ATTR_SIZE];
-     udi_ubit8_t       attr_min_len;
-     udi_ubit8_t       attr_max[UDI_MAX_ATTR_SIZE];
-     udi_ubit8_t       attr_max_len;
-     udi_instance_attr_type_t  attr_type;
-     udi_ubit32_t      attr_stride;
-};
-struct udi_enumerate_cb_s
-{
-     udi_cb_t  gcb;
-     udi_ubit32_t      child_ID;
-     void      *child_data;
-     udi_instance_attr_list_t  *attr_list;
-     udi_ubit8_t       attr_valid_length;
-     const udi_filter_element_t        *filter_list;
-     udi_ubit8_t       filter_list_length;
-     udi_ubit8_t       parent_ID;
-};
-/* Special parent_ID filter values */
-#define UDI_ANY_PARENT_ID      0
-
-/**
- * \brief 
- */
-extern void    udi_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID );
-/**
- * \brief Values for ::udi_devmgmt_req \a mgmt_op
- */
-enum eDMGMT
-{
-       UDI_DMGMT_PREPARE_TO_SUSPEND = 1,
-       UDI_DMGMT_SUSPEND,
-       UDI_DMGMT_SHUTDOWN,
-       UDI_DMGMT_PARENT_SUSPENDED,
-       UDI_DMGMT_RESUME,
-       UDI_DMGMT_UNBIND
-};
-
-extern void    udi_devmgmt_ack(udi_mgmt_cb_t *cb, udi_ubit8_t flags, udi_status_t status);
-//!\brief Values for flags
-#define UDI_DMGMT_NONTRANSPARENT       (1U<<0)
-//!\brief Meta-Specific Status Codes
-#define UDI_DMGMT_STAT_ROUTING_CHANGE  (UDI_STAT_META_SPECIFIC|1)
-
-extern void udi_final_cleanup_req(udi_mgmt_cb_t *cb);
-extern void udi_final_cleanup_ack(udi_mgmt_cb_t *cb);
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi/strmem.h b/Modules/Interfaces/UDI/include/udi/strmem.h
deleted file mode 100644 (file)
index f540a3e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * \file udi_strmem.h
- */
-#ifndef _UDI_STRMEM_H_
-#define _UDI_STRMEM_H_
-
-/**
- * \brief Gets the length of a C style string
- */
-extern udi_size_t      udi_strlen(const char *s);
-
-/**
- * \brief Appends to a string
- */
-extern char *udi_strcat(char *s1, const char *s2);
-extern char *udi_strncat(char *s1, const char *s2, udi_size_t n);
-
-/**
- * \brief Compares Strings/Memory
- */
-extern udi_sbit8_t udi_strcmp(const char *s1, const char *s2);
-extern udi_sbit8_t udi_strncmp(const char *s1, const char *s2, udi_size_t n);
-extern udi_sbit8_t udi_memcmp(const void *s1, const void *s2, udi_size_t n);
-
-extern char *udi_strcpy(char *s1, const char *s2);
-extern char *udi_strncpy(char *s1, const char *s2, udi_size_t n);
-extern void *udi_memcpy(void *s1, const void *s2, udi_size_t n);
-extern void *udi_memmove(void *s1, const void *s2, udi_size_t n);
-
-extern char *udi_strncpy_rtrim(char *s1, const char *s2, udi_size_t n);
-
-extern char *udi_strchr(const char *s, char c);
-extern char *udi_strrchr(const char *s, char c);
-extern void *udi_memchr (const void *s, udi_ubit8_t c, udi_size_t n);
-
-extern void *udi_memset(void *s, udi_ubit8_t c, udi_size_t n);
-extern udi_ubit32_t udi_strtou32(const char *s, char **endptr, int base);
-
-
-extern udi_size_t udi_snprintf(char *s, udi_size_t max_bytes, const char *format, ...);
-
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/include/udi_physio.h b/Modules/Interfaces/UDI/include/udi_physio.h
deleted file mode 100644 (file)
index 1397b1c..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * \file udi_physio.h
- */
-#ifndef _UDI_PHYSIO_H_
-#define _UDI_PHYSIO_H_
-
-#include <udi.h>
-
-// === TYPEDEFS ===
-// DMA Core
-typedef _udi_handle_t  udi_dma_handle_t;
-#define        UDI_NULL_DMA_HANDLE     _NULL_HANDLE
-typedef Uint64 udi_busaddr64_t;        //!< \note Opaque
-typedef struct udi_scgth_element_32_s  udi_scgth_element_32_t;
-typedef struct udi_scgth_element_64_s  udi_scgth_element_64_t;
-typedef struct udi_scgth_s     udi_scgth_t;
-typedef _udi_handle_t  udi_dma_constraints_t;
-#define UDI_NULL_DMA_CONSTRAINTS       _NULL_HANDLE
-/**
- * \name DMA constraints attributes
- * \{
- */
-typedef udi_ubit8_t udi_dma_constraints_attr_t;
-/* DMA Convenience Attribute Codes */
-#define UDI_DMA_ADDRESSABLE_BITS          100
-#define UDI_DMA_ALIGNMENT_BITS            101
-/* DMA Constraints on the Entire Transfer */
-#define UDI_DMA_DATA_ADDRESSABLE_BITS     110
-#define UDI_DMA_NO_PARTIAL                111
-/* DMA Constraints on the Scatter/Gather  List */
-#define UDI_DMA_SCGTH_MAX_ELEMENTS        120
-#define UDI_DMA_SCGTH_FORMAT              121
-#define UDI_DMA_SCGTH_ENDIANNESS          122
-#define UDI_DMA_SCGTH_ADDRESSABLE_BITS    123
-#define UDI_DMA_SCGTH_MAX_SEGMENTS        124
-/* DMA Constraints on Scatter/Gather Segments */
-#define UDI_DMA_SCGTH_ALIGNMENT_BITS      130
-#define UDI_DMA_SCGTH_MAX_EL_PER_SEG      131
-#define UDI_DMA_SCGTH_PREFIX_BYTES        132
-/* DMA Constraints on Scatter/Gather Elements */
-#define UDI_DMA_ELEMENT_ALIGNMENT_BITS    140
-#define UDI_DMA_ELEMENT_LENGTH_BITS       141
-#define UDI_DMA_ELEMENT_GRANULARITY_BITS 142
-/* DMA Constraints for Special Addressing */
-#define UDI_DMA_ADDR_FIXED_BITS           150
-#define UDI_DMA_ADDR_FIXED_TYPE           151
-#define UDI_DMA_ADDR_FIXED_VALUE_LO       152
-#define UDI_DMA_ADDR_FIXED_VALUE_HI       153
-/* DMA Constraints on DMA Access Behavior */
-#define UDI_DMA_SEQUENTIAL                160
-#define UDI_DMA_SLOP_IN_BITS              161
-#define UDI_DMA_SLOP_OUT_BITS             162
-#define UDI_DMA_SLOP_OUT_EXTRA            163
-#define UDI_DMA_SLOP_BARRIER_BITS         164
-/* Values for UDI_DMA_SCGTH_ENDIANNESS */
-#define UDI_DMA_LITTLE_ENDIAN             (1U<<6)
-#define UDI_DMA_BIG_ENDIAN                (1U<<5)
-/* Values for UDI_DMA_ADDR_FIXED_TYPE */
-#define UDI_DMA_FIXED_ELEMENT             1
-/**
- * \}
- */
-// DMA Constraints Management
-typedef struct udi_dma_constraints_attr_spec_s udi_dma_constraints_attr_spec_t;
-typedef void udi_dma_constraints_attr_set_call_t(
-       udi_cb_t *gcb, udi_dma_constraints_t new_constraints, udi_status_t status
-       );
-typedef        struct udi_dma_limits_s udi_dma_limits_t;
-
-
-// === STRUCTURES ===
-// --- DMA Constraints Management ---
-struct udi_dma_constraints_attr_spec_s
-{
-     udi_dma_constraints_attr_t        attr_type;
-     udi_ubit32_t      attr_value;
-};
-// --- DMA Core ---
-struct udi_dma_limits_s
-{
-     udi_size_t max_legal_contig_alloc;
-     udi_size_t max_safe_contig_alloc;
-     udi_size_t cache_line_size;
-};
-struct udi_scgth_element_32_s
-{
-     udi_ubit32_t      block_busaddr;
-     udi_ubit32_t      block_length;
-};
-struct udi_scgth_element_64_s
-{
-     udi_busaddr64_t   block_busaddr;
-     udi_ubit32_t      block_length;
-     udi_ubit32_t      el_reserved;
-};
-/* Extension Flag */
-#define UDI_SCGTH_EXT                    0x80000000
-struct udi_scgth_s
-{
-     udi_ubit16_t      scgth_num_elements;
-     udi_ubit8_t       scgth_format;
-     udi_boolean_t     scgth_must_swap;
-     union {
-          udi_scgth_element_32_t       *el32p;
-          udi_scgth_element_64_t       *el64p;
-     } scgth_elements;
-     union {
-          udi_scgth_element_32_t       el32;
-          udi_scgth_element_64_t       el64;
-     } scgth_first_segment;
-};
-/* Values for scgth_format */
-#define UDI_SCGTH_32                     (1U<<0)
-#define UDI_SCGTH_64                     (1U<<1)
-#define UDI_SCGTH_DMA_MAPPED             (1U<<6)
-#define UDI_SCGTH_DRIVER_MAPPED          (1U<<7)
-
-
-
-// === FUNCTIONS ===
-// --- DMA Constraints Management ---
-extern void udi_dma_constraints_attr_set(
-       udi_dma_constraints_attr_set_call_t     *callback,
-       udi_cb_t        *gcb,
-       udi_dma_constraints_t   src_constraints,
-       const udi_dma_constraints_attr_spec_t   *attr_list,
-       udi_ubit16_t    list_length,
-       udi_ubit8_t     flags
-       );
-/* Constraints Flags */
-#define UDI_DMA_CONSTRAINTS_COPY (1U<<0)
-
-extern void udi_dma_constraints_attr_reset(
-       udi_dma_constraints_t   constraints,
-       udi_dma_constraints_attr_t      attr_type
-       );
-
-extern void udi_dma_constraints_free(udi_dma_constraints_t constraints);
-
-#include <physio/meta_intr.h>
-#include <physio/meta_bus.h>
-
-
-#endif
diff --git a/Modules/Interfaces/UDI/logging.c b/Modules/Interfaces/UDI/logging.c
deleted file mode 100644 (file)
index 2e58e37..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * \file logging.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-
-// === PROTOTYPES ===
-
-// === CODE ===
-void udi_log_write( udi_log_write_call_t *callback, udi_cb_t *gcb,
-       udi_trevent_t trace_event, udi_ubit8_t severity, udi_index_t meta_idx,
-       udi_status_t original_status, udi_ubit32_t msgnum, ... )
-{
-       Log("UDI Log");
-}
-
-EXPORT(udi_log_write);
diff --git a/Modules/Interfaces/UDI/main.c b/Modules/Interfaces/UDI/main.c
deleted file mode 100644 (file)
index a4a1504..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Acess2 UDI Layer
- */
-#define DEBUG  0
-#define VERSION        ((0<<8)|1)
-#include <acess.h>
-#include <modules.h>
-#include <udi.h>
-
-// === PROTOTYPES ===
- int   UDI_Install(char **Arguments);
- int   UDI_DetectDriver(void *Base);
- int   UDI_LoadDriver(void *Base);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
-tModuleLoader  gUDI_Loader = {
-       NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
-};
-
-// === CODE ===
-/**
- * \fn int UDI_Install(char **Arguments)
- * \brief Stub intialisation routine
- */
-int UDI_Install(char **Arguments)
-{
-       Module_RegisterLoader( &gUDI_Loader );
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Detects if a driver should be loaded by the UDI subsystem
- */
-int UDI_DetectDriver(void *Base)
-{
-       if( Binary_FindSymbol(Base, "udi_init_info", NULL) == 0) {
-               return 0;
-       }
-       
-       return 1;
-}
-
-/**
- * \fn int UDI_LoadDriver(void *Base)
- */
-int UDI_LoadDriver(void *Base)
-{
-       udi_init_t      *info;
-       char    *udiprops = NULL;
-        int    udiprops_size = 0;
-        int    i;
-       // int  j;
-       
-       Log_Debug("UDI", "UDI_LoadDriver: (Base=%p)", Base);
-       
-       if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
-               Binary_Unload(Base);
-               return 0;
-       }
-       
-       if( Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops) == 0 ) {
-               Log_Warning("UDI", "_udiprops is not defined, this is usually bad");
-       }
-       else {
-               Uint    udiprops_end = 0;
-                int    i, j, nLines;
-               char    **udipropsptrs;
-               
-               if( Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end) == 0)
-                       Log_Warning("UDI", "_udiprops_end is not defined");
-               Log_Debug("UDI", "udiprops_end = %p", udiprops_end);
-               udiprops_size = udiprops_end - (Uint)udiprops;
-               Log_Debug("UDI", "udiprops = %p, udiprops_size = 0x%x", udiprops, udiprops_size);
-               
-               Debug_HexDump("UDI_LoadDriver", udiprops, udiprops_size);
-               
-               nLines = 1;
-               for( i = 0; i < udiprops_size; i++ )
-               {
-                       if( udiprops[i] == '\0' )
-                               nLines ++;
-               }
-               
-               Log_Debug("UDI", "nLines = %i", nLines);
-               
-               udipropsptrs = malloc( sizeof(char*)*nLines );
-               udipropsptrs[0] = udiprops;
-               j = 0;
-               for( i = 0; i < udiprops_size; i++ )
-               {
-                       if( udiprops[i] == '\0' ) {
-                               //Log_Debug("UDI", "udipropsptrs[%i] = '%s'", j, udipropsptrs[j]);
-                               udipropsptrs[j++] = &udiprops[i+1];
-                       }
-               }
-               Log_Debug("UDI", "udipropsptrs[%i] = '%s'", j, udipropsptrs[j]);
-               Log_Debug("UDI", "udiprops = \"%s\"", udiprops);
-       }
-       
-       
-       Log("primary_init_info = %p = {", info->primary_init_info);
-       {
-               Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
-               Log("  .usage_ind_op: %p() - 0x%02x",
-                       info->primary_init_info->mgmt_ops->usage_ind_op,
-                       info->primary_init_info->mgmt_op_flags[0]
-                       );
-               Log("  .enumerate_req_op: %p() - 0x%02x",
-                       info->primary_init_info->mgmt_ops->enumerate_req_op,
-                       info->primary_init_info->mgmt_op_flags[1]
-                       );
-               Log("  .devmgmt_req_op: %p() - 0x%02x",
-                       info->primary_init_info->mgmt_ops->devmgmt_req_op,
-                       info->primary_init_info->mgmt_op_flags[2]
-                       );
-               Log("  .final_cleanup_req_op: %p() - 0x%02x",
-                       info->primary_init_info->mgmt_ops->final_cleanup_req_op,
-                       info->primary_init_info->mgmt_op_flags[3]
-                       );
-               Log(" }");
-               Log(" .mgmt_scratch_requirement = 0x%x", info->primary_init_info->mgmt_scratch_requirement);
-               Log(" .enumeration_attr_list_length = 0x%x", info->primary_init_info->enumeration_attr_list_length);
-               Log(" .rdata_size = 0x%x", info->primary_init_info->rdata_size);
-               Log(" .child_data_size = 0x%x", info->primary_init_info->child_data_size);
-               Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
-       }
-       Log("}");
-       Log("secondary_init_list = %p", info->secondary_init_list);
-       Log("ops_init_list = %p", info->ops_init_list);
-       
-       for( i = 0; info->ops_init_list[i].ops_idx; i++ )
-       {
-               Log("info->ops_init_list[%i] = {", i);
-               Log(" .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
-               Log(" .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
-               Log(" .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
-               Log(" .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
-               Log(" .ops_vector = %p", info->ops_init_list[i].ops_vector);
-//             Log(" .op_flags = %p", info->ops_init_list[i].op_flags);
-               Log("}");
-       }
-       
-       return 0;
-}
diff --git a/Modules/Interfaces/UDI/mem.c b/Modules/Interfaces/UDI/mem.c
deleted file mode 100644 (file)
index a09d54c..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * \file mem.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-
-// === EXPORTS ===
-EXPORT(udi_mem_alloc);
-EXPORT(udi_mem_free);
-
-// === CODE ===
-void udi_mem_alloc(
-       udi_mem_alloc_call_t *callback,
-       udi_cb_t        *gcb,
-       udi_size_t      size,
-       udi_ubit8_t     flags
-       )
-{
-       void    *buf = malloc(size);
-       if(buf)
-       {
-               if( !(flags & UDI_MEM_NOZERO) )
-                       memset(buf, 0, size);
-       }
-       callback(gcb, buf);
-}
-
-void udi_mem_free(void *target_mem)
-{
-       free(target_mem);
-}
diff --git a/Modules/Interfaces/UDI/meta_gio.c b/Modules/Interfaces/UDI/meta_gio.c
deleted file mode 100644 (file)
index 1618c27..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * \file meta_gio.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-
-// === EXPORTS ===
-EXPORT(udi_gio_bind_req);
-EXPORT(udi_gio_bind_ack);
-EXPORT(udi_gio_unbind_req);
-EXPORT(udi_gio_unbind_ack);
-EXPORT(udi_gio_xfer_req);
-EXPORT(udi_gio_xfer_ack);
-EXPORT(udi_gio_xfer_nak);
-EXPORT(udi_gio_event_res);
-EXPORT(udi_gio_event_ind);
-EXPORT(udi_gio_event_res_unused);
-
-// === CODE ===
-void udi_gio_bind_req(udi_gio_bind_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_gio_bind_ack(
-       udi_gio_bind_cb_t       *cb,
-       udi_ubit32_t    device_size_lo,
-       udi_ubit32_t    device_size_hi,
-       udi_status_t    status
-       )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_gio_unbind_req(udi_gio_bind_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_gio_unbind_ack(udi_gio_bind_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_gio_xfer_req(udi_gio_xfer_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_gio_xfer_ack(udi_gio_xfer_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_gio_xfer_nak(udi_gio_xfer_cb_t *cb, udi_status_t status)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_gio_event_res(udi_gio_event_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_gio_event_ind(udi_gio_event_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_gio_event_res_unused(udi_gio_event_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
diff --git a/Modules/Interfaces/UDI/meta_mgmt.c b/Modules/Interfaces/UDI/meta_mgmt.c
deleted file mode 100644 (file)
index 45a02c4..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * \file meta_mgmt.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-
-// === EXPORTS ===
-EXPORT(udi_devmgmt_req);
-EXPORT(udi_devmgmt_ack);
-EXPORT(udi_final_cleanup_req);
-EXPORT(udi_final_cleanup_ack);
-EXPORT(udi_static_usage);
-EXPORT(udi_enumerate_no_children);
-
-// === CODE ===
-void udi_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID )
-{      
-       ENTER("pcb imgmt_op iparent_ID", cb, mgmt_op, parent_ID);
-       LEAVE('-');
-}
-
-void udi_devmgmt_ack(udi_mgmt_cb_t *cb, udi_ubit8_t flags, udi_status_t status)
-{
-       ENTER("pcb xflags istatus", cb, flags, status);
-       LEAVE('-');
-}
-
-void udi_final_cleanup_req(udi_mgmt_cb_t *cb)
-{
-       ENTER("pcb", cb);
-       LEAVE('-');
-}
-
-void udi_final_cleanup_ack(udi_mgmt_cb_t *cb)
-{
-       ENTER("pcb", cb);
-       LEAVE('-');
-}
-
-void udi_static_usage(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_enumerate_no_children(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
-{
-       UNIMPLEMENTED();
-}
diff --git a/Modules/Interfaces/UDI/physio.c b/Modules/Interfaces/UDI/physio.c
deleted file mode 100644 (file)
index 881c9f4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * \file physio.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-#include <udi_physio.h>
-
-// === EXPORTS ===
-EXPORT(udi_dma_constraints_attr_reset);
-EXPORT(udi_dma_constraints_free);
-
-// === CODE ===
-void udi_dma_constraints_attr_reset(
-       udi_dma_constraints_t   constraints,
-       udi_dma_constraints_attr_t      attr_type
-       )
-{
-       UNIMPLEMENTED();
-}
-
-void udi_dma_constraints_free(udi_dma_constraints_t constraints)
-{
-       UNIMPLEMENTED();
-}
diff --git a/Modules/Interfaces/UDI/physio/meta_bus.c b/Modules/Interfaces/UDI/physio/meta_bus.c
deleted file mode 100644 (file)
index e1e6a47..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * \file physio/meta_bus.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-#include <udi_physio.h>
-
-// === EXPORTS ===
-EXPORT(udi_bus_unbind_req);
-EXPORT(udi_bus_unbind_ack);
-EXPORT(udi_bus_bind_req);
-EXPORT(udi_bus_bind_ack);
-
-// === CODE ===
-void udi_bus_unbind_req(udi_bus_bind_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_bus_unbind_ack(udi_bus_bind_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_bus_bind_req(udi_bus_bind_cb_t *cb)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_bus_bind_ack(
-       udi_bus_bind_cb_t       *cb,
-       udi_dma_constraints_t   dma_constraints,
-       udi_ubit8_t     preferred_endianness,
-       udi_status_t    status
-       )
-{
-       UNIMPLEMENTED();
-}
diff --git a/Modules/Interfaces/UDI/physio/meta_intr.c b/Modules/Interfaces/UDI/physio/meta_intr.c
deleted file mode 100644 (file)
index f4f5096..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * \file physio/meta_intr.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-#include <udi_physio.h>
-
-// === EXPORTS ===
-EXPORT(udi_intr_attach_req);
-EXPORT(udi_intr_attach_ack);
-EXPORT(udi_intr_attach_ack_unused);
-EXPORT(udi_intr_detach_req);
-EXPORT(udi_intr_detach_ack);
-EXPORT(udi_intr_detach_ack_unused);
-EXPORT(udi_intr_event_ind);
-
-// === CODE ===
-void udi_intr_attach_req(udi_intr_attach_cb_t *intr_attach_cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
-{
-       UNIMPLEMENTED();
-}
-void udi_intr_attach_ack_unused(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_intr_detach_req(udi_intr_detach_cb_t *intr_detach_cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
-{
-       UNIMPLEMENTED();
-}
-void udi_intr_detach_ack_unused(udi_intr_detach_cb_t *intr_detach_cb)
-{
-       UNIMPLEMENTED();
-}
-
-void udi_intr_event_ind(udi_intr_event_cb_t *intr_event_cb, udi_ubit8_t flags)
-{
-       UNIMPLEMENTED();
-}
diff --git a/Modules/Interfaces/UDI/physio_main.c b/Modules/Interfaces/UDI/physio_main.c
deleted file mode 100644 (file)
index f5e7aa0..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * \file logging.c
- * \author John Hodge (thePowersGang)
- */
-#include <common.h>
-#include <udi.h>
-#include <udi_physio.h>
-
-// === CODE ===
-void udi_bus_bind_req(udi_bus_bind_cb_t *cb)
-{
-}
-
-void udi_bus_unbind_req(udi_bus_bind_cb_t *cb)
-{
-}
diff --git a/Modules/Interfaces/UDI/strmem.c b/Modules/Interfaces/UDI/strmem.c
deleted file mode 100644 (file)
index 53cc933..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * \file strmem.c
- * \author John Hodge (thePowersGang)
- */
-#include <acess.h>
-#include <udi.h>
-
-// === EXPORTS ===
-EXPORT(udi_snprintf);
-
-// === CODE ===
-udi_size_t udi_snprintf(char *s, udi_size_t max_bytes, const char *format, ...)
-{
-       udi_size_t      ret;
-       va_list args;
-       va_start(args, format);
-       
-       ret = vsnprintf(s, max_bytes, format, args);
-       
-       va_end(args);
-       return ret;
-}
diff --git a/Modules/Libraries/SunRPC/proto.h b/Modules/Libraries/SunRPC/proto.h
deleted file mode 100644 (file)
index 150fc42..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Acess2 Kernel
- * - Sun RPC (RFC 1057) implementation
- * proto.h
- * - Protocol definition
- */
-#ifndef _SUNRPC_PROTO_H_
-#define _SUNRPC_PROTO_H_
-
-struct sRPC_CallBody
-{
-       Uint32  RPCVers;        //!< Version (2)
-       Uint32  Program;        //!< Program Identifier
-       Uint32  Version;        //!< Program Version
-       
-};
-
-struct sRPC_Message
-{
-       tNet32  XID;    //!< Transaction Identifier
-       union
-       {
-               struct sRPC_CallBody    Call;
-       };
-};
-
-#endif
-
diff --git a/Modules/Makefile.tpl b/Modules/Makefile.tpl
deleted file mode 100644 (file)
index f1c31a5..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-
-# Acess2 Module/Driver Templater Makefile
-# Makefile.tpl
-
-_CPPFLAGS := $(CPPFLAGS)
-
--include $(dir $(lastword $(MAKEFILE_LIST)))../Makefile.cfg
-
-LIBINCLUDES := $(addprefix -I$(ACESSDIR)/Modules/,$(DEPS))
-LIBINCLUDES := $(addsuffix /include,$(LIBINCLUDES))
-
-CPPFLAGS := -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include
-CPPFLAGS += -DARCH=$(ARCH) -DARCH_is_$(ARCH) -DARCHDIR_is_$(ARCHDIR)
-CPPFLAGS += $(_CPPFLAGS)
-CPPFLAGS += $(LIBINCLUDES)
-CFLAGS := -std=gnu99 -Wall -fno-stack-protector -g -O3
-
-ifneq ($(CATEGORY),)
-       FULLNAME := $(CATEGORY)_$(NAME)
-else
-       FULLNAME := $(NAME)
-endif
-
-CPPFLAGS += -D_MODULE_NAME_=\"$(FULLNAME)\"
-
-ifneq ($(BUILDTYPE),static)
-       _SUFFIX := dyn_$(ARCH)
-       BIN := ../$(FULLNAME).kmd.$(ARCH)
-       CFLAGS += $(DYNMOD_CFLAGS) -fPIC
-else
-       _SUFFIX := st_$(ARCH)
-       CFLAGS += $(KERNEL_CFLAGS)
-       BIN := ../$(NAME).xo.$(ARCH)
-endif
-
-OBJ := $(addprefix obj-$(_SUFFIX)/,$(OBJ))
-#OBJ := $(addsuffix .$(_SUFFIX),$(OBJ))
-
-DEPFILES := $(filter %.o,$(OBJ))
-DEPFILES := $(DEPFILES:%.o=%.d)
-
-.PHONY: all clean
-
-all: $(BIN)
-
-clean:
-       $(RM) $(BIN) $(BIN).dsm $(KOBJ) $(OBJ) $(DEPFILES) $(EXTRA)
-       $(RM) -r obj-$(_SUFFIX)
-
-install: $(BIN)
-ifneq ($(BUILDTYPE),static)
-       @$(xMKDIR) $(DISTROOT)/Modules/$(ARCH); true
-       $(xCP) $(BIN) $(DISTROOT)/Modules/$(ARCH)/$(NAME).kmd
-else
-endif
-
-
-ifneq ($(BUILDTYPE),static)
-$(BIN): %.kmd.$(ARCH): $(OBJ)
-       @echo --- $(LD) -o $@
-       @$(LD) --allow-shlib-undefined -shared -nostdlib -o $@ $(OBJ) -defsym=DriverInfo=_DriverInfo_$(FULLNAME) $(LDFLAGS)
-       @$(DISASM) $(BIN) > $(BIN).dsm
-else
-$(BIN): %.xo.$(ARCH): $(OBJ)
-       @echo --- $(LD) -o $@
-       @$(LD) -r -o $@ $(OBJ) $(LDFLAGS)
-endif
-
-obj-$(_SUFFIX)/%.o: %.c Makefile $(CFGFILES)
-       @echo --- $(CC) -o $@
-       @mkdir -p $(dir $@)
-       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
-       @$(CC) -M $(CPPFLAGS) -MT $@ -o obj-$(_SUFFIX)/$*.d $<
-
--include $(DEPFILES)
diff --git a/Modules/Network/Makefile.tpl b/Modules/Network/Makefile.tpl
deleted file mode 100644 (file)
index d5c0b3c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = Network
-
--include ../../Makefile.tpl
diff --git a/Modules/Network/NE2000/Makefile b/Modules/Network/NE2000/Makefile
deleted file mode 100644 (file)
index 7e74022..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = ne2000.o
-NAME = NE2000
-
--include ../Makefile.tpl
diff --git a/Modules/Network/NE2000/ne2000.c b/Modules/Network/NE2000/ne2000.c
deleted file mode 100644 (file)
index d05b2a3..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-/* Acess2
- * NE2000 Driver
- * 
- * See: ~/Sources/bochs/bochs.../iodev/ne2k.cc
- */
-#define        DEBUG   1
-#define VERSION        ((0<<8)|50)
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <drv_pci.h>
-#include <api_drv_network.h>
-#include <semaphore.h>
-
-// === CONSTANTS ===
-#define        MEM_START       0x40
-#define        MEM_END         0xC0
-#define RX_FIRST       (MEM_START)
-#define RX_LAST                (MEM_START+RX_BUF_SIZE-1)
-#define        RX_BUF_SIZE     0x40
-#define TX_FIRST       (MEM_START+RX_BUF_SIZE)
-#define TX_LAST                (MEM_END)
-#define        TX_BUF_SIZE     0x40
-#define        MAX_PACKET_QUEUE        10
-
-static const struct {
-       Uint16  Vendor;
-       Uint16  Device;
-} csaCOMPAT_DEVICES[] = {
-       {0x10EC, 0x8029},       // Realtek 8029
-       {0x10EC, 0x8129}        // Realtek 8129
-};
-#define NUM_COMPAT_DEVICES     ((int)(sizeof(csaCOMPAT_DEVICES)/sizeof(csaCOMPAT_DEVICES[0])))
-
-enum eNe2k_Page0Read {
-       CMD = 0,        //!< the master command register
-       CLDA0,          //!< Current Local DMA Address 0
-       CLDA1,          //!< Current Local DMA Address 1
-       BNRY,           //!< Boundary Pointer (for ringbuffer)
-       TSR,            //!< Transmit Status Register
-       NCR,            //!< collisions counter
-       FIFO,           //!< (for what purpose ??)
-       ISR,            //!< Interrupt Status Register
-       CRDA0,          //!< Current Remote DMA Address 0
-       CRDA1,          //!< Current Remote DMA Address 1
-       RSR = 0xC       //!< Receive Status Register
-};
-
-enum eNe2k_Page0Write {
-       PSTART = 1,     //!< page start (init only)
-       PSTOP,          //!< page stop  (init only)
-       TPSR = 4,       //!< transmit page start address
-       TBCR0,          //!< transmit byte count (low)
-       TBCR1,          //!< transmit byte count (high)
-       RSAR0 = 8,      //!< remote start address (lo)
-       RSAR1,  //!< remote start address (hi)
-       RBCR0,  //!< remote byte count (lo)
-       RBCR1,  //!< remote byte count (hi)
-       RCR,    //!< receive config register
-       TCR,    //!< transmit config register
-       DCR,    //!< data config register    (init)
-       IMR             //!< interrupt mask register (init)
-};
-
-enum eNe2k_Page1Read {
-       CURR = 7        //!< current page
-};
-
-// === TYPES ===
-typedef struct sNe2k_Card {
-       Uint16  IOBase; //!< IO Port Address from PCI
-       Uint8   IRQ;    //!< IRQ Assigned from PCI
-       
-       tSemaphore      Semaphore;      //!< Semaphore for incoming packets
-        int    NextRXPage;     //!< Next expected RX page
-       
-        int    NextMemPage;    //!< Next Card Memory page to use
-               
-       char    Name[2];        // "0"
-       tVFS_Node       Node;   //!< VFS Node
-       Uint8   MacAddr[6];     //!< Cached MAC address
-} tCard;
-
-// === PROTOTYPES ===
- int   Ne2k_Install(char **Arguments);
-char   *Ne2k_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *Ne2k_FindDir(tVFS_Node *Node, const char *Name);
- int   Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data);
-Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
-Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-
- int   Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer);
-Uint8  Ne2k_int_GetWritePage(tCard *Card, Uint16 Length);
-void   Ne2k_IRQHandler(int IntNum, void *Ptr);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, Ne2k, Ne2k_Install, NULL, NULL);
-tVFS_NodeType  gNe2K_RootNodeType = {
-       .ReadDir = Ne2k_ReadDir,
-       .FindDir = Ne2k_FindDir,
-       .IOCtl = Ne2k_IOCtl
-       };
-tVFS_NodeType  gNe2K_DevNodeType = {
-       .Write = Ne2k_Write,
-       .Read = Ne2k_Read,
-       .IOCtl = Ne2k_IOCtl     
-       };
-tDevFS_Driver  gNe2k_DriverInfo = {
-       NULL, "ne2k",
-       {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Type = &gNe2K_RootNodeType
-       }
-};
-Uint16 gNe2k_BaseAddress;
- int   giNe2k_CardCount = 0;
-tCard  *gpNe2k_Cards = NULL;
-
-// === CODE ===
-/**
- * \fn int Ne2k_Install(char **Options)
- * \brief Installs the NE2000 Driver
- */
-int Ne2k_Install(char **Options)
-{
-        int    i, j, k;
-        int    count, base;
-       tPCIDev id;
-       
-       // --- Scan PCI Bus ---
-       // Count Cards
-       giNe2k_CardCount = 0;
-       for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
-       {
-               giNe2k_CardCount += PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device );
-       }
-       
-       if( giNe2k_CardCount == 0 )     return MODULE_ERR_NOTNEEDED;
-       
-       // Enumerate Cards
-       k = 0;
-       gpNe2k_Cards = calloc( giNe2k_CardCount, sizeof(tCard) );
-       
-       for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
-       {
-               count = PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device );
-               for( j = 0; j < count; j ++,k ++ )
-               {
-                       id = PCI_GetDevice( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, j );
-                       // Create Structure
-                       base = PCI_GetBAR( id, 0 );
-                       gpNe2k_Cards[ k ].IOBase = base;
-                       gpNe2k_Cards[ k ].IRQ = PCI_GetIRQ( id );
-                       gpNe2k_Cards[ k ].NextMemPage = 64;
-                       gpNe2k_Cards[ k ].NextRXPage = RX_FIRST;
-                       
-                       // Install IRQ Handler
-                       IRQ_AddHandler(gpNe2k_Cards[ k ].IRQ, Ne2k_IRQHandler, &gpNe2k_Cards[k]);
-                       
-                       // Reset Card
-                       outb( base + 0x1F, inb(base + 0x1F) );
-                       while( (inb( base+ISR ) & 0x80) == 0 );
-                       outb( base + ISR, 0x80 );
-                       
-                       // Initialise Card
-                       outb( base + CMD, 0x40|0x21 );  // Page 1, No DMA, Stop
-                       outb( base + CURR, RX_FIRST );  // Current RX page
-                       outb( base + CMD, 0x21 );       // No DMA and Stop
-                       outb( base + DCR, 0x49 );       // Set WORD mode
-                       outb( base + IMR, 0x00 );       // Interrupt Mask Register
-                       outb( base + ISR, 0xFF );
-                       outb( base + RCR, 0x20 );       // Reciever to Monitor
-                       outb( base + TCR, 0x02 );       // Transmitter OFF (TCR.LB = 1, Internal Loopback)
-                       
-                       // Read MAC Address
-                       outb( base + RBCR0, 6*4 );      // Remote Byte Count
-                       outb( base + RBCR1, 0 );
-                       outb( base + RSAR0, 0 );        // Clear Source Address
-                       outb( base + RSAR1, 0 );
-                       outb( base + CMD, 0x0A );       // Remote Read, Start
-                       gpNe2k_Cards[ k ].MacAddr[0] = inb(base+0x10);//        inb(base+0x10);
-                       gpNe2k_Cards[ k ].MacAddr[1] = inb(base+0x10);//        inb(base+0x10);
-                       gpNe2k_Cards[ k ].MacAddr[2] = inb(base+0x10);//        inb(base+0x10);
-                       gpNe2k_Cards[ k ].MacAddr[3] = inb(base+0x10);//        inb(base+0x10);
-                       gpNe2k_Cards[ k ].MacAddr[4] = inb(base+0x10);//        inb(base+0x10);
-                       gpNe2k_Cards[ k ].MacAddr[5] = inb(base+0x10);//        inb(base+0x10);
-                       
-                       outb( base+PSTART, RX_FIRST);   // Set Receive Start
-                       outb( base+BNRY, RX_LAST-1);    // Set Boundary Page
-                       outb( base+PSTOP, RX_LAST);     // Set Stop Page
-                       outb( base+ISR, 0xFF ); // Clear all ints
-                       outb( base+CMD, 0x22 ); // No DMA, Start
-                       outb( base+IMR, 0x3F ); // Set Interupt Mask
-                       outb( base+RCR, 0x0F ); // Set WRAP and allow all packet matches
-                       outb( base+TCR, 0x00 ); // Set Normal Transmitter mode
-                       outb( base+TPSR, 0x40); // Set Transmit Start
-                       
-                       Log_Log("Ne2k", "Card %i 0x%04x IRQ%i %02x:%02x:%02x:%02x:%02x:%02x",
-                               k, base, gpNe2k_Cards[ k ].IRQ,
-                               gpNe2k_Cards[k].MacAddr[0], gpNe2k_Cards[k].MacAddr[1],
-                               gpNe2k_Cards[k].MacAddr[2], gpNe2k_Cards[k].MacAddr[3],
-                               gpNe2k_Cards[k].MacAddr[4], gpNe2k_Cards[k].MacAddr[5]
-                               );
-                       
-                       // Set VFS Node
-                       gpNe2k_Cards[ k ].Name[0] = '0'+k;
-                       gpNe2k_Cards[ k ].Name[1] = '\0';
-                       gpNe2k_Cards[ k ].Node.ImplPtr = &gpNe2k_Cards[ k ];
-                       gpNe2k_Cards[ k ].Node.NumACLs = 0;     // Root Only
-                       gpNe2k_Cards[ k ].Node.CTime = now();
-                       gpNe2k_Cards[ k ].Node.Type = &gNe2K_DevNodeType;
-                       
-                       // Initialise packet semaphore
-                       // - Start at zero, no max
-                       Semaphore_Init( &gpNe2k_Cards[k].Semaphore, 0, 0, "NE2000", gpNe2k_Cards[ k ].Name );
-               }
-       }
-       
-       gNe2k_DriverInfo.RootNode.Size = giNe2k_CardCount;
-       DevFS_AddDevice( &gNe2k_DriverInfo );
-       return MODULE_ERR_OK;
-}
-
-/**
- * \fn char *Ne2k_ReadDir(tVFS_Node *Node, int Pos)
- */
-char *Ne2k_ReadDir(tVFS_Node *Node, int Pos)
-{
-       char    ret[2];
-       if(Pos < 0 || Pos >= giNe2k_CardCount)  return NULL;
-       ret[0] = '0'+Pos;
-       ret[1] = '\0';
-       return strdup(ret);
-}
-
-/**
- * \fn tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name)
- */
-tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name)
-{
-       if(Name[0] == '\0' || Name[1] != '\0')  return NULL;
-       
-       return &gpNe2k_Cards[ Name[0]-'0' ].Node;
-}
-
-static const char *casIOCtls[] = { DRV_IOCTLNAMES, DRV_NETWORK_IOCTLNAMES, NULL };
-/**
- * \fn int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
- * \brief IOCtl calls for a network device
- */
-int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch( ID )
-       {
-       BASE_IOCTLS(DRV_TYPE_NETWORK, "NE2000", VERSION, casIOCtls);
-       }
-       
-       // If this is the root, return
-       if( Node == &gNe2k_DriverInfo.RootNode ) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Device specific settings
-       switch( ID )
-       {
-       case NET_IOCTL_GETMAC:
-               if( !CheckMem(Data, 6) ) {
-                       LEAVE('i', -1);
-                       return -1;
-               }
-               memcpy( Data, ((tCard*)Node->ImplPtr)->MacAddr, 6 );
-               LEAVE('i', 1);
-               return 1;
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
- * \brief Send a packet from the network card
- */
-Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       tCard   *Card = (tCard*)Node->ImplPtr;
-       const Uint16    *buf = Buffer;
-        int    rem = Length;
-        int    page;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       // TODO: Lock
-       
-       // Sanity Check Length
-       if(Length > TX_BUF_SIZE*256) {
-               Log_Warning(
-                       "Ne2k",
-                       "Ne2k_Write - Attempting to send over TX_BUF_SIZE*256 (%i) bytes (%i)",
-                       TX_BUF_SIZE*256, Length
-                       );
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Make sure that the card is in page 0
-       outb(Card->IOBase + CMD, 0|0x22);       // Page 0, Start, NoDMA
-       
-       // Clear Remote DMA Flag
-       outb(Card->IOBase + ISR, 0x40); // Bit 6
-       
-       // Send Size - Transfer Byte Count Register
-       outb(Card->IOBase + TBCR0, Length & 0xFF);
-       outb(Card->IOBase + TBCR1, Length >> 8);
-       
-       // Send Size - Remote Byte Count Register
-       outb(Card->IOBase + RBCR0, Length & 0xFF);
-       outb(Card->IOBase + RBCR1, Length >> 8);
-       
-       // Set up transfer
-       outb(Card->IOBase + RSAR0, 0x00);       // Page Offset
-       page = Ne2k_int_GetWritePage(Card, Length);
-       outb(Card->IOBase + RSAR1, page);       // Page Offset
-       // Start
-       outb(Card->IOBase + CMD, 0|0x10|0x2);   // Page 0, Remote Write, Start
-       
-       // Send Data
-       for(rem = Length; rem > 0; rem -= 2) {
-               outw(Card->IOBase + 0x10, *buf++);
-       }
-       
-       while( !(inb(Card->IOBase + ISR) & 0x40) )      // Wait for Remote DMA Complete
-               ;       //Proc_Yield();
-       
-       outb( Card->IOBase + ISR, 0x40 );       // ACK Interrupt
-       
-       // Send Packet
-       outb(Card->IOBase + TPSR, page);
-       outb(Card->IOBase + CMD, 0|0x10|0x4|0x2);
-       
-       // Complete DMA
-       //outb(Card->IOBase + CMD, 0|0x20);
-       
-       LEAVE('i', Length);
-       return Length;
-}
-
-/**
- * \fn Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Wait for and read a packet from the network card
- */
-Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tCard   *Card = (tCard*)Node->ImplPtr;
-       Uint8   page;
-       Uint8   data[256];
-       struct {
-               Uint8   Status;
-               Uint8   NextPacketPage;
-               Uint16  Length; // Little Endian
-       }       *pktHdr;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       // Wait for packets
-       if( Semaphore_Wait( &Card->Semaphore, 1 ) != 1 )
-       {
-               // Error or interrupted
-               LEAVE_RET('i', 0);
-       }
-       
-       outb(Card->IOBase, 0x22 | (1 << 6));    // Page 6
-       LOG("CURR : 0x%02x", inb(Card->IOBase + CURR));
-       
-       // Get current read page
-       page = Card->NextRXPage;
-       LOG("page = %i", page);
-       
-       Ne2k_int_ReadDMA(Card, page, 1, data);
-       
-       pktHdr = (void*)data;
-       
-       LOG("pktHdr->Status = 0x%x", pktHdr->Status);
-       LOG("pktHdr->NextPacketPage = %i", pktHdr->NextPacketPage);
-       LOG("pktHdr->Length = 0x%03x", pktHdr->Length);
-       
-       // Have we read all the required bytes yet?
-       if(pktHdr->Length < 256 - 4)
-       {
-               if(Length > pktHdr->Length)
-                       Length = pktHdr->Length;
-               memcpy(Buffer, &data[4], Length);
-       }
-       // No? oh damn, now we need to allocate a buffer
-       else
-       {
-                int    pages = pktHdr->NextPacketPage - page;
-               char    *buf = malloc( pages*256 );
-               
-               LOG("pktHdr->Length (%i) > 256 - 4, allocated buffer %p", pktHdr->Length, buf);
-               
-               if(!buf)        LEAVE_RET('i', -1);
-               
-               // Copy the already read data
-               memcpy(buf, data, 256);
-               
-               // Read all the needed pages
-               page ++;
-               if(page == RX_LAST+1)   page = RX_FIRST;
-               
-               if( page + pages > RX_LAST )
-               {
-                        int    first_count = RX_LAST+1 - page;
-                        int    tmp = 0;
-                       tmp += Ne2k_int_ReadDMA(Card, page, first_count, buf+256);
-                       tmp += Ne2k_int_ReadDMA(Card, RX_FIRST, pages-1-first_count, buf+(first_count+1)*256);
-                       LOG("composite return count = %i", tmp);
-               }
-               else
-                       Ne2k_int_ReadDMA(Card, page, pages-1, buf+256);
-               
-               // Wrap length to the packet length
-               if(Length > pktHdr->Length)
-                       Length = pktHdr->Length;
-               else if( Length < pktHdr->Length ) {
-                       Log_Warning("NE2000", "Packet truncated! (%i bytes truncated to %i)",
-                               pktHdr->Length, Length);
-               }
-               memcpy(Buffer, &buf[4], Length);
-               
-               free(buf);
-       }
-       
-       // Write BNRY (maximum page for incoming packets)
-       if(pktHdr->NextPacketPage == RX_FIRST)
-               outb( Card->IOBase + BNRY, RX_LAST-1 );
-       else
-               outb( Card->IOBase + BNRY, pktHdr->NextPacketPage-1 );
-       // Set next RX Page and decrement the waiting list
-       Card->NextRXPage = pktHdr->NextPacketPage;
-       
-       LEAVE('i', Length);
-       return Length;
-}
-
-int Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer)
-{
-        int    i;
-       
-       // Sanity check
-       if( !(0 <= FirstPage && FirstPage < 256) ) {
-               Log_Warning("NE2000", "Ne2k_int_ReadDMA: BUG - FirstPage(%i) not 8-bit", FirstPage);
-               return -1;
-       }
-       if( !(0 <= NumPages && NumPages < 256) ) {
-               Log_Warning("NE2000", "Ne2k_int_ReadDMA: BUG - NumPages(%i) not 8-bit", NumPages);
-               return -1;
-       }
-       
-       ENTER("pCard iFirstPage iNumPages pBuffer", Card, FirstPage, NumPages, Buffer);
-       
-       // Make sure that the card is in bank 0
-       outb(Card->IOBase + CMD, 0|0x22);       // Bank 0, Start, NoDMA
-       outb(Card->IOBase + ISR, 0x40); // Clear Remote DMA Flag
-       
-       // Set up transfer
-       outb(Card->IOBase + RBCR0, 0);
-       outb(Card->IOBase + RBCR1, NumPages);   // page count
-       outb(Card->IOBase + RSAR0, 0x00);       // Page Offset
-       outb(Card->IOBase + RSAR1, FirstPage);  // Page Number
-       outb(Card->IOBase + CMD, 0|0x08|0x2);   // Bank 0, Remote Read, Start
-       
-       // TODO: Less expensive
-       //while( !(inb(Card->IOBase + ISR) & 0x40) ) {
-       //      HALT();
-       //      LOG("inb(ISR) = 0x%02x", inb(Card->IOBase + ISR));
-       //}
-       HALT(); // Small delay?
-       
-       // Read data
-       for(i = 0; i < 128*NumPages; i ++)
-               ((Uint16*)Buffer)[i] = inw(Card->IOBase + 0x10);
-               
-       
-       outb(Card->IOBase + ISR, 0x40); // Clear Remote DMA Flag
-       
-       LEAVE('i', NumPages);
-       return NumPages;
-}
-
-/**
- * \fn Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
- */
-Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
-{
-       Uint8   ret = Card->NextMemPage;
-       
-       Card->NextMemPage += (Length + 0xFF) >> 8;
-       if(Card->NextMemPage >= TX_LAST) {
-               Card->NextMemPage -= TX_BUF_SIZE;
-       }
-       
-       return ret;
-}
-
-/**
- * \fn void Ne2k_IRQHandler(int IntNum)
- */
-void Ne2k_IRQHandler(int IntNum, void *Ptr)
-{
-       Uint8   byte;
-       tCard   *card = Ptr;
-
-       if(card->IRQ != IntNum) return;
-       
-       byte = inb( card->IOBase + ISR );
-       
-       LOG("byte = 0x%02x", byte);
-                       
-                       
-       // Reset All (save for RDMA), that's polled
-       outb( card->IOBase + ISR, 0xFF&(~0x40) );
-                       
-       // 0: Packet recieved (no error)
-       if( byte & 1 )
-       {
-               //if( card->NumWaitingPackets > MAX_PACKET_QUEUE )
-               //      card->NumWaitingPackets = MAX_PACKET_QUEUE;
-               if( Semaphore_Signal( &card->Semaphore, 1 ) != 1 ) {
-                       // Oops?
-               }
-       }
-       // 1: Packet sent (no error)
-       // 2: Recieved with error
-       // 3: Transmission Halted (Excessive Collisions)
-       // 4: Recieve Buffer Exhausted
-       // 5: 
-       // 6: Remote DMA Complete
-       // 7: Reset
-}
diff --git a/Modules/Network/PCnet-FASTIII/Makefile b/Modules/Network/PCnet-FASTIII/Makefile
deleted file mode 100644 (file)
index 1c7f3e9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = rtl8139.o
-NAME = RTL8139
-
--include ../Makefile.tpl
diff --git a/Modules/Network/PCnet-FASTIII/pcnet-fast3.c b/Modules/Network/PCnet-FASTIII/pcnet-fast3.c
deleted file mode 100644 (file)
index bb4f83a..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Acess2 PCnet-FAST III Driver
- * - By John Hodge (thePowersGang)
- */
-#define        DEBUG   0
-#define VERSION        ((0<<8)|10)
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <drv_pci.h>
-#include <api_drv_network.h>
-#include <semaphore.h>
-
-// === CONSTANTS ===
-#define VENDOR_ID      0x1022
-#define DEVICE_ID      0x2000
-
-enum eRegs
-{
-       REG_APROM0      = 0x00,
-       REG_APROM4      = 0x04,
-       REG_APROM8      = 0x08,
-       REG_APROMC      = 0x0C,
-       REG_RDP         = 0x10, // 16 bit
-       REG_RAP         = 0x14, // 8-bit
-       REG_RESET       = 0x18, // 16-bit
-       REG_BDP         = 0x1C, // 16-bit
-};
-
-enum eCSR_Regs
-{
-       CSR_STATUS,     // CSR0 - Am79C973/Am79C975 Controller Status
-       CSR_IBA0,       // CSR1 - Initialization Block Address[15:0]
-       CSR_IBA1,       // CSR2 - Initialization Block Address[31:16]
-       CSR_INTMASK,    // CSR3 - Interrupt Masks and Deferral Control
-       
-       CSR_MAC0 = 12,  // CSR12 - Physical Address[15:0]
-       CSR_MAC1 = 13,  // CSR13 - Physical Address[31:16]
-       CSR_MAC2 = 14,  // CSR14 - Physical Address[47:32]
-       CSR_MODE = 15,  // CSR15 - Mode
-       
-       CSR_RXBASE0 = 24,       // CSR24 - Base Address of Receive Ring Lower
-       CSR_RXBASE1 = 25,       // CSR25 - Base Address of Receive Ring Upper
-       CSR_TXBASE0 = 30,       // CSR26 - Base Address of Transmit Ring Lower
-       CSR_TXBASE1 = 31,       // CSR27 - Base Address of Transmit Ring Upper
-       
-       CSR_RXLENGTH = 76,      // CSR76 - Receive Ring Length
-       CSR_TXLENGTH = 78,      // CSR78 - Transmit Ring Length
-};
-
-enum eBCR_Regs
-{
-       BCR_PHYCS = 32, // BCR32 - Internal PHY Control and Status
-       BCR_PHYADDR,    // BCR33 - Internal PHY Address
-       BCR_PHYMGMT,    // BCR34 - Internal PHY Management Data
-};
-
-// === TYPES ===
-typedef struct sCard
-{
-       Uint16  IOBase;
-       Uint8   IRQ;
-       
-        int    NumWaitingPackets;
-       
-       char    Name[2];
-       tVFS_Node       Node;
-       Uint8   MacAddr[6];
-}      tCard;
-
-// === PROTOTYPES ===
- int   PCnet3_Install(char **Options);
-char   *PCnet3_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *PCnet3_FindDir(tVFS_Node *Node, const char *Filename);
- int   PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
-Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
- int   PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Arg);
-void   PCnet3_IRQHandler(int Num);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, PCnet3, PCnet3_Install, NULL, NULL);
-tDevFS_Driver  gPCnet3_DriverInfo = {
-       NULL, "PCnet3",
-       {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = PCnet3_ReadDir,
-       .FindDir = PCnet3_FindDir,
-       .IOCtl = PCnet3_RootIOCtl
-       }
-};
- int   giPCnet3_CardCount;
-tCard  *gaPCnet3_Cards;
-
-// === CODE ===
-/**
- * \brief Installs the PCnet3 Driver
- */
-int PCnet3_Install(char **Options)
-{
-        int    id = -1;
-        int    i = 0;
-       Uint16  base;
-       tCard   *card;
-       
-       giPCnet3_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
-       Log_Debug("PCnet3", "%i cards", giPCnet3_CardCount);
-       
-       if( giPCnet3_CardCount == 0 )   return MODULE_ERR_NOTNEEDED;
-       
-       gaPCnet3_Cards = calloc( giPCnet3_CardCount, sizeof(tCard) );
-       
-       while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1 )
-       {
-               card = &gaPCnet3_Cards[i];
-               base = PCI_GetBAR( id, 0 );
-               if( !(base & 1) ) {
-                       Log_Warning("PCnet3", "Driver does not support MMIO, skipping card");
-                       card->IOBase = 0;
-                       card->IRQ = 0;
-                       continue ;
-               }
-               base &= ~1;
-               card->IOBase = base;
-               card->IRQ = PCI_GetIRQ( id );
-               
-               // Install IRQ Handler
-               IRQ_AddHandler(card->IRQ, PCnet3_IRQHandler);
-               
-               
-               
-               Log_Log("PCnet3", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
-                       i, card->IOBase, card->IRQ,
-                       card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
-                       card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
-                       );
-               
-               i ++;
-       }
-       
-       gPCnet3_DriverInfo.RootNode.Size = giPCnet3_CardCount;
-       DevFS_AddDevice( &gPCnet3_DriverInfo );
-       
-       return MODULE_ERR_OK;
-}
-
-// --- Root Functions ---
-char *PCnet3_ReadDir(tVFS_Node *Node, int Pos)
-{
-       if( Pos < 0 || Pos >= giPCnet3_CardCount )      return NULL;
-       
-       return strdup( gaPCnet3_Cards[Pos].Name );
-}
-
-tVFS_Node *PCnet3_FindDir(tVFS_Node *Node, const char *Filename)
-{
-       //TODO: It might be an idea to supprt >10 cards
-       if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
-       if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
-       return &gaPCnet3_Cards[ Filename[0]-'0' ].Node;
-}
-
-const char *csaPCnet3_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
-int PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_RootIOCtls);
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-// --- File Functions ---
-Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tCard   *card = Node->ImplPtr;
-       Uint16  read_ofs, pkt_length;
-        int    new_read_ofs;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
-retry:
-       if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
-       {
-               LEAVE_RET('i', 0);
-       }
-       
-       Mutex_Acquire( &card->ReadMutex );
-       
-       read_ofs = inw( card->IOBase + CAPR );
-       LOG("raw read_ofs = %i", read_ofs);
-       read_ofs = (read_ofs + 0x10) & 0xFFFF;
-       LOG("read_ofs = %i", read_ofs);
-       
-       pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
-       
-       // Calculate new read offset
-       new_read_ofs = read_ofs + pkt_length + 4;
-       new_read_ofs = (new_read_ofs + 3) & ~3; // Align
-       if(new_read_ofs > card->ReceiveBufferLength) {
-               LOG("wrapping read_ofs");
-               new_read_ofs -= card->ReceiveBufferLength;
-       }
-       new_read_ofs -= 0x10;   // I dunno
-       LOG("new_read_ofs = %i", new_read_ofs);
-       
-       // Check for errors
-       if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
-               // Update CAPR
-               outw(card->IOBase + CAPR, new_read_ofs);
-               Mutex_Release( &card->ReadMutex );
-               goto retry;     // I feel evil
-       }
-       
-       // Get packet
-       if( Length > pkt_length )       Length = pkt_length;
-       memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
-       
-       // Update CAPR
-       outw(card->IOBase + CAPR, new_read_ofs);
-       
-       Mutex_Release( &card->ReadMutex );
-       
-       LEAVE('i', Length);
-       
-       return Length;
-}
-
-Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-        int    td;
-       Uint32  status;
-       tCard   *card = Node->ImplPtr;
-       
-       if( Length > 1500 )     return 0;       // MTU exceeded
-       
-       ENTER("pNode XLength pBuffer", Node, Length, Buffer);
-       
-       // TODO: Implement a semaphore for avaliable transmit buffers
-
-       // Find an avaliable descriptor
-       Mutex_Acquire(&card->CurTXProtector);
-       td = card->CurTXDescriptor;
-       card->CurTXDescriptor ++;
-       card->CurTXDescriptor %= 4;
-       Mutex_Release(&card->CurTXProtector);
-       // - Lock it
-       Mutex_Acquire( &card->TransmitInUse[td] );
-       
-       LOG("td = %i", td);
-       
-       // Transmit using descriptor `td`
-       LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]);
-       outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
-       LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]);
-       // Copy to buffer
-       memcpy(card->TransmitBuffers[td], Buffer, Length);
-       // Start
-       status = 0;
-       status |= Length & 0x1FFF;      // 0-12: Length
-       status |= 0 << 13;      // 13: OWN bit
-       status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
-       LOG("status = 0x%08x", status);
-       outd(card->IOBase + TSD0 + td*4, status);
-       
-       LEAVE('i', (int)Length);
-       
-       return Length;
-}
-
-const char *csaPCnet3_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
-int PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tCard   *card = Node->ImplPtr;
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_NodeIOCtls);
-       case NET_IOCTL_GETMAC:
-               if( !CheckMem(Data, 6) ) {
-                       LEAVE('i', -1);
-                       return -1;
-               }
-               memcpy( Data, card->MacAddr, 6 );
-               LEAVE('i', 1);
-               return 1;
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-void PCnet3_IRQHandler(int Num)
-{
-        int    i, j;
-       tCard   *card;
-       Uint16  status;
-
-       LOG("Num = %i", Num);
-       
-       for( i = 0; i < giPCnet3_CardCount; i ++ )
-       {
-               card = &gaPCnet3_Cards[i];
-               if( Num != card->IRQ )  break;
-               
-               status = inw(card->IOBase + ISR);
-               LOG("status = 0x%02x", status);
-               
-               // Transmit OK, a transmit descriptor is now free
-               if( status & FLAG_ISR_TOK )
-               {
-                       for( j = 0; j < 4; j ++ )
-                       {
-                               if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
-                                       Mutex_Release( &card->TransmitInUse[j] );
-                                       // TODO: Update semaphore once implemented
-                               }
-                       }
-                       outw(card->IOBase + ISR, FLAG_ISR_TOK);
-               }
-               
-               // Recieve OK, inform read
-               if( status & FLAG_ISR_ROK )
-               {
-                        int    read_ofs, end_ofs;
-                        int    packet_count = 0;
-                        int    len;
-                       
-                       // Scan recieve buffer for packets
-                       end_ofs = inw(card->IOBase + CBA);
-                       read_ofs = card->SeenOfs;
-                       LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
-                       if( read_ofs > end_ofs )
-                       {
-                               while( read_ofs < card->ReceiveBufferLength )
-                               {
-                                       packet_count ++;
-                                       len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
-                                       LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
-                                               packet_count, read_ofs,
-                                               *(Uint16*)&card->ReceiveBuffer[read_ofs],
-                                               len
-                                               );
-                                       if(len > 2000) {
-                                               Log_Warning("PCnet3", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len);
-                                       }
-                                       read_ofs += len + 4;
-                                       read_ofs = (read_ofs + 3) & ~3; // Align
-                               }
-                               read_ofs -= card->ReceiveBufferLength;
-                               LOG("wrapped read_ofs");
-                       }
-                       while( read_ofs < end_ofs )
-                       {
-                               packet_count ++;
-                               LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
-                                       packet_count, read_ofs,
-                                       *(Uint16*)&card->ReceiveBuffer[read_ofs],
-                                       *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
-                                       );
-                               read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
-                               read_ofs = (read_ofs + 3) & ~3; // Align
-                       }
-                       if( read_ofs != end_ofs ) {
-                               Log_Warning("PCnet3", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs);
-                               read_ofs = end_ofs;
-                       }
-                       card->SeenOfs = read_ofs;
-                       
-                       LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
-                       
-                       if( packet_count )
-                       {
-                               if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) {
-                                       // Oops?
-                               }
-                               VFS_MarkAvaliable( &card->Node, 1 );
-                       }
-                       
-                       outw(card->IOBase + ISR, FLAG_ISR_ROK);
-               }
-       }
-}
diff --git a/Modules/Network/RTL8139/Makefile b/Modules/Network/RTL8139/Makefile
deleted file mode 100644 (file)
index 1c7f3e9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = rtl8139.o
-NAME = RTL8139
-
--include ../Makefile.tpl
diff --git a/Modules/Network/RTL8139/rtl8139.c b/Modules/Network/RTL8139/rtl8139.c
deleted file mode 100644 (file)
index 1e9ac89..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Acess2 RTL8139 Driver
- * - By John Hodge (thePowersGang)
- */
-#define        DEBUG   0
-#define VERSION        ((0<<8)|20)
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <drv_pci.h>
-#include <api_drv_network.h>
-#include <semaphore.h>
-
-// === CONSTANTS ===
-#define VENDOR_ID      0x10EC
-#define DEVICE_ID      0x8139
-
-enum eRTL8139_Regs
-{
-       // MAC Address
-       MAC0, MAC1, MAC2,
-       MAC3, MAC4, MAC5,
-       
-       // Multicast Registers
-       MAR0 = 0x08, MAR1, MAR2, MAR3,
-       MAR4, MAR5, MAR6, MAR7,
-       
-       // Transmit status of descriptors 0 - 3
-       TSD0 = 0x10,    TSD1 = 0x14,
-       TSD2 = 0x18,    TSD3 = 0x1C,
-       // Transmit start addresses
-       TSAD0 = 0x20,   TSAD1 = 0x24,
-       TSAD2 = 0x28,   TSAD3 = 0x2C,
-       
-       RBSTART = 0x30, //!< Recieve Buffer Start (DWord)
-       // Early Recieve Byte Count
-       ERBCR = 0x34,   // 16-bits
-       // Early RX Status Register
-       ERSR = 0x36,
-       
-       // ??, ??, ??, RST, RE, TE, ??, ??
-       CMD     = 0x37,
-       
-       CAPR    = 0x38, // Current address of packet read
-       CBA     = 0x3A, // Current Buffer Address - Total byte count in RX buffer
-       
-       IMR     = 0x3C, // Interrupt mask register
-       ISR     = 0x3E, // Interrupt status register
-       
-       TCR     = 0x40, // Transmit Configuration Register
-       RCR     = 0x44, // Recieve Configuration Register
-       TCTR    = 0x48, // 32-bit timer (count)
-       MPC     = 0x4C, // Missed packet count (due to RX overflow)
-       
-       CR_9346 = 0x50,
-       CONFIG0 = 0x51,
-       CONFIG1 = 0x52,
-       // 0x53 resvd
-       TIMERINT = 0x54,        // Fires a timeout when TCTR equals this value
-       
-};
-
-#define FLAG_ISR_TOK   0x04
-#define FLAG_ISR_ROK   0x01
-
-// === TYPES ===
-typedef struct sCard
-{
-       Uint16  IOBase;
-       Uint8   IRQ;
-       
-        int    NumWaitingPackets;
-       
-       char    *ReceiveBuffer;
-       tPAddr  PhysReceiveBuffer;
-        int    ReceiveBufferLength;
-        int    SeenOfs;        //!< End of the most recently seen packet (by IRQ)
-       tMutex  ReadMutex;
-       tSemaphore      ReadSemaphore;
-       
-       char    *TransmitBuffers[4];
-       tPAddr  PhysTransmitBuffers[4];
-       tMutex  TransmitInUse[4];
-       tMutex  CurTXProtector; //!< Protects \a .CurTXDescriptor
-        int    CurTXDescriptor;
-       
-       char    Name[2];
-       tVFS_Node       Node;
-       Uint8   MacAddr[6];
-}      tCard;
-
-// === PROTOTYPES ===
- int   RTL8139_Install(char **Options);
-char   *RTL8139_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
- int   RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
-Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
- int   RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
-void   RTL8139_IRQHandler(int Num, void *Ptr);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
-tVFS_NodeType  gRTL8139_RootNodeType = {
-       .ReadDir = RTL8139_ReadDir,
-       .FindDir = RTL8139_FindDir,
-       .IOCtl = RTL8139_IOCtl
-       };
-tVFS_NodeType  gRTL8139_DevNodeType = {
-       .Write = RTL8139_Write,
-       .Read = RTL8139_Read,
-       .IOCtl = RTL8139_IOCtl  
-       };
-tDevFS_Driver  gRTL8139_DriverInfo = {
-       NULL, "RTL8139",
-       {
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Type = &gRTL8139_RootNodeType
-       }
-};
- int   giRTL8139_CardCount;
-tCard  *gaRTL8139_Cards;
-
-// === CODE ===
-/**
- * \brief Installs the RTL8139 Driver
- */
-int RTL8139_Install(char **Options)
-{
-        int    id = -1;
-        int    i = 0;
-       Uint16  base;
-       tCard   *card;
-       
-       giRTL8139_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
-       
-       if( giRTL8139_CardCount == 0 )  return MODULE_ERR_NOTNEEDED;
-
-       Log_Debug("RTL8139", "%i cards", giRTL8139_CardCount);  
-       gaRTL8139_Cards = calloc( giRTL8139_CardCount, sizeof(tCard) );
-       
-       for( i = 0 ; (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1; i ++ )
-       {
-               card = &gaRTL8139_Cards[i];
-               base = PCI_GetBAR( id, 0 );
-               if( !(base & 1) ) {
-                       Log_Warning("RTL8139", "Driver does not support MMIO, skipping card (addr %x)",
-                               base);
-                       card->IOBase = 0;
-                       card->IRQ = 0;
-                       continue ;
-               }
-               base &= ~1;
-               card->IOBase = base;
-               card->IRQ = PCI_GetIRQ( id );
-               
-               // Install IRQ Handler
-               IRQ_AddHandler(card->IRQ, RTL8139_IRQHandler, card);
-               
-               // Power on
-               outb( base + CONFIG1, 0x00 );
-
-               // Reset (0x10 to CMD)
-               outb( base + CMD, 0x10 );       
-               while( inb(base + CMD) & 0x10 ) ;
-               
-               // Set up recieve buffer
-               // - Allocate 3 pages below 4GiB for the recieve buffer (Allows 8k+16+1500)
-               card->ReceiveBuffer = (void*)MM_AllocDMA( 3, 32, &card->PhysReceiveBuffer );
-               card->ReceiveBufferLength = 8*1024;
-               outd(base + RBSTART, (Uint32)card->PhysReceiveBuffer);
-               outd(base + CBA, 0);
-               outd(base + CAPR, 0);
-               // Set IMR to Transmit OK and Receive OK
-               outw(base + IMR, 0x5);
-               
-               // Set up transmit buffers
-               // - 2 non-contiguous pages (each page can fit 2 1500 byte packets)
-               card->TransmitBuffers[0] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[0] );
-               card->TransmitBuffers[1] = card->TransmitBuffers[0] + 0x800;
-               card->PhysTransmitBuffers[1] = card->PhysTransmitBuffers[0] + 0x800;
-               
-               card->TransmitBuffers[2] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[2] );
-               card->TransmitBuffers[3] = card->TransmitBuffers[2] + 0x800;
-               card->PhysTransmitBuffers[3] = card->PhysTransmitBuffers[2] + 0x800;
-               
-               outd(base + TSAD0, card->PhysTransmitBuffers[0]);
-               outd(base + TSAD1, card->PhysTransmitBuffers[1]);
-               outd(base + TSAD2, card->PhysTransmitBuffers[2]);
-               outd(base + TSAD3, card->PhysTransmitBuffers[3]);
-               
-               // Set recieve buffer size and recieve mask
-               // - Bit 7 being set tells the card to overflow the recieve buffer if needed
-               //   (i.e. when the packet starts at the end of the bufffer, it overflows up
-               //    to 1500 bytes)
-               outd(base + RCR, 0x8F);
-       
-               // Recive Enable and Transmit Enable    
-               outb(base + CMD, 0x0C);
-               
-               // Get the card's MAC address
-               card->MacAddr[0] = inb(base+MAC0);
-               card->MacAddr[1] = inb(base+MAC1);
-               card->MacAddr[2] = inb(base+MAC2);
-               card->MacAddr[3] = inb(base+MAC3);
-               card->MacAddr[4] = inb(base+MAC4);
-               card->MacAddr[5] = inb(base+MAC5);
-               
-               // Set VFS Node
-               card->Name[0] = '0'+i;
-               card->Name[1] = '\0';
-               card->Node.ImplPtr = card;
-               card->Node.NumACLs = 0;
-               card->Node.CTime = now();
-               card->Node.Type = &gRTL8139_DevNodeType;
-               
-               Log_Log("RTL8139", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
-                       i, card->IOBase, card->IRQ,
-                       card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
-                       card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
-                       );
-       }
-       
-       gRTL8139_DriverInfo.RootNode.Size = giRTL8139_CardCount;
-       DevFS_AddDevice( &gRTL8139_DriverInfo );
-       
-       return MODULE_ERR_OK;
-}
-
-// --- Root Functions ---
-char *RTL8139_ReadDir(tVFS_Node *Node, int Pos)
-{
-       if( Pos < 0 || Pos >= giRTL8139_CardCount )     return NULL;
-       
-       return strdup( gaRTL8139_Cards[Pos].Name );
-}
-
-tVFS_Node *RTL8139_FindDir(tVFS_Node *Node, const char *Filename)
-{
-       //TODO: It might be an idea to supprt >10 cards
-       if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
-       if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
-       return &gaRTL8139_Cards[ Filename[0]-'0' ].Node;
-}
-
-const char *csaRTL8139_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
-int RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_RootIOCtls);
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-// --- File Functions ---
-Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-       tCard   *card = Node->ImplPtr;
-       Uint16  read_ofs, pkt_length;
-        int    new_read_ofs;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
-retry:
-       if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
-       {
-               LEAVE_RET('i', 0);
-       }
-       
-       Mutex_Acquire( &card->ReadMutex );
-       
-       read_ofs = inw( card->IOBase + CAPR );
-       LOG("raw read_ofs = %i", read_ofs);
-       read_ofs = (read_ofs + 0x10) & 0xFFFF;
-       LOG("read_ofs = %i", read_ofs);
-       
-       pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
-       
-       // Calculate new read offset
-       new_read_ofs = read_ofs + pkt_length + 4;
-       new_read_ofs = (new_read_ofs + 3) & ~3; // Align
-       if(new_read_ofs > card->ReceiveBufferLength) {
-               LOG("wrapping read_ofs");
-               new_read_ofs -= card->ReceiveBufferLength;
-       }
-       new_read_ofs -= 0x10;   // I dunno
-       LOG("new_read_ofs = %i", new_read_ofs);
-       
-       // Check for errors
-       if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
-               // Update CAPR
-               outw(card->IOBase + CAPR, new_read_ofs);
-               Mutex_Release( &card->ReadMutex );
-               goto retry;     // I feel evil
-       }
-       
-       // Get packet
-       if( Length > pkt_length )       Length = pkt_length;
-       memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
-       
-       // Update CAPR
-       outw(card->IOBase + CAPR, new_read_ofs);
-       
-       Mutex_Release( &card->ReadMutex );
-       
-       LEAVE('i', Length);
-       
-       return Length;
-}
-
-Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-        int    td;
-       Uint32  status;
-       tCard   *card = Node->ImplPtr;
-       
-       if( Length > 1500 )     return 0;       // MTU exceeded
-       
-       ENTER("pNode XLength pBuffer", Node, Length, Buffer);
-       
-       // TODO: Implement a semaphore for avaliable transmit buffers
-
-       // Find an avaliable descriptor
-       Mutex_Acquire(&card->CurTXProtector);
-       td = card->CurTXDescriptor;
-       card->CurTXDescriptor ++;
-       card->CurTXDescriptor %= 4;
-       Mutex_Release(&card->CurTXProtector);
-       // - Lock it
-       Mutex_Acquire( &card->TransmitInUse[td] );
-       
-       LOG("td = %i", td);
-       
-       // Transmit using descriptor `td`
-       LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]);
-       outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
-       LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]);
-       // Copy to buffer
-       memcpy(card->TransmitBuffers[td], Buffer, Length);
-       // Start
-       status = 0;
-       status |= Length & 0x1FFF;      // 0-12: Length
-       status |= 0 << 13;      // 13: OWN bit
-       status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
-       LOG("status = 0x%08x", status);
-       outd(card->IOBase + TSD0 + td*4, status);
-       
-       LEAVE('i', (int)Length);
-       
-       return Length;
-}
-
-const char *csaRTL8139_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
-int RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       tCard   *card = Node->ImplPtr;
-       ENTER("pNode iID pData", Node, ID, Data);
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_NodeIOCtls);
-       case NET_IOCTL_GETMAC:
-               if( !CheckMem(Data, 6) ) {
-                       LEAVE('i', -1);
-                       return -1;
-               }
-               memcpy( Data, card->MacAddr, 6 );
-               LEAVE('i', 1);
-               return 1;
-       }
-       LEAVE('i', 0);
-       return 0;
-}
-
-void RTL8139_IRQHandler(int Num, void *Ptr)
-{
-        int    j;
-       tCard   *card = Ptr;
-       Uint16  status;
-
-       LOG("Num = %i", Num);
-       
-       if( Num != card->IRQ )  return;
-               
-       status = inw(card->IOBase + ISR);
-       LOG("status = 0x%02x", status);
-               
-       // Transmit OK, a transmit descriptor is now free
-       if( status & FLAG_ISR_TOK )
-       {
-               for( j = 0; j < 4; j ++ )
-               {
-                       if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
-                               Mutex_Release( &card->TransmitInUse[j] );
-                               // TODO: Update semaphore once implemented
-                       }
-               }
-               outw(card->IOBase + ISR, FLAG_ISR_TOK);
-       }
-       
-       // Recieve OK, inform read
-       if( status & FLAG_ISR_ROK )
-       {
-                int    read_ofs, end_ofs;
-                int    packet_count = 0;
-                int    len;
-               
-               // Scan recieve buffer for packets
-               end_ofs = inw(card->IOBase + CBA);
-               read_ofs = card->SeenOfs;
-               LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
-               if( read_ofs > end_ofs )
-               {
-                       while( read_ofs < card->ReceiveBufferLength )
-                       {
-                               packet_count ++;
-                               len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
-                               LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
-                                       packet_count, read_ofs,
-                                       *(Uint16*)&card->ReceiveBuffer[read_ofs],
-                                       len
-                                       );
-                               if(len > 2000) {
-                                       Log_Warning("RTL8139", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len);
-                               }
-                               read_ofs += len + 4;
-                               read_ofs = (read_ofs + 3) & ~3; // Align
-                       }
-                       read_ofs -= card->ReceiveBufferLength;
-                       LOG("wrapped read_ofs");
-               }
-               while( read_ofs < end_ofs )
-               {
-                       packet_count ++;
-                       LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
-                               packet_count, read_ofs,
-                               *(Uint16*)&card->ReceiveBuffer[read_ofs],
-                               *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
-                               );
-                       read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
-                       read_ofs = (read_ofs + 3) & ~3; // Align
-               }
-               if( read_ofs != end_ofs ) {
-                       Log_Warning("RTL8139", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs);
-                       read_ofs = end_ofs;
-               }
-               card->SeenOfs = read_ofs;
-               
-               LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
-               
-               if( packet_count )
-               {
-                       if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) {
-                               // Oops?
-                       }
-                       VFS_MarkAvaliable( &card->Node, 1 );
-               }
-               
-               outw(card->IOBase + ISR, FLAG_ISR_ROK);
-       }       
-}
diff --git a/Modules/Sound/SoundBlaster16/Makefile b/Modules/Sound/SoundBlaster16/Makefile
deleted file mode 100644 (file)
index 9384859..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o
-NAME = SoundBlaster16
-
--include ../Makefile.tpl
diff --git a/Modules/Sound/SoundBlaster16/main.c b/Modules/Sound/SoundBlaster16/main.c
deleted file mode 100644 (file)
index f2d056c..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*\r
- * Acess2 SoundBlaster16 Driver\r
- */\r
-#define DEBUG  0\r
-#include <acess.h>\r
-#include <errno.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include <fs_devfs.h>\r
-#include <drv_pci.h>\r
-#include <api_drv_sound.h>\r
-\r
-#define INT\r
-\r
-// === TYPES ===\r
-typedef struct sSB16\r
-{\r
-       Uint16  Base;\r
-}      tSB16;\r
-\r
-// === CONSTANTS ===\r
-enum {\r
-       SB16_PORT_RESET = 0x6,\r
-       SB16_PORT_READ  = 0xA,\r
-       SB16_PORT_WRITE = 0xC,\r
-       SB16_PORT_AVAIL = 0xE\r
-};\r
-#define SB16_BASE_PORT 0x200\r
-enum {\r
-       SB16_CMD_RAW8    = 0x10,        // 8-bit DAC value follows\r
-       SB16_CMD_DMAFREQ = 0x40,        // followed by TIME_CONSTANT = 256 - 1000000 / frequency\r
-       SB16_CMD_DMASTOP = 0xD0,\r
-       SB16_CMD_SPKRON  = 0xD1,\r
-       SB16_CMD_SPKROFF = 0xD3,\r
-       SB16_CMD_DMACONT = 0xD4,\r
-       \r
-       // DMA Types (uses channel 1)\r
-       // - Followed by 16-bit length (well, length - 1)\r
-       SB16_CMD_DMA_8BIT = 0x14,\r
-};\r
-\r
-\r
-// === PROTOTYPES ===\r
-// Driver\r
- int   SB16_Install(char **Arguments);\r
-void   SB16_Uninstall();\r
-// Filesystem\r
-Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
- int   SB16_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, 0x0032, SoundBlaster16, SB16_Install, SB16_Uninstall, "PCI", NULL);\r
-tDevFS_Driver  gBGA_DriverStruct = {\r
-       NULL, "SoundBlaster16",\r
-       {\r
-       .Write = SB16_Write,\r
-       .IOCtl = SB16_IOCtl\r
-       }\r
-};\r
-\r
-// === CODE ===\r
-int SB16_Install(char **Arguments)\r
-{\r
-        int    jumper_port_setting = 1;        // 1-6 incl\r
-       \r
-       // Reset\r
-       outb(card->Base+SB16_PORT_RESET, 1);\r
-       // - Wait 3us\r
-       outb(card->Base+SB16_PORT_RESET, 0);\r
-       \r
-       SB16_ReadDSP(card);\r
-       \r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-void SB16_Uninstall()\r
-{\r
-}\r
-\r
-/**\r
- * \fn Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
- * \brief Write to the framebuffer\r
- */\r
-Uint64 SB16_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
-{      \r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn int SB16_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
- * \brief Handle messages to the device\r
- */\r
-int SB16_IOCtl(tVFS_Node *Node, int ID, void *Data)\r
-{\r
-       return -1;\r
-}\r
-\r
-//\r
-int SB16_WriteDSP(tSB16 *Card, Uint8 Value)\r
-{\r
-       // Wait for the card to be ready\r
-       while( inb(Card->Base+SB16_PORT_WRITE) & 0x80 )\r
-               ;\r
-       \r
-       outb(Card->Base+SB16_PORT_WRITE, Value);\r
-       \r
-       return 0;\r
-}\r
-\r
-Uint8 SB16_ReadDSP(tSB16 *Card)\r
-{\r
-       // Wait for bit 7 of AVAIL\r
-       while( !(inb(card->Base+SB16_PORT_AVAIL) & 0x80) )\r
-               ;\r
-       return inb(card->Base+SB16_PORT_READ);\r
-}\r
diff --git a/Modules/Sound/SoundBlaster16/sbdsp.txt b/Modules/Sound/SoundBlaster16/sbdsp.txt
deleted file mode 100644 (file)
index 94364cd..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-
-                  ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-                  Â³ Programming the SoundBlaster DSP Â³
-                  Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-                  Written for the PC-GPE by Mark Feldman
-              e-mail address : [email protected]
-                               [email protected]
-
-             ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-             Â³      THIS FILE MAY NOT BE DISTRIBUTED     Â³
-             Â³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. Â³
-             Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Disclaimer Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-I assume no responsibility whatsoever for any effect that this file, the
-information contained therein or the use thereof has on you, your sanity,
-computer, spouse, children, pets or anything else related to you or your
-existance. No warranty is provided nor implied with this information.
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Introduction Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-The SoundBlaster is capable of both FM and digitised sounds. The FM wave
-is fully Adlib compatible, so check the ADLIB.TXT file for info
-on how to program it. This file will concentrate on recording and playback
-of digital samples through the SoundBlaster CT-DSP 1321 chip.
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ The SoundBlaster DSP I/O Ports Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-The DSP (Digital Sound Processor) chip is programmed through 4 ports which
-are determined by the SoundBlaster base address jumper setting:
-
-                    RESET    2x6h
-
-                READ DATA    2xAh
-
-WRITE COMMAND/DATA output
-WRITE BUFFER STATUS input    2xCh
-
-
-           DATA AVAILABLE    2xEh
-
-where x = 1 for base address jumper setting 210h
-      x = 2 for base address jumper setting 220h
-      .
-      .
-      x = 6 for base address jumper setting 260h
-
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Resetting the DSP Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-You have to reset the DSP before you program it. This is done with the
-following procedure :
-
-1) Write a 1 to the SoundBlaster RESET port (2x6h)
-2) Wait for 3 micro-seconds
-3) Write a 0 to the SoundBlaster RESET port (2x6h)
-4) Read the byte from the DATA AVAILABLE (2xEh) port until bit 7 = 1
-5) Poll for a ready byte (AAh) from the READ DATA port (2xAh). Before
-   reading the READ DATA port it is avdvisable.
-
-The DSP usually takes somewhere around 100 micro-seconds to reset itself.
-If it fails to do within a reasonable time (say 200 micro-seconds) then
-an error has occurred, possibly an incorrect I/O address is being used.
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Writing to the DSP Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-A value can be written to the DSP with the following procedure :
-
-1) Read the DSP's WRITE BUFFER STATUS port (2xCh) until bit 7 = 0
-2) Write the value to the WRITE COMMAND/DATA port (2xCh)
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Reading the DSP Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-A value can be read from the DSP with the following procedure :
-
-1) Read the DSP's DATA AVAILABLE port (2xEh) until bit 7 = 1
-2) Read the data from the READ DATA port (2xAh)
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Turning the speaker on and controlling DMA Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-Speaker and DMA control are handled by writing one of the following bytes
-to the DSP:
-
-                     ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-                     Â³ Value   Description     Â³
-                     ÃƒÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
-                     Â³ D0h    DMA Stop         Â³
-                     Â³ D1h    Turn speaker on  Â³
-                     Â³ D3h    Turn speaker off Â³
-                     Â³ D4h    DMA Continue     Â³
-                     Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-DMA is discussed below. The DMA commands shown here can be used to pause
-the sample during DMA playback playback.
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Writing to the DAC Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-The DAC (Digital to Analog Converter) is the part of the card which converts
-a sample number (ie 0 -> 255) to a sound level. To generate a square sound
-wave at maximum volume (for example) you could alternate writing 0's and
-255's to the DAC.
-
-Programming the DAC in direct mode involves the main program setting the
-DAC to a desired value. Only 8 bit DAC is available in direct mode. To set
-the DAC level you write the value 10h to the DSP followed by the sample
-number (0 -> 255). Note that no sound will be heard unless the speaker has
-been turned on. In direct mode the main program is responsible for the
-timing between samples, the DAC can output sound samples as fast as the
-calling program can change it. Typically the timer interrupt is reprogrammed
-and used to generate the timing required for a sample playback. Info on
-programming the PIT chip can be found in the PIT.TXT file.
-
-The DAC can also be programmed to accept values sent to it via the DMA
-chip. Draeden has written an excellent article on programming the DMA chip
-(see DMA_VLA.TXT) so only a brief example of it's use will be given here.
-The important thing to remember is that the DMA chip cannot transfer data
-which crosses between page breaks. If the data does cross page breaks then
-it will have to be split up into several transfers, with one page per
-transfer.
-
-Setting the playback frequency for the DMA transfer is done by writing
-the value 40h to the DSP followed by TIME_CONSTANT, where
-TIME_CONSTANT = 256 - 1000000 / frequency
-
-There are several types of DMA transfers available. The following table
-lists them:
-
-      ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-      Â³DMA_TYPE_VALUE   Description             Frequency Range    Â³
-      ÃƒÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
-      Â³    14h          8 bit                   4KHz -> 23 KHz     Â³
-      Â³    74h          4 bit ADPCM             4KHz -> 12 KHz     Â³
-      Â³    75h          4 bit ADPCM with        4KHz -> 12 KHz     Â³
-      Â³                 reference byte                             Â³
-      Â³    76h          2.6 bit ADPCM           4KHz -> 13 KHz     Â³
-      Â³    77h          2.6 bit ADPCM with      4KHz -> 13 KHz     Â³
-      Â³                 reference byte                             Â³
-      Â³    16h          2 bit ADPCM             4KHz -> 11 KHz     Â³
-      Â³    17h          2 bit ADPCM with        4KHz -> 11 KHz     Â³
-      Â³                 reference byte                             Â³
-      Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-ADPCM stands for Adaptive Pulse Code Modulation, a sound compression
-technique where the difference between successive samples is stored rather
-than their actual values. In the modes with reference bytes, the first
-byte is the actual starting value. Having modes with and without reference
-bytes means you can output successive blocks without the need for a
-reference byte at the start of each one.
-
-The procedure for doing a DMA transfer is as follows:
-
-1) Load the sound data into memory
-2) Set up the DMA chip for the tranfer
-3) Set the DSP TIME_CONSTANT to the sampling rate
-4) Write DMA_TYPE_VALUE value to the DSP
-5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
-   DATA_LENGTH = number of bytes to send - 1
-
-Note that the DMA chip must be programmed before the BSP.
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Reading from the ADC Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-Reading samples from the ADC (Analog to Digital Converter) can also be
-done in either direct or DMA mode.
-
-To read a sample in direct mode write the value 20h to the DSP and then
-read the value from the DSP. Simple as that!
-
-To set up the DSP for a DMA transfer, follow this procedure :
-
-1) Get a memory buffer ready to hold the sample
-2) Set up the DMA chip for the transfer
-3) Set the DSP TIME_CONSTANT to the sampling rate
-4) Write the value 24h to the DSP
-5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where
-   DATA_LENGTH = number of bytes to read - 1
-
-Note that the DMA chip must be programmed before the BSP.
-
-DMA reads only support 8 bit mode, compressed modes are done by software and
-stored in the voc file. I haven't tried to figure out how the compression is
-done. If someone does figure it out I'd like to know about it!
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Programming the DMA Chip Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-As mentioned before, Draeden has written a very good article on the dma
-chip, but here is a brief run down on what you would need to do to program
-the DMA channel 1 for the DSP in real mode:
-
-1) Calculate the 20 bit address of the memory buffer you are using
-   where Base Address = Segment * 16 + Offset
-   eg 1234h:5678h = 179B8h
-2) Send the value 05h to port 0Ah (mask off channel 1)
-3) Send the value 00h to port 0Ch (clear the internal DMA flip/flop)
-4) Send the value 49h to port 0Bh (for playback) or
-                  45h to port 0Bh (for recording)
-5) Write the LSB (bits 0 -> 7) of the 20 bit memory address to port 02h
-6) Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort 02h
-7) Write the Page (bits 16 -> 19) of the 20 bit memory address to port 83h
-8) Send the LSB of DATA_LENGTH to port 03h
-9) Send the MSB of DATA_LENGTH to port 03h
-10) Send the value 01h to port 0Ah (enable channel 1)
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ End of DMA Interrupt Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-When a DMA transfer is complete an interrupt is generated. The actual
-interrupt number depends on the SoundBlaster card's IRQ jumper setting:
-
-                         ÃšÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-                         Â³ IRQ Jumper             Â³
-                         Â³  Setting     Interrupt Â³
-                         ÃƒÃ„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
-                         Â³    2            0Ah    Â³
-                         Â³    3            0Bh    Â³
-                         Â³    5            0Dh    Â³
-                         Â³    7            0Fh    Â³
-                         Ã€Ã„ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-To service one of these interrupts you must perform these 3 tasks:
-
-1) Acknowledge the DSP interrupt by reading the DATA AVAILABLE port (2xEh)
-   once.
-2) If there are more blocks to transfer then set them up
-3) Output value 20h (EOI) to the interrupt controller port 20h
-
-Of course, as with any hardware interrupt you must also leave the
-state of the system (registers etc..) the way it was when the interrupt
-was called.
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ A Simple DSP Pascal Unit Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-{
-
-  DSP.PAS - A demo SoundBlaster DSP unit for real mode
-
-  By Mark Feldman
-}
-
-Unit DSP;
-
-Interface
-
-{ ResetDSP returns true if reset was successful
-  base should be 1 for base address 210h, 2 for 220h etc... }
-function ResetDSP(base : word) : boolean;
-
-{ Write DAC sets the speaker output level }
-procedure WriteDAC(level : byte);
-
-{ ReadDAC reads the microphone input level }
-function ReadDAC : byte;
-
-{ SpeakerOn connects the DAC to the speaker }
-function SpeakerOn: byte;
-
-{ SpeakerOff disconnects the DAC from the speaker,
-  but does not affect the DAC operation }
-function SpeakerOff: byte;
-
-{ Functions to pause DMA playback }
-procedure DMAStop;
-procedure DMAContinue;
-
-{ Playback plays a sample of a given size back at a given frequency using
-  DMA channel 1. The sample must not cross a page boundry }
-procedure Playback(sound : Pointer; size : word; frequency : word);
-
-Implementation
-
-Uses Crt;
-
-var      DSP_RESET : word;
-     DSP_READ_DATA : word;
-    DSP_WRITE_DATA : word;
-  DSP_WRITE_STATUS : word;
-    DSP_DATA_AVAIL : word;
-
-function ResetDSP(base : word) : boolean;
-begin
-
-  base := base * $10;
-
-  { Calculate the port addresses }
-  DSP_RESET := base + $206;
-  DSP_READ_DATA := base + $20A;
-  DSP_WRITE_DATA := base + $20C;
-  DSP_WRITE_STATUS := base + $20C;
-  DSP_DATA_AVAIL := base + $20E;
-
-  { Reset the DSP, and give some nice long delays just to be safe }
-  Port[DSP_RESET] := 1;
-  Delay(10);
-  Port[DSP_RESET] := 0;
-  Delay(10);
-  if (Port[DSP_DATA_AVAIL] And $80 = $80) And
-     (Port[DSP_READ_DATA] = $AA) then
-    ResetDSP := true
-  else
-    ResetDSP := false;
-end;
-
-procedure WriteDSP(value : byte);
-begin
-  while Port[DSP_WRITE_STATUS] And $80 <> 0 do;
-  Port[DSP_WRITE_DATA] := value;
-end;
-
-function ReadDSP : byte;
-begin
-  while Port[DSP_DATA_AVAIL] and $80 = 0 do;
-  ReadDSP := Port[DSP_READ_DATA];
-end;
-
-procedure WriteDAC(level : byte);
-begin
-  WriteDSP($10);
-  WriteDSP(level);
-end;
-
-function ReadDAC : byte;
-begin
-  WriteDSP($20);
-  ReadDAC := ReadDSP;
-end;
-
-function SpeakerOn: byte;
-begin
-  WriteDSP($D1);
-end;
-
-function SpeakerOff: byte;
-begin
-  WriteDSP($D3);
-end;
-
-procedure DMAContinue;
-begin
-  WriteDSP($D4);
-end;
-
-procedure DMAStop;
-begin
-  WriteDSP($D0);
-end;
-
-procedure Playback(sound : Pointer; size : word; frequency : word);
-var time_constant : word;
-     page, offset : word;
-begin
-
-  SpeakerOn;
-
-  size := size - 1;
-
-  { Set up the DMA chip }
-  offset := Seg(sound^) Shl 4 + Ofs(sound^);
-  page := (Seg(sound^) + Ofs(sound^) shr 4) shr 12;
-  Port[$0A] := 5;
-  Port[$0C] := 0;
-  Port[$0B] := $49;
-  Port[$02] := Lo(offset);
-  Port[$02] := Hi(offset);
-  Port[$83] := page;
-  Port[$03] := Lo(size);
-  Port[$03] := Hi(size);
-  Port[$0A] := 1;
-
-  { Set the playback frequency }
-  time_constant := 256 - 1000000 div frequency;
-  WriteDSP($40);
-  WriteDSP(time_constant);
-
-  { Set the playback type (8-bit) }
-  WriteDSP($14);
-  WriteDSP(Lo(size));
-  WriteDSP(Hi(size));
-end;
-
-end.
-
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ References Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-Title : The SoundBlaster Developpers Kit
-Publishers : Creative Labs Inc
-             Creative Technology PTE LTD
-
-Title : Sound Blaster - The Official Book
-Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge
-Publishers : Osborne/McGraw Hill
-ISBN : 0-07-881907-5
-
-Some of the information in this file was either obtained from or verified
-by the source code in a public domain library called SOUNDX by Peter
-Sprenger. I haven't tried using his library yet (I don't have a C compiler
-at the moment) but it looks very well done and contains numerous sound card
-detection routines. Says Peter : "It would be nice, that when you make
-something commercial with my routines, that you send me a copy of your
-project or send me some bucks, just enough for pizza and coke to support my
-night programming sessions. If you send me nothing, ok. But USE the stuff,
-if you can need it!". Heh...a REAL programmer!
-
-ftpsite: ftp.uwp.edu
-directory: /pub/msdos/demos/programming/game-dev/source
-filename: soundx.zip
-
-ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
-³ Sound Familiar? Â³
-ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
-
-What the...why is there a faint glimmer of sunlight outside? HOLY $#!^!! It's
-5:30am! I'm goin' to bed!
-
diff --git a/Modules/Storage/ATA/Makefile b/Modules/Storage/ATA/Makefile
deleted file mode 100644 (file)
index 2292342..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = main.o io.o mbr.o
-NAME = ATA
-
--include ../Makefile.tpl
diff --git a/Modules/Storage/ATA/common.h b/Modules/Storage/ATA/common.h
deleted file mode 100644 (file)
index 891d2bb..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Acess2 IDE Harddisk Driver
- * - main.c
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-#include <acess.h>
-#include <vfs.h>
-
-// === CONSTANTS ===
-#define        MAX_ATA_DISKS   4
-#define        SECTOR_SIZE     512
-#define        ATA_TIMEOUT     2000    // 2s timeout
-// Needed out of io.c because it's the max for Read/WriteDMA
-#define        MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
-
-// === STRUCTURES ===
-typedef struct
-{
-       Uint8   BootCode[0x1BE];
-       struct {
-               Uint8   Boot;
-               Uint8   Unused1;        // Also CHS Start
-               Uint16  StartHi;        // Also CHS Start
-               Uint8   SystemID;
-               Uint8   Unused2;        // Also CHS Length
-               Uint16  LengthHi;       // Also CHS Length
-               Uint32  LBAStart;
-               Uint32  LBALength;
-       } __attribute__ ((packed)) Parts[4];
-       Uint16  BootFlag;       // = 0xAA 55
-} __attribute__ ((packed))     tMBR;
-
-typedef struct
-{
-       Uint64  Start;
-       Uint64  Length;
-       char    Name[4];
-       tVFS_Node       Node;
-}      tATA_Partition;
-
-typedef struct
-{
-       Uint64  Sectors;
-       char    Name[2];
-       tVFS_Node       Node;
-        int    NumPartitions;
-       tATA_Partition  *Partitions;
-}      tATA_Disk;
-
-// === GLOBALS ===
-extern tATA_Disk       gATA_Disks[];
-
-// === FUNCTIONS ===
-// --- Common ---
-extern void    ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
-
-// --- MBR Parsing ---
-extern void    ATA_ParseMBR(int Disk, tMBR *MBR);
-
-// --- IO Functions ---
-extern int     ATA_SetupIO(void);
-extern Uint64  ATA_GetDiskSize(int Disk);
-extern int     ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
-extern int     ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer);
-
-#endif
diff --git a/Modules/Storage/ATA/io.c b/Modules/Storage/ATA/io.c
deleted file mode 100644 (file)
index b8a15d0..0000000
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Acess2 IDE Harddisk Driver
- * - io.c
- *
- * Disk Input/Output control
- */
-#define DEBUG  0
-#include <acess.h>
-#include <modules.h>   // Needed for error codes
-#include <drv_pci.h>
-#include "common.h"
-
-// === MACROS ===
-#define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
-
-// === Constants ===
-#define        IDE_PRI_BASE    0x1F0
-#define IDE_PRI_CTRL   0x3F6
-#define        IDE_SEC_BASE    0x170
-#define IDE_SEC_CTRL   0x376
-
-#define        IDE_PRDT_LAST   0x8000
-/**
- \enum HddControls
- \brief Commands to be sent to HDD_CMD
-*/
-enum HddControls {
-       HDD_PIO_R28 = 0x20,
-       HDD_PIO_R48 = 0x24,
-       HDD_DMA_R48 = 0x25,
-       HDD_PIO_W28 = 0x30,
-       HDD_PIO_W48 = 0x34,
-       HDD_DMA_W48 = 0x35,
-       HDD_DMA_R28 = 0xC8,
-       HDD_DMA_W28 = 0xCA,
-       HDD_IDENTIFY = 0xEC
-};
-
-// === TYPES ===
-/**
- * \brief PRDT Entry
- */
-typedef struct
-{
-       Uint32  PBufAddr;       // Physical Buffer Address
-       Uint16  Bytes;  // Size of transfer entry
-       Uint16  Flags;  // Flags
-} __attribute__ ((packed))     tPRDT_Ent;
-
-/**
- * \brief Structure returned by the ATA IDENTIFY command
- */
-typedef struct
-{
-       Uint16  Flags;          // 1
-       Uint16  Usused1[9];     // 10
-       char    SerialNum[20];  // 20
-       Uint16  Usused2[3];     // 23
-       char    FirmwareVer[8]; // 27
-       char    ModelNumber[40];        // 47
-       Uint16  SectPerInt;     // 48 - Low byte only
-       Uint16  Unused3;        // 49
-       Uint16  Capabilities[2];        // 51
-       Uint16  Unused4[2];     // 53
-       Uint16  ValidExtData;   // 54
-       Uint16  Unused5[5];      // 59
-       Uint16  SizeOfRWMultiple;       // 60
-       Uint32  Sectors28;      // LBA 28 Sector Count
-       Uint16  Unused6[100-62];
-       Uint64  Sectors48;      // LBA 48 Sector Count
-       Uint16  Unused7[256-104];
-} __attribute__ ((packed))     tIdentify;
-
-// === PROTOTYPES ===
- int   ATA_SetupIO(void);
-Uint64 ATA_GetDiskSize(int Disk);
-Uint16 ATA_GetBasePort(int Disk);
-// Read/Write DMA
- int   ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
- int   ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer);
-// IRQs
-void   ATA_IRQHandlerPri(int UNUSED(IRQ), void *UNUSED(Ptr));
-void   ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr));
-// Controller IO
-Uint8  ATA_int_BusMasterReadByte(int Ofs);
-Uint32 ATA_int_BusMasterReadDWord(int Ofs);
-void   ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
-void   ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
-
-// === GLOBALS ===
-// - BusMaster IO Addresses
-Uint32 gATA_BusMasterBase;     //!< True Address (IO/MMIO)
-Uint8  *gATA_BusMasterBasePtr; //!< Paging Mapped MMIO (If needed)
-// - IRQs
- int   gATA_IRQPri = 14;
- int   gATA_IRQSec = 15;
-volatile int   gaATA_IRQs[2] = {0};
-// - Locks to avoid tripping
-tMutex glaATA_ControllerLock[2];
-// - Buffers!
-Uint8  gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
-// - PRDTs
-tPRDT_Ent      gATA_PRDTs[2] = {
-       {0, 512, IDE_PRDT_LAST},
-       {0, 512, IDE_PRDT_LAST}
-};
-tPAddr gaATA_PRDT_PAddrs[2];
-
-// === CODE ===
-/**
- * \brief Sets up the ATA controller's DMA mode
- */
-int ATA_SetupIO(void)
-{
-        int    ent;
-
-       ENTER("");
-
-       // Get IDE Controller's PCI Entry
-       ent = PCI_GetDeviceByClass(0x010100, 0xFFFF00, -1);
-       LOG("ent = %i", ent);
-       gATA_BusMasterBase = PCI_GetBAR(ent, 4);
-       if( gATA_BusMasterBase == 0 ) {
-               Log_Warning("ATA", "It seems that there is no Bus Master Controller on this machine. Get one");
-               // TODO: Use PIO mode instead
-               LEAVE('i', MODULE_ERR_NOTNEEDED);
-               return MODULE_ERR_NOTNEEDED;
-       }
-       
-       LOG("BAR5 = 0x%x", PCI_GetBAR(ent, 5));
-       LOG("IRQ = %i", PCI_GetIRQ(ent));
-       
-       // Map memory
-       if( !(gATA_BusMasterBase & 1) )
-       {
-               if( gATA_BusMasterBase < 0x100000 )
-                       gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
-               else
-                       gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
-               LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
-       }
-       else {
-               // Bit 0 is left set as a flag to other functions
-               LOG("gATA_BusMasterBase = IO 0x%x", gATA_BusMasterBase & ~1);
-       }
-
-       // Register IRQs and get Buffers
-       IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri, NULL );
-       IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec, NULL );
-
-       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
-       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
-
-       LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
-
-       gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
-       LOG("gaATA_PRDT_PAddrs[0] = 0x%x", gaATA_PRDT_PAddrs[0]);
-       ATA_int_BusMasterWriteDWord(4, gaATA_PRDT_PAddrs[0]);
-       
-       gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
-       LOG("gaATA_PRDT_PAddrs[1] = 0x%x", gaATA_PRDT_PAddrs[1]);
-       ATA_int_BusMasterWriteDWord(12, gaATA_PRDT_PAddrs[1]);
-
-       // Enable controllers
-       outb(IDE_PRI_BASE+1, 1);
-       outb(IDE_SEC_BASE+1, 1);
-       outb(IDE_PRI_CTRL, 0);
-       outb(IDE_SEC_CTRL, 0);
-       
-       // Make sure interrupts are ACKed
-       ATA_int_BusMasterWriteByte(2, 0x4);
-       ATA_int_BusMasterWriteByte(10, 0x4);
-
-       // return
-       LEAVE('i', MODULE_ERR_OK);
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Get the size (in sectors) of a disk
- * \param Disk Disk to get size of
- * \return Number of sectors reported
- * 
- * Does an ATA IDENTIFY
- */
-Uint64 ATA_GetDiskSize(int Disk)
-{
-       union {
-               Uint16  buf[256];
-               tIdentify       identify;
-       }       data;
-       Uint16  base;
-       Uint8   val;
-        int    i;
-       ENTER("iDisk", Disk);
-
-       base = ATA_GetBasePort( Disk );
-
-       // Send Disk Selector
-       if(Disk & 1)    // Slave
-               outb(base+6, 0xB0);
-       else    // Master
-               outb(base+6, 0xA0);
-       IO_DELAY();
-       
-       // Check for a floating bus
-       if( 0xFF == inb(base+7) ) {
-               LOG("Floating bus");
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Check for the controller
-       // - Write to two RW ports and attempt to read back
-       outb(base+0x02, 0x66);
-       outb(base+0x03, 0xFF);
-       if(inb(base+0x02) != 0x66 || inb(base+0x03) != 0xFF) {
-               LOG("No controller");
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       // Send ATA IDENTIFY
-       outb(base+7, HDD_IDENTIFY);
-       IO_DELAY();
-       val = inb(base+7);      // Read status
-       LOG("val = 0x%02x", val);
-       if(val == 0) {
-               LEAVE('i', 0);
-               return 0;       // Disk does not exist
-       }
-
-       // Poll until BSY clears or ERR is set
-       // TODO: Timeout?
-       while( (val & 0x80) && !(val & 1) )
-               val = inb(base+7);
-       LOG("BSY unset (0x%x)", val);
-       // and, wait for DRQ to set
-       while( !(val & 0x08) && !(val & 1))
-               val = inb(base+7);
-       LOG("DRQ set (0x%x)", val);
-
-       // Check for an error
-       if(val & 1) {
-               LEAVE('i', 0);
-               return 0;       // Error occured, so return false
-       }
-
-       // Read Data
-       for( i = 0; i < 256; i++ )
-               data.buf[i] = inw(base);
-
-       // Return the disk size
-       if(data.identify.Sectors48 != 0) {
-               LEAVE('X', data.identify.Sectors48);
-               return data.identify.Sectors48;
-       }
-       else {
-               LEAVE('x', data.identify.Sectors28);
-               return data.identify.Sectors28;
-       }
-}
-
-/**
- * \fn Uint16 ATA_GetPortBase(int Disk)
- * \brief Returns the base port for a given disk
- */
-Uint16 ATA_GetBasePort(int Disk)
-{
-       switch(Disk)
-       {
-       case 0: case 1:         return IDE_PRI_BASE;
-       case 2: case 3:         return IDE_SEC_BASE;
-       }
-       return 0;
-}
-
-/**
- * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- * \return Boolean Failure
- */
-int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
-{
-        int    cont = (Disk>>1)&1;     // Controller ID
-        int    disk = Disk & 1;
-       Uint16  base;
-       Sint64  timeoutTime;
-
-       ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
-
-       // Check if the count is small enough
-       if(Count > MAX_DMA_SECTORS) {
-               Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)",
-                       Count, MAX_DMA_SECTORS);
-               LEAVE('i');
-               return 1;
-       }
-       
-       // Hack to make debug hexdump noticable
-       #if 1
-       memset(Buffer, 0xFF, Count*SECTOR_SIZE);
-       #endif
-
-       // Get exclusive access to the disk controller
-       Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
-
-       // Set Size
-       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
-       // Get Port Base
-       base = ATA_GetBasePort(Disk);
-
-       // Reset IRQ Flag
-       gaATA_IRQs[cont] = 0;
-
-       #if 1
-       if( cont == 0 ) {
-               outb(IDE_PRI_CTRL, 4);
-               IO_DELAY();
-               outb(IDE_PRI_CTRL, 0);
-       }
-       else {
-               outb(IDE_SEC_CTRL, 4);
-               IO_DELAY();
-               outb(IDE_SEC_CTRL, 0);
-       }
-       #endif
-
-       // Set up transfer
-       if( Address > 0x0FFFFFFF )      // Use LBA48
-       {
-               outb(base+0x6, 0x40 | (disk << 4));
-               IO_DELAY();
-               outb(base+0x2, 0 >> 8); // Upper Sector Count
-               outb(base+0x3, Address >> 24);  // Low 2 Addr
-               outb(base+0x4, Address >> 28);  // Mid 2 Addr
-               outb(base+0x5, Address >> 32);  // High 2 Addr
-       }
-       else
-       {
-               // Magic, Disk, High Address nibble
-               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
-               //outb(base+0x06, 0xA0 | (disk << 4) | ((Address >> 24) & 0x0F));
-               IO_DELAY();
-       }
-
-       //outb(base+0x01, 0x01);        //?
-       outb(base+0x02, Count & 0xFF);          // Sector Count
-       outb(base+0x03, Address & 0xFF);                // Low Addr
-       outb(base+0x04, (Address >> 8) & 0xFF); // Middle Addr
-       outb(base+0x05, (Address >> 16) & 0xFF);        // High Addr
-
-       LOG("Starting Transfer");
-       
-       // HACK: Ensure the PRDT is reset
-       ATA_int_BusMasterWriteDWord(cont*8+4, gaATA_PRDT_PAddrs[cont]);
-       ATA_int_BusMasterWriteByte(cont*8, 4);  // Reset IRQ
-       
-       LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
-       if( Address > 0x0FFFFFFF )
-               outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
-       else
-               outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
-
-       // Start transfer
-       ATA_int_BusMasterWriteByte( cont * 8, 9 );      // Read and start
-
-       // Wait for transfer to complete
-       timeoutTime = now() + ATA_TIMEOUT;
-       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
-       {
-               HALT();
-       }
-
-       // Complete Transfer
-       ATA_int_BusMasterWriteByte( cont * 8, 8 );      // Read and stop
-
-       #if DEBUG
-       {
-               Uint8   val = inb(base+0x7);
-               LOG("Status byte = 0x%02x, Controller Status = 0x%02x",
-                       val, ATA_int_BusMasterReadByte(cont * 8 + 2));
-       }
-       #else
-       inb(base+0x7);
-       #endif
-
-       if( gaATA_IRQs[cont] == 0 )
-       {
-               if( ATA_int_BusMasterReadByte(cont * 8 + 2) & 0x4 ) {
-                       Log_Error("ATA", "BM Status reports an interrupt, but none recieved");
-                       ATA_int_BusMasterWriteByte(cont*8 + 2, 4);      // Clear interrupt
-                       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-                       Mutex_Release( &glaATA_ControllerLock[ cont ] );
-                       LEAVE('i', 0);
-                       return 0;
-               }
-
-               #if 1
-               Debug_HexDump("ATA", Buffer, 512);
-               #endif
-               
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               Log_Warning("ATA",
-                       "Read timeout on disk %i (Reading sector 0x%llx)",
-                       Disk, Address);
-               // Return error
-               LEAVE('i', 1);
-               return 1;
-       }
-       else {
-               LOG("Transfer Completed & Acknowledged");
-               // Copy to destination buffer
-               memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-
-               LEAVE('i', 0);
-               return 0;
-       }
-}
-
-/**
- * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- * \brief Write up to \a MAX_DMA_SECTORS to a disk
- * \param Disk Disk ID to write to
- * \param Address      LBA of first sector
- * \param Count        Number of sectors to write (must be >= \a MAX_DMA_SECTORS)
- * \param Buffer       Source buffer for data
- * \return Boolean Failure
- */
-int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer)
-{
-        int    cont = (Disk>>1)&1;     // Controller ID
-        int    disk = Disk & 1;
-       Uint16  base;
-       Sint64  timeoutTime;
-
-       // Check if the count is small enough
-       if(Count > MAX_DMA_SECTORS)     return 1;
-
-       // Get exclusive access to the disk controller
-       Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
-
-       // Set Size
-       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
-       // Get Port Base
-       base = ATA_GetBasePort(Disk);
-
-       // Reset IRQ Flag
-       gaATA_IRQs[cont] = 0;
-       
-       // Set up transfer
-       outb(base+0x01, 0x00);
-       if( Address > 0x0FFFFFFF )      // Use LBA48
-       {
-               outb(base+0x6, 0x40 | (disk << 4));
-               outb(base+0x2, 0 >> 8); // Upper Sector Count
-               outb(base+0x3, Address >> 24);  // Low 2 Addr
-               outb(base+0x3, Address >> 28);  // Mid 2 Addr
-               outb(base+0x3, Address >> 32);  // High 2 Addr
-       }
-       else
-       {
-               // Magic, Disk, High Address nibble
-               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
-       }
-
-       outb(base+0x02, (Uint8) Count);         // Sector Count
-       outb(base+0x03, (Uint8) Address);               // Low Addr
-       outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
-       outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
-       if( Address > 0x0FFFFFFF )
-               outb(base+0x07, HDD_DMA_W48);   // Write Command (LBA48)
-       else
-               outb(base+0x07, HDD_DMA_W28);   // Write Command (LBA28)
-
-       // Copy to output buffer
-       memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
-
-       // Start transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 1 );     // Write and start
-
-       // Wait for transfer to complete
-       timeoutTime = now() + ATA_TIMEOUT;
-       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
-       {
-               HALT();
-       }
-
-       // Complete Transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
-
-       // If the IRQ is unset, return error
-       if( gaATA_IRQs[cont] == 0 ) {
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               return 1;       // Error
-       }
-       else {
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               return 0;
-       }
-}
-
-/**
- * \brief Primary ATA Channel IRQ handler
- */
-void ATA_IRQHandlerPri(int UNUSED(IRQ), void *UNUSED(Ptr))
-{
-       Uint8   val;
-
-       // IRQ bit set for Primary Controller
-       val = ATA_int_BusMasterReadByte( 0x2 );
-       LOG("IRQ val = 0x%x", val);
-       if(val & 4) {
-               LOG("IRQ hit (val = 0x%x)", val);
-               ATA_int_BusMasterWriteByte( 0x2, 4 );
-               gaATA_IRQs[0] = 1;
-               return ;
-       }
-}
-
-/**
- * \brief Second ATA Channel IRQ handler
- */
-void ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr))
-{
-       Uint8   val;
-       // IRQ bit set for Secondary Controller
-       val = ATA_int_BusMasterReadByte( 0xA );
-       LOG("IRQ val = 0x%x", val);
-       if(val & 4) {
-               LOG("IRQ hit (val = 0x%x)", val);
-               ATA_int_BusMasterWriteByte( 0xA, 4 );
-               gaATA_IRQs[1] = 1;
-               return ;
-       }
-}
-
-/**
- * \brief Read an 8-bit value from a Bus Master register
- * \param Ofs  Register offset
- */
-Uint8 ATA_int_BusMasterReadByte(int Ofs)
-{
-       if( gATA_BusMasterBase & 1 )
-               return inb( (gATA_BusMasterBase & ~1) + Ofs );
-       else
-               return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
-}
-
-/**
- * \brief Read an 32-bit value from a Bus Master register
- * \param Ofs  Register offset
- */
-Uint32 ATA_int_BusMasterReadDWord(int Ofs)
-{
-       if( gATA_BusMasterBase & 1 )
-               return ind( (gATA_BusMasterBase & ~1) + Ofs );
-       else
-               return *(Uint32*)(gATA_BusMasterBasePtr + Ofs);
-}
-
-/**
- * \brief Writes a byte to a Bus Master Register
- * \param Ofs  Register Offset
- * \param Value        Value to write
- */
-void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
-{
-       if( gATA_BusMasterBase & 1 )
-               outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
-       else
-               *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
-}
-
-/**
- * \brief Writes a 32-bit value to a Bus Master Register
- * \param Ofs  Register offset
- * \param Value        Value to write
- */
-void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
-{
-       if( gATA_BusMasterBase & 1 )
-               outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
-       else
-               *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
-}
diff --git a/Modules/Storage/ATA/main.c b/Modules/Storage/ATA/main.c
deleted file mode 100644 (file)
index 41228d8..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Acess2 IDE Harddisk Driver
- * - main.c
- */
-#define DEBUG  0
-#define VERSION        0x0032
-#include <acess.h>
-#include <modules.h>
-#include <vfs.h>
-#include <fs_devfs.h>
-#include <api_drv_common.h>
-#include <api_drv_disk.h>
-#include "common.h"
-
-// === MACROS ===
-#define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
-
-// === PROTOTYPES ===
- int   ATA_Install(char **Arguments);
-void   ATA_SetupPartitions(void);
-void   ATA_SetupVFS(void);
- int   ATA_ScanDisk(int Disk);
-void   ATA_ParseGPT(int Disk);
-void   ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
-Uint16 ATA_GetBasePort(int Disk);
-// Filesystem Interface
-char   *ATA_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *ATA_FindDir(tVFS_Node *Node, const char *Name);
-Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
- int   ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
-// Read/Write Interface/Quantiser
-Uint   ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
-Uint   ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
-tVFS_NodeType  gATA_RootNodeType = {
-       .TypeName = "ATA Root Node",
-       .ReadDir = ATA_ReadDir,
-       .FindDir = ATA_FindDir
-       };
-tVFS_NodeType  gATA_DiskNodeType = {
-       .TypeName = "ATA Volume",
-       .Read = ATA_ReadFS,
-       .Write = ATA_WriteFS,
-       .IOCtl = ATA_IOCtl
-       };
-tDevFS_Driver  gATA_DriverInfo = {
-       NULL, "ata",
-       {
-               .NumACLs = 1,
-               .Size = -1,
-               .Flags = VFS_FFLAG_DIRECTORY,
-               .ACLs = &gVFS_ACL_EveryoneRX,
-               .Type = &gATA_RootNodeType
-       }
-};
-tATA_Disk      gATA_Disks[MAX_ATA_DISKS];
- int   giATA_NumNodes;
-tVFS_Node      **gATA_Nodes;
-
-// === CODE ===
-/**
- * \brief Initialise the ATA driver
- */
-int ATA_Install(char **Arguments)
-{
-       int     ret;
-
-       ret = ATA_SetupIO();
-       if(ret) return ret;
-
-       ATA_SetupPartitions();
-
-       ATA_SetupVFS();
-
-       if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
-               return MODULE_ERR_MISC;
-
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Scan all disks, looking for partitions
- */
-void ATA_SetupPartitions(void)
-{
-        int    i;
-       for( i = 0; i < MAX_ATA_DISKS; i ++ )
-       {
-               if( !ATA_ScanDisk(i) ) {
-                       gATA_Disks[i].Name[0] = '\0';   // Mark as unused
-                       continue;
-               }
-       }
-}
-
-/**
- * \brief Sets up the ATA drivers VFS information and registers with DevFS
- */
-void ATA_SetupVFS(void)
-{
-        int    i, j, k;
-
-       // Count number of nodes needed
-       giATA_NumNodes = 0;
-       for( i = 0; i < MAX_ATA_DISKS; i++ )
-       {
-               if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
-               giATA_NumNodes ++;
-               giATA_NumNodes += gATA_Disks[i].NumPartitions;
-       }
-
-       // Allocate Node space
-       gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
-
-       // Set nodes
-       k = 0;
-       for( i = 0; i < MAX_ATA_DISKS; i++ )
-       {
-               if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
-               gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
-               for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
-                       gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
-       }
-
-       gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
-}
-
-/**
- * \brief Scan a disk, getting the size and any paritions
- * \param Disk Disk ID to scan
- */
-int ATA_ScanDisk(int Disk)
-{
-       tVFS_Node       *node;
-       tMBR    mbr;
-
-       ENTER("iDisk", Disk);
-       
-       // Get the disk size
-       gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
-       if(gATA_Disks[ Disk ].Sectors == 0)
-       {
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
-
-       // Create Name
-       gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
-       gATA_Disks[ Disk ].Name[1] = '\0';
-
-       #if 1
-       {
-               Uint64  val = gATA_Disks[ Disk ].Sectors / 2;
-               char    *units = "KiB";
-               if( val > 4*1024 ) {
-                       val /= 1024;
-                       units = "MiB";
-               }
-               else if( val > 4*1024 ) {
-                       val /= 1024;
-                       units = "GiB";
-               }
-               else if( val > 4*1024 ) {
-                       val /= 1024;
-                       units = "TiB";
-               }
-               Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
-                       gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
-       }
-       #endif
-
-       // Get pointer to vfs node and populate it
-       node = &gATA_Disks[ Disk ].Node;
-       node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
-       node->NumACLs = 0;      // Means Superuser only can access it
-       node->Inode = (Disk << 8) | 0xFF;
-       node->ImplPtr = gATA_Disks[ Disk ].Name;
-
-       node->ATime = node->MTime = node->CTime = now();
-
-       node->Type = &gATA_DiskNodeType;
-
-       // --- Scan Partitions ---
-       LOG("Reading MBR");
-       // Read Boot Sector
-       if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
-               Log_Warning("ATA", "Error in reading MBR on %i", Disk);
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       // Check for a GPT table
-       if(mbr.Parts[0].SystemID == 0xEE)
-               ATA_ParseGPT(Disk);
-       else    // No? Just parse the MBR
-               ATA_ParseMBR(Disk, &mbr);
-       
-       #if DEBUG >= 2
-       ATA_ReadDMA( Disk, 1, 1, &mbr );
-       Debug_HexDump("ATA_ScanDisk", &mbr, 512);
-       #endif
-
-       LEAVE('i', 1);
-       return 1;
-}
-
-/**
- * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
- * \brief Fills a parition's information structure
- */
-void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
-{
-       ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
-       Part->Start = Start;
-       Part->Length = Length;
-       Part->Name[0] = 'A'+Disk;
-       if(Num >= 10) {
-               Part->Name[1] = '1'+Num/10;
-               Part->Name[2] = '1'+Num%10;
-               Part->Name[3] = '\0';
-       } else {
-               Part->Name[1] = '1'+Num;
-               Part->Name[2] = '\0';
-       }
-       Part->Node.NumACLs = 0; // Only root can read/write raw block devices
-       Part->Node.Inode = (Disk << 8) | Num;
-       Part->Node.ImplPtr = Part->Name;
-
-       Part->Node.Type = &gATA_DiskNodeType;
-       Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
-       LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
-       LEAVE('-');
-}
-
-/**
- * \fn void ATA_ParseGPT(int Disk)
- * \brief Parses the GUID Partition Table
- */
-void ATA_ParseGPT(int Disk)
-{
-       ///\todo Support GPT Disks
-       Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
-}
-
-/**
- * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
- */
-char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
-{
-       if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
-       return strdup( gATA_Nodes[Pos]->ImplPtr );
-}
-
-/**
- * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
- */
-tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
-{
-        int    part;
-       tATA_Disk       *disk;
-       
-       // Check first character
-       if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
-               return NULL;
-       disk = &gATA_Disks[Name[0]-'A'];
-       // Raw Disk
-       if(Name[1] == '\0') {
-               if( disk->Sectors == 0 && disk->Name[0] == '\0')
-                       return NULL;
-               return &disk->Node;
-       }
-
-       // Partitions
-       if(Name[1] < '0' || '9' < Name[1])      return NULL;
-       if(Name[2] == '\0') {   // <= 9
-               part = Name[1] - '0';
-               part --;
-               return &disk->Partitions[part].Node;
-       }
-       // > 9
-       if('0' > Name[2] || '9' < Name[2])      return NULL;
-       if(Name[3] != '\0')     return NULL;
-
-       part = (Name[1] - '0') * 10;
-       part += Name[2] - '0';
-       part --;
-       return &disk->Partitions[part].Node;
-
-}
-
-/**
- * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- */
-Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-        int    disk = Node->Inode >> 8;
-        int    part = Node->Inode & 0xFF;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
-       // Raw Disk Access
-       if(part == 0xFF)
-       {
-               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
-       }
-       // Partition
-       else
-       {
-               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
-               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
-       }
-
-       {
-               int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
-               //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
-               //Debug_HexDump("ATA_ReadFS", Buffer, Length);
-               LEAVE('i', ret);
-               return ret;
-       }
-}
-
-/**
- * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
- */
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-        int    disk = Node->Inode >> 8;
-        int    part = Node->Inode & 0xFF;
-
-       // Raw Disk Access
-       if(part == 0xFF)
-       {
-               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
-                       return 0;
-               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
-       }
-       // Partition
-       else
-       {
-               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
-                       return 0;
-               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
-               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
-       }
-
-       Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
-       Debug_HexDump("ATA_WriteFS", Buffer, Length);
-       return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
-}
-
-const char     *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
-/**
- * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief IO Control Funtion
- */
-int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
-{
-       switch(Id)
-       {
-       BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
-       
-       case DISK_IOCTL_GETBLOCKSIZE:
-               return 512;     
-       
-       default:
-               return 0;
-       }
-       return 0;
-}
-
-// --- Disk Access ---
-/**
- * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
- */
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
-{
-        int    ret;
-       Uint    offset;
-       Uint    done = 0;
-
-       // Pass straight on to ATA_ReadDMAPage if we can
-       if(Count <= MAX_DMA_SECTORS)
-       {
-               ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
-               if(ret == 0)    return 0;
-               return Count;
-       }
-
-       // Else we will have to break up the transfer
-       offset = 0;
-       while(Count > MAX_DMA_SECTORS)
-       {
-               ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
-               // Check for errors
-               if(ret != 1)    return done;
-               // Change Position
-               done += MAX_DMA_SECTORS;
-               Count -= MAX_DMA_SECTORS;
-               offset += MAX_DMA_SECTORS*SECTOR_SIZE;
-       }
-
-       ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
-       if(ret != 1)    return 0;
-       return done+Count;
-}
-
-/**
- * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
- */
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
-{
-        int    ret;
-       Uint    offset;
-       Uint    done = 0;
-
-       // Pass straight on to ATA_WriteDMA, if we can
-       if(Count <= MAX_DMA_SECTORS)
-       {
-               ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
-               if(ret == 0)    return 0;
-               return Count;
-       }
-
-       // Else we will have to break up the transfer
-       offset = 0;
-       while(Count > MAX_DMA_SECTORS)
-       {
-               ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
-               // Check for errors
-               if(ret != 1)    return done;
-               // Change Position
-               done += MAX_DMA_SECTORS;
-               Count -= MAX_DMA_SECTORS;
-               offset += MAX_DMA_SECTORS*SECTOR_SIZE;
-       }
-
-       ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
-       if(ret != 1)    return 0;
-       return done+Count;
-}
diff --git a/Modules/Storage/ATA/mbr.c b/Modules/Storage/ATA/mbr.c
deleted file mode 100644 (file)
index a294ca8..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Acess2 IDE Harddisk Driver
- * - MBR Parsing Code
- * mbr.c
- */
-#define DEBUG  0
-#include <acess.h>
-#include "common.h"
-
-// === PROTOTYPES ===
-void   ATA_ParseMBR(int Disk, tMBR *MBR);
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
-
-// === GLOBALS ===
-
-// === CODE ===
-/**
- * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
- */
-void ATA_ParseMBR(int Disk, tMBR *MBR)
-{
-        int    i, j = 0, k = 4;
-       Uint64  extendedLBA;
-       Uint64  base, len;
-       
-       ENTER("iDisk", Disk);
-       
-       // Count Partitions
-       gATA_Disks[Disk].NumPartitions = 0;
-       extendedLBA = 0;
-       for( i = 0; i < 4; i ++ )
-       {
-               if( MBR->Parts[i].SystemID == 0 )       continue;
-               if(     MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 // LBA 28
-               ||      MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 // LBA 48
-                       )
-               {
-                       if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
-                               LOG("Extended Partition at 0x%llx", MBR->Parts[i].LBAStart);
-                               if(extendedLBA != 0) {
-                                       Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
-                                       continue;
-                               }
-                               extendedLBA = MBR->Parts[i].LBAStart;
-                               continue;
-                       }
-                       LOG("Primary Partition at 0x%llx", MBR->Parts[i].LBAStart);
-                       
-                       gATA_Disks[Disk].NumPartitions ++;
-                       continue;
-               }
-               // Invalid Partition, so don't count it
-       }
-       while(extendedLBA != 0)
-       {
-               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
-               if( extendedLBA == -1 ) break;
-               gATA_Disks[Disk].NumPartitions ++;
-       }
-       LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
-       
-       // Create patition array
-       gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
-       
-       // --- Fill Partition Info ---
-       extendedLBA = 0;
-       for( j = 0, i = 0; i < 4; i ++ )
-       {
-               LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
-               if( MBR->Parts[i].SystemID == 0 )       continue;
-               if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
-               {
-                       base = MBR->Parts[i].LBAStart;
-                       len = MBR->Parts[i].LBALength;
-               }
-               else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 58
-               {
-                       base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
-                       len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
-               }
-               else
-                       continue;
-               
-               if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
-                       if(extendedLBA != 0) {
-                               Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
-                               continue;
-                       }
-                       extendedLBA = base;
-                       continue;
-               }
-               // Create Partition
-               ATA_int_MakePartition(
-                       &gATA_Disks[Disk].Partitions[j], Disk, j,
-                       base, len
-                       );
-               j ++;
-               
-       }
-       // Scan extended partitions
-       while(extendedLBA != 0)
-       {
-               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
-               if(extendedLBA == -1)   break;
-               ATA_int_MakePartition(
-                       &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
-                       );
-       }
-       
-       LEAVE('-');
-}
-
-/**
- * \brief Reads an extended partition
- * \return LBA of next Extended, -1 on error, 0 for last
- */
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
-{
-       Uint64  link = 0;
-        int    bFoundPart = 0;;
-        int    i;
-       tMBR    mbr;
-       Uint64  base, len;
-       
-       if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
-               return -1;      // Stop on Errors
-       
-       for( i = 0; i < 4; i ++ )
-       {
-               if( mbr.Parts[i].SystemID == 0 )        continue;
-               
-               // LBA 24
-               if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
-                       base = mbr.Parts[i].LBAStart;
-                       len = mbr.Parts[i].LBALength;
-               }
-               // LBA 48
-               else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
-                       base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
-                       len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
-               }
-               else {
-                       Log_Warning("ATA MBR",
-                               "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
-                               mbr.Parts[i].Boot, Disk, Addr, i
-                               );
-                       return -1;
-               }
-               
-               switch(mbr.Parts[i].SystemID)
-               {
-               case 0xF:
-               case 0x5:
-                       if(link != 0) {
-                               Log_Warning("ATA MBR",
-                                       "Disk %i has two forward links in the extended partition",
-                                       Disk
-                                       );
-                               return -1;
-                       }
-                       link = base;
-                       break;
-               default:
-                       if(bFoundPart) {
-                               Warning("ATA MBR",
-                                       "Disk %i has more than one partition in the extended partition at 0x%llx",
-                                       Disk, Addr
-                                       );
-                               return -1;
-                       }
-                       bFoundPart = 1;
-                       *Base = base;
-                       *Length = len;
-                       break;
-               }
-       }
-       
-       if(!bFoundPart) {
-               Log_Warning("ATA MBR",
-                       "No partition in extended partiton, Disk %i 0x%llx",
-                       Disk, Addr);
-               return -1;
-       }
-       
-       return link;
-}
diff --git a/Modules/Storage/FDD/Makefile b/Modules/Storage/FDD/Makefile
deleted file mode 100644 (file)
index 1596553..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ = fdd.o
-NAME = FDD
-
--include ../Makefile.tpl
diff --git a/Modules/Storage/FDD/fdd.c b/Modules/Storage/FDD/fdd.c
deleted file mode 100644 (file)
index 9cf808d..0000000
+++ /dev/null
@@ -1,957 +0,0 @@
-/*
- * AcessOS 0.1
- * Floppy Disk Access Code
- */
-#define DEBUG  0
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include <api_drv_disk.h>
-#include <dma.h>
-#include <iocache.h>
-
-#define WARN   0
-
-// === CONSTANTS ===
-// --- Current Version
-#define FDD_VERSION     ((0<<8)|(75))
-
-// --- Options
-#define FDD_SEEK_TIMEOUT       10      // Timeout for a seek operation
-#define MOTOR_ON_DELAY 500             // Miliseconds
-#define MOTOR_OFF_DELAY        2000    // Miliseconds
-#define        FDD_MAX_READWRITE_ATTEMPTS      16
-
-// === TYPEDEFS ===
-/**
- * \brief Representation of a floppy drive
- */
-typedef struct sFloppyDrive
-{
-        int    type;
-       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off
-        int    track[2];
-        int    timer;
-       tVFS_Node       Node;
-       #if !USE_CACHE
-       tIOCache        *CacheHandle;
-       #endif
-} t_floppyDevice;
-
-/**
- * \brief Cached Sector
- */
-typedef struct {
-       Uint64  timestamp;
-       Uint16  disk;
-       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)
-       Uint8   data[512];
-} t_floppySector;
-
-// === CONSTANTS ===
-static const char      *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };
-static const int       cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };
-static const short     cPORTBASE[] = { 0x3F0, 0x370 };
-#if DEBUG
-static const char      *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};
-#endif
-
-enum FloppyPorts {
-       PORT_STATUSA    = 0x0,
-       PORT_STATUSB    = 0x1,
-       PORT_DIGOUTPUT  = 0x2,
-       PORT_MAINSTATUS = 0x4,
-       PORT_DATARATE   = 0x4,
-       PORT_DATA       = 0x5,
-       PORT_DIGINPUT   = 0x7,
-       PORT_CONFIGCTRL = 0x7
-};
-
-#define CMD_FLAG_MULTI_TRACK   0x80    //!< Multitrack
-#define CMD_FLAG_MFM_ENCODING  0x40    //!< MFM Encoding Mode (Always set for read/write/format/verify)
-#define CMD_FLAG_SKIP_MODE     0x20    //!< Skip Mode (don't use)
-enum FloppyCommands {
-       CMD_READ_TRACK      = 0x02,
-       CMD_SPECIFY         = 0x03,
-       CMD_SENSE_STATUS    = 0x04,
-       CMD_WRITE_DATA      = 0x05,
-       CMD_READ_DATA       = 0x06,
-       CMD_RECALIBRATE     = 0x07,
-       CMD_SENSE_INTERRUPT = 0x08,
-       CMD_WRITE_DEL_DATA  = 0x09,
-       CMD_READ_SECTOR_ID  = 0x0A,
-       // 0x0B - ?
-       CMD_READ_DEL_DATA       = 0x0C,
-       CMD_FORMAT_TRACK    = 0x0D,
-       // 0x0E - ?
-       CMD_SEEK_TRACK      = 0x0F,
-       CMD_VERSION         = 0x10,
-       
-       CMD_LOCK            = 0x14,     //!< Save controller parameters
-       
-       CMD_CONFIGURE       = 0x13
-};
-
-// === PROTOTYPES ===
-// --- Filesystem
- int   FDD_Install(char **Arguments);
-void   FDD_UnloadModule();
-// --- VFS Methods
-char   *FDD_ReadDir(tVFS_Node *Node, int pos);
-tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
- int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
-Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
-// --- Functions for IOCache/DrvUtil
-Uint   FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);
-// --- Raw Disk Access
- int   FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);
- int   FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);
-// --- Helpers
- int   FDD_WaitIRQ();
-void   FDD_IRQHandler(int Num, void *Ptr);
-void   FDD_SenseInt(int base, Uint8 *sr0, Uint8 *cyl);
-
- int   FDD_Reset(int id);
-void   FDD_Recalibrate(int disk);
- int   FDD_Reconfigure(int ID);
-
- int   FDD_int_SeekTrack(int disk, int head, int track);
-void   FDD_int_TimerCallback(void *Arg);
-void   FDD_int_StopMotor(int Disk);
-void   FDD_int_StopMotorCallback(void *Arg);
-void   FDD_int_StartMotor(int Disk);
- int   FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);
-
- int   FDD_int_SendByte(int base, Uint8 Byte);
- int   FDD_int_GetByte(int base, Uint8 *Byte);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "x86_ISADMA", NULL);
-t_floppyDevice gFDD_Devices[2];
-tMutex glFDD;
-volatile int   gbFDD_IrqFired = 0;
-tDevFS_Driver  gFDD_DriverInfo = {
-       NULL, "fdd",
-       {
-       .Size = -1,
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .ReadDir = FDD_ReadDir,
-       .FindDir = FDD_FindDir,
-       .IOCtl = FDD_IOCtl
-       }
-};
-
-// === CODE ===
-/**
- * \fn int FDD_Install(char **Arguments)
- * \brief Installs floppy driver
- */
-int FDD_Install(char **Arguments)
-{
-       Uint8 data;
-       char    **args = Arguments;
-       
-       // Determine Floppy Types (From CMOS)
-       outb(0x70, 0x10);
-       data = inb(0x71);
-       gFDD_Devices[0].type = data >> 4;
-       gFDD_Devices[1].type = data & 0xF;
-       gFDD_Devices[0].track[0] = -1;
-       gFDD_Devices[1].track[1] = -1;
-       
-       Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);
-       
-       if( data == 0 ) {
-               return MODULE_ERR_NOTNEEDED;
-       }
-       
-       // Handle arguments
-       if(args) {
-               for(;*args;args++)
-               {
-                       if(strcmp(*args, "disable")==0)
-                               return MODULE_ERR_NOTNEEDED;
-               }
-       }
-       
-       // Install IRQ6 Handler
-       IRQ_AddHandler(6, FDD_IRQHandler, NULL);
-
-       // Ensure the FDD version is 0x90
-       {
-               Uint8   tmp = 0;
-               FDD_int_SendByte(cPORTBASE[0], CMD_VERSION);
-               FDD_int_GetByte(cPORTBASE[0], &tmp);
-               if( tmp != 0x90 ) {
-                       Log_Error("FDD", "Version(0x%2x) != 0x90", tmp);
-                       return MODULE_ERR_NOTNEEDED;
-               }
-       }
-
-       // Configure
-       FDD_Reconfigure(0);
-
-       // Reset Primary FDD Controller
-       if( FDD_Reset(0) != 0 ) {
-               return MODULE_ERR_MISC;
-       }
-
-       #if 0
-       {
-                int    retries;
-               // Recalibrate disks
-               LOG("Recalibrate disks (16x seek)");
-               retries = 16;
-               while(FDD_int_SeekTrack(0, 0, 1) == 0 && retries --)
-                       Threads_Yield();        // set track
-               if(retries < 0) LEAVE_RET('i', -1);
-       
-               retries = 16;
-               while(FDD_int_SeekTrack(0, 1, 1) == 0 && retries --)
-                       Threads_Yield();        // set track
-               if(retries < 0) LEAVE_RET('i', -1);
-       }
-       #endif
-       
-       
-       // Initialise Root Node
-       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
-               = gFDD_DriverInfo.RootNode.ATime = now();
-       
-       // Initialise Child Nodes
-       gFDD_Devices[0].Node.Inode = 0;
-       gFDD_Devices[0].Node.Flags = 0;
-       gFDD_Devices[0].Node.NumACLs = 0;
-       gFDD_Devices[0].Node.Read = FDD_ReadFS;
-       gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS;
-       memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));
-       
-       gFDD_Devices[1].Node.Inode = 1;
-       
-       // Set Lengths
-       gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];
-       gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];
-       
-       // Create Sector Cache
-       if( cFDD_SIZES[data >> 4] )
-       {
-               gFDD_Devices[0].CacheHandle = IOCache_Create(
-                       FDD_WriteSector, 0, 512,
-                       gFDD_Devices[0].Node.Size / (512*4)
-                       );      // Cache is 1/4 the size of the disk
-       }
-       if( cFDD_SIZES[data & 15] )
-       {
-               gFDD_Devices[1].CacheHandle = IOCache_Create(
-                       FDD_WriteSector, 0, 512,
-                       gFDD_Devices[1].Node.Size / (512*4)
-                       );      // Cache is 1/4 the size of the disk
-       }
-       
-       // Register with devfs
-       DevFS_AddDevice(&gFDD_DriverInfo);
-       
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Prepare the module for removal
- */
-void FDD_UnloadModule()
-{
-        int    i;
-       DevFS_DelDevice( &gFDD_DriverInfo );
-       Mutex_Acquire(&glFDD);
-       for(i=0;i<4;i++) {
-               Time_RemoveTimer(gFDD_Devices[i].timer);
-               FDD_int_StopMotor(i);
-       }
-       Mutex_Release(&glFDD);
-       //IRQ_Clear(6);
-}
-
-/**
- * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)
- * \brief Read Directory
- */
-char *FDD_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
-{
-       char    name[2] = "0\0";
-
-       if(Pos >= 2 || Pos < 0) return NULL;
-       
-       if(gFDD_Devices[Pos].type == 0) return VFS_SKIP;
-       
-       name[0] += Pos;
-       
-       return strdup(name);
-}
-
-/**
- * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *filename);
- * \brief Find File Routine (for vfs_node)
- */
-tVFS_Node *FDD_FindDir(tVFS_Node *UNUSED(Node), const char *Filename)
-{
-        int    i;
-       
-       ENTER("sFilename", Filename);
-       
-       // Sanity check string
-       if(Filename == NULL) {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Check string length (should be 1)
-       if(Filename[0] == '\0' || Filename[1] != '\0') {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       // Get First character
-       i = Filename[0] - '0';
-       
-       // Check for 1st disk and if it is present return
-       if(i == 0 && gFDD_Devices[0].type != 0) {
-               LEAVE('p', &gFDD_Devices[0].Node);
-               return &gFDD_Devices[0].Node;
-       }
-       
-       // Check for 2nd disk and if it is present return
-       if(i == 1 && gFDD_Devices[1].type != 0) {
-               LEAVE('p', &gFDD_Devices[1].Node);
-               return &gFDD_Devices[1].Node;
-       }
-       
-       // Else return null
-       LEAVE('n');
-       return NULL;
-}
-
-static const char      *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
-/**
- * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data)
- * \brief Stub ioctl function
- */
-int FDD_IOCtl(tVFS_Node *UNUSED(Node), int ID, void *Data)
-{
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_DISK, "FDD", FDD_VERSION, casIOCTLS);
-       
-       case DISK_IOCTL_GETBLOCKSIZE:   return 512;     
-       
-       default:
-               return 0;
-       }
-}
-
-/**
- * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read Data from a disk
-*/
-Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-        int    ret;
-       
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-       
-       if(Node == NULL) {
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       if(Node->Inode != 0 && Node->Inode != 1) {
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode);
-       LEAVE('i', ret);
-       return ret;
-}
-
-/**
- * \brief Reads \a Count contiguous sectors from a disk
- * \param SectorAddr   Address of the first sector
- * \param Count        Number of sectors to read
- * \param Buffer       Destination Buffer
- * \param Disk Disk Number
- * \return Number of sectors read
- * \note Used as a ::DrvUtil_ReadBlock helper
- */
-Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)
-{
-       Uint    ret = 0;
-       while(Count --)
-       {
-               if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 )
-                       return ret;
-               
-               Buffer = (void*)( (tVAddr)Buffer + 512 );
-               SectorAddr ++;
-               ret ++;
-       }
-       return ret;
-}
-
-int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)
-{
-        int    cyl, head, sec;
-        int    spt, base;
-        int    i;
-        int    lba = SectorAddr;
-       Uint8   st0=0, st1=0, st2=0, bps=0;     // Status Values
-       
-       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
-       
-       base = cPORTBASE[Disk >> 1];
-       
-       LOG("Calculating Disk Dimensions");
-       // Get CHS position
-       if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1)
-       {
-               LEAVE('i', -1);
-               return -1;
-       }
-       LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);
-
-       // Start the motor      
-       Mutex_Acquire(&glFDD);  // Lock to stop the motor stopping on us
-       Time_RemoveTimer(gFDD_Devices[Disk].timer);     // Remove Old Timer
-       // Start motor if needed
-       if(gFDD_Devices[Disk].motorState != 2)  FDD_int_StartMotor(Disk);
-       Mutex_Release(&glFDD);
-       
-       // Wait for spinup
-       LOG("Wait for the motor to spin up");
-       while(gFDD_Devices[Disk].motorState == 1)       Threads_Yield();
-       
-       LOG("Acquire Spinlock");
-       Mutex_Acquire(&glFDD);
-       
-       // Read Data from DMA
-       LOG("Setting DMA for read");
-       DMA_SetChannel(2, 512, !Write); // Read/Write 512 Bytes from channel 2
-       
-       LOG("Sending command");
-       
-       #define SENDB(__data)   if(FDD_int_SendByte(base, __data)) { FDD_Reset(Disk >> 1); continue; }
-
-       for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
-       {
-               FDD_int_SeekTrack(Disk, head, cyl);
-               if( Write ) {
-                       SENDB(CMD_WRITE_DATA|CMD_FLAG_MFM_ENCODING);
-               }
-               else {
-                       SENDB(CMD_READ_DATA|CMD_FLAG_MFM_ENCODING);
-               }
-               SENDB( (head << 2) | (Disk&1) );
-               SENDB(cyl & 0xFF);
-               SENDB(head & 0xFF);
-               SENDB(sec & 0xFF);
-               SENDB(0x02);    // Bytes Per Sector (Real BPS=128*2^{val})
-               SENDB(spt);     // SPT
-               SENDB(0x1B);    // Gap Length (27 is default)
-               SENDB(0xFF);    // Data Length
-               
-               // Wait for IRQ
-               if( Write ) {
-                       LOG("Writing Data");
-                       DMA_WriteData(2, 512, Buffer);
-                       LOG("Waiting for Data to be written");
-                       if( FDD_WaitIRQ() ) { FDD_Reset(Disk>>1); continue; }
-               }
-               else {
-                       LOG("Waiting for data to be read");
-                       if( FDD_WaitIRQ() ) { FDD_Reset(Disk>>1); continue; }
-                       LOG("Reading Data");
-                       DMA_ReadData(2, 512, Buffer);
-               }
-               
-               // Clear Input Buffer
-               LOG("Clearing Input Buffer");
-               // Status Values
-               FDD_int_GetByte(base, &st0);
-               FDD_int_GetByte(base, &st1);
-               FDD_int_GetByte(base, &st2);
-               
-               // Cylinder, Head and Sector (mutilated in some way)
-               FDD_int_GetByte(base, NULL);    // Cylinder
-               FDD_int_GetByte(base, NULL);    // Head
-               FDD_int_GetByte(base, NULL);    // Sector
-               // Should be the BPS set above (0x02)
-               FDD_int_GetByte(base, &bps);
-               
-               // Check Status
-               // - Error Code
-               if(st0 & 0xC0) {
-                       LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);
-                       continue;
-               }
-               // - Status Flags
-               if(st0 & 0x08) {        LOG("Drive not ready"); continue;       }
-               if(st1 & 0x80) {        LOG("End of Cylinder"); continue;       }
-               if(st1 & 0x20) {        LOG("CRC Error");       continue;       }
-               if(st1 & 0x10) {        LOG("Controller Timeout");      continue;       }
-               if(st1 & 0x04) {        LOG("No Data Found");   continue;       }
-               if(st1 & 0x01 || st2 & 0x01) {
-                       LOG("No Address mark found");
-                       continue;
-               }
-               if(st2 & 0x40) {        LOG("Deleted address mark");    continue;       }
-               if(st2 & 0x20) {        LOG("CRC error in data");       continue;       }
-               if(st2 & 0x10) {        LOG("Wrong Cylinder");  continue;       }
-               if(st2 & 0x04) {        LOG("uPD765 sector not found"); continue;       }
-               if(st2 & 0x02) {        LOG("Bad Cylinder");    continue;       }
-               
-               if(bps != 0x2) {
-                       LOG("Returned BPS = 0x%02x, not 0x02", bps);
-                       continue;
-               }
-               
-               if(st1 & 0x02) {
-                       LOG("Floppy not writable");
-                       // Return error without triggering the attempt count check
-                       i = FDD_MAX_READWRITE_ATTEMPTS+1;
-                       break;
-               }
-               
-               // Success!
-               break;
-       }
-       #undef SENDB
-       
-       // Release Spinlock
-       LOG("Realeasing Spinlock and setting motor to stop");
-       Mutex_Release(&glFDD);
-       
-       if(i == FDD_MAX_READWRITE_ATTEMPTS) {
-               Log_Warning("FDD", "Exceeded %i attempts in %s the disk",
-                       FDD_MAX_READWRITE_ATTEMPTS,
-                       (Write ? "writing to" : "reading from")
-                       );
-       }
-       
-       // Don't turn the motor off now, wait for a while
-       FDD_int_StopMotor(Disk);
-
-       // Error check
-       if( i < FDD_MAX_READWRITE_ATTEMPTS ) {
-               LEAVE('i', 0);
-               return 0;
-       }
-       else {
-               LEAVE('i', 1);
-               return 1;
-       }
-}
-
-/**
- * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
- * \brief Read a sector from disk
- * \todo Make real-hardware safe (account for read errors)
- */
-int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
-{
-        int    ret;
-       
-       ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
-       
-       if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {
-               LEAVE('i', 1);
-               return 1;
-       }
-       
-       // Pass to general function
-       ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer);
-
-       if( ret == 0 ) {
-               IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );
-               LEAVE('i', 1);
-               return 1;
-       }
-       else {
-               LOG("Reading failed");
-               LEAVE('i', 0);
-               return 0;
-       }
-}
-
-/**
- * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
- * \brief Write a sector to the floppy disk
- * \note Not Implemented
- */
-int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
-{
-       Log_Warning("FDD", "Read Only at the moment");
-       return -1;
-}
-
-/**
- * \brief Seek disk to selected track
- */
-int FDD_int_SeekTrack(int disk, int head, int track)
-{
-       Uint8   sr0=0, cyl=0;
-        int    base, i, bUnclean;
-       
-       base = cPORTBASE[disk>>1];
-       
-       // Check if seeking is needed
-       if(gFDD_Devices[disk].track[head] == track)
-               return 1;
-       
-       // - Seek Head 0
-       for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
-       {
-               if(i && bUnclean)       FDD_Reset(disk >> 1);
-               bUnclean = 1;
-               if(FDD_int_SendByte(base, CMD_SEEK_TRACK))      continue;
-               if(FDD_int_SendByte(base, (head<<2)|(disk&1)))  continue;
-               if(FDD_int_SendByte(base, track))       continue;
-               FDD_WaitIRQ();
-               FDD_SenseInt(base, &sr0, &cyl); // Wait for IRQ
-
-               bUnclean = 0;
-               if( cyl != track )
-                       continue;       // Try again
-               if( (sr0 & 0xF0) != 0x20 ) {
-                       LOG("sr0 = 0x%x", sr0);
-                       continue ;
-               }
-       
-               break;
-       }
-
-       if( i == FDD_MAX_READWRITE_ATTEMPTS ) {
-               Log_Warning("FDD", "Unable to seek to track %i on disk %i",
-                       track, disk);
-               return 0;
-       }       
-
-       // Set Track in structure
-       gFDD_Devices[disk].track[head] = track;
-
-       LOG("Time_Delay(100)"); 
-       // Wait for Head to settle
-       Time_Delay(100);
-       
-       return 1;
-}
-
-/**
- * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
- * \brief Get Dimensions of a disk
- */
-int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
-{
-       switch(type) {
-       case 0:
-               return 0;
-       
-       // 360Kb 5.25"
-       case 1:
-               *spt = 9;
-               *s = (lba % 9) + 1;
-               *c = lba / 18;
-               *h = (lba / 9) & 1;
-               break;
-       
-       // 1220Kb 5.25"
-       case 2:
-               *spt = 15;
-               *s = (lba % 15) + 1;
-               *c = lba / 30;
-               *h = (lba / 15) & 1;
-               break;
-       
-       // 720Kb 3.5"
-       case 3:
-               *spt = 9;
-               *s = (lba % 9) + 1;
-               *c = lba / 18;
-               *h = (lba / 9) & 1;
-               break;
-       
-       // 1440Kb 3.5"
-       case 4:
-               *spt = 18;
-               *s = (lba % 18) + 1;
-               *c = lba / 36;
-               *h = (lba / 18) & 1;
-               //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);
-               break;
-               
-       // 2880Kb 3.5"
-       case 5:
-               *spt = 36;
-               *s = (lba % 36) + 1;
-               *c = lba / 72;
-               *h = (lba / 32) & 1;
-               break;
-               
-       default:
-               return -2;
-       }
-       return 1;
-}
-
-/**
- * \fn void FDD_IRQHandler(int Num)
- * \brief Handles IRQ6
- */
-void FDD_IRQHandler(int Num, void *Ptr)
-{
-       gbFDD_IrqFired = 1;
-}
-
-/**
- * \brief Wait for the FDD IRQ to fire
- * \return Boolean failure (1 for timeout)
- */
-inline int FDD_WaitIRQ()
-{
-       tTime   end = now() + 2000;
-       
-       // Wait for IRQ
-       while(!gbFDD_IrqFired && now() < end)
-               Threads_Yield();
-
-       if( !gbFDD_IrqFired ) {
-               Log_Warning("FDD", "FDD_WaitIRQ - Timeout");
-               return 1;
-       }       
-
-       gbFDD_IrqFired = 0;
-       return 0;
-}
-
-void FDD_SenseInt(int base, Uint8 *sr0, Uint8 *cyl)
-{
-       FDD_int_SendByte(base, CMD_SENSE_INTERRUPT);
-       FDD_int_GetByte(base, sr0);
-       FDD_int_GetByte(base, cyl);
-}
-
-/**
- * void FDD_int_SendByte(int base, char byte)
- * \brief Sends a command to the controller
- */
-int FDD_int_SendByte(int base, Uint8 byte)
-{
-       tTime   end = now() + 1000;     // 1s
-       
-       while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
-               Threads_Yield();        //Delay
-//             Time_Delay(10); //Delay
-
-       if( inb(base + PORT_MAINSTATUS) & 0x40 ) {
-               Log_Warning("FDD", "FDD_int_SendByte: DIO set, is this ok?");
-               return -2;
-       }
-       
-       if( now() > end )
-       {
-               Log_Warning("FDD", "FDD_int_SendByte: Timeout sending byte 0x%x to base 0x%x", byte, base);
-               return 1;
-       }
-       outb(base + PORT_DATA, byte);
-//     Log_Debug("FDD", "FDD_int_SendByte: Sent 0x%02x to 0x%x", byte, base);
-       return 0;
-}
-
-/**
- * int FDD_int_GetByte(int base, char byte)
- * \brief Receive data from fdd controller
- */
-int FDD_int_GetByte(int base, Uint8 *value)
-{
-       tTime   end = now() + 1000;     // 1s
-       
-       while( (inb(base + PORT_MAINSTATUS) & 0x80) != 0x80 && now() < end )
-               Time_Delay(10);
-       
-       if( !(inb(base + PORT_MAINSTATUS) & 0x40) ) {
-               Log_Warning("FDD", "FDD_int_GetByte: DIO unset, is this ok?");
-               return -2;
-       }
-
-       if( now() > end )
-       {
-               Log_Warning("FDD", "FDD_int_GetByte: Timeout reading byte from base 0x%x", base);
-               return -1;
-       }
-       
-       if(value)
-               *value = inb(base + PORT_DATA);
-       else
-               inb(base + PORT_DATA);
-       return 0;
-}
-
-/**
- * \brief Recalibrate the specified disk
- */
-void FDD_Recalibrate(int disk)
-{
-       ENTER("idisk", disk);
-       
-       LOG("Starting Motor");
-       FDD_int_StartMotor(disk);
-       // Wait for Spinup
-       while(gFDD_Devices[disk].motorState <= 1)       Threads_Yield();
-       
-       LOG("Sending Calibrate Command");
-       FDD_int_SendByte(cPORTBASE[disk>>1], CMD_RECALIBRATE);
-       FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);
-       
-       LOG("Waiting for IRQ");
-       FDD_WaitIRQ();
-       FDD_SenseInt(cPORTBASE[disk>>1], NULL, NULL);
-       
-       LOG("Stopping Motor");
-       FDD_int_StopMotor(disk);
-       LEAVE('-');
-}
-
-/**
- * \brief Reconfigure the controller
- */
-int FDD_Reconfigure(int ID)
-{
-       Uint16  base = cPORTBASE[ID];
-       
-       ENTER("iID", ID);
-       
-       FDD_int_SendByte(base, CMD_CONFIGURE);
-       FDD_int_SendByte(base, 0);
-       // Implied seek enabled, FIFO Enabled, Drive Polling Disabled, data buffer threshold 8 bytes
-       FDD_int_SendByte(base, (1 << 6) | (0 << 5) | (0 << 4) | 7);
-       FDD_int_SendByte(base, 0);      // Precompensation - use default
-       
-       // Commit
-       FDD_int_SendByte(base, CMD_LOCK|CMD_FLAG_MULTI_TRACK);
-       FDD_int_GetByte(base, NULL);
-       
-       LEAVE('i', 0);
-       return 0;
-}
-
-/**
- * \brief Reset the specified FDD controller
- */
-int FDD_Reset(int id)
-{
-       Uint16  base = cPORTBASE[id];
-       Uint8   motor_state;
-       
-       ENTER("iID", id);
-
-       // Reset the card
-       motor_state = inb(base + PORT_DIGOUTPUT) & 0xF0;
-       outb(base + PORT_DIGOUTPUT, motor_state|0);     // Disable FDC
-       Time_Delay(1);
-       outb(base + PORT_DIGOUTPUT, motor_state|8|4);   // Re-enable FDC (DMA and Enable)
-       
-       // Set the data rate
-       outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s
-
-       // Wait for IRQ
-       LOG("Awaiting IRQ");
-       
-       FDD_WaitIRQ();
-
-       FDD_SenseInt(base, NULL, NULL);
-       
-       // Specify
-       FDD_int_SendByte(base, CMD_SPECIFY);    // Step and Head Load Times
-       FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)
-       FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1
-
-       LOG("Recalibrating Disk");
-       FDD_Recalibrate((id<<1)|0);
-       FDD_Recalibrate((id<<1)|1);
-
-       LEAVE_RET('i', 0);
-}
-
-/**
- * \fn void FDD_int_TimerCallback()
- * \brief Called by timer
- */
-void FDD_int_TimerCallback(void *Arg)
-{
-        int    disk = (Uint)Arg;
-       ENTER("iarg", disk);
-       if(gFDD_Devices[disk].motorState == 1)
-               gFDD_Devices[disk].motorState = 2;
-       Time_RemoveTimer(gFDD_Devices[disk].timer);
-       gFDD_Devices[disk].timer = -1;
-       LEAVE('-');
-}
-
-/**
- * \fn void FDD_int_StartMotor(char disk)
- * \brief Starts FDD Motor
- */
-void FDD_int_StartMotor(int disk)
-{
-       Uint8   state;
-       if( gFDD_Devices[disk].motorState != 0 )        return ;
-       // Set motor ON bit
-       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
-       state |= 1 << (4+disk);
-       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
-       // Mark as spinning up
-       gFDD_Devices[disk].motorState = 1;
-       // Schedule a timer for when it's up to speed
-       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)(Uint)disk);
-}
-
-/**
- * \brief Schedule the drive motor to stop
- * \param Disk Disk number to stop
- */
-void FDD_int_StopMotor(int Disk)
-{
-       // Ignore if the motor is aready off
-       if( gFDD_Devices[Disk].motorState == 0 )        return ;
-       
-       // Don't double-schedule timer
-       if( gFDD_Devices[Disk].timer != -1 )
-       {
-               Time_RemoveTimer( gFDD_Devices[Disk].timer );
-       }
-       
-       gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotorCallback, (void*)(Uint)Disk);
-}
-
-/**
- * \brief Stops FDD Motor
- */
-void FDD_int_StopMotorCallback(void *Arg)
-{
-       Uint8   state, disk = (Uint)Arg;
-
-       // Mutex is only locked if disk is in use
-       if( Mutex_IsLocked(&glFDD) )    return ;
-
-       ENTER("iDisk", disk);
-
-       // Clear motor on bit   
-       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
-       state &= ~( 1 << (4+disk) );
-       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
-       
-       // Mark as off
-       gFDD_Devices[disk].motorState = 0;
-
-       LEAVE('-');
-}
-
diff --git a/Modules/Storage/FDDv2/Makefile b/Modules/Storage/FDDv2/Makefile
deleted file mode 100644 (file)
index 97aae0c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#
-
-DEPS = x86/ISADMA
-OBJ = main.o fdc.o
-NAME = FDDv2
-
--include ../Makefile.tpl
diff --git a/Modules/Storage/FDDv2/common.h b/Modules/Storage/FDDv2/common.h
deleted file mode 100644 (file)
index 4d6a4f7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Acess2 82077AA FDC
- * - By John Hodge (thePowersGang)
- *
- * common.h
- * - Common definitions
- */
-#ifndef _FDC_COMMON_H_
-#define _FDC_COMMON_H_
-
-#include <mutex.h>
-#include <timers.h>
-
-// === CONSTANTS ===
-#define MAX_DISKS      8       // 4 per controller, 2 controllers
-#define TRACKS_PER_DISK        (1440*2/18)
-#define BYTES_PER_TRACK        (18*512)
-
-// === TYPEDEFS ===
-typedef struct sFDD_Drive      tDrive;
-
-// === STRUCTURES ===
-struct sFDD_Drive
-{
-        int    bValid;
-        int    bInserted;
-        int    MotorState;
-       tTimer  *Timer;
-
-       tMutex  Mutex;
-       
-       void    *TrackData[TRACKS_PER_DISK];    // Whole tracks are read
-};
-
-// === FUNCTIONS ===
-extern int     FDD_SetupIO(void);
-extern int     FDD_int_ReadWriteTrack(int Disk, int Track, int bWrite, void *Buffer);
-
-// === GLOBALS ===
-extern tDrive  gaFDD_Disks[MAX_DISKS];
-
-#endif
-
diff --git a/Modules/Storage/FDDv2/fdc.c b/Modules/Storage/FDDv2/fdc.c
deleted file mode 100644 (file)
index e86b31c..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Acess2 82077AA FDC
- * - By John Hodge (thePowersGang)
- *
- * fdc.c
- * - FDC IO Functions
- */
-#define DEBUG  0
-#include <acess.h>
-#include "common.h"
-#include <dma.h>
-#include <timers.h>
-
-// === CONSTANTS ===
-#define MOTOR_ON_DELAY 500
-#define MOTOR_OFF_DELAY        2000
-
-enum eMotorState
-{
-       MOTOR_OFF,
-       MOTOR_ATSPEED,
-};
-
-enum eFDC_Registers
-{
-       FDC_DOR  = 0x02,        // Digital Output Register
-       FDC_MSR  = 0x04,        // Master Status Register (Read Only)
-       FDC_FIFO = 0x05,        // FIFO port
-       FDC_CCR  = 0x07         // Configuration Control Register (write only)
-};
-
-enum eFDC_Commands
-{
-       CMD_SPECIFY = 3,            // Specify parameters
-       CMD_WRITE_DATA = 5,         // Write Data
-       CMD_READ_DATA = 6,          // Read Data
-       CMD_RECALIBRATE = 7,        // Recalibrate a drive
-       CMD_SENSE_INTERRUPT = 8,    // Sense (Ack) an interrupt
-       CMD_SEEK = 15,              // Seek to a track
-};
-
-// === PROTOTYPES ===
- int   FDD_SetupIO(void);
- int   FDD_int_ReadWriteTrack(int Disk, int Track, int bWrite, void *Buffer);
- int   FDD_int_SeekToTrack(int Disk, int Track);
- int   FDD_int_Calibrate(int Disk);
- int   FDD_int_Reset(int Disk);
-// --- FIFO
- int   FDD_int_WriteData(Uint16 Base, Uint8 Data);
- int   FDD_int_ReadData(Uint16 Base, Uint8 *Data);
-void   FDD_int_SenseInterrupt(Uint16 Base, Uint8 *ST0, Uint8 *Cyl);
-// --- Motor Control
- int   FDD_int_StartMotor(int Disk);
- int   FDD_int_StopMotor(int Disk);
-void   FDD_int_StopMotorCallback(void *Ptr);
-// --- Helpers
- int   FDD_int_HandleST0Error(const char *Fcn, int Disk, Uint8 ST0);
-Uint16 FDD_int_GetBase(int Disk, int *Drive);
-// --- Interrupt
-void   FDD_int_ClearIRQ(void);
- int   FDD_int_WaitIRQ(void);
-void   FDD_int_IRQHandler(int IRQ, void *Ptr);
-
-// === GLOBALS ===
-/**
- * \brief Marker for IRQ6
- * \todo Convert into a semaphore?
- */
- int   gbFDD_IRQ6Fired;
-/**
- * \brief Protector for DMA and IRQ6
- */
-tMutex gFDD_IOMutex;
-
-// === CODE ===
-/**
- * \brief Set up FDC IO
- * \return Boolean failure
- *
- * Registers the IRQ handler and resets the controller
- */
-int FDD_SetupIO(void)
-{
-       // Install IRQ6 Handler
-       IRQ_AddHandler(6, FDD_int_IRQHandler, NULL);
-       
-       // Reset controller
-       FDD_int_Reset(0);
-       // TODO: All controllers
-       
-       return 0;
-}
-
-/**
- * \brief Read/Write data from/to a disk
- * \param Disk Global disk number
- * \param Track Track number (Cyl*2+Head)
- * \param bWrite Toggle write mode
- * \param Buffer Destination/Source buffer
- * \return Boolean failure
- */
-int FDD_int_ReadWriteTrack(int Disk, int Track, int bWrite, void *Buffer)
-{
-       Uint8   cmd;
-        int    i, _disk;
-       Uint16  base = FDD_int_GetBase(Disk, &_disk);
-        int    cyl = Track >> 1, head = Track & 1;
-
-       ENTER("iDisk iTrack ibWrite pBuffer", Disk, Track, bWrite, Buffer);
-
-       Mutex_Acquire( &gFDD_IOMutex );
-       
-       // Initialise DMA for read/write
-       // TODO: Support non 1.44MiB FDs
-       DMA_SetChannel(2, BYTES_PER_TRACK, !bWrite);
-       
-       // Select command
-       if( bWrite )
-               cmd = CMD_WRITE_DATA | 0xC0;
-       else
-               cmd = CMD_READ_DATA | 0xC0;
-
-       LOG("cmd = 0x%x", cmd);
-       
-       // Seek
-       if( FDD_int_SeekToTrack(Disk, Track) ) {
-               Mutex_Release( &gFDD_IOMutex );
-               LEAVE('i', -1);
-               return -1;
-       }
-       LOG("Track seek done");
-
-       for( i = 0; i < 20; i ++ )
-       {
-               LOG("Starting motor");
-               FDD_int_StartMotor(Disk);
-
-               // Write data
-               if( bWrite )
-                       DMA_WriteData(2, BYTES_PER_TRACK, Buffer);      
-       
-               LOG("Sending command stream");
-               FDD_int_WriteData(base, cmd);
-               FDD_int_WriteData(base, (head << 2) | _disk);
-               FDD_int_WriteData(base, cyl);
-               FDD_int_WriteData(base, head);
-               FDD_int_WriteData(base, 1);     // First Sector
-               FDD_int_WriteData(base, 2);     // Bytes per sector (128*2^n)
-               FDD_int_WriteData(base, 18);    // 18 tracks (full disk) - TODO: Non 1.44
-               FDD_int_WriteData(base, 0x1B);  // Gap length - TODO: again
-               FDD_int_WriteData(base, 0xFF);  // Data length - ?
-       
-               LOG("Waiting for IRQ");
-               FDD_int_WaitIRQ();
-       
-               // No Sense Interrupt
-               
-               LOG("Reading result");
-               Uint8   st0=0, st1=0, st2=0, bps=0;
-               FDD_int_ReadData(base, &st0);
-               FDD_int_ReadData(base, &st1);   // st1
-               FDD_int_ReadData(base, &st2);   // st2
-               FDD_int_ReadData(base, NULL);   // rcy - Mutilated Cyl
-               FDD_int_ReadData(base, NULL);   // rhe - Mutilated Head
-               FDD_int_ReadData(base, NULL);   // rse - Mutilated sector
-               FDD_int_ReadData(base, &bps);   // bps - Should be the same as above
-
-               if( st0 & 0xc0 ) {
-                       FDD_int_HandleST0Error(__func__, Disk, st0);
-                       continue ;
-               }
-       
-               if( st2 & 0x02 ) {
-                       Log_Debug("FDD", "Disk %i is not writable", Disk);
-                       Mutex_Release( &gFDD_IOMutex );
-                       LEAVE('i', 2);
-                       return 2;
-               }
-               
-               if( st0 & 0x08 ) {
-                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: Drive not ready");
-                       continue ;
-               }
-
-
-               if( st1 & 0x80 ) {
-                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: End of cylinder");
-                       continue ;
-               }
-
-               if( st1 & (0x20|0x10|0x04|0x01) ) {
-                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: st1 = 0x%x", st1);
-                       continue;
-               }
-               
-               if( st2 & (0x40|0x20|0x10|0x04|0x01) ) {
-                       Log_Debug("FDD", "FDD_int_ReadWriteTrack: st2 = 0x%x", st2);
-                       continue ;
-               }
-               
-               if( bps != 0x2 ) {
-                       Log_Debug("FDD", "Wanted bps = 2 (512), got %i", bps);
-                       continue ;
-               }
-
-               // Read back data
-               if( !bWrite )
-                       DMA_ReadData(2, BYTES_PER_TRACK, Buffer);
-               
-               LOG("All data done");
-               FDD_int_StopMotor(Disk);
-               Mutex_Release( &gFDD_IOMutex );
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       Log_Debug("FDD", "%i retries exhausted", i);
-       FDD_int_StopMotor(Disk);
-       Mutex_Release( &gFDD_IOMutex );
-       LEAVE('i', 1);
-       return 1;
-}
-
-/**
- * \brief Seek to a specific track
- * \param Disk Global disk number
- * \param Track Track number (Cyl*2+Head)
- * \return Boolean failure
- */
-int FDD_int_SeekToTrack(int Disk, int Track)
-{
-       Uint8   st0=0, res_cyl=0;
-        int    cyl, head;
-        int    _disk;
-       Uint16  base = FDD_int_GetBase(Disk, &_disk);;
-
-       ENTER("iDisk iTrack", Disk, Track);
-       
-       cyl = Track / 2;
-       head = Track % 2;
-
-       LOG("cyl = %i, head = %i", cyl, head);
-       
-       FDD_int_StartMotor(Disk);
-       
-       for( int i = 0; i < 10; i ++ )
-       {
-               LOG("Sending command");
-               FDD_int_ClearIRQ();
-               FDD_int_WriteData(base, CMD_SEEK);
-               FDD_int_WriteData(base, (head << 2) + _disk);
-               FDD_int_WriteData(base, cyl);
-       
-               LOG("Waiting for IRQ");
-               FDD_int_WaitIRQ();
-               FDD_int_SenseInterrupt(base, &st0, &res_cyl);
-       
-               if( st0 & 0xC0 )
-               {
-                       FDD_int_HandleST0Error(__func__, Disk, st0);
-                       continue ;
-               }
-               
-               if( res_cyl == cyl ) {
-                       FDD_int_StopMotor(Disk);
-                       LEAVE('i', 0);
-                       return 0;
-               }
-       }
-       
-       Log_Error("FDD", "FDD_int_SeekToTrack: 10 retries exhausted\n");
-       FDD_int_StopMotor(Disk);
-       LEAVE('i', 1);
-       return 1;
-}
-
-/**
- * \brief Calibrate a drive
- * \param Disk Global disk number
- */
-int FDD_int_Calibrate(int Disk)
-{
-        int    _disk;
-       Uint16  base = FDD_int_GetBase(Disk, &_disk);
-       FDD_int_StartMotor(Disk);
-       
-       for( int i = 0; i < 10; i ++ )
-       {
-               Uint8   st0=0, cyl = -1;
-       
-               FDD_int_ClearIRQ();     
-               FDD_int_WriteData(base, CMD_RECALIBRATE);
-               FDD_int_WriteData(base, _disk);
-               
-               FDD_int_WaitIRQ();
-       
-               FDD_int_SenseInterrupt(base, &st0, &cyl);
-               
-               if( st0 & 0xC0 ) {
-                       FDD_int_HandleST0Error(__func__, Disk, st0);
-                       continue ;
-               }
-               
-               if( cyl == 0 )
-               {
-                       FDD_int_StopMotor(Disk);
-                       return 0;
-               }
-       }
-       
-       Log_Error("FDD", "FDD_int_Calibrate: Retries exhausted");
-       
-       return 1;
-}
-
-/**
- * \brief Reset a controller
- * \param Base Controller base address
- */
-int FDD_int_Reset(int Disk)
-{
-       Uint8   tmp;
-        int    _disk;
-       Uint16  base = FDD_int_GetBase(Disk, &_disk);
-
-       tmp = inb(base + FDC_DOR) & 0xF0;
-       outb( base + FDC_DOR, 0x00 );
-       Time_Delay(1);
-       outb( base + FDC_DOR, tmp | 0x0C );
-
-       FDD_int_SenseInterrupt(base, NULL, NULL);
-
-       outb(base + FDC_CCR, 0x00);     // 500KB/s
-
-       FDD_int_WriteData(base, CMD_SPECIFY);   // Step and Head Load Times
-       FDD_int_WriteData(base, 0xDF);  // Step Rate Time, Head Unload Time (Nibble each)
-       FDD_int_WriteData(base, 0x02);  // Head Load Time >> 1
-
-       // TODO: Recalibrate all present disks
-       FDD_int_Calibrate(Disk);
-       return 0;
-}
-
-/**
- * \brief Write a byte to the FIFO
- */
-int FDD_int_WriteData(Uint16 Base, Uint8 Data)
-{
-       for( int i = 0; i < 100; i ++ )
-       {
-               if( inb(Base + FDC_MSR) & 0x80 )
-               {
-                       outb(Base + FDC_FIFO, Data);
-                       return 0;
-               }
-               Time_Delay(10);
-       }
-       Log_Error("FDD", "Write timeout");
-       return 1;
-}
-
-/**
- * \brief Read a byte from the FIFO
- */
-int FDD_int_ReadData(Uint16 Base, Uint8 *Data)
-{
-       for( int i = 0; i < 100; i ++ )
-       {
-               if( inb(Base + FDC_MSR) & 0x80 )
-               {
-                       Uint8 tmp = inb(Base + FDC_FIFO);
-                       if(Data) *Data = tmp;
-                       return 0;
-               }
-               Time_Delay(10);
-       }
-       Log_Error("FDD", "Read timeout");
-       return 1;
-}
-
-/**
- * \brief Acknowledge an interrupt
- * \param Base Controller base address
- * \param ST0  Location to store the ST0 value
- * \param Cyl  Current cylinder
- */
-void FDD_int_SenseInterrupt(Uint16 Base, Uint8 *ST0, Uint8 *Cyl)
-{
-       FDD_int_WriteData(Base, CMD_SENSE_INTERRUPT);
-       FDD_int_ReadData(Base, ST0);
-       FDD_int_ReadData(Base, Cyl);
-}
-
-/**
- * \brief Start the motor on a disk
- */
-int FDD_int_StartMotor(int Disk)
-{
-        int    _disk;
-       Uint16  base = FDD_int_GetBase(Disk, &_disk);
-       
-       // Clear the motor off timer    
-       Time_RemoveTimer(gaFDD_Disks[Disk].Timer);
-       gaFDD_Disks[Disk].Timer = NULL;
-
-       // Check if the motor is already on
-       if( gaFDD_Disks[Disk].MotorState == MOTOR_ATSPEED )
-               return 0;
-
-       // Turn motor on
-       outb(base + FDC_DOR, inb(base+FDC_DOR) | (1 << (_disk + 4)));
-
-       // Wait for it to reach speed
-       Time_Delay(MOTOR_ON_DELAY);
-
-       gaFDD_Disks[Disk].MotorState = MOTOR_ATSPEED;
-
-       return 0;
-}
-
-/**
- * \brief Schedule the motor to stop
- */
-int FDD_int_StopMotor(int Disk)
-{
-       if( gaFDD_Disks[Disk].MotorState != MOTOR_ATSPEED )
-               return 0;
-       if( gaFDD_Disks[Disk].Timer != NULL )
-               return 0;
-
-       gaFDD_Disks[Disk].Timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotorCallback, (void*)(tVAddr)Disk);
-
-       return 0;
-}
-
-/**
- * \brief Actually stop the motor
- * \param Ptr  Actaully the global disk number
- */
-void FDD_int_StopMotorCallback(void *Ptr)
-{
-        int    Disk = (tVAddr)Ptr;
-        int    _disk;
-       Uint16  base = FDD_int_GetBase(Disk, &_disk);
-
-       gaFDD_Disks[Disk].Timer = NULL;
-       gaFDD_Disks[Disk].MotorState = MOTOR_OFF;
-       
-       outb(base + FDC_DOR, inb(base+FDC_DOR) & ~(1 << (_disk + 4)));
-
-       return ;
-}
-
-/**
- * \brief Converts a global disk number into a controller and drive
- * \param Disk Global disk number
- * \param Drive        Destination for controller disk number
- * \return Controller base address
- */
-Uint16 FDD_int_GetBase(int Disk, int *Drive)
-{
-       if(Drive)       *Drive = Disk & 3;
-       switch(Disk >> 2)
-       {
-       case 0: return 0x3F0;
-       case 1: return 0x370;
-       default:
-               return 0;
-       }
-}
-
-/**
- * \brief Convert a ST0 error value into a message
- * \param Fcn  Calling function name
- * \parma Disk Global disk number
- * \param ST0  ST0 Value
- * \return Boolean failure
- */
-int FDD_int_HandleST0Error(const char *Fcn, int Disk, Uint8 ST0)
-{
-       static const char *status_type[] = {
-               0, "Error", "Invalid", "Drive Error"
-       };
-
-       Log_Debug("FDD", "%s: Disk %i ST0 Status = %s (0x%x & 0xC0 = 0x%x)",
-               Fcn, Disk, status_type[ST0 >> 6], ST0, ST0 & 0xC0
-               );
-       return 0;
-}
-
-/**
- * \brief Clear the IRQ fired flag
- */
-void FDD_int_ClearIRQ(void)
-{
-       gbFDD_IRQ6Fired = 0;
-}
-
-/**
- * \brief Wait for an IRQ to fire
- */
-int FDD_int_WaitIRQ(void)
-{
-       while(gbFDD_IRQ6Fired == 0)
-               Threads_Yield();
-       return 0;
-}
-
-/**
- * \brief IRQ Handler
- * \param IRQ  IRQ Number (unused)
- * \param Ptr  Data Pointer (unused)
- */
-void FDD_int_IRQHandler(int IRQ, void *Ptr)
-{
-       gbFDD_IRQ6Fired = 1;
-}
-
diff --git a/Modules/Storage/FDDv2/main.c b/Modules/Storage/FDDv2/main.c
deleted file mode 100644 (file)
index bec157c..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Acess2 82077AA FDC
- * - By John Hodge (thePowersGang)
- *
- * fdc.c
- * - Core file
- */
-#define DEBUG  0
-#include <acess.h>
-#include <modules.h>
-#include <fs_devfs.h>
-#include "common.h"
-#include <api_drv_disk.h>
-
-// === CONSTANTS ===
-#define FDD_VERSION    VER2(1,10)
-
-// === STRUCTURES ===
-
-// === PROTOTYPES ===
- int   FDD_Install(char **Arguments);
- int   FDD_RegisterFS(void);
-// --- VFS
-char   *FDD_ReadDir(tVFS_Node *Node, int pos);
-tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
- int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
-Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
-// --- Helpers
- int   FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, FDD_VERSION, Storage_FDDv2, FDD_Install, NULL, "x86_ISADMA", NULL);
-tDrive gaFDD_Disks[MAX_DISKS];
-tVFS_Node      gaFDD_DiskNodes[MAX_DISKS];
-tVFS_NodeType  gFDD_RootNodeType = {
-       .TypeName = "FDD Root Node",
-       .ReadDir = FDD_ReadDir,
-       .FindDir = FDD_FindDir,
-       .IOCtl = FDD_IOCtl
-       };
-tVFS_NodeType  gFDD_DevNodeType = {
-       .TypeName = "FDD Device",
-       .Read = FDD_ReadFS,
-       .Write = NULL   // FDD_WriteFS?
-       };
-tDevFS_Driver  gFDD_DriverInfo = {
-       NULL, "fdd",
-       {
-       .Size = -1,
-       .NumACLs = 1,
-       .ACLs = &gVFS_ACL_EveryoneRX,
-       .Flags = VFS_FFLAG_DIRECTORY,
-       .Type = &gFDD_RootNodeType
-       }
-       };
-
-// === CODE ===
-int FDD_Install(char **Arguments)
-{
-       // Query CMOS memory
-       {
-               Uint8   data;
-               outb(0x70, 0x10);
-               data = inb(0x71);
-               
-               // NOTE: CMOS only reports 2 disks
-               if( (data & 0xF0) == 0x40 )
-                       gaFDD_Disks[0].bValid = gaFDD_Disks[0].bInserted = 1;
-               if( (data & 0x0F) == 0x04 )
-                       gaFDD_Disks[1].bValid = gaFDD_Disks[1].bInserted = 1;
-               
-               if( gaFDD_Disks[0].bValid == 0 && gaFDD_Disks[1].bValid == 0 )
-                       return MODULE_ERR_NOTNEEDED;
-       }
-       
-       // Initialise controller
-       FDD_SetupIO();
-
-       FDD_RegisterFS();
-
-       return 0;
-}
-
-/**
- * \brief Register the FDD driver with DevFS
- */
-int FDD_RegisterFS(void)
-{
-       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
-               = gFDD_DriverInfo.RootNode.ATime = now();
-
-       for( int i = 0; i < MAX_DISKS; i ++ )
-       {
-               if( !gaFDD_Disks[i].bValid )    continue ;
-       
-               // Initialise Child Nodes
-               gaFDD_DiskNodes[i].Inode = i;
-               gaFDD_DiskNodes[i].Flags = 0;
-               gaFDD_DiskNodes[i].NumACLs = 0;
-               gaFDD_DiskNodes[i].Type = &gFDD_DevNodeType;
-               gaFDD_DiskNodes[i].Size = 1440*1024;    // TODO: Non 1.44 disks
-       }
-       
-       DevFS_AddDevice( &gFDD_DriverInfo );
-       return 0;
-}
-
-/**
- * \brief Get the name of the \a Pos th item in the driver root
- * \param Node Root node (unused)
- * \param Pos  Position
- * \return Heap string of node name
- */
-char *FDD_ReadDir(tVFS_Node *Node, int Pos)
-{
-       char    ret_tpl[2];
-       if(Pos < 0 || Pos > MAX_DISKS )
-               return NULL;
-       if(gaFDD_Disks[Pos].bValid)
-               return VFS_SKIP;
-       
-       ret_tpl[0] = '0' + Pos;
-       ret_tpl[1] = '\0';
-       return strdup(ret_tpl);
-}
-
-/**
- * \brief Get a node by name
- * \param Node Root node (unused)
- * \param Name Drive name
- * \return Pointer to node structure
- */
-tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *Name)
-{
-        int    pos;
-       if( '0' > Name[0] || Name[0] > '9' )    return NULL;
-       if( Name[1] != '\0' )   return NULL;
-       
-       pos = Name[0] - '0';
-       
-       return &gaFDD_DiskNodes[pos];
-}
-
-static const char      *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
-/**
- * \brief Driver root IOCtl Handler
- * \param Node Root node (unused)
- * \param ID   IOCtl ID
- * \param Data IOCtl specific data pointer
- */
-int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-       switch(ID)
-       {
-       BASE_IOCTLS(DRV_TYPE_DISK, "FDDv2", FDD_VERSION, casIOCTLS);
-       
-       case DISK_IOCTL_GETBLOCKSIZE:   return 512;
-       
-       default:
-               return -1;
-       }
-}
-
-/**
- * \brief Read from a disk
- * \param Node Disk node
- * \param Offset       Byte offset in disk
- * \param Length       Number of bytes to read
- * \param Buffer       Destination buffer
- * \return Number of bytes read
- */
-Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
-        int    disk = Node->Inode;
-        int    track;
-        int    rem_len;
-       char    *dest = Buffer;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
-       if( Offset > Node->Size )       LEAVE_RET('i', 0);
-       if( Length > Node->Size )       Length = Node->Size;
-       if( Offset + Length > Node->Size )
-               Length = Node->Size - Offset;
-       if( Length == 0 )       return 0;
-
-       rem_len = Length;
-
-       track = Offset / BYTES_PER_TRACK;
-       Offset %= BYTES_PER_TRACK;      
-
-       if( Offset )
-       {
-                int    len;
-               if(rem_len > BYTES_PER_TRACK - Offset)
-                       len = BYTES_PER_TRACK - Offset;
-               else
-                       len = rem_len;
-               FDD_int_ReadWriteWithinTrack(disk, track, 0, Offset, len, dest);
-               dest += len;
-               rem_len -= len;
-               track ++;
-       }
-
-       if( rem_len > 0)
-       {
-               while( rem_len > BYTES_PER_TRACK )
-               {
-                       FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, BYTES_PER_TRACK, dest);
-                       dest += BYTES_PER_TRACK;
-                               rem_len -= BYTES_PER_TRACK;
-                       track ++;
-               }
-
-               FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, rem_len, dest);
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
-
-/**
- * \brief Read from a track
- */
-int FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer)
-{
-       if( Offset > BYTES_PER_TRACK || Length > BYTES_PER_TRACK )
-               return 1;
-       if( Offset + Length > BYTES_PER_TRACK )
-               return 1;
-
-       if( Length == 0 )
-               return 0;
-       
-       ENTER("iDisk iTrack bbWrite xOffset xLength pBuffer",
-               Disk, Track, bWrite, Offset, Length, Buffer);
-       
-       Mutex_Acquire( &gaFDD_Disks[Disk].Mutex );
-
-       // If the cache doesn't exist, create it
-       if( !gaFDD_Disks[Disk].TrackData[Track] )
-       {
-               gaFDD_Disks[Disk].TrackData[Track] = malloc( BYTES_PER_TRACK );
-               // Don't bother reading if this is a whole track write
-               if( !(bWrite && Offset == 0 && Length == BYTES_PER_TRACK) )
-               {
-                       LOG("Reading track");
-                       FDD_int_ReadWriteTrack(Disk, Track, 0, gaFDD_Disks[Disk].TrackData[Track]);
-               }
-       }
-       
-       // Read/Write
-       if( bWrite )
-       {
-               // Write to cache then commit cache to disk
-               char    *dest = gaFDD_Disks[Disk].TrackData[Track];
-               LOG("Write to cache");
-               memcpy( dest + Offset, Buffer, Length );
-               FDD_int_ReadWriteTrack(Disk, Track, 1, gaFDD_Disks[Disk].TrackData[Track]);
-       }
-       else
-       {
-               // Read from cache
-               char    *src = gaFDD_Disks[Disk].TrackData[Track];
-               LOG("Read from cache");
-               memcpy(Buffer, src + Offset, Length);
-       }
-       
-       Mutex_Release( &gaFDD_Disks[Disk].Mutex );
-
-       LEAVE('i', 0);
-       return 0;
-}
diff --git a/Modules/Storage/Makefile.tpl b/Modules/Storage/Makefile.tpl
deleted file mode 100644 (file)
index d5291f6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = Storage
-
--include ../../Makefile.tpl
diff --git a/Modules/USB/Core/Makefile b/Modules/USB/Core/Makefile
deleted file mode 100644 (file)
index 4d6e684..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-#
-
-OBJ  = main.o
-OBJ += usb.o usb_lowlevel.o usb_devinit.o usb_io.o usb_poll.o
-OBJ += hub.o
-CPPFLAGS = -Iinclude
-NAME = Core
-
--include ../Makefile.tpl
diff --git a/Modules/USB/Core/hub.c b/Modules/USB/Core/hub.c
deleted file mode 100644 (file)
index 849e8a3..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * hub.c
- * - Basic hub driver
- */
-#define DEBUG  1
-#include <usb_hub.h>
-
-#define MAX_PORTS      32      // Not actually a max, but used for DeviceRemovable
-
-
-#define GET_STATUS     0
-#define CLEAR_FEATURE  1
-// resvd
-#define SET_FEATURE    3
-
-#define PORT_CONNECTION        0
-#define PORT_ENABLE    1
-#define PORT_SUSPEND   2
-#define PORT_OVER_CURRENT      3
-#define PORT_RESET     4
-#define PORT_POWER     8
-#define PORT_LOW_SPEED 9
-#define C_PORT_CONNECTION      16
-#define C_PORT_ENABLE  17
-#define C_PORT_SUSPEND 18
-#define C_PORT_OVER_CURRENT    19
-#define C_PORT_RESET   20
-#define PORT_TEST      21
-#define PORT_INDICATOR 21
-
-struct sHubDescriptor
-{
-       Uint8   DescLength;
-       Uint8   DescType;       // = 0x29
-       Uint8   NbrPorts;
-       Uint16  HubCharacteristics;
-       Uint8   PwrOn2PwrGood;  // 2 ms intervals
-       Uint8   HubContrCurrent;        // Max internal current (mA)
-       Uint8   DeviceRemovable[MAX_PORTS];
-};
-
-struct sHubInfo
-{
-       tUSBHub *HubPtr;
-        int    PowerOnDelay;   // in ms
-        int    nPorts;
-       Uint8   DeviceRemovable[];
-};
-
-// === PROTOTYPES ===
-void   Hub_Connected(tUSBInterface *Dev);
-void   Hub_Disconnected(tUSBInterface *Dev);
-void   Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-void   Hub_int_HandleChange(tUSBInterface *Dev, int Port);
-
-// === GLOBALS ===
-tUSBDriver     gUSBHub_Driver = {
-       .Name = "Hub",
-       .Match = {.Class = {0x090000, 0xFF0000}},
-       .Connected = Hub_Connected,
-       .Disconnected = Hub_Disconnected,
-       .MaxEndpoints = 1,
-       .Endpoints = {
-               {0x83, Hub_PortStatusChange}
-       }
-};
-
-// === CODE ===
-#if 0
-int Hub_DriverInitialise(char **Arguments)
-{
-       USB_RegisterDriver( &gUSBHub_Driver );
-       return 0;
-}
-#endif
-
-void Hub_Connected(tUSBInterface *Dev)
-{
-       struct sHubDescriptor   hub_desc;
-       struct sHubInfo *info;  
-
-       // Read hub descriptor (Class descriptor 0x29)
-       USB_ReadDescriptor(Dev, 0x129, 0, sizeof(hub_desc), &hub_desc);
-
-       LOG("%i Ports", hub_desc.NbrPorts);
-       LOG("Takes %i ms for power to stabilise", hub_desc.PwrOn2PwrGood*2);
-
-       // Allocate infomation structure
-       info = malloc(sizeof(*info) + (hub_desc.NbrPorts+7)/8);
-       if(!info) {
-               Log_Error("USBHub", "malloc() failed");
-               return ;
-       }
-       USB_SetDeviceDataPtr(Dev, info);
-
-       // Fill data
-       info->nPorts = hub_desc.NbrPorts;
-       info->PowerOnDelay = hub_desc.PwrOn2PwrGood * 2;
-       memcpy(info->DeviceRemovable, hub_desc.DeviceRemovable, (hub_desc.NbrPorts+7)/8);
-       // Register
-       info->HubPtr = USB_RegisterHub(Dev, info->nPorts);
-
-       // Register poll on endpoint
-       USB_StartPollingEndpoint(Dev, 1);
-}
-
-void Hub_Disconnected(tUSBInterface *Dev)
-{
-       struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
-       USB_RemoveHub(info->HubPtr);
-       free(info);
-}
-
-void Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
-{
-       Uint8   *status = Data;
-       struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
-        int    i;
-       for( i = 0; i < info->nPorts; i += 8, status ++ )
-       {
-               if( i/8 >= Length )     break;
-               if( *status == 0 )      continue;
-       
-               for( int j = 0; j < 8; j ++ )
-                       if( *status & (1 << j) )
-                               Hub_int_HandleChange(Dev, i+j);
-       }
-}
-
-void Hub_int_HandleChange(tUSBInterface *Dev, int Port)
-{
-       struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
-       Uint16  status[2];      // Status, Change
-       
-       // Get port status
-       USB_Request(Dev, 0, 0xA3, GET_STATUS, 0, Port, 4, status);
-
-       LOG("Port %i: status = {0b%b, 0b%b}", Port, status[0], status[1]);
-       
-       // Handle connections / disconnections
-       if( status[1] & 0x0001 )
-       {
-               if( status[0] & 0x0001 ) {
-                       // Connected
-                       // - Power on port
-                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_POWER, Port, 0, NULL);
-                       Time_Delay(info->PowerOnDelay);
-                       // - Reset
-                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_RESET, Port, 0, NULL);
-                       Time_Delay(20); // Spec says 10ms after reset, but how long is reset?
-                       // - Enable
-                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_ENABLE, Port, 0, NULL);
-                       // - Poke USB Stack
-                       USB_DeviceConnected(info->HubPtr, Port);
-               }
-               else {
-                       // Disconnected
-                       USB_DeviceDisconnected(info->HubPtr, Port);
-               }
-               
-               USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_CONNECTION, Port, 0, NULL);
-       }
-       
-       // Reset change
-       if( status[1] & 0x0010 )
-       {
-               if( status[0] & 0x0010 ) {
-                       // Reset complete
-               }
-               else {
-                       // Useful?
-               }
-               // ACK
-               USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_RESET, Port, 0, NULL);
-       }
-}
diff --git a/Modules/USB/Core/include/usb_core.h b/Modules/USB/Core/include/usb_core.h
deleted file mode 100644 (file)
index 43af16f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb_core.h
- * - Core USB IO Header 
- */
-#ifndef _USB_CORE_H_
-#define _USB_CORE_H_
-
-#include <acess.h>
-
-typedef struct sUSBInterface   tUSBInterface;
-typedef struct sUSBDriver      tUSBDriver;
-
-typedef void   (*tUSB_DataCallback)(tUSBInterface *Dev, int EndPt, int Length, void *Data);
-
-/**
- */
-struct sUSBDriver
-{
-       tUSBDriver      *Next;
-       
-       const char      *Name;
-
-        int    MatchType;      // 0: Interface, 1: Device, 2: Vendor
-       union { 
-               struct {
-                       // 23:16 - Interface Class
-                       // 15:8  - Interface Sub Class
-                       // 7:0   - Interface Protocol
-                       Uint32  ClassCode;
-                       Uint32  ClassMask;
-               } Class;
-               struct {
-                       Uint16  VendorID;
-                       Uint16  DeviceID;
-               } VendorDev;
-       } Match;
-
-       void    (*Connected)(tUSBInterface *Dev);
-       void    (*Disconnected)(tUSBInterface *Dev);
-
-        int    MaxEndpoints;   
-       struct {
-               // USB Attrbute byte
-               // NOTE: Top bit indicates the direction (1=Input)
-               Uint8   Attributes;
-               // Data availiable Callback
-               tUSB_DataCallback       DataAvail;
-       } Endpoints[];
-};
-
-extern void    *USB_GetDeviceDataPtr(tUSBInterface *Dev);
-extern void    USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
-
-extern void    USB_StartPollingEndpoint(tUSBInterface *Dev, int Endpoint);
-extern void    USB_ReadDescriptor(tUSBInterface *Dev, int Type, int Index, int Length, void *Data);
-extern void    USB_Request(tUSBInterface *Dev, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
-// TODO: Async
-extern void    USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-extern void    USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-extern void    USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback);
-
-#endif
-
diff --git a/Modules/USB/Core/include/usb_host.h b/Modules/USB/Core/include/usb_host.h
deleted file mode 100644 (file)
index c5f3e39..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb_host.h
- * - USB Host Controller Interface
- */
-#ifndef _USB_HOST_H_
-#define _USB_HOST_H_
-
-#include "usb_core.h"
-#include "usb_hub.h"
-
-typedef struct sUSBHostDef     tUSBHostDef;
-
-typedef void   (*tUSBHostCb)(void *DataPtr, void *Data, int Length);
-
-typedef void   *(*tUSBHostOp)(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb CB, void *CbData, void *Data, size_t Length);
-
-/**
- * \brief Defines a USB Host Controller type
- */
-struct sUSBHostDef
-{
-       tUSBHostOp      SendIN;
-       tUSBHostOp      SendOUT;
-       tUSBHostOp      SendSETUP;
-
-        int    (*IsOpComplete)(void *Ptr, void *OpPtr);
-
-       void    (*CheckPorts)(void *Ptr);
-};
-
-extern tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
-
-#endif
-
diff --git a/Modules/USB/Core/include/usb_hub.h b/Modules/USB/Core/include/usb_hub.h
deleted file mode 100644 (file)
index 6b32d49..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb_hub.h
- * - Core Hub Definitions
- */
-#ifndef _USB_HUB_H_
-#define _USB_HUB_H_
-
-#include "usb_core.h"
-
-typedef struct sUSBHub tUSBHub;
-
-/**
- * \brief Register a device as a hub
- * 
- * Used by the hub class initialisation routine.
- */
-extern tUSBHub *USB_RegisterHub(tUSBInterface *Device, int nPorts);
-extern void    USB_RemoveHub(tUSBHub *Hub);
-
-extern void    USB_DeviceConnected(tUSBHub *Hub, int Port);
-extern void    USB_DeviceDisconnected(tUSBHub *Hub, int Port);
-
-#endif
-
diff --git a/Modules/USB/Core/main.c b/Modules/USB/Core/main.c
deleted file mode 100644 (file)
index df7f174..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Acess2
- * USB Stack
- */
-#define VERSION        ( (0<<8)| 5 )
-#define DEBUG  1
-#include <acess.h>
-#include <vfs.h>
-#include <fs_devfs.h>
-#include <modules.h>
-#include "usb.h"
-
-// === IMPORTS ===
-extern void    USB_PollThread(void *unused);
-extern void    USB_AsyncThread(void *Unused);
-
-// === PROTOTYPES ===
- int   USB_Install(char **Arguments);
-void   USB_Cleanup(void);
-char   *USB_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *USB_FindDir(tVFS_Node *Node, const char *Name);
- int   USB_IOCtl(tVFS_Node *Node, int Id, void *Data);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, USB_Core, USB_Install, NULL, NULL);
-tVFS_NodeType  gUSB_RootNodeType = {
-       .ReadDir = USB_ReadDir,
-       .FindDir = USB_FindDir,
-       .IOCtl = USB_IOCtl
-};
-tDevFS_Driver  gUSB_DrvInfo = {
-       NULL, "usb", {
-               .NumACLs = 1,
-               .ACLs = &gVFS_ACL_EveryoneRX,
-               .Flags = VFS_FFLAG_DIRECTORY,
-               .Type = &gUSB_RootNodeType
-       }
-};
-tUSBHost       *gUSB_Hosts = NULL;
-
-// === CODE ===
-/**
- * \brief Called once module is loaded
- */
-int USB_Install(char **Arguments)
-{
-       Log_Warning("USB", "Not Complete - Devel Only");
-       
-       Proc_SpawnWorker(USB_PollThread, NULL);
-       Proc_SpawnWorker(USB_AsyncThread, NULL);
-       
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Called just before module is unloaded
- */
-void USB_Cleanup()
-{
-}
-
-/**
- * \fn char *USB_ReadDir(tVFS_Node *Node, int Pos)
- * \brief Read from the USB root
- */
-char *USB_ReadDir(tVFS_Node *Node, int Pos)
-{
-       return NULL;
-}
-
-/**
- * \fn tVFS_Node *USB_FindDir(tVFS_Node *Node, const char *Name)
- * \brief Locate an entry in the USB root
- */
-tVFS_Node *USB_FindDir(tVFS_Node *Node, const char *Name)
-{
-       return NULL;
-}
-
-/**
- * \brief Handles IOCtl Calls to the USB driver
- */
-int USB_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
-       return 0;
-}
diff --git a/Modules/USB/Core/usb.c b/Modules/USB/Core/usb.c
deleted file mode 100644 (file)
index b319580..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb.c
- * - USB Structure
- */
-#define DEBUG  1
-#include <acess.h>
-#include <vfs.h>
-#include <drv_pci.h>
-#include "usb.h"
-
-// === IMPORTS ===
-extern tUSBHost        *gUSB_Hosts;
-extern tUSBDriver gUSBHub_Driver;
-
-// === STRUCTURES ===
-
-// === PROTOTYPES ===
-tUSBHub        *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
-
-// === GLOBALS ===
-tUSBDriver     *gpUSB_InterfaceDrivers = &gUSBHub_Driver;
-
-// === CODE ===
-tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts)
-{
-       tUSBHost        *host;
-       
-       host = malloc(sizeof(tUSBHost) + nPorts*sizeof(void*));
-       if(!host) {
-               // Oh, bugger.
-               return NULL;
-       }
-       host->HostDef = HostDef;
-       host->Ptr = ControllerPtr;
-       memset(host->AddressBitmap, 0, sizeof(host->AddressBitmap));
-
-       host->RootHubDev.ParentHub = NULL;
-       host->RootHubDev.Host = host;
-       host->RootHubDev.Address = 0;
-
-//     host->RootHubIf.Next = NULL;
-       host->RootHubIf.Dev = &host->RootHubDev;
-       host->RootHubIf.Driver = NULL;
-       host->RootHubIf.Data = NULL;
-       host->RootHubIf.nEndpoints = 0;
-
-       host->RootHub.Interface = &host->RootHubIf;
-       host->RootHub.nPorts = nPorts;
-       memset(host->RootHub.Devices, 0, sizeof(void*)*nPorts);
-
-       // TODO: Lock
-       host->Next = gUSB_Hosts;
-       gUSB_Hosts = host;
-
-       return &host->RootHub;
-}
-
-// --- Drivers ---
-void USB_RegisterDriver(tUSBDriver *Driver)
-{
-       Log_Warning("USB", "TODO: Implement USB_RegisterDriver");
-}
-
-tUSBDriver *USB_int_FindDriverByClass(Uint32 ClassCode)
-{
-       ENTER("xClassCode", ClassCode);
-       for( tUSBDriver *ret = gpUSB_InterfaceDrivers; ret; ret = ret->Next )
-       {
-               LOG(" 0x%x & 0x%x == 0x%x?", ClassCode, ret->Match.Class.ClassMask, ret->Match.Class.ClassCode);
-               if( (ClassCode & ret->Match.Class.ClassMask) == ret->Match.Class.ClassCode )
-               {
-                       LOG("Found '%s'", ret->Name);
-                       LEAVE('p', ret);
-                       return ret;
-               }
-       }
-       LEAVE('n');
-       return NULL;
-}
-
-// --- Hub Registration ---
-// NOTE: Doesn't do much nowdays
-tUSBHub *USB_RegisterHub(tUSBInterface *Device, int PortCount)
-{
-       tUSBHub *ret;
-       
-       ret = malloc(sizeof(tUSBHub) + sizeof(ret->Devices[0])*PortCount);
-       ret->Interface = Device;
-       ret->nPorts = PortCount;
-       memset(ret->Devices, 0, sizeof(ret->Devices[0])*PortCount);
-       return ret;
-}
-
-void USB_RemoveHub(tUSBHub *Hub)
-{
-       for( int i = 0; i < Hub->nPorts; i ++ )
-       {
-               if( Hub->Devices[i] )
-               {
-                       USB_DeviceDisconnected( Hub, i );
-               }
-       }
-       free(Hub);
-}
-
diff --git a/Modules/USB/Core/usb.h b/Modules/USB/Core/usb.h
deleted file mode 100644 (file)
index 5a13363..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- * 
- * usb.h
- * - USB Internal definitions
- */
-#ifndef _USB_H_
-#define _USB_H_
-
-#include <usb_core.h>
-#include <usb_hub.h>
-#include <usb_host.h>
-
-typedef struct sUSBHost        tUSBHost;
-typedef struct sUSBDevice      tUSBDevice;
-typedef struct sUSBEndpoint    tUSBEndpoint;
-
-// === STRUCTURES ===
-/**
- * \brief USB Hub data
- */
-struct sUSBHub
-{
-       tUSBInterface   *Interface;
-       
-        int    nPorts;
-       tUSBDevice      *Devices[];
-};
-
-struct sUSBEndpoint
-{
-       tUSBEndpoint    *Next;  // (usb_poll.c) Clock list
-       tUSBInterface   *Interface;
-        int    EndpointIdx;    // Interface endpoint index
-        int    EndpointNum;    // Device endpoint num
-       
-        int    PollingPeriod;  // In 1ms intervals
-        int    MaxPacketSize;  // In bytes
-       Uint8   Type;   // Same as sUSBDriver.Endpoints.Type
-       
-        int    PollingAtoms;   // (usb_poll.c) Period in clock list
-       void    *InputData;
-};
-
-/**
- * \brief Structure for a device's interface
- */
-struct sUSBInterface
-{
-//     tUSBInterface   *Next;
-       tUSBDevice      *Dev;
-
-       tUSBDriver      *Driver;
-       void    *Data;
-       
-        int    nEndpoints;
-       tUSBEndpoint    Endpoints[];
-};
-
-/**
- * \brief Defines a single device on the USB Bus
- */
-struct sUSBDevice
-{
-       tUSBHub *ParentHub;
-
-       /**
-        * \brief Host controller used
-        */
-       tUSBHost        *Host;
-        int    Address;
-
-        int    nInterfaces;
-       tUSBInterface   *Interfaces[];
-};
-
-struct sUSBHost
-{
-       struct sUSBHost *Next;
-       
-       tUSBHostDef     *HostDef;
-       void    *Ptr;
-       
-       Uint8   AddressBitmap[128/8];
-       
-       tUSBDevice      RootHubDev;
-       tUSBInterface   RootHubIf;
-       tUSBHub RootHub;
-};
-
-extern tUSBDriver      *USB_int_FindDriverByClass(Uint32 ClassCode);
-
-#endif
diff --git a/Modules/USB/Core/usb_devinit.c b/Modules/USB/Core/usb_devinit.c
deleted file mode 100644 (file)
index d01d7d1..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Acess 2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb_devinit.c
- * - USB Device Initialisation
- */
-#define DEBUG  1
-
-#include <acess.h>
-#include <vfs.h>
-#include <drv_pci.h>
-#include "usb.h"
-#include "usb_proto.h"
-#include "usb_lowlevel.h"
-
-// === PROTOTYPES ===
-void   USB_DeviceConnected(tUSBHub *Hub, int Port);
-void   USB_DeviceDisconnected(tUSBHub *Hub, int Port);
-void   *USB_GetDeviceDataPtr(tUSBInterface *Dev);
-void   USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
- int   USB_int_AllocateAddress(tUSBHost *Host);
-
-// === CODE ===
-void USB_DeviceConnected(tUSBHub *Hub, int Port)
-{
-       tUSBDevice      tmpdev;
-       tUSBDevice      *dev = &tmpdev;
-       if( Port >= Hub->nPorts )       return ;
-       if( Hub->Devices[Port] )        return ;
-
-       ENTER("pHub iPort", Hub, Port);
-
-       // Device should be in 'Default' state
-       
-       // Create structure
-       dev->ParentHub = Hub;
-       dev->Host = Hub->Interface->Dev->Host;
-       dev->Address = 0;
-
-       // 1. Assign an address
-       dev->Address = USB_int_AllocateAddress(dev->Host);
-       if(dev->Address == 0) {
-               Log_Error("USB", "No addresses avaliable on host %p", dev->Host);
-               free(dev);
-               LEAVE('-');
-               return ;
-       }
-       USB_int_SendSetupSetAddress(dev->Host, dev->Address);
-       LOG("Assigned address %i", dev->Address);
-       
-       // 2. Get device information
-       {
-               struct sDescriptor_Device       desc;
-               LOG("Getting device descriptor");
-               // Endpoint 0, Desc Type 1, Index 0
-               USB_int_ReadDescriptor(dev, 0, 1, 0, sizeof(desc), &desc);
-               
-               LOG("Device Descriptor = {");
-               LOG(" .Length = %i", desc.Length);
-               LOG(" .Type = %i", desc.Type);
-               LOG(" .USBVersion = 0x%04x", desc.USBVersion);
-               LOG(" .DeviceClass = 0x%02x", desc.DeviceClass);
-               LOG(" .DeviceSubClass = 0x%02x", desc.DeviceSubClass);
-               LOG(" .DeviceProtocol = 0x%02x", desc.DeviceProtocol);
-               LOG(" .MaxPacketSize = 0x%02x", desc.MaxPacketSize);
-               LOG(" .VendorID = 0x%04x", desc.VendorID);
-               LOG(" .ProductID = 0x%04x", desc.ProductID);
-               LOG(" .DeviceID = 0x%04x", desc.DeviceID);
-               LOG(" .ManufacturerStr = Str %i", desc.ManufacturerStr);
-               LOG(" .ProductStr = Str %i", desc.ProductStr);
-               LOG(" .SerialNumberStr = Str %i", desc.SerialNumberStr);
-               LOG(" .NumConfigurations = %i", desc.SerialNumberStr);
-               LOG("}");
-               
-               if( desc.ManufacturerStr )
-               {
-                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ManufacturerStr);
-                       LOG("ManufacturerStr = '%s'", tmp);
-                       free(tmp);
-               }
-               if( desc.ProductStr )
-               {
-                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ProductStr);
-                       LOG("ProductStr = '%s'", tmp);
-                       free(tmp);
-               }
-               if( desc.SerialNumberStr )
-               {
-                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.SerialNumberStr);
-                       LOG("SerialNumbertStr = '%s'", tmp);
-                       free(tmp);
-               }
-       }
-
-       // TODO: Support alternate configurations
-       
-       // 3. Get configurations
-       for( int i = 0; i < 1; i ++ )
-       {
-               struct sDescriptor_Configuration        desc;
-               void    *full_buf;
-               char    *cur_ptr;
-       
-               USB_int_ReadDescriptor(dev, 0, 2, i, sizeof(desc), &desc);
-               LOG("Configuration Descriptor %i = {", i);
-               LOG(" .Length = %i", desc.Length);
-               LOG(" .Type = %i", desc.Type);
-               LOG(" .TotalLength = 0x%x", LittleEndian16(desc.TotalLength));
-               LOG(" .NumInterfaces = %i", desc.NumInterfaces);
-               LOG(" .ConfigurationValue = %i", desc.ConfigurationValue);
-               LOG(" .ConfigurationStr = %i", desc.ConfigurationStr);
-               LOG(" .AttributesBmp = 0b%b", desc.AttributesBmp);
-               LOG(" .MaxPower = %i (*2mA)", desc.MaxPower);
-               LOG("}");
-               if( desc.ConfigurationStr ) {
-                       char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ConfigurationStr);
-                       LOG("ConfigurationStr = '%s'", tmp);
-                       free(tmp);
-               }
-
-               // TODO: Split here and allow some method of selection
-
-               // Allocate device now that we have the configuration
-               dev = malloc(sizeof(tUSBDevice) + desc.NumInterfaces * sizeof(void*));
-               memcpy(dev, &tmpdev, sizeof(tUSBDevice));
-               dev->nInterfaces = desc.NumInterfaces;
-       
-               // Allocate a temp buffer for config info
-               cur_ptr = full_buf = malloc( LittleEndian16(desc.TotalLength) );
-               USB_int_ReadDescriptor(dev, 0, 2, i, desc.TotalLength, full_buf);
-
-               cur_ptr += desc.Length;
-
-               // TODO: Interfaces
-               for( int j = 0; j < desc.NumInterfaces; j ++ )
-               {
-                       struct sDescriptor_Interface *iface;
-                       tUSBInterface   *dev_if;
-                       iface = (void*)cur_ptr;
-                       // TODO: Sanity check with remaining space
-                       cur_ptr += sizeof(*iface);
-
-                       LOG("Interface %i/%i = {", i, j);
-                       LOG(" .InterfaceNum = %i", iface->InterfaceNum);
-                       LOG(" .NumEndpoints = %i", iface->NumEndpoints);
-                       LOG(" .InterfaceClass = 0x%x", iface->InterfaceClass);
-                       LOG(" .InterfaceSubClass = 0x%x", iface->InterfaceSubClass);
-                       LOG(" .InterfaceProcol = 0x%x", iface->InterfaceProtocol);
-
-                       if( iface->InterfaceStr ) {
-                               char    *tmp = USB_int_GetDeviceString(dev, 0, iface->InterfaceStr);
-                               LOG(" .InterfaceStr = %i '%s'", iface->InterfaceStr, tmp);
-                               free(tmp);
-                       }
-                       LOG("}");
-
-                       dev_if = malloc(sizeof(tUSBInterface) + iface->NumEndpoints*sizeof(dev_if->Endpoints[0]));
-                       dev_if->Dev = dev;
-                       dev_if->Driver = NULL;
-                       dev_if->Data = NULL;
-                       dev_if->nEndpoints = iface->NumEndpoints;
-                       dev->Interfaces[j] = dev_if;
-
-                       // Copy interface data
-                       for( int k = 0; k < iface->NumEndpoints; k ++ )
-                       {
-                               struct sDescriptor_Endpoint *endpt;
-                               endpt = (void*)cur_ptr;
-                               // TODO: Sanity check with remaining space
-                               cur_ptr += sizeof(*endpt);
-                               
-                               LOG("Endpoint %i/%i/%i = {", i, j, k);
-                               LOG(" .Address = 0x%2x", endpt->Address);
-                               LOG(" .Attributes = 0b%8b", endpt->Attributes);
-                               LOG(" .MaxPacketSize = %i", LittleEndian16(endpt->MaxPacketSize));
-                               LOG(" .PollingInterval = %i", endpt->PollingInterval);
-                               LOG("}");
-                               
-                               dev_if->Endpoints[k].Next = NULL;
-                               dev_if->Endpoints[k].Interface = dev_if;
-                               dev_if->Endpoints[k].EndpointIdx = k;
-                               dev_if->Endpoints[k].EndpointNum = endpt->Address & 0x7F;
-                               dev_if->Endpoints[k].PollingPeriod = endpt->PollingInterval;
-                               dev_if->Endpoints[k].MaxPacketSize = LittleEndian16(endpt->MaxPacketSize);
-                               dev_if->Endpoints[k].Type = endpt->Attributes | (endpt->Address & 0x80);
-                               dev_if->Endpoints[k].PollingAtoms = 0;
-                               dev_if->Endpoints[k].InputData = NULL;
-                       }
-                       
-                       // Initialise driver
-                       dev_if->Driver = USB_int_FindDriverByClass(
-                                ((int)iface->InterfaceClass << 16)
-                               |((int)iface->InterfaceSubClass << 8)
-                               |((int)iface->InterfaceProtocol << 0)
-                               );
-                       if(!dev_if->Driver) {
-                               Log_Notice("USB", "No driver for Class %02x:%02x:%02x",
-                                       iface->InterfaceClass, iface->InterfaceSubClass, iface->InterfaceProtocol
-                                       );
-                       }
-                       else {
-                               dev_if->Driver->Connected( dev_if );
-                       }
-               }
-               
-               free(full_buf);
-       }
-
-       // Done.
-       LEAVE('-');
-}
-
-void USB_DeviceDisconnected(tUSBHub *Hub, int Port)
-{
-       
-}
-
-void *USB_GetDeviceDataPtr(tUSBInterface *Dev) { return Dev->Data; }
-void USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr) { Dev->Data = Ptr; }
-
-int USB_int_AllocateAddress(tUSBHost *Host)
-{
-        int    i;
-       for( i = 1; i < 128; i ++ )
-       {
-               if(Host->AddressBitmap[i/8] & (1 << (i%8)))
-                       continue ;
-               Host->AddressBitmap[i/8] |= 1 << (i%8);
-               return i;
-       }
-       return 0;
-}
-
-void USB_int_DeallocateAddress(tUSBHost *Host, int Address)
-{
-       Host->AddressBitmap[Address/8] &= ~(1 << (Address%8));
-}
-
diff --git a/Modules/USB/Core/usb_io.c b/Modules/USB/Core/usb_io.c
deleted file mode 100644 (file)
index 25ff59d..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb_io.c
- * - High-level IO
- */
-#define DEBUG  0
-
-#include <usb_core.h>
-#include "usb.h"
-#include "usb_lowlevel.h"
-#include <workqueue.h>
-
-typedef struct sAsyncOp        tAsyncOp;
-
-struct sAsyncOp
-{
-       tAsyncOp        *Next;
-       tUSBEndpoint    *Endpt;
-        int    Length;
-       void    *Data;
-};
-
-// === PROTOTYPES ===
-void   USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data);
-void   USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
-void   USB_AsyncCallback(void *Ptr, void *Buf, int Length);
-void   USB_AsyncThread(void *unused);
-
-// === GLOBALS ===
-tWorkqueue     gUSB_AsyncQueue;
-
-// === CODE ===
-void USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data)
-{
-       USB_int_ReadDescriptor(Iface->Dev, 0, Type, Index, Length, Data);
-}
-
-void USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data)
-{
-        int    endpt;
-
-       // Sanity check
-       if(Endpoint < 0 || Endpoint >= Iface->nEndpoints)
-               return ;        
-
-       // Get endpoint number
-       if(Endpoint)
-               endpt = Iface->Endpoints[Endpoint-1].EndpointNum;
-       else
-               endpt = 0;
-       
-       USB_int_Request(Iface->Dev->Host, Iface->Dev->Address, endpt, Type, Req, Value, Index, Len, Data);
-}
-
-
-void USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
-{
-       Log_Warning("USB", "TODO: Implement USB_SendData");
-}
-
-void USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
-{
-       Log_Warning("USB", "TODO: Implement USB_RecvData");
-}
-
-void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback)
-{
-       tAsyncOp *op;
-       tUSBHost *host;
-
-       ENTER("pDev iEndpoint iLength pDataBuf", Dev, Endpoint, Length, DataBuf); 
-
-       op = malloc(sizeof(*op));
-       op->Next = NULL;
-       op->Endpt = &Dev->Endpoints[Endpoint-1];
-       op->Length = Length;
-       op->Data = DataBuf;
-
-       // TODO: Handle transfers that are larger than one packet
-
-       host = Dev->Dev->Host;
-       LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum);
-       host->HostDef->SendIN(
-               host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum,
-               0, USB_AsyncCallback, op,
-               DataBuf, Length
-               );
-       
-       LEAVE('-');
-
-//     Log_Warning("USB", "TODO: Implement USB_RecvDataA");
-}
-
-void USB_AsyncCallback(void *Ptr, void *Buf, int Length)
-{
-       tAsyncOp *op = Ptr;
-       op->Length = Length;
-       LOG("adding %p to work queue", op);
-       Workqueue_AddWork(&gUSB_AsyncQueue, op);
-}
-
-void USB_AsyncThread(void *Unused)
-{
-       Threads_SetName("USB Async IO Thread");
-       for(;;)
-       {
-               tAsyncOp *op = Workqueue_GetWork(&gUSB_AsyncQueue);
-               tUSBInterface   *iface = op->Endpt->Interface;
-
-               LOG("op = %p", op);     
-
-               iface->Driver->Endpoints[op->Endpt->EndpointIdx].DataAvail(
-                       iface, op->Endpt->EndpointIdx,
-                       op->Length, op->Data);
-       }
-}
-
diff --git a/Modules/USB/Core/usb_lowlevel.c b/Modules/USB/Core/usb_lowlevel.c
deleted file mode 100644 (file)
index 0e53bad..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Acess 2 USB Stack
- * - By John Hodge (thePowersGang)
- * 
- * usb_lowlevel.c
- * - Low Level IO
- */
-#define DEBUG  1
-#include <acess.h>
-#include "usb.h"
-#include "usb_proto.h"
-#include "usb_lowlevel.h"
-
-// === PROTOTYPES ===
-void   *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
- int   USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
- int   USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
-char   *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
- int   _UTF16to8(Uint16 *Input, int InputLen, char *Dest);
-
-// === CODE ===
-void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
-{
-       void    *hdl;
-       // TODO: Sanity check (and check that Type is valid)
-       struct sDeviceRequest   req;
-       req.ReqType = Type;
-       req.Request = Req;
-       req.Value = LittleEndian16( Val );
-       req.Index = LittleEndian16( Indx );
-       req.Length = LittleEndian16( Len );
-       
-       hdl = Host->HostDef->SendSETUP(Host->Ptr, Addr, EndPt, 0, NULL, NULL, &req, sizeof(req));
-
-       // TODO: Data toggle?
-       // TODO: Multi-packet transfers
-       if( Type & 0x80 )
-       {
-               void    *hdl2;
-               
-               hdl = Host->HostDef->SendIN(Host->Ptr, Addr, EndPt, 0, NULL, NULL, Data, Len);
-
-               hdl2 = Host->HostDef->SendOUT(Host->Ptr, Addr, EndPt, 0, NULL, NULL, NULL, 0);
-               while( Host->HostDef->IsOpComplete(Host->Ptr, hdl2) == 0 )
-                       Time_Delay(1);
-       }
-       else
-       {
-               void    *hdl2;
-               
-               if( Len > 0 )
-                       hdl = Host->HostDef->SendOUT(Host->Ptr, Addr, EndPt, 0, NULL, NULL, Data, Len);
-               else
-                       hdl = NULL;
-               
-               // Status phase (DataToggle=1)
-               hdl2 = Host->HostDef->SendIN(Host->Ptr, Addr, EndPt, 1, NULL, NULL, NULL, 0);
-               while( Host->HostDef->IsOpComplete(Host->Ptr, hdl2) == 0 )
-                       Time_Delay(1);
-       }
-       return hdl;
-}
-
-int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address)
-{
-       USB_int_Request(Host, 0, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
-       return 0;
-}
-
-int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest)
-{
-       const int       ciMaxPacketSize = 0x400;
-       struct sDeviceRequest   req;
-        int    bToggle = 0;
-       void    *final;
-
-       req.ReqType = 0x80;
-       switch( Type & 0xF00 )
-       {
-       case 0x000:     req.ReqType |= (0 << 5);        break;  // Standard
-       case 0x100:     req.ReqType |= (1 << 5);        break;  // Class
-       case 0x200:     req.ReqType |= (2 << 5);        break;  // Vendor
-       }
-
-       req.Request = 6;        // GET_DESCRIPTOR
-       req.Value = LittleEndian16( ((Type & 0xFF) << 8) | (Index & 0xFF) );
-       req.Index = LittleEndian16( 0 );        // TODO: Language ID
-       req.Length = LittleEndian16( Length );
-       
-       Dev->Host->HostDef->SendSETUP(
-               Dev->Host->Ptr, Dev->Address, Endpoint,
-               0, NULL, NULL,
-               &req, sizeof(req)
-               );
-       
-       bToggle = 1;
-       while( Length > ciMaxPacketSize )
-       {
-               Dev->Host->HostDef->SendIN(
-                       Dev->Host->Ptr, Dev->Address, Endpoint,
-                       bToggle, NULL, NULL,
-                       Dest, ciMaxPacketSize
-                       );
-               bToggle = !bToggle;
-               Length -= ciMaxPacketSize;
-       }
-
-       final = Dev->Host->HostDef->SendIN(
-               Dev->Host->Ptr, Dev->Address, Endpoint,
-               bToggle, INVLPTR, NULL,
-               Dest, Length
-               );
-
-       while( Dev->Host->HostDef->IsOpComplete(Dev->Host->Ptr, final) == 0 )
-               Time_Delay(1);
-
-       return 0;
-}
-
-char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index)
-{
-       struct sDescriptor_String       str;
-        int    src_len, new_len;
-       char    *ret;
-
-       if(Index == 0)  return strdup("");
-       
-       USB_int_ReadDescriptor(Dev, Endpoint, 3, Index, sizeof(str), &str);
-       if(str.Length < 2) {
-               Log_Error("USB", "String %p:%i:%i:%i descriptor is undersized (%i)",
-                       Dev->Host, Dev->Address, Endpoint, Index, str.Length);
-               return NULL;
-       }
-//     if(str.Length > sizeof(str)) {
-//             // IMPOSSIBLE!
-//             Log_Error("USB", "String is %i bytes, which is over prealloc size (%i)",
-//                     str.Length, sizeof(str)
-//                     );
-//     }
-       src_len = (str.Length - 2) / sizeof(str.Data[0]);
-
-       LOG("&str = %p, src_len = %i", &str, src_len);
-
-       new_len = _UTF16to8(str.Data, src_len, NULL);   
-       ret = malloc( new_len + 1 );
-       _UTF16to8(str.Data, src_len, ret);
-       ret[new_len] = 0;
-       return ret;
-}
-
-int _UTF16to8(Uint16 *Input, int InputLen, char *Dest)
-{
-        int    str_len, cp_len;
-       Uint32  saved_bits = 0;
-       str_len = 0;
-       for( int i = 0; i < InputLen; i ++)
-       {
-               Uint32  cp;
-               Uint16  val = Input[i];
-               if( val >= 0xD800 && val <= 0xDBFF )
-               {
-                       // Multibyte - Leading
-                       if(i + 1 > InputLen) {
-                               cp = '?';
-                       }
-                       else {
-                               saved_bits = (val - 0xD800) << 10;
-                               saved_bits += 0x10000;
-                               continue ;
-                       }
-               }
-               else if( val >= 0xDC00 && val <= 0xDFFF )
-               {
-                       if( !saved_bits ) {
-                               cp = '?';
-                       }
-                       else {
-                               saved_bits |= (val - 0xDC00);
-                               cp = saved_bits;
-                       }
-               }
-               else
-                       cp = val;
-
-               cp_len = WriteUTF8((Uint8*)Dest, cp);
-               if(Dest)
-                       Dest += cp_len;
-               str_len += cp_len;
-
-               saved_bits = 0;
-       }
-       
-       return str_len;
-}
-
diff --git a/Modules/USB/Core/usb_lowlevel.h b/Modules/USB/Core/usb_lowlevel.h
deleted file mode 100644 (file)
index 9159cba..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- * 
- * usb_lowlevel.h
- * - Low-Level USB IO Functions
- */
-#ifndef _USB_LOWLEVEL_H_
-#define _USB_LOWLEVEL_H_
-
-extern void    *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
-extern int     USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
-extern int     USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
-extern char    *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
-
-#endif
diff --git a/Modules/USB/Core/usb_poll.c b/Modules/USB/Core/usb_poll.c
deleted file mode 100644 (file)
index b6927fe..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * usb_poll.c
- * - Endpoint polling
- */
-#define DEBUG  1
-#include <usb_core.h>
-#include "usb.h"
-
-#define POLL_ATOM      25      // 25ms atom
-#define POLL_MAX       256     // Max period that can be nominated
-#define POLL_SLOTS     ((int)(POLL_MAX/POLL_ATOM))
-
-// === IMPORTS ===
-extern tUSBHost        *gUSB_Hosts;
-
-// === PROTOTYPES ===
-void   USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint);
-
-// === GLOBALS ===
-tUSBEndpoint   *gUSB_PollQueues[POLL_MAX/POLL_ATOM];
- int   giUSB_PollPosition;     // Index into gUSB_PollQueues
-
-// === CODE ===
-void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint)
-{
-       tUSBEndpoint    *endpt;
-
-       // Some sanity checks
-       if(Endpoint <= 0 || Endpoint > Iface->nEndpoints)       return ;
-       endpt = &Iface->Endpoints[Endpoint-1];
-       if(endpt->PollingPeriod > POLL_MAX || endpt->PollingPeriod <= 0)
-               return ;
-
-       // TODO: Check that this endpoint isn't already on the queue
-
-       endpt->InputData = malloc(endpt->MaxPacketSize);
-
-       // Determine polling period in atoms
-       endpt->PollingAtoms = (endpt->PollingPeriod + POLL_ATOM-1) / POLL_ATOM;
-       if(endpt->PollingAtoms > POLL_SLOTS)    endpt->PollingAtoms = POLL_SLOTS;
-       // Add to poll queue
-       // TODO: Locking
-       {
-                int    idx = giUSB_PollPosition + 1;
-               if(idx >= POLL_SLOTS)   idx -= POLL_SLOTS;
-               endpt->Next = gUSB_PollQueues[idx];
-               gUSB_PollQueues[idx] = endpt;
-       }
-}
-
-/**
- * \brief USB polling thread
- */
-int USB_PollThread(void *unused)
-{
-       Threads_SetName("USB Polling Thread");
-       for(;;)
-       {
-               tUSBEndpoint    *ep, *prev;
-
-               if(giUSB_PollPosition == 0)
-               {
-                       // Check hosts
-                       for( tUSBHost *host = gUSB_Hosts; host; host = host->Next )
-                       {
-                               host->HostDef->CheckPorts(host->Ptr);
-                       }
-               }
-
-//             Log_Debug("USBPoll", "giUSB_PollPosition = %i", giUSB_PollPosition);
-
-               // A little evil for neater code
-               prev = (void*)( (tVAddr)&gUSB_PollQueues[giUSB_PollPosition] - offsetof(tUSBEndpoint, Next) );
-
-               // Process queue
-//             LOG("giUSB_PollPosition = %i", giUSB_PollPosition);
-               for( ep = gUSB_PollQueues[giUSB_PollPosition]; ep; prev = ep, ep = ep->Next )
-               {
-                        int    period_in_atoms = ep->PollingAtoms;
-//                     LOG("%i: ep = %p", giUSB_PollPosition, ep);
-
-                       // Check for invalid entries
-                       if(period_in_atoms < 0 || period_in_atoms > POLL_ATOM)
-                       {
-                               Log_Warning("USB", "Endpoint on polling queue with invalid period");
-                               continue ;
-                       }
-                       // Check for entries to delete
-                       if(period_in_atoms == 0)
-                       {
-                               // Remove
-                               prev->Next = ep->Next;
-                               ep->PollingAtoms = -1;  // Mark as removed
-                               ep = prev;      // Make sure prev is kept valid
-                               continue ;
-                       }
-
-                       // Read data
-                       // TODO: Check the endpoint
-                       // TODO: Async checking?
-                       // - Send the read request on all of them then wait for the first to complete
-                       USB_RecvDataA(
-                               ep->Interface, ep->EndpointIdx+1,
-                               ep->MaxPacketSize, ep->InputData,
-                               ep->Interface->Driver->Endpoints[ep->EndpointIdx].DataAvail
-                               );
-                               
-                       // Call callback
-
-                       // Reschedule
-                       if( period_in_atoms != POLL_SLOTS )
-                       {
-                                int    newqueue_id = (giUSB_PollPosition + period_in_atoms) % POLL_SLOTS;
-                               tUSBEndpoint    **newqueue = &gUSB_PollQueues[newqueue_id];
-                               
-                               prev->Next = ep->Next;
-                               
-                               ep->Next = *newqueue;
-                               *newqueue = ep;
-                               ep = prev;
-                       }
-               }
-               giUSB_PollPosition ++;
-               if(giUSB_PollPosition == POLL_SLOTS)
-                       giUSB_PollPosition = 0;
-               // TODO: Check for a longer delay
-               Time_Delay(POLL_ATOM);
-       }
-}
-
diff --git a/Modules/USB/Core/usb_proto.h b/Modules/USB/Core/usb_proto.h
deleted file mode 100644 (file)
index 5641dd2..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Acess2 USB Stack
- * - By John Hodge (thePowersGang)
- * 
- * usb_proto.h
- * - USB Core Protocol Definitions
- */
-#ifndef _USB_PROTO_H_
-#define _USB_PROTO_H_
-
-struct sDeviceRequest
-{
-       Uint8   ReqType;
-       Uint8   Request;
-       Uint16  Value;
-       Uint16  Index;
-       Uint16  Length;
-};
-
-/*
- */
-struct sDescriptor_Device
-{
-       Uint8   Length;
-       Uint8   Type;   // = 1
-       Uint16  USBVersion;     // BCD, 0x210 = 2.10
-       Uint8   DeviceClass;
-       Uint8   DeviceSubClass;
-       Uint8   DeviceProtocol;
-       Uint8   MaxPacketSize;
-       
-       Uint16  VendorID;
-       Uint16  ProductID;
-       Uint16  DeviceID;       // BCD
-       
-       Uint8   ManufacturerStr;
-       Uint8   ProductStr;
-       Uint8   SerialNumberStr;
-       
-       Uint8   NumConfigurations;
-} PACKED;
-
-struct sDescriptor_Configuration
-{
-       Uint8   Length;
-       Uint8   Type;   // = 2
-       
-       Uint16  TotalLength;
-       Uint8   NumInterfaces;
-       Uint8   ConfigurationValue;
-       Uint8   ConfigurationStr;
-       Uint8   AttributesBmp;
-       Uint8   MaxPower;       // in units of 2 mA
-} PACKED;
-
-struct sDescriptor_String
-{
-       Uint8   Length;
-       Uint8   Type;   // = 3
-       
-       Uint16  Data[128-1];    // (256 bytes - 2 bytes) / Uint16
-} PACKED;
-
-struct sDescriptor_Interface
-{
-       Uint8   Length;
-       Uint8   Type;   // = 4
-       
-       Uint8   InterfaceNum;
-       Uint8   AlternateSetting;
-       Uint8   NumEndpoints;   // Excludes endpoint 0
-       
-       Uint8   InterfaceClass; // 
-       Uint8   InterfaceSubClass;
-       Uint8   InterfaceProtocol;
-       
-       Uint8   InterfaceStr;
-} PACKED;
-
-struct sDescriptor_Endpoint
-{
-       Uint8   Length;
-       Uint8   Type;   // = 5
-       Uint8   Address;        // 3:0 Endpoint Num, 7: Direction (1=IN)
-       /**
-        * 1:0 - Transfer Type
-        * - 00 = Control
-        * - 01 = Isochronous
-        * - 10 = Bulk
-        * - 11 = Interrupt
-        * 3:2 - Synchronisation type (Isonchronous only)
-        * - 00 = No Synchronisation
-        * - 01 = Asynchronous
-        * - 10 = Adaptive
-        * - 11 = Synchronous
-        * 5:4 - Usage type (Isonchronous only)
-        * - 00 = Data endpoint
-        * - 01 = Feedback endpoint
-        */
-       Uint8   Attributes;
-       
-       Uint16  MaxPacketSize;
-       
-       /**
-        * 
-        */
-       Uint8   PollingInterval;
-} PACKED;
-
-#endif
-
diff --git a/Modules/USB/HID/hid.h b/Modules/USB/HID/hid.h
deleted file mode 100644 (file)
index 373496e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Acess2 USB Stack HID Driver
- * - By John Hodge (thePowersGang)
- *
- * hid.h
- * - Core header
- */
-#ifndef _HID_H_
-#define _HID_H_
-
-// Report Descriptor Types
-// - 0: Main
-//  > 8: Input - Axis/Button etc
-//  > 9: Output - LED/Position
-//  > B: Feature -
-//  > A: Collection - Group of Input/Output/Feature
-//  > C: End collection
-// - 1: Global (Not restored on main)
-// - 2: Local
-//  > 
-// - 3: Reserved/Unused
-
-// I/O/F Data Values
-#define HID_IOF_CONSTANT       0x001   //!< Host Read-only
-#define HID_IOF_VARIABLE       0x002   //!< 
-
-struct sLongItem
-{
-       Uint8   Header; // 0xFE (Tag 15, Type 3, Size 2)
-       Uint8   DataSize;
-       Uint8   Tag;
-};
-
-struct sDescriptor_HID
-{
-       Uint8   Length;
-       Uint8   Type;   // 
-       Uint16  Version;        // 0x0111 = 1.11
-       Uint8   CountryCode;
-       Uint8   NumDescriptors; // >= 1
-       struct {
-               Uint8   DescType;
-               Uint16  DescLen;
-       } Descriptors[];
-}
-
-#endif
diff --git a/Modules/USB/HID/keysyms.h b/Modules/USB/HID/keysyms.h
deleted file mode 100644 (file)
index 558464e..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Acess2 USB Stack HID Driver
- * - By John Hodge (thePowersGang)
- *
- * usb_keysyms.h
- * - USB HID Keyboard Symbols
- */
-#ifndef _USB_KEYSYMS_H_
-#define _USB_KEYSYMS_H_
-
-enum eUSB_Keysyms
-{
-       KEYSYM_NONE,
-       KEYSYM_ERRORROLLOVER,
-       KEYSYM_POSTFAIL,
-       KEYSYM_ERRORUNDEFINED,
-       // 0x04 / 4
-       KEYSYM_a, KEYSYM_b, KEYSYM_c,
-       KEYSYM_d, KEYSYM_e, KEYSYM_f,
-       KEYSYM_g, KEYSYM_h, KEYSYM_i,
-       KEYSYM_j, KEYSYM_k, KEYSYM_l,
-       KEYSYM_m, KEYSYM_n, KEYSYM_o,
-       KEYSYM_p, KEYSYM_q, KEYSYM_r,
-       KEYSYM_s, KEYSYM_t, KEYSYM_u,
-       KEYSYM_v, KEYSYM_w, KEYSYM_x,
-       KEYSYM_y, KEYSYM_z,
-       
-       // 0x1E / 30
-       KEYSYM_1, KEYSYM_2,
-       KEYSYM_3, KEYSYM_4,
-       KEYSYM_5, KEYSYM_6,
-       KEYSYM_7, KEYSYM_8,
-       KEYSYM_9, KEYSYM_0,
-       
-       KEYSYM_RETURN,  // Enter
-       KEYSYM_ESC,     // Esc.
-       KEYSYM_BACKSP,  // Backspace
-       KEYSYM_TAB,     // Tab
-       KEYSYM_SPACE,   // Spacebar
-       KEYSYM_MINUS,   // - _
-       KEYSYM_EQUALS,  // = +
-       KEYSYM_SQUARE_OPEN,     // [ {
-       KEYSYM_SQUARE_CLOSE,    // ] }
-       KEYSYM_BACKSLASH,       // \ |
-       KEYSYM_HASH_TILDE,      // # ~ (Non-US)
-       KEYSYM_SEMICOLON,       // ; :
-       KEYSYM_QUOTE,   // ' "
-       KEYSYM_GRAVE_TILDE,     // Grave Accent, Tilde
-       KEYSYM_COMMA,   // , <
-       KEYSYM_PERIOD,  // . >
-       KEYSYM_SLASH,   // / ?
-       KEYSYM_CAPS,    // Caps Lock
-       KEYSYM_F1, KEYSYM_F2,
-       KEYSYM_F3, KEYSYM_F4,
-       KEYSYM_F5, KEYSYM_F6,
-       KEYSYM_F7, KEYSYM_F8,
-       KEYSYM_F9, KEYSYM_F10,
-       KEYSYM_F11, KEYSYM_F12,
-       KEYSYM_PRINTSCREEN,
-       KEYSYM_SCROLLLOCK,
-       KEYSYM_PAUSE,
-       KEYSYM_INSERT,
-       KEYSYM_HOME,
-       KEYSYM_PGUP,
-       KEYSYM_DELETE,
-       KEYSYM_END,
-       KEYSYM_PGDN,
-       KEYSYM_RIGHTARROW,
-       KEYSYM_LEFTARROW,
-       KEYSYM_DOWNARROW,
-       KEYSYM_UPARROW,
-       
-       KEYSYM_NUMLOCK,
-       KEYSYM_KPSLASH,
-       KEYSYM_KPSTAR,
-       KEYSYM_KPMINUS,
-       KEYSYM_KPPLUS,
-       KEYSYM_KPENTER,
-       KEYSYM_KP1,
-       KEYSYM_KP2,
-       KEYSYM_KP3,
-       KEYSYM_KP4,
-       KEYSYM_KP5,
-       KEYSYM_KP7,
-       KEYSYM_KP8,
-       KEYSYM_KP9
-       KEYSYM_KP0,
-       KEYSYM_KPPERIOD,
-       
-       KEYSYM_NONUS_BACKSLASH,
-       KEYSYM_APPLICATION,     // Windows Key
-       KEYSYM_POWER,
-       KEYSYM_KPEQUALS,
-       
-       KEYSYM_F13, KEYSYM_F14,
-       KEYSYM_F15, KEYSYM_F16,
-       KEYSYM_F17, KEYSYM_F18,
-       KEYSYM_F19, KEYSYM_F20,
-       KEYSYM_F21, KEYSYM_F22,
-       KEYSYM_F23, KEYSYM_F24,
-       KEYSYM_EXECUTE,
-       KEYSYM_HELP,
-       KEYSYM_MENU,
-       KEYSYM_SELECT,
-       KEYSYM_STOP,
-       KEYSYM_AGAIN,
-       KEYSYM_UNDO,
-       KEYSYM_CUT,
-       KEYSYM_COPY,
-       KEYSYM_PASTE,
-       KEYSYM_FIND,
-       KEYSYM_MUTE,
-       KEYSYM_VOLUP,
-       KEYSYM_VOLDN,
-       KEYSYM_LOCKING_CAPS,    // Physically toggles
-       KEYSYM_LOGKING_NUM,
-       KEYSYM_LOGKING_SCROLL,
-       KEYSYM_KPCOMMA
-       
-       // TODO: Define the rest
-};
-
-#endif
-
diff --git a/Modules/USB/HID/main.c b/Modules/USB/HID/main.c
deleted file mode 100644 (file)
index 31375b0..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Acess2 USB Stack HID Driver
- * - By John Hodge (thePowersGang)
- *
- * main.c
- * - Driver Core
- */
-#define DEBUG  0
-#define VERSION        VER2(0,1)
-#include <acess.h>
-#include <usb_core.h>
-
-// === PROTOTYPES ===
- int   HID_Initialise(const char **Arguments);
-void   HID_DeviceConnected(tUSBInterface *Dev);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, USB_HID, HID_Initialise, NULL, "USB_Core", NULL);
-tUSBDriver     gHID_Driver = {
-       .Name = "HID",
-       .Match = {.Class = {0x030000, 0xFF0000}},
-       .Connected = HID_DeviceConnected,
-};
-
-// === CODE ===
-int HID_Initialise(const char **Arguments)
-{
-       USB_RegisterDriver( &gHID_Driver );
-       return 0;
-}
-
-void HID_DeviceConnected(tUSBInterface *Dev)
-{
-       
-}
-
diff --git a/Modules/USB/Makefile.tpl b/Modules/USB/Makefile.tpl
deleted file mode 100644 (file)
index 8df7098..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = USB
-
--include ../../Makefile.tpl
diff --git a/Modules/USB/UHCI/Makefile b/Modules/USB/UHCI/Makefile
deleted file mode 100644 (file)
index 798159a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#
-
-OBJ = uhci.o
-CPPFLAGS = -I../Core/include
-NAME = UHCI
-
--include ../Makefile.tpl
diff --git a/Modules/USB/UHCI/uhci.c b/Modules/USB/UHCI/uhci.c
deleted file mode 100644 (file)
index 7b40b14..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Acess 2 USB Stack
- * - By John Hodge (thePowersGang)
- *
- * Universal Host Controller Interface
- */
-#define DEBUG  0
-#define VERSION        VER2(0,5)
-#include <acess.h>
-#include <vfs.h>
-#include <drv_pci.h>
-#include <modules.h>
-#include <usb_host.h>
-#include "uhci.h"
-
-// === CONSTANTS ===
-#define        MAX_CONTROLLERS 4
-#define NUM_TDs        1024
-
-// === PROTOTYPES ===
- int   UHCI_Initialise(char **Arguments);
-void   UHCI_Cleanup();
-tUHCI_TD       *UHCI_int_AllocateTD(tUHCI_Controller *Cont);
-void   UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD);
-void   *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void   *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void   *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData,  void *Buf, size_t Length);
-void   *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
- int   UHCI_IsTransferComplete(void *Ptr, void *Handle);
- int   UHCI_Int_InitHost(tUHCI_Controller *Host);
-void   UHCI_CheckPortUpdate(void *Ptr);
-void   UHCI_InterruptHandler(int IRQ, void *Ptr);
-// 
-static void    _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value);
-static void    _OutWord(tUHCI_Controller *Host, int Reg, Uint16 Value);
-static void    _OutDWord(tUHCI_Controller *Host, int Reg, Uint32 Value);
-static Uint16  _InWord(tUHCI_Controller *Host, int Reg);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, USB_UHCI, UHCI_Initialise, NULL, "USB_Core", NULL);
-tUHCI_TD       gaUHCI_TDPool[NUM_TDs];
-tUHCI_Controller       gUHCI_Controllers[MAX_CONTROLLERS];
-tUSBHostDef    gUHCI_HostDef = {
-       .SendIN = UHCI_DataIN,
-       .SendOUT = UHCI_DataOUT,
-       .SendSETUP = UHCI_SendSetup,
-       .CheckPorts = UHCI_CheckPortUpdate,
-       .IsOpComplete = UHCI_IsTransferComplete
-       };
-
-// === CODE ===
-/**
- * \fn int UHCI_Initialise()
- * \brief Called to initialise the UHCI Driver
- */
-int UHCI_Initialise(char **Arguments)
-{
-        int    i=0, id=-1;
-        int    ret;
-       
-       ENTER("");
-       
-       // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices
-       while( (id = PCI_GetDeviceByClass(0x0C0300, 0xFFFFFF, id)) >= 0 && i < MAX_CONTROLLERS )
-       {
-               tUHCI_Controller        *cinfo = &gUHCI_Controllers[i];
-               Uint32  base_addr;
-               // NOTE: Check "protocol" from PCI?
-               
-               cinfo->PciId = id;
-               base_addr = PCI_GetBAR(id, 4);
-               
-               if( base_addr & 1 )
-               {
-                       cinfo->IOBase = base_addr & ~1;
-                       cinfo->MemIOMap = NULL;
-               }
-               else
-               {
-                       cinfo->MemIOMap = (void*)MM_MapHWPages(base_addr, 1);
-               }
-               cinfo->IRQNum = PCI_GetIRQ(id);
-               
-               Log_Debug("UHCI", "Controller PCI #%i: IO Base = 0x%x, IRQ %i",
-                       id, base_addr, cinfo->IRQNum);
-               
-               IRQ_AddHandler(cinfo->IRQNum, UHCI_InterruptHandler, cinfo);
-       
-               // Initialise Host
-               ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]);
-               // Detect an error
-               if(ret != 0) {
-                       LEAVE('i', ret);
-                       return ret;
-               }
-               
-               cinfo->RootHub = USB_RegisterHost(&gUHCI_HostDef, cinfo, 2);
-               LOG("cinfo->RootHub = %p", cinfo->RootHub);
-
-               i ++;
-       }
-
-       if(i == 0) {
-               LEAVE('i', MODULE_ERR_NOTNEEDED);
-               return MODULE_ERR_NOTNEEDED;
-       }
-
-       if(i == MAX_CONTROLLERS) {
-               Log_Warning("UHCI", "Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest");
-       }
-       LEAVE('i', MODULE_ERR_OK);
-       return MODULE_ERR_OK;
-}
-
-/**
- * \fn void UHCI_Cleanup()
- * \brief Called just before module is unloaded
- */
-void UHCI_Cleanup()
-{
-}
-
-tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont)
-{
-        int    i;
-       for(i = 0; i < NUM_TDs; i ++)
-       {
-               if(gaUHCI_TDPool[i].Link == 0) {
-                       gaUHCI_TDPool[i].Link = 1;
-                       gaUHCI_TDPool[i].Control = 1 << 23;
-                       return &gaUHCI_TDPool[i];
-               }
-               // Still in use? Skip
-               if( gaUHCI_TDPool[i].Control & (1 << 23) )
-                       continue ;
-               // Is there a callback on it? Skip
-               if( gaUHCI_TDPool[i]._info.Callback )
-                       continue ;
-               // TODO: Garbage collect, but that means removing from the list too
-               #if 0
-               // Ok, this is actually unused
-               gaUHCI_TDPool[i].Link = 1;
-               gaUHCI_TDPool[i].Control = 1 << 23;
-               return &gaUHCI_TDPool[i];
-               #endif
-       }
-       return NULL;
-}
-
-tUHCI_TD *UHCI_int_GetTDFromPhys(tPAddr PAddr)
-{
-       // TODO: Fix this to work with a non-contiguous pool
-       static tPAddr   td_pool_base;
-       const int pool_size = NUM_TDs;
-        int    offset;
-       if(!td_pool_base)       td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
-       offset = (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
-       if( offset < 0 || offset >= pool_size )
-       {
-               Log_Error("UHCI", "TD PAddr %P not from pool", PAddr);
-               return NULL;
-       }
-       return gaUHCI_TDPool + offset;
-}
-
-void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD)
-{
-        int    next_frame = (_InWord(Cont, FRNUM) + 2) & (1024-1);
-       tUHCI_TD        *prev_td;
-       Uint32  link;
-
-       // TODO: How to handle FRNUM incrementing while we are in this function?
-
-       // Empty list
-       if( Cont->FrameList[next_frame] & 1 )
-       {
-               // TODO: Ensure 32-bit paddr
-               Cont->FrameList[next_frame] = MM_GetPhysAddr( (tVAddr)TD );
-               TD->Control |= (1 << 24);       // Ensure that there is an interrupt for each used frame
-               LOG("next_frame = %i", next_frame);     
-               return;
-       }
-
-       // Find the end of the list
-       link = Cont->FrameList[next_frame];
-       do {
-               prev_td = UHCI_int_GetTDFromPhys(link);
-               link = prev_td->Link;
-       } while( !(link & 1) );
-       
-       // Append
-       prev_td->Link = MM_GetPhysAddr( (tVAddr)TD );
-
-       LOG("next_frame = %i, prev_td = %p", next_frame, prev_td);
-}
-
-/**
- * \brief Send a transaction to the USB bus
- * \param Cont Controller pointer
- * \param Addr Function Address * 16 + Endpoint
- * \param bTgl Data toggle value
- */
-void *UHCI_int_SendTransaction(
-       tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl,
-       tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
-{
-       tUHCI_TD        *td;
-
-       if( Length > 0x400 )    return NULL;    // Controller allows up to 0x500, but USB doesn't
-
-       td = UHCI_int_AllocateTD(Cont);
-
-       if( !td ) {
-               // TODO: Wait for one to free?
-               Log_Error("UHCI", "No avaliable TDs, transaction dropped");
-               return NULL;
-       }
-
-       td->Link = 1;
-       td->Control = (Length - 1) & 0x7FF;
-       td->Control |= (1 << 23);
-       td->Token  = ((Length - 1) & 0x7FF) << 21;
-       td->Token |= (bTgl & 1) << 19;
-       td->Token |= (Addr & 0xF) << 15;
-       td->Token |= ((Addr/16) & 0xFF) << 8;
-       td->Token |= Type;
-
-       // TODO: Ensure 32-bit paddr
-       if( ((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE ) {
-               Log_Warning("UHCI", "TODO: Support non single page transfers (%x + %x > %x)",
-                       (tVAddr)Data & (PAGE_SIZE-1), Length, PAGE_SIZE
-                       );
-               // TODO: Need to enable IOC to copy the data back
-//             td->BufferPointer = 
-               td->_info.bCopyData = 1;
-               return NULL;
-       }
-       else {
-               td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
-               td->_info.bCopyData = 0;
-       }
-
-       // Interrupt on completion
-       if( Cb ) {
-               td->Control |= (1 << 24);
-               LOG("IOC Cb=%p CbData=%p", Cb, CbData);
-               td->_info.Callback = Cb;        // NOTE: if ERRPTR then the TD is kept allocated until checked
-               td->_info.CallbackPtr = CbData;
-       }
-       
-       td->_info.DataPtr = Data;
-
-       UHCI_int_AppendTD(Cont, td);
-
-       return td;
-}
-
-void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
-{
-       return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x69, DataTgl, Cb, CbData, Buf, Length);
-}
-
-void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
-{
-       return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0xE1, DataTgl, Cb, CbData, Buf, Length);
-}
-
-void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
-{
-       return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, Cb, CbData, Buf, Length);
-}
-
-int UHCI_IsTransferComplete(void *Ptr, void *Handle)
-{
-       tUHCI_TD        *td = Handle;
-        int    ret;
-       ret = !(td->Control & (1 << 23));
-       if(ret) {
-               td->_info.Callback = NULL;
-               td->Link = 0;
-       }
-       return ret;
-}
-
-// === INTERNAL FUNCTIONS ===
-/**
- * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host)
- * \brief Initialises a UHCI host controller
- * \param Host Pointer - Host to initialise
- */
-int UHCI_Int_InitHost(tUHCI_Controller *Host)
-{
-       ENTER("pHost", Host);
-
-       _OutWord( Host, USBCMD, 4 );    // GRESET
-       // TODO: Wait for at least 10ms
-       _OutWord( Host, USBCMD, 0 );    // GRESET
-       
-       // Allocate Frame List
-       // - 1 Page, 32-bit address
-       // - 1 page = 1024  4 byte entries
-       Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList);
-       if( !Host->FrameList ) {
-               Log_Warning("UHCI", "Unable to allocate frame list, aborting");
-               LEAVE('i', -1);
-               return -1;
-       }
-       LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList);
-       memsetd( Host->FrameList, 1, 1024 );    // Clear List (Disabling all entries)
-       
-       //! \todo Properly fill frame list
-       
-       // Set frame length to 1 ms
-       _OutByte( Host, SOFMOD, 64 );
-       
-       // Set Frame List
-       _OutDWord( Host, FLBASEADD, Host->PhysFrameList );
-       _OutWord( Host, FRNUM, 0 );
-       
-       // Enable Interrupts
-       _OutWord( Host, USBINTR, 0x000F );
-       PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 );
-
-       // Enable processing
-       _OutWord( Host, USBCMD, 0x0001 );
-
-       LEAVE('i', 0);
-       return 0;
-}
-
-void UHCI_CheckPortUpdate(void *Ptr)
-{
-       tUHCI_Controller        *Host = Ptr;
-       // Enable ports
-       for( int i = 0; i < 2; i ++ )
-       {
-                int    port = PORTSC1 + i*2;
-               Uint16  status;
-       
-               status = _InWord(Host, port);
-               // Check for port change
-               if( !(status & 0x0002) )        continue;
-               _OutWord(Host, port, 0x0002);
-               
-               // Check if the port is connected
-               if( !(status & 1) )
-               {
-                       // Tell the USB code it's gone.
-                       USB_DeviceDisconnected(Host->RootHub, i);
-                       continue;
-               }
-               else
-               {
-                       LOG("Port %i has something", i);
-                       // Reset port (set bit 9)
-                       LOG("Reset");
-                       _OutWord(Host, port, 0x0200);
-                       Time_Delay(50); // 50ms delay
-                       _OutWord(Host, port, _InWord(Host, port) & ~0x0200);
-                       // Enable port
-                       LOG("Enable");
-                       Time_Delay(50); // 50ms delay
-                       _OutWord(Host, port, _InWord(Host, port) | 0x0004);
-                       // Tell USB there's a new device
-                       USB_DeviceConnected(Host->RootHub, i);
-               }
-       }
-}
-
-void UHCI_InterruptHandler(int IRQ, void *Ptr)
-{
-       tUHCI_Controller *Host = Ptr;
-        int    frame = (_InWord(Host, FRNUM) - 1) & 0x3FF;
-       Uint16  status = _InWord(Host, USBSTS);
-//     Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x, frame = %i", status, frame);
-       
-       // Interrupt-on-completion
-       if( status & 1 )
-       {
-               tPAddr  link;
-               
-               for( int i = 0; i < 10; i ++ )
-               {
-                       link = Host->FrameList[frame];
-                       Host->FrameList[frame] = 1;
-                       while( link && !(link & 1) )
-                       {
-                               tUHCI_TD *td = UHCI_int_GetTDFromPhys(link);
-                                int    byte_count = (td->Control&0x7FF)+1;
-                               LOG("link = 0x%x, td = %p, byte_count = %i", link, td, byte_count);
-                               // Handle non-page aligned destination
-                               // TODO: This will break if the destination is not in global memory
-                               if(td->_info.bCopyData)
-                               {
-                                       void *ptr = (void*)MM_MapTemp(td->BufferPointer);
-                                       Log_Debug("UHCI", "td->_info.DataPtr = %p", td->_info.DataPtr);
-                                       memcpy(td->_info.DataPtr, ptr, byte_count);
-                                       MM_FreeTemp((tVAddr)ptr);
-                               }
-                               // Callback
-                               if(td->_info.Callback && td->_info.Callback != INVLPTR)
-                               {
-                                       LOG("Calling cb %p", td->_info.Callback);
-                                       td->_info.Callback(td->_info.CallbackPtr, td->_info.DataPtr, byte_count);
-                                       td->_info.Callback = NULL;
-                               }
-                               link = td->Link;
-                               if( td->_info.Callback != INVLPTR )
-                                       td->Link = 0;
-                       }
-                       
-                       if(frame == 0)
-                               frame = 0x3ff;
-                       else
-                               frame --;
-               }
-               
-//             Host->LastCleanedFrame = frame;
-       }
-
-       LOG("status = 0x%02x", status);
-       _OutWord(Host, USBSTS, status);
-}
-
-void _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value)
-{
-       if( Host->MemIOMap )
-               ((Uint8*)Host->MemIOMap)[Reg] = Value;
-       else
-               outb(Host->IOBase + Reg, Value);
-}
-
-void _OutWord(tUHCI_Controller *Host, int Reg, Uint16 Value)
-{
-       if( Host->MemIOMap )
-               Host->MemIOMap[Reg/2] = Value;
-       else
-               outw(Host->IOBase + Reg, Value);
-}
-
-void _OutDWord(tUHCI_Controller *Host, int Reg, Uint32 Value)
-{
-       if( Host->MemIOMap )
-               ((Uint32*)Host->MemIOMap)[Reg/4] = Value;
-       else
-               outd(Host->IOBase + Reg, Value);
-}
-
-Uint16 _InWord(tUHCI_Controller *Host, int Reg)
-{
-       if( Host->MemIOMap )
-               return Host->MemIOMap[Reg/2];
-       else
-               return inw(Host->IOBase + Reg);
-}
-
diff --git a/Modules/USB/UHCI/uhci.h b/Modules/USB/UHCI/uhci.h
deleted file mode 100644 (file)
index a93459a..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * AcessOS Version 1
- * USB Stack
- * - Universal Host Controller Interface
- */
-#ifndef _UHCI_H_
-#define _UHCI_H_
-
-// === TYPES ===
-typedef struct sUHCI_Controller        tUHCI_Controller;
-typedef struct sUHCI_TD        tUHCI_TD;
-typedef struct sUHCI_QH        tUHCI_QH;
-
-// === STRUCTURES ===
-struct sUHCI_Controller
-{
-       /**
-        * \brief PCI Device ID
-        */
-       Uint16  PciId;
-       
-       /**
-        * \brief IO Base Address
-        */
-       Uint16  IOBase;
-       
-       /**
-        * \brief Memory Mapped-IO base address
-        */
-       Uint16  *MemIOMap;
-
-       /**
-        * \brief IRQ Number assigned to the device
-        */
-        int    IRQNum;
-
-       /**
-        * \brief Number of the last frame to be cleaned
-        */
-        int    LastCleanedFrame;
-       
-       /**
-        * \brief Frame list
-        * 
-        * 31:4 - Frame Pointer
-        * 3:2 - Reserved
-        * 1 - QH/TD Selector
-        * 0 - Terminate (Empty Pointer)
-        */
-       Uint32  *FrameList;
-       
-       /**
-        * \brief Physical Address of the Frame List
-        */
-       tPAddr  PhysFrameList;
-
-       tUSBHub *RootHub;
-};
-
-struct sUHCI_TD
-{
-       /**
-        * \brief Next Entry in list
-        * 
-        * 31:4 - Address
-        * 3 - Reserved
-        * 2 - Depth/Breadth Select
-        * 1 - QH/TD Select
-        * 0 - Terminate (Last in List)
-        */
-       Uint32  Link;
-       
-       /**
-        * \brief Control and Status Field
-        * 
-        * 31:30 - Reserved
-        * 29 - Short Packet Detect (Input Only)
-        * 28:27 - Number of Errors Allowed
-        * 26 - Low Speed Device (Communicating with a low speed device)
-        * 25 - Isynchonious Select
-        * 24 - Interrupt on Completion (IOC)
-        * 23:16 - Status
-        *     23 - Active
-        *     22 - Stalled
-        *     21 - Data Buffer Error
-        *     20 - Babble Detected
-        *     19 - NAK Detected
-        *     18 - CRC/Timout Error
-        *     17 - Bitstuff Error
-        *     16 - Reserved
-        * 15:11 - Reserved
-        * 10:0 - Actual Length (Number of bytes transfered)
-        */
-       Uint32  Control;
-       
-       /**
-        * \brief Packet Header
-        * 
-        * 31:21 - Maximum Length (0=1, Max 0x4FF, 0x7FF=0)
-        * 20 - Reserved
-        * 19 - Data Toggle
-        * 18:15 - Endpoint
-        * 14:8 - Device Address
-        * 7:0 - PID (Packet Identifcation) - Only 96, E1, 2D allowed
-        *
-        * 0x96 = Data IN
-        * 0xE1 = Data Out
-        * 0x2D = Setup
-        */
-       Uint32  Token;
-       
-       /**
-        * \brief Pointer to the data to send
-        */
-       Uint32  BufferPointer;
-
-       struct
-       {
-               tUSBHostCb      Callback;
-               void    *CallbackPtr;
-               void    *DataPtr;
-                int    bCopyData;
-       } _info;
-} __attribute__((aligned(16)));
-
-struct sUHCI_QH
-{
-       /**
-        * \brief Next Entry in list
-        * 
-        * 31:4 - Address
-        * 3:2 - Reserved
-        * 1 - QH/TD Select
-        * 0 - Terminate (Last in List)
-        */
-       Uint32  Next;
-
-       
-       /**
-        * \brief Next Entry in list
-        * 
-        * 31:4 - Address
-        * 3:2 - Reserved
-        * 1 - QH/TD Select
-        * 0 - Terminate (Last in List)
-        */
-       Uint32  Child;
-};
-
-// === ENUMERATIONS ===
-enum eUHCI_IOPorts {
-       /**
-        * \brief USB Command Register
-        * 
-        * 15:8 - Reserved
-        * 7 - Maximum Packet Size selector (1: 64 bytes, 0: 32 bytes)
-        * 6 - Configure Flag (No Hardware Effect)
-        * 5 - Software Debug (Don't think it will be needed)
-        * 4 - Force Global Resume
-        * 3 - Enter Global Suspend Mode
-        * 2 - Global Reset (Resets all devices on the bus)
-        * 1 - Host Controller Reset (Reset just the controller)
-        * 0 - Run/Stop
-        */
-       USBCMD  = 0x00,
-       /**
-        * \brief USB Status Register
-        * 
-        * 15:6 - Reserved
-        * 5 - HC Halted, set to 1 when USBCMD:RS is set to 0
-        * 4 - Host Controller Process Error (Errors related to the bus)
-        * 3 - Host System Error (Errors related to the OS/PCI Bus)
-        * 2 - Resume Detect (Set if a RESUME command is sent to the Controller)
-        * 1 - USB Error Interrupt
-        * 0 - USB Interrupts (Set if a transaction with the IOC bit set is completed)
-        */
-       USBSTS  = 0x02,
-       /**
-        * \brief USB Interrupt Enable Register
-        * 
-        * 15:4 - Reserved
-        * 3 - Short Packet Interrupt Enable
-        * 2 - Interrupt on Complete (IOC) Enable
-        * 1 - Resume Interrupt Enable
-        * 0 - Timout / CRC Error Interrupt Enable
-        */
-       USBINTR = 0x04,
-       /**
-        * \brief Frame Number (Index into the Frame List)
-        * 
-        * 15:11 - Reserved
-        * 10:0 - Index (Incremented each approx 1ms)
-        */
-       FRNUM   = 0x06,
-       /**
-        * \brief Frame List Base Address
-        * 
-        * 31:12 - Pysical Address >> 12
-        * 11:0 - Reserved (Set to Zero)
-        */
-       FLBASEADD = 0x08,       // 32-bit
-       /**
-        * \brief Start-of-frame Modify Register
-        * \note 8-bits only
-        * 
-        * Sets the size of a frame
-        * Frequency = (11936+n)/12000 kHz
-        * 
-        * 7 - Reserved
-        * 6:0 -
-        */
-       SOFMOD = 0x0C,  // 8bit
-       /**
-        * \brief Port Status and Controll Register (Port 1)
-        * 
-        * 15:13 - Reserved
-        * 12 - Suspend
-        * 11:10 - Reserved
-        * 9 - Port Reset
-        * 8 - Low Speed Device Attached
-        * 5:4 - Line Status
-        * 3 - Port Enable/Disable Change - Used for detecting device removal
-        * 2 - Port Enable/Disable
-        * 1 - Connect Status Change
-        * 0 - Current Connect Status
-        */
-       PORTSC1 = 0x10,
-       /**
-        * \brief Port Status and Controll Register (Port 2)
-        * 
-        * See ::PORTSC1
-        */
-       PORTSC2 = 0x12
-};
-
-#endif
diff --git a/Modules/armv7/GIC/Makefile b/Modules/armv7/GIC/Makefile
deleted file mode 100644 (file)
index d4a72b6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ := gic.o
-NAME := GIC
-
--include ../Makefile.tpl
diff --git a/Modules/armv7/GIC/gic.c b/Modules/armv7/GIC/gic.c
deleted file mode 100644 (file)
index 8dbab3a..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ARMv7 GIC Support
- * - By John Hodge (thePowersGang)
- * 
- * gic.c
- * - GIC Core
- */
-#define DEBUG  1
-
-#include <acess.h>
-#include <modules.h>
-#include "gic.h"
-#include <options.h>
-
-#define N_IRQS 1024
-
-// === IMPORTS ===
-extern void    *gpIRQHandler;
-
-// === TYPES ===
-typedef void (*tIRQ_Handler)(int, void*);
-
-// === PROTOTYPES ===
- int   GIC_Install(char **Arguments);
-void   GIC_IRQHandler(void);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x100, armv7_GIC, GIC_Install, NULL, NULL);
-Uint32 *gpGIC_DistributorBase;
-Uint32 *gpGIC_InterfaceBase;
-tPAddr gGIC_DistributorAddr;
-tPAddr gGIC_InterfaceAddr;
-tIRQ_Handler   gaIRQ_Handlers[N_IRQS];
-void   *gaIRQ_HandlerData[N_IRQS];
-
-// === CODE ===
-int GIC_Install(char **Arguments)
-{
-       // Realview PB
-       gGIC_InterfaceAddr   = 0x1e000000;
-       gGIC_DistributorAddr = 0x1e001000;
-
-       // Initialise
-       gpGIC_InterfaceBase = (void*)MM_MapHWPages(gGIC_InterfaceAddr, 1);
-       LOG("gpGIC_InterfaceBase = %p", gpGIC_InterfaceBase);
-       gpGIC_DistributorBase = (void*)MM_MapHWPages(gGIC_DistributorAddr, 1);
-       LOG("gpGIC_DistributorBase = %p", gpGIC_DistributorBase);
-
-       gpGIC_InterfaceBase[GICC_PMR] = 0xFF;   
-       gpGIC_InterfaceBase[GICC_CTLR] = 1;     // Enable CPU
-       gpGIC_DistributorBase[GICD_CTLR] = 1;   // Enable Distributor
-
-       gpIRQHandler = GIC_IRQHandler;
-
-       __asm__ __volatile__ ("cpsie if");      // Enable IRQs and FIQs
-
-       return MODULE_ERR_OK;
-}
-
-void GIC_IRQHandler(void)
-{
-       Uint32  num = gpGIC_InterfaceBase[GICC_IAR];
-//     Log_Debug("GIC", "IRQ 0x%x", num);
-       gaIRQ_Handlers[num]( num, gaIRQ_HandlerData[num] );
-       gpGIC_InterfaceBase[GICC_EOIR] = num;
-}
-
-int IRQ_AddHandler(int IRQ, tIRQ_Handler Handler, void *Ptr)
-{
-       if( IRQ < 0 || IRQ >= N_IRQS-32 ) {
-               return 1;
-       }
-       
-       LOG("IRQ = %i", IRQ);
-       IRQ += 32;      // 32 internal IRQs
-       LOG("IRQ = %i (after adjust)", IRQ);
-       LOG("mask = 0x%x", 1 << (IRQ & (31-1)));
-       gpGIC_DistributorBase[GICD_ISENABLER0+IRQ/32] = 1 << (IRQ & (32-1));
-       ((Uint8*)&gpGIC_DistributorBase[GICD_ITARGETSR0])[IRQ] = 1;
-       
-//     Log_Warning("GIC", "TODO: Implement IRQ_AddHandler");
-       
-       if( gaIRQ_Handlers[IRQ] )
-               return 2;
-       
-       gaIRQ_Handlers[IRQ] = Handler;
-       gaIRQ_HandlerData[IRQ] = Ptr;
-       
-       return 0;
-}
-
diff --git a/Modules/armv7/GIC/gic.h b/Modules/armv7/GIC/gic.h
deleted file mode 100644 (file)
index d7a5a8d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * ARMv7 GIC Support
- * - By John Hodge (thePowersGang)
- * 
- * gic.h
- * - GIC Core Definitions
- */
-#ifndef _ARM7_GIC_H_
-#define _ARM7_GIC_H_
-
-enum eGICD_Registers
-{
-       GICD_CTLR       = 0x000/4,      // Distributor Control Register
-       GICD_TYPER      = 0x004/4,      // Interrupt Controller Type
-       GICD_IIDR       = 0x008/4,      // Distributor Implementer Identifcation
-       
-       GICD_IGROUPR0   = 0x080/4,      // Interrupt Group Register (#0)
-       GICD_ISENABLER0 = 0x100/4,      // Interrupt Set-Enable Register #0 (128*8=1024)
-       GICD_ICENABLER0 = 0x180/4,      // Interrupt Clear-Enable Register #0
-       GICD_ISPENDR0   = 0x200/4,      // Interrupt Set-Pending Register #0
-       GICD_ICPENDR0   = 0x280/4,      // Interrupt Clear-Pending Register #0
-       GICD_ISACTIVER0 = 0x300/4,      // Interrupt Set-Active Register (GICv2)
-       GICD_ICACTIVER0 = 0x380/4,      // Interrupt Clear-Active Register (GICv2)
-       
-       GICD_IPRIORITYR0 = 0x400/4,     // Interrupt priority registers (254*4 = )
-       
-       GICD_ITARGETSR0 = 0x800/4,      // Interrupt Processor Targets Register (8*4)
-
-       GICD_ICFGR0     = 0xC00/4,      // Interrupt Configuration Register (64*4)
-       GICD_NSACR0     = 0xE00/4,      // Non-secure Access Control Register (64*4)
-       GICD_SIGR       = 0xF00/4,      // Software Generated Interrupt Register (Write Only)
-       GICD_CPENDSGIR0 = 0xF10/4,      // SGI Clear-Pending Registers (4*4)
-       GICD_SPENDSGIR0 = 0xF20/4,      // SGI Set-Pending Registers (4*4)
-};
-
-enum eGICC_Registers
-{
-       GICC_CTLR   = 0x000/4,  // CPU Interface Control Register
-       GICC_PMR    = 0x004/4,  // Interrupt Priority Mask Register
-       GICC_BPR    = 0x008/4,  // Binary Point Register
-       GICC_IAR    = 0x00C/4,  // Interrupt Acknowledge Register
-       GICC_EOIR   = 0x010/4,  // End of Interrupt Register
-       GICC_RPR    = 0x014/4,  // Running Priority Register
-       GICC_HPPIR  = 0x018/4,  // Highest Priority Pending Interrupt Register
-       GICC_ABPR   = 0x01C/4,  // Aliased Binary Point Register
-       GICC_AIAR   = 0x020/4,  // Aliased Interrupt Acknowledge Register,
-       GICC_AEOIR  = 0x024/4,  // Aliased End of Interrupt Register
-       GICC_AHPPIR = 0x028/4,  // Aliased Highest Priority Pending Interrupt Register
-
-       GICC_APR0   = 0x0D0/4,  // Active Priorities Registers (4*4)
-       GICC_NSAPR0 = 0x0E0/4,  // Non-secure Active Priorities Registers (4*4)
-       
-       GICC_IIDR   = 0x0FC/4,  // CPU Interface Identifcation Register
-       GICC_DIR    = 0x0FC/4,  // Deactivate Interrupt Register (Write Only)
-};
-
-#endif
diff --git a/Modules/armv7/Makefile.tpl b/Modules/armv7/Makefile.tpl
deleted file mode 100644 (file)
index 58eb3c9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = armv7
-
--include ../../Makefile.tpl
diff --git a/Modules/link.ld b/Modules/link.ld
deleted file mode 100644 (file)
index 503f63d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Acess2 Kernel Modules
- * Linker Script
- */
-
-ENTRY(ModuleEntry)
-OUTPUT_FORMAT(elf32-i386)
-
-SECTIONS 
-{
-       . = 0 + SIZEOF_HEADERS;
-       
-       .text : AT(ADDR(.text)) {
-               textzero = .;
-               *(.text)
-       }
-       
-       .rodata ALIGN(0x1000): AT(ADDR(.rodata)) {
-               *(.rodata)
-               *(.rdata)
-               DriverInfo = .;
-               *(KMODULES)
-       }
-       
-       .data ALIGN (0x1000) : AT(ADDR(.data)) {
-               *(.data)
-       }
-
-       .bss : AT(ADDR(.bss)) {
-               _sbss = .;
-               *(COMMON)
-               *(.bss)
-               _ebss = .;
-       }
-}
diff --git a/Modules/x86/ISADMA/Makefile b/Modules/x86/ISADMA/Makefile
deleted file mode 100644 (file)
index b74c63f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ := dma.o
-NAME := ISADMA
-
--include ../Makefile.tpl
diff --git a/Modules/x86/ISADMA/dma.c b/Modules/x86/ISADMA/dma.c
deleted file mode 100644 (file)
index 732a93c..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*\r
- * AcessOS 1.0\r
- * DMA Driver\r
- */\r
-#include <acess.h>\r
-#include <modules.h>\r
-\r
-#define DMA_SIZE       (0x2400)\r
-#define DMA_ADDRESS(c) ((c)*DMA_SIZE+0x500)    //Save Space for IDT and BDA\r
-\r
-#define LOWB(x)        ((x)&0xFF)\r
-#define HIB(x) (((x)>>8)&0xFF)\r
-#define HIW(x) (((x)>>16)&0xFFFF)\r
-\r
-// === TYPES ===\r
-typedef struct\r
-{\r
-        int    mode;\r
-       char    *address;\r
-} t_dmaChannel;\r
-\r
-// === PROTOTYPES ===\r
- int   DMA_Install(char **Arguments);\r
-void   DMA_SetChannel(int Channel, int length, int read);\r
- int   DMA_ReadData(int channel, int count, void *buffer);\r
- int   DMA_WriteData(int channel, int count, const void *buffer);\r
-\r
-// === CONSTANTS ===\r
-const Uint8 cMASKPORT [8] = { 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 };\r
-const Uint8 cMODEPORT [8] = { 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 };\r
-const Uint8 cCLEARPORT[8] = { 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 };\r
-const Uint8 cPAGEPORT [8] = { 0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A };\r
-const Uint8 cADDRPORT [8] = { 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC };\r
-const Uint8 cCOUNTPORT[8] = { 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE };\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, 0x0100, x86_ISADMA, DMA_Install, NULL, NULL);\r
-char   *dma_addresses[8];\r
-t_dmaChannel   dma_channels[8];\r
-\r
-// === CODE ===\r
-/**\r
- * \brief Initialise DMA channels\r
- * \param Arguments    Arguments passed at boot time\r
- */\r
-int DMA_Install(char **Arguments)\r
-{\r
-       Uint    i;\r
-       for(i=8;i--;)\r
-       {\r
-               outb( cMASKPORT[i], 0x04 | (i & 0x3) ); // mask channel\r
-               outb( cCLEARPORT[i], 0x00 );\r
-               outb( cMODEPORT[i], 0x48 | (i & 0x3) ); //Read Flag\r
-               outb( 0xd8, 0xff);      //Reset Flip-Flop\r
-               outb( cADDRPORT[i], LOWB(DMA_ADDRESS(i)) );     // send address\r
-               outb( cADDRPORT[i], HIB(DMA_ADDRESS(i)) );      // send address\r
-               outb( 0xd8, 0xff);      //Reset Flip-Flop\r
-               outb( cCOUNTPORT[i], LOWB(DMA_SIZE) );      // send size\r
-               outb( cCOUNTPORT[i], HIB(DMA_SIZE) );       // send size\r
-               outb( cPAGEPORT[i], LOWB(HIW(DMA_ADDRESS(i))) );        // send page\r
-               outb( cMASKPORT[i], i & 0x3 );              // unmask channel\r
-               \r
-               dma_channels[i].mode = 0;\r
-               dma_addresses[i] = (char*)DMA_ADDRESS(i);\r
-               dma_addresses[i] += KERNEL_BASE;\r
-       }\r
-       return MODULE_ERR_OK;\r
-}\r
-\r
-/**\r
- * \fn void DMA_SetChannel(int Channel, int length, int read)\r
- * \brief Set DMA Channel Length and RW\r
- */\r
-void DMA_SetChannel(int Channel, int length, int read)\r
-{\r
-       Uint    chan = Channel & 7;\r
-       read = !!read;\r
-       if(length > DMA_SIZE)   length = DMA_SIZE;\r
-       length --;      //Adjust for DMA\r
-       outb( cMASKPORT[chan], 0x04 | (chan & 0x3) );           // mask channel\r
-       outb( cCLEARPORT[chan], 0x00 );\r
-       outb( cMODEPORT[chan], (0x44 + (!read)*4) | (chan & 0x3) );\r
-       outb( cADDRPORT[chan], LOWB(DMA_ADDRESS(chan)) );               // send address\r
-       outb( cADDRPORT[chan], HIB(DMA_ADDRESS(chan)) );                // send address\r
-       outb( cPAGEPORT[chan], HIW(DMA_ADDRESS(chan)) );                // send page\r
-       outb( cCOUNTPORT[chan], LOWB(length) );      // send size\r
-       outb( cCOUNTPORT[chan], HIB(length) );       // send size\r
-       outb( cMASKPORT[chan], chan & 0x3 );              // unmask channel\r
-       dma_addresses[chan] = (char*)DMA_ADDRESS(chan);\r
-       dma_addresses[chan] += KERNEL_BASE;\r
-}\r
-\r
-/**\r
- * \fn void DMA_ReadData(int channel, int count, void *buffer)\r
- * \brief Read data from a DMA buffer\r
- */\r
-int DMA_ReadData(int channel, int count, void *buffer)\r
-{\r
-       if(channel < 0 || channel > 7)\r
-               return -1;\r
-       if(count < 0 || count > DMA_SIZE)\r
-               return -2;\r
-       //LogF("memcpy(*0x%x, dma_channels[channel].address, count)\n", buffer\r
-       memcpy(buffer, dma_addresses[channel], count);\r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn void DMA_WriteData(int channel, int count, void *buffer)\r
- * \brief Write data to a DMA buffer\r
- */\r
-int DMA_WriteData(int channel, int count, const void *buffer)\r
-{\r
-       if(channel < 0 || channel > 7)\r
-               return -1;\r
-       if(count < 0 || count > DMA_SIZE)\r
-               return -2;\r
-       \r
-       memcpy(dma_addresses[channel], buffer, count);\r
-       \r
-       return 0;\r
-}\r
diff --git a/Modules/x86/ISADMA/include/dma.h b/Modules/x86/ISADMA/include/dma.h
deleted file mode 100644 (file)
index b1a6d1a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Acess2 DMA Driver
- */
-#ifndef _DMA_H_
-#define _DMA_H_
-
-extern void    DMA_SetChannel(int channel, int length, int read);
-extern int     DMA_ReadData(int channel, int count, void *buffer);
-extern int     DMA_WriteData(int channel, int count, void *buffer);
-
-#endif
diff --git a/Modules/x86/Makefile.tpl b/Modules/x86/Makefile.tpl
deleted file mode 100644 (file)
index 61b234f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-CATEGORY = x86
-
--include ../../Makefile.tpl
diff --git a/Modules/x86/VGAText/Makefile b/Modules/x86/VGAText/Makefile
deleted file mode 100644 (file)
index 8f1aee6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-#
-
-OBJ := vga.o
-NAME := VGAText
-
--include ../Makefile.tpl
diff --git a/Modules/x86/VGAText/vga.c b/Modules/x86/VGAText/vga.c
deleted file mode 100644 (file)
index 41f0bd0..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Acess2 VGA Controller Driver
- */
-#define DEBUG  0
-#include <acess.h>
-#include <fs_devfs.h>
-#include <api_drv_video.h>
-#include <modules.h>
-
-// === CONSTANTS ===
-#define        VGA_WIDTH       80
-#define        VGA_HEIGHT      25
-
-// === PROTOTYPES ===
- int   VGA_Install(char **Arguments);
-Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
- int   VGA_IOCtl(tVFS_Node *Node, int Id, void *Data);
-Uint8  VGA_int_GetColourNibble(Uint16 col);
-Uint16 VGA_int_GetWord(const tVT_Char *Char);
-void   VGA_int_SetCursor(Sint16 x, Sint16 y);
-// --- 2D Acceleration Functions --
-void   VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
-void   VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x000A, x86_VGAText, VGA_Install, NULL, NULL);
-tVFS_NodeType  gVGA_NodeType = {
-       //.Read = VGA_Read,
-       .Write = VGA_Write,
-       .IOCtl = VGA_IOCtl
-       };
-tDevFS_Driver  gVGA_DevInfo = {
-       NULL, "x86_VGAText",
-       {
-       .NumACLs = 0,
-       .Size = VGA_WIDTH*VGA_HEIGHT*sizeof(tVT_Char),
-       .Type = &gVGA_NodeType
-       }
-};
-Uint16 *gVGA_Framebuffer = (void*)( KERNEL_BASE|0xB8000 );
- int   giVGA_BufferFormat = VIDEO_BUFFMT_TEXT;
-tDrvUtil_Video_2DHandlers      gVGA_2DFunctions = {
-       NULL,
-       VGA_2D_Fill,
-       VGA_2D_Blit
-};
-
-// === CODE ===
-/**
- * \fn int VGA_Install(char **Arguments)
- */
-int VGA_Install(char **Arguments)
-{
-       Uint8   byte;
-       
-       // Enable Bright Backgrounds
-       inb(0x3DA);     // Reset flipflop
-       outb(0x3C0, 0x30);      // Index 0x10, PAS
-       byte = inb(0x3C1);
-       byte &= ~8;     // Disable Blink
-       outb(0x3C0, byte);      // Write value
-       
-       
-       // Install DevFS
-       DevFS_AddDevice( &gVGA_DevInfo );
-       
-       return MODULE_ERR_OK;
-}
-
-/**
- * \brief Writes a string of bytes to the VGA controller
- */
-Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
-{
-       if( giVGA_BufferFormat == VIDEO_BUFFMT_TEXT )
-       {
-                int    num = Length / sizeof(tVT_Char);
-                int    ofs = Offset / sizeof(tVT_Char);
-                int    i = 0;
-               const tVT_Char  *chars = Buffer;
-               Uint16  word;
-               
-               //ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-               
-               for( ; num--; i ++, ofs ++)
-               {
-                       word = VGA_int_GetWord( &chars[i] );
-                       gVGA_Framebuffer[ ofs ] = word;
-               }
-               
-               //LEAVE('X', Length);
-               return Length;
-       }
-       else if( giVGA_BufferFormat == VIDEO_BUFFMT_2DSTREAM )
-       {
-               return DrvUtil_Video_2DStream(NULL, Buffer, Length, &gVGA_2DFunctions, sizeof(gVGA_2DFunctions));
-       }
-       else
-       {
-               return 0;
-       }
-}
-
-/**
- * \fn int VGA_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief IO Control Call
- */
-int VGA_IOCtl(tVFS_Node *Node, int ID, void *Data)
-{
-        int    rv;
-       switch(ID)
-       {
-       case DRV_IOCTL_TYPE:    return DRV_TYPE_VIDEO;
-       case DRV_IOCTL_IDENT:   memcpy(Data, "VGA\0", 4);       return 1;
-       case DRV_IOCTL_VERSION: *(int*)Data = 50;       return 1;
-       case DRV_IOCTL_LOOKUP:  return 0;
-       
-       case VIDEO_IOCTL_GETSETMODE:    return 0;       // Mode 0 only
-       case VIDEO_IOCTL_FINDMODE:
-               if( !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)) )        return -1;
-               ((tVideo_IOCtl_Mode*)Data)->id = 0;     // Text Only!
-       case VIDEO_IOCTL_MODEINFO:
-               if( !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)) )        return -1;
-               if( ((tVideo_IOCtl_Mode*)Data)->id != 0)        return 0;
-               ((tVideo_IOCtl_Mode*)Data)->width = VGA_WIDTH*giVT_CharWidth;
-               ((tVideo_IOCtl_Mode*)Data)->height = VGA_HEIGHT*giVT_CharHeight;
-               ((tVideo_IOCtl_Mode*)Data)->bpp = 4;
-               return 1;
-       
-       case VIDEO_IOCTL_SETBUFFORMAT:
-               if( !CheckMem(Data, sizeof(int)) )      return -1;
-               switch( *(int*)Data )
-               {
-               case VIDEO_BUFFMT_TEXT:
-               case VIDEO_BUFFMT_2DSTREAM:
-                       rv = giVGA_BufferFormat;
-                       giVGA_BufferFormat = *(int*)Data;
-//                     Log_Debug("VGA", "Buffer format set to %i", giVGA_BufferFormat);
-                       return rv;
-               default:
-                       break;
-               }
-               return -1;
-       
-       case VIDEO_IOCTL_SETCURSOR:
-               VGA_int_SetCursor( ((tVideo_IOCtl_Pos*)Data)->x, ((tVideo_IOCtl_Pos*)Data)->y );
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)
- * \brief Converts a 12-bit colour into a VGA 4-bit colour
- */
-Uint8 VGA_int_GetColourNibble(Uint16 col)
-{
-       Uint8   ret = 0;
-        int    bright = 0;
-       
-       col = col & 0xCCC;
-       col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
-       bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
-       
-       switch(col)
-       {
-       //      Black
-       case 0x00:      ret = 0x0;      break;
-       // Dark Grey
-       case 0x15:      ret = 0x8;      break;
-       // Blues
-       case 0x01:
-       case 0x02:      ret = 0x1;      break;
-       case 0x03:      ret = 0x9;      break;
-       // Green
-       case 0x04:
-       case 0x08:      ret = 0x2;      break;
-       case 0x0C:      ret = 0xA;      break;
-       // Reds
-       case 0x10:
-       case 0x20:      ret = 0x4;      break;
-       case 0x30:      ret = 0xC;      break;
-       // Light Grey
-       case 0x2A:      ret = 0x7;      break;
-       // White
-       case 0x3F:      ret = 0xF;      break;
-       
-       default:
-               ret |= (col & 0x03 ? 1 : 0);
-               ret |= (col & 0x0C ? 2 : 0);
-               ret |= (col & 0x30 ? 4 : 0);
-               ret |= (bright ? 8 : 0);
-               break;
-       }
-       return ret;
-}
-
-/**
- * \fn Uint16 VGA_int_GetWord(tVT_Char *Char)
- * \brief Convers a character structure to a VGA character word
- */
-Uint16 VGA_int_GetWord(const tVT_Char *Char)
-{
-       Uint16  ret;
-       Uint16  col;
-       
-       // Get Character
-       if(Char->Ch < 128)
-               ret = Char->Ch;
-       else {
-               switch(Char->Ch)
-               {
-               default:        ret = 0;        break;
-               }
-       }
-       
-       col = VGA_int_GetColourNibble(Char->BGCol);
-       ret |= col << 12;
-       
-       col = VGA_int_GetColourNibble(Char->FGCol);
-       ret |= col << 8;
-       
-       return ret;
-}
-
-/**
- * \fn void VGA_int_SetCursor(Sint16 x, Sint16 y)
- * \brief Updates the cursor position
- */
-void VGA_int_SetCursor(Sint16 x, Sint16 y)
-{
-        int    pos = x+y*VGA_WIDTH;
-       if(x == -1 || y == -1)
-               pos = -1;
-       outb(0x3D4, 14);
-       outb(0x3D5, pos >> 8);
-       outb(0x3D4, 15);
-       outb(0x3D5, pos);
-}
-
-void VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
-{
-       tVT_Char        ch;
-       Uint16  word, *buf;
-
-       X /= giVT_CharWidth;
-       W /= giVT_CharWidth;
-       Y /= giVT_CharHeight;
-       H /= giVT_CharHeight;
-
-       ch.Ch = 0x20;
-       ch.BGCol  = (Colour & 0x0F0000) >> (16-8);
-       ch.BGCol |= (Colour & 0x000F00) >> (8-4);
-       ch.BGCol |= (Colour & 0x00000F);
-       word = VGA_int_GetWord(&ch);
-
-       Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
-
-       if( X > VGA_WIDTH || Y > VGA_HEIGHT )   return ;
-       if( X + W > VGA_WIDTH ) W = VGA_WIDTH - X;
-       if( Y + H > VGA_HEIGHT )        H = VGA_HEIGHT - Y;
-
-       buf = gVGA_Framebuffer + Y*VGA_WIDTH + X;
-
-       
-       while( H -- ) {
-                int    i;
-               for( i = 0; i < W; i ++ )
-                       *buf++ = word;
-               buf += VGA_WIDTH - W;
-       }
-}
-
-void VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
-{
-       Uint16  *src, *dst;
-
-       DstX /= giVT_CharWidth;
-       SrcX /= giVT_CharWidth;
-       W /= giVT_CharWidth;
-
-       DstY /= giVT_CharHeight;
-       SrcY /= giVT_CharHeight;
-       H /= giVT_CharHeight;
-
-//     Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
-
-       if( SrcX > VGA_WIDTH || SrcY > VGA_HEIGHT )     return ;
-       if( SrcX + W > VGA_WIDTH )      W = VGA_WIDTH - SrcX;
-       if( SrcY + H > VGA_HEIGHT )     H = VGA_HEIGHT - SrcY;
-       if( DstX > VGA_WIDTH || DstY > VGA_HEIGHT )     return ;
-       if( DstX + W > VGA_WIDTH )      W = VGA_WIDTH - DstX;
-       if( DstY + H > VGA_HEIGHT )     H = VGA_HEIGHT - DstY;
-
-
-       src = gVGA_Framebuffer + SrcY*VGA_WIDTH + SrcX;
-       dst = gVGA_Framebuffer + DstY*VGA_WIDTH + DstX;
-
-       if( src > dst )
-       {
-               // Simple copy
-               while( H-- ) {
-                       memcpy(dst, src, W*2);
-                       dst += VGA_WIDTH;
-                       src += VGA_WIDTH;
-               }
-       }
-       else
-       {
-               dst += H*VGA_WIDTH;
-               src += H*VGA_WIDTH;
-               while( H -- ) {
-                        int    i;
-                       dst -= VGA_WIDTH-W;
-                       src -= VGA_WIDTH-W;
-                       for( i = W; i --; )     *--dst = *--src;
-               }
-       }
-}
diff --git a/Notes/AcessFS.txt b/Notes/AcessFS.txt
new file mode 100644 (file)
index 0000000..7c74beb
--- /dev/null
@@ -0,0 +1,54 @@
+Acess File System
+- Database Design
+
+== Data Strutures ==
+Blocks are of a size specified in the superblock
+- Superblock
+ > Fixed offset: 1024 bytes
+- Field Table
+ > Offset set in superblock
+- Index Table
+- Inode Table
+
+=== Superblock ===
+struct sSuperblock {
+       Uint8   Magic[4];       // == '\xACFS'+Version
+       Uint8   BlockSize;      // TrueSize = 2^(7+BlockSize)
+};
+
+=== Field Table ===
+struct sFieldTableEntry {
+       Uint16  Ident;
+       Uint8   Type;
+       Uint8   Length;
+       char    Text[];
+} FieldTable[SuperBlock.NFields];
+
+=== Index Table ==
+struct sIndexTableEntry {
+       Uint16  Field;
+       Uint16  CheckSum;
+       Uint32  Block;
+} IndexTable[SuperBlock.NFields];
+
+=== Index Table entry ==
+struct {
+       Uint32  NumEntries;
+       Uint32  Links[];
+};
+
+=== Inode Table ===
+struct sInodeTable {
+       
+};
+
+=== Inode ===
+struct sInodeEntry {
+       Uint16  Name;
+       Uint8   Size;
+       Uint8   Checksum;
+       Uint8   data[];
+};
+
+Each `sInodeEntry` defines an entry in a "database"
+
diff --git a/Notes/Spinlocks.txt b/Notes/Spinlocks.txt
new file mode 100644 (file)
index 0000000..b4f6b84
--- /dev/null
@@ -0,0 +1,26 @@
+SHORTLOCK()
+       cli; lock cmpxchg
+SHORTREL()
+       lock and ; sti
+
+
+LONGLOCK()
+       mov eax, 1
+       lock cmpxchg lock.lock, eax
+       if(eax) {
+               SHORTLOCK(lock.listLock)
+               // add to list (linked list, 4 static entries)
+               SHORTREL(lock.listLock)
+               for(;;)
+               {
+                       check owner
+                       mov eax, 1
+                       lock cmpxchg lock.lock, eax
+                       if(!eax)        break;  // got lock
+                       Threads_Sleep();
+               }
+       }
+
+LONGREL()
+       lock and lock.lock, 0
+       pop off front of list, free entry, wake thread
diff --git a/Notes/VFS - Select.txt b/Notes/VFS - Select.txt
new file mode 100644 (file)
index 0000000..70e1993
--- /dev/null
@@ -0,0 +1,25 @@
+select()
+- Implemented using a wait queue for every file descriptor
+- That requires waiting on sockets to be centeralised
+
+All wait tasks (reads on VTerm, Pipes, PTYs, network sockets) use the kernel
+version of select with an inifinite timeout.
+They then signal the VFS using their VFS node pointer as a reference
+
+The VFS function select()
+- Maintains a list of processes on each node (if select has been called on that node)
+- Each process maybe has a semaphore on it (to use the semaphore code to maintain the process list)
+ > Could maybe use a mutex instead
+
+
+VFS_Select(int, fd_set* read, fd_set* write, fd_set* except)
+
+read is the set of sockets that we are waiting to read from
+write         "           "           "           be able to write to
+except        "           "           "        for possible errors on
+
+
+Hence, each VFS_Node has three listener lists (or just pointers)
+- One for when data is avaliable
+- One for when space is avaliable for writing
+- One for when an error occurs (closed pipe, etc ...)
diff --git a/Notes/VTerm.txt b/Notes/VTerm.txt
new file mode 100644 (file)
index 0000000..6173108
--- /dev/null
@@ -0,0 +1,53 @@
+
+== Read ==
+- UTF-8 / UCS-4 Character Stream
+ > Selected with mode call
+
+== Write ==
+UTF-8 Emulation Text Mode:
+- Emuates a character device
+ > VT-100/ANSI Control Codes
+ > Characters/Symbols are sent as UTF-8
+
+/*
+Native Text Mode:
+- NxM 64-bit entries
+ > UCS-32 Codepoint (if a diacritic is encountered, the previous character is modified)
+ > 12-bit (16 encoded) Foreground
+ > 12-bit (16 encoded) Background
+*/
+
+Framebuffer Graphics:
+- WxH 32-bit (3x 8-bit channels) framebuffer
+- Write to entire framebuffer
+
+Accellerated Graphics:
+- Command Stream
+ > Each Node.Write call is a single command
+ + NOP (-)
+ + Direct (Uint16 X, Y, W, H, Uint32 Data[])
+ + Blit (Uint16 W, H, SrcX, SrxY, DstX, DstY, Uint32 Data[])
+ + Fill (Uint16 X, Y, W, H)
+ + Rect (Uint16 X, Y, W, H)
+ + Line (Uint16 X, Y, W, H)
+ + Text (Uint16 X, Y, Size, Font)
+ + ShowTile (Uint16 ID, Uint16 X, Y)
+ + DelTile (Uint16 ID)
+- Extra IOCtls
+ + int LoadFont(char *Path)
+ + UnloadFont(int *ID)
+ + int MakeTile(struct {Uint16 W, H, Uint32 Data[]} *Img)
+ + DelTile(int *ID)
+- Allow fast switch between Accel/Framebuffer?
+- Min Reqd Tile Size 32x32
+ > Tiles should be driver emulated if unavaliable by hardware
+3D Graphics: (Can be emulated if not avaliable, or just denied)
+- Command Stream
+ >
+ + NOP (-)
+ + FlipBuffer (-)
+ + LoadTexture(Uint16 ID, W, H, Uint32 Data[])
+ + UnloadTexture(Uint16 ID)
+ + SetTexture(Uint16 ID)
+ + Triangle (Uint16 Texture, Uint32[3+3+2][3])

UCC git Repository :: git.ucc.asn.au