Initial commit of kernel only
authorJohn Hodge <tpg@portege.(none)>
Mon, 21 Sep 2009 08:23:50 +0000 (16:23 +0800)
committerJohn Hodge <tpg@portege.(none)>
Mon, 21 Sep 2009 08:23:50 +0000 (16:23 +0800)
Known Bugs:
- Copy-on-write causes errors
- Other MM_Clone/MM_Clear bugs

75 files changed:
Kernel/GenSyscalls.php [new file with mode: 0644]
Kernel/Makefile [new file with mode: 0644]
Kernel/Makefile.cfg [new file with mode: 0644]
Kernel/arch/x86/Makefile [new file with mode: 0644]
Kernel/arch/x86/desctab.asm [new file with mode: 0644]
Kernel/arch/x86/errors.c [new file with mode: 0644]
Kernel/arch/x86/include/arch.h [new file with mode: 0644]
Kernel/arch/x86/include/mm_phys.h [new file with mode: 0644]
Kernel/arch/x86/include/mm_virt.h [new file with mode: 0644]
Kernel/arch/x86/include/mp.h [new file with mode: 0644]
Kernel/arch/x86/include/proc.h [new file with mode: 0644]
Kernel/arch/x86/irq.c [new file with mode: 0644]
Kernel/arch/x86/lib.c [new file with mode: 0644]
Kernel/arch/x86/link.ld [new file with mode: 0644]
Kernel/arch/x86/main.c [new file with mode: 0644]
Kernel/arch/x86/mm_phys.c [new file with mode: 0644]
Kernel/arch/x86/mm_virt.c [new file with mode: 0644]
Kernel/arch/x86/proc.c [new file with mode: 0644]
Kernel/arch/x86/start.asm [new file with mode: 0644]
Kernel/arch/x86/time.c [new file with mode: 0644]
Kernel/bin/bin_elf.h [new file with mode: 0644]
Kernel/bin/elf.c [new file with mode: 0644]
Kernel/binary.c [new file with mode: 0644]
Kernel/debug.c [new file with mode: 0644]
Kernel/drv/Makefile [new file with mode: 0644]
Kernel/drv/ata_x86.c [new file with mode: 0644]
Kernel/drv/bochsvbe.c [new file with mode: 0644]
Kernel/drv/kb.c [new file with mode: 0644]
Kernel/drv/kb_kbdus.h [new file with mode: 0644]
Kernel/drv/pci.c [new file with mode: 0644]
Kernel/drv/vga.c [new file with mode: 0644]
Kernel/drv/vterm.c [new file with mode: 0644]
Kernel/drv/vterm_font_8x16.h [new file with mode: 0644]
Kernel/drv/vterm_font_8x8.h [new file with mode: 0644]
Kernel/heap.c [new file with mode: 0644]
Kernel/include/binary.h [new file with mode: 0644]
Kernel/include/binary_ext.h [new file with mode: 0644]
Kernel/include/common.h [new file with mode: 0644]
Kernel/include/drv_pci.h [new file with mode: 0644]
Kernel/include/errno.h [new file with mode: 0644]
Kernel/include/fs_devfs.h [new file with mode: 0644]
Kernel/include/heap.h [new file with mode: 0644]
Kernel/include/init.h [new file with mode: 0644]
Kernel/include/mboot.h [new file with mode: 0644]
Kernel/include/modules.h [new file with mode: 0644]
Kernel/include/syscalls.h [new file with mode: 0644]
Kernel/include/syscalls.inc.asm [new file with mode: 0644]
Kernel/include/syscalls_old.h [new file with mode: 0644]
Kernel/include/tpl_drv_common.h [new file with mode: 0644]
Kernel/include/tpl_drv_keyboard.h [new file with mode: 0644]
Kernel/include/tpl_drv_video.h [new file with mode: 0644]
Kernel/include/vfs.h [new file with mode: 0644]
Kernel/include/vfs_ext.h [new file with mode: 0644]
Kernel/include/vfs_int.h [new file with mode: 0644]
Kernel/include/vfs_ramfs.h [new file with mode: 0644]
Kernel/lib.c [new file with mode: 0644]
Kernel/messages.c [new file with mode: 0644]
Kernel/modules.c [new file with mode: 0644]
Kernel/proc.c [new file with mode: 0644]
Kernel/syscalls.c [new file with mode: 0644]
Kernel/syscalls.lst [new file with mode: 0644]
Kernel/system.c [new file with mode: 0644]
Kernel/vfs.c [new file with mode: 0644]
Kernel/vfs/acls.c [new file with mode: 0644]
Kernel/vfs/dir.c [new file with mode: 0644]
Kernel/vfs/fs/devfs.c [new file with mode: 0644]
Kernel/vfs/fs/fat.c [new file with mode: 0644]
Kernel/vfs/fs/fs_fat.h [new file with mode: 0644]
Kernel/vfs/fs/root.c [new file with mode: 0644]
Kernel/vfs/io.c [new file with mode: 0644]
Kernel/vfs/main.c [new file with mode: 0644]
Kernel/vfs/memfile.c [new file with mode: 0644]
Kernel/vfs/mount.c [new file with mode: 0644]
Kernel/vfs/nodecache.c [new file with mode: 0644]
Kernel/vfs/open.c [new file with mode: 0644]

diff --git a/Kernel/GenSyscalls.php b/Kernel/GenSyscalls.php
new file mode 100644 (file)
index 0000000..7397f9d
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+$gLines = file("syscalls.lst");
+
+$lSyscalls = array();
+$i = 0;
+foreach($gLines as $line)
+{
+       $line = trim($line);
+       if(empty($line))        continue;
+       
+       //echo $line,"\n";
+       //echo intVal($line),"\n";
+       if( intVal($line) != 0)
+               $i = $line;
+       else
+               $lSyscalls[$i++] = explode("\t", $line, 2);
+       //echo $i,"\n";
+}
+$lMax = $i;
+
+$lAsmInc = "; Acess2
+; System Calls List
+; 
+
+";
+$lHeader  = "/*
+ * AcessOS Microkernel Version
+ * syscalls.h
+ */
+#ifndef _SYSCALLS_H
+#define _SYSCALLS_H
+
+enum eSyscalls {
+";
+$i = 0;
+foreach($lSyscalls as $num=>$call)
+{
+       if($i != $num)  {
+               $lHeader .= "\n";
+               $lAsmInc .= "\n";
+       }
+       
+       $lHeader .= "\t{$call[0]}";
+       if($i != $num)  $lHeader .= " = {$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 .= "\tNUM_SYSCALLS,\n";
+$lHeader .= "\tSYS_DEBUG = 0x100       // 0x100 - Print a debug string\n";
+$lHeader .= "};\n\n";
+$lHeader .= "static const char *cSYSCALL_NAMES[] = {\n\t";
+
+$j = 0;
+for($i=0;$i<$lMax;$i++)
+{
+       $lHeader .= "\"".$lSyscalls[$i][0]."\",";
+       $j ++;
+       if($j == 6) {
+               $lHeader .= "\n\t";
+               $j = 0;
+       }
+}
+$lHeader .= "\"\"\n};\n#endif\n";
+
+//echo $lHeader;
+
+$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/Makefile b/Kernel/Makefile
new file mode 100644 (file)
index 0000000..0c90022
--- /dev/null
@@ -0,0 +1,63 @@
+# 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
+
+RM = rm -f
+
+MAKEDEP                = $(CC) -M
+
+CPPFLAGS       += -I./include -I./arch/$(ARCHDIR)/include -DARCH=$(ARCH)
+CFLAGS         += -Wall -Werror -O3 -fno-stack-protector -fno-builtin -fleading-underscore
+ASFLAGS                += -D ARCH=\"$(ARCH)\"
+LDFLAGS                += -T arch/$(ARCHDIR)/link.ld
+
+OBJ = $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
+OBJ += heap.o messages.o debug.o modules.o lib.o syscalls.o system.o
+OBJ += binary.o bin/elf.o
+OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o vfs/memfile.o vfs/nodecache.o
+OBJ += vfs/fs/root.o vfs/fs/devfs.o vfs/fs/fat.o
+OBJ += drv/pci.o drv/ata_x86.o drv/vterm.o drv/vga.o drv/kb.o
+OBJ := $(addsuffix .$(ARCH), $(OBJ))
+BIN = ../Acess2.$(ARCH).bin
+
+DEPFILES  = $(filter %.o.$(ARCH),$(OBJ))
+DEPFILES := $(DEPFILES:%.o.$(ARCH)=%.d.$(ARCH))
+
+SRCFILES  = $(OBJ:%.o.$(ARCH)=%.c)
+SRCFILES := $(SRCFILES:%.ao.$(ARCH)=%.asm)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+       @$(RM) $(BIN) $(OBJ) $(DEPFILES)
+
+$(BIN): $(OBJ) arch/$(ARCHDIR)/link.ld Makefile
+       @echo --- LD -o $(BIN)
+       @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) -Map ../Map.$(ARCH).txt
+       @objdump $(BIN) -D > $(BIN).dsm
+       @cp $(BIN) /mnt/AcessFDD/
+       @wc -l $(SRCFILES) > LineCounts.$(ARCH).txt
+       @git commit
+
+%.ao.$(ARCH): %.asm Makefile
+       @echo --- NASM -o $@
+       @$(AS) $(ASFLAGS) $< -o $@
+
+%.o.$(ARCH): %.c Makefile
+       @echo --- GCC -o $@
+       @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
+       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $*.d.$(ARCH) $<
+
+include/syscalls.h:    syscalls.lst Makefile
+       php GenSyscalls.php
+
+# Dependency Files
+-include $(DEPFILES)
diff --git a/Kernel/Makefile.cfg b/Kernel/Makefile.cfg
new file mode 100644 (file)
index 0000000..8e186b8
--- /dev/null
@@ -0,0 +1,6 @@
+# 
+# Acess2 Makefile Config
+# Makefile.cfg
+
+ARCH = i386
+ARCHDIR = x86
diff --git a/Kernel/arch/x86/Makefile b/Kernel/arch/x86/Makefile
new file mode 100644 (file)
index 0000000..335d219
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Acess2 Kernel
+# i386 Architecture Makefile
+# arch/i386/Makefile
+
+# Assuming build machine is 32-bit ELF
+CC = gcc
+AS = nasm
+LD = ld
+OBJDUMP = objdump
+
+CPPFLAGS       =
+CFLAGS         =
+ASFLAGS                = -f elf
+
+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 time.o
diff --git a/Kernel/arch/x86/desctab.asm b/Kernel/arch/x86/desctab.asm
new file mode 100644 (file)
index 0000000..a66bfa3
--- /dev/null
@@ -0,0 +1,296 @@
+; AcessOS Microkernel Version
+;
+; desctab.asm
+[BITS 32]
+
+%if ARCH == "i386"
+MAX_CPUS       equ     1
+%else
+MAX_CPUS       equ     8
+%endif
+GDT_SIZE       equ     (1+2*2+MAX_CPUS)*8      ; 4 Permission levels
+
+[section .data]
+; GDT
+[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
+       times MAX_CPUS  dd 0, 0
+_gGDTptr:
+       dw      GDT_SIZE-1
+       dd      _gGDT
+; IDT
+ALIGN 8
+_gIDT:
+       times   256     dd      0x00080000,0x00000F00
+_gIDTPtr:
+       dw      256 * 16 - 1    ; Limit
+       dd      _gIDT           ; Base
+
+[section .text]
+[global _Desctab_Install]
+_Desctab_Install:
+       ; Set GDT
+       lgdt [_gGDTptr]
+       mov ax, 0x10    ; PL0 Data
+       mov ss, ax
+       mov ds, ax
+       mov es, ax
+       mov gs, ax
+       mov fs, ax
+       jmp 0x08:.pl0code
+.pl0code:
+
+       ; Set IDT
+%macro SETISR  1
+       mov eax, _Isr%1
+       mov     WORD [_gIDT + %1*8], ax
+       shr eax, 16
+       mov     WORD [_gIDT + %1*8+6], ax
+       mov     ax, WORD [_gIDT + %1*8 + 4]
+       or ax, 0x8000
+       mov     WORD [_gIDT + %1*8 + 4], ax
+%endmacro
+%macro SETUSER 1
+       mov     ax, WORD [_gIDT + %1*8 + 4]
+       or ax, 0x6000
+       mov     WORD [_gIDT + %1*8 + 4], ax
+%endmacro
+       %assign i       0
+       %rep 32
+       SETISR  i
+       %assign i i+1
+       %endrep
+       
+       SETISR  0xAC
+       SETUSER 0xAC
+       
+       %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
+
+; IRQs
+; - Timer
+[global _Isr240]
+_Isr240:
+       push 0
+       jmp SchedulerBase
+; - Assignable
+%assign i      0xF1
+%rep 16
+       DEF_IRQ i
+%assign i i+1
+%endrep
+
+; ---------------------
+; Common error handling
+; ---------------------
+[extern _ErrorHandler]
+ErrorCommon:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       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
+       
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       popa
+       add esp, 8      ; Error Code and ID
+       iret
+
+; ------------
+; IRQ Handling
+; ------------
+[extern _IRQ_Handler]
+IRQCommon:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       push esp
+       call _IRQ_Handler
+       add esp, 4
+       
+       pop gs
+       pop fs
+       pop es
+       pop ds
+       popa
+       add esp, 8      ; Error Code and ID
+       iret
+
+; --------------
+; Task Scheduler
+; --------------
+[extern _Proc_Scheduler]
+SchedulerBase:
+       pusha
+       push ds
+       push es
+       push fs
+       push gs
+       
+       mov eax, [esp+12*4]     ; CPU Number
+       push eax        ; Pus as argument
+       
+       call _Proc_Scheduler
+       
+       add esp, 4      ; Remove Argument
+       
+       pop gs
+       pop fs
+       pop es
+       pop ds
+
+       mov dx, 0x20
+       mov al, 0x20
+       out dx, al              ; ACK IRQ
+       popa
+       add esp, 4      ; CPU ID
+       ; No Error code / int num
+       iret
diff --git a/Kernel/arch/x86/errors.c b/Kernel/arch/x86/errors.c
new file mode 100644 (file)
index 0000000..a8d89ac
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Acess2 - x86 Architecture
+ * arch/x86/errors.c
+ * - CPU Error Handler
+ */
+#include <common.h>
+
+// === IMPORTS ===
+extern void    MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
+extern void Proc_DumpThreads();
+
+// === CODE ===
+/**
+ * \fn void ErrorHandler(tRegs *Regs)
+ * \brief General Error Handler
+ */
+void ErrorHandler(tRegs *Regs)
+{
+       Uint    cr;
+       __asm__ __volatile__ ("cli");
+       
+       if(Regs->int_num == 14)
+       {
+               __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
+               MM_PageFault( cr, Regs->err_code, Regs );
+               return ;
+       }
+       
+       Warning("CPU Error %i, Code: 0x%x", Regs->int_num, Regs->err_code);
+       Warning(" CS:EIP = 0x%04x:%08x", Regs->cs, Regs->eip);
+       Warning(" SS:ESP = 0x%04x:%08x", Regs->ss, Regs->esp);
+       Warning(" EFLAGS = 0x%08x", Regs->eflags);
+       Warning(" EAX %08x EBX %08x", Regs->eax, Regs->ebx);
+       Warning(" ECX %08x EDX %08x", Regs->ecx, Regs->edx);
+       Warning(" ESP %08x EBP %08x", Regs->esp, Regs->ebp);
+       Warning(" ESI %08x EDI %08x", Regs->esi, Regs->edi);
+       Warning(" DS %04x ES %04x", Regs->ds, Regs->es);
+       Warning(" 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%08x", cr);
+       __asm__ __volatile__ ("mov %%cr3, %0":"=r"(cr));
+       Warning(" CR3: 0x%08x", cr);
+       
+       // Dump running threads
+       Proc_DumpThreads();
+       
+       for(;;) __asm__ __volatile__ ("hlt");
+}
diff --git a/Kernel/arch/x86/include/arch.h b/Kernel/arch/x86/include/arch.h
new file mode 100644 (file)
index 0000000..9c16b18
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Acess2
+ * - x86 Architecture
+ * arch/i386/include/arch.h
+ */
+#ifndef _ARCH_H_
+#define _ARCH_H_
+
+// - Memory Layout
+#define        MM_USER_MIN     0x00200000
+#define        USER_STACK_SZ   0x00010000
+#define        USER_STACK_TOP  0x00200000
+#define        MM_USER_MAX     0xBC000000
+#define        MM_PPD_MIN      0xBC000000      // Per-Process Data
+#define        MM_PPD_VFS      0xBC000000      // 
+#define MM_PPD_CFG     0xBFFFF000      // 
+#define        MM_PPD_MAX      0xB0000000
+#define        KERNEL_BASE     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  0xF0000000      // 512 MiB
+
+#define BITS   32
+
+// - Processor/Machine Specific Features
+#if ARCH == i386
+// Uses no advanced features
+# define       USE_MP  0
+# define       USE_PAE 0
+#elif ARCH == i586
+// All Enabled
+# define       USE_MP  1
+# define       USE_PAE 1
+#else
+# error "Unknown architecture '" #ARCH "'"
+#endif
+
+// === MACROS ===
+#define LOCK(lockptr)  do {int v=1;\
+       while(v)__asm__ __volatile__("lock xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(lockptr));}while(0)
+#define        RELEASE(lockptr)        __asm__ __volatile__("lock andl $0, (%%edi)"::"D"(lockptr));
+
+// === 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;
+
+#if USE_PAE
+typedef Uint64 tPAddr;
+#else
+typedef Uint32 tPAddr;
+#endif
+typedef Uint32 tVAddr;
+
+typedef void (*tThreadFunction)(void*);
+
+typedef struct {
+    Uint       gs, fs, es, ds;
+    Uint       edi, esi, ebp, kesp;
+       Uint    ebx, edx, ecx, eax;
+    Uint       int_num, err_code;
+    Uint       eip, cs;
+       Uint    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;
+
+typedef struct {
+       Uint16  LimitLow;
+       Uint16  BaseLow;
+       Uint8   BaseMid;
+       Uint8   Access;
+       struct {
+               unsigned LimitHi:       4;
+               unsigned Flags:         4;
+       } __attribute__ ((packed));
+       Uint8   BaseHi;
+} __attribute__ ((packed)) tGDT;
+
+// --- Interface Flags & Macros
+#define CLONE_VM       0x10
+
+#endif // !defined(_ARCH_H_)
diff --git a/Kernel/arch/x86/include/mm_phys.h b/Kernel/arch/x86/include/mm_phys.h
new file mode 100644 (file)
index 0000000..65ab091
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * AcessOS Microkernel Version
+ * mm_phys.h
+ */
+#ifndef _MM_PHYS_H
+#define _MM_PHYS_H
+
+// === FUNCTIONS ===
+extern Uint32  MM_AllocPhys();
+extern void    MM_RefPhys(Uint32 Addr);
+extern void    MM_DerefPhys(Uint32 Addr);
+
+#endif
diff --git a/Kernel/arch/x86/include/mm_virt.h b/Kernel/arch/x86/include/mm_virt.h
new file mode 100644 (file)
index 0000000..8b7508c
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * AcessOS Microkernel Version
+ * mm_phys.h
+ */
+#ifndef _MM_PHYS_H
+#define _MM_PHYS_H
+
+// === FUNCTIONS ===
+extern void    MM_SetCR3(Uint32 CR3);
+extern tPAddr  MM_Allocate(Uint VAddr);
+extern void    MM_Deallocate(Uint VAddr);
+extern int     MM_Map(Uint VAddr, tPAddr PAddr);
+extern Uint    MM_Clone();
+extern Uint    MM_NewKStack();
+
+#endif
diff --git a/Kernel/arch/x86/include/mp.h b/Kernel/arch/x86/include/mp.h
new file mode 100644 (file)
index 0000000..f64cd0b
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ */
+#ifndef _MP_H
+#define _MP_H
+
+#define MPTABLE_IDENT  ('_'|('M'<<8)|('P'<<16)|('_'<<24))
+
+typedef struct sMPInfo {
+       Uint    Sig;    // '_MP_'
+       Uint    MPConfig;
+       Uint8   Length;
+       Uint8   Version;
+       Uint8   Checksum;
+       Uint8   Features[5];    // 2-4 are unused
+} tMPInfo;
+
+#endif
diff --git a/Kernel/arch/x86/include/proc.h b/Kernel/arch/x86/include/proc.h
new file mode 100644 (file)
index 0000000..6e559be
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * AcessOS Microkernel Version
+ * proc.h
+ */
+#ifndef _PROC_H
+#define _PROC_H
+
+// === CONSTANTS ===
+#define GETMSG_IGNORE  ((void*)-1)
+
+// === TYPES ===
+typedef struct sMessage {
+       struct sMessage *Next;
+       Uint    Source;
+       Uint    Length;
+       Uint8   Data[];
+} tMsg;        // sizeof = 12+
+
+typedef struct sThread {
+       struct sThread  *Next;
+        int    IsLocked;
+        int    Status; //!< Thread Status
+       
+       Uint    TID;    //!< Thread ID
+       Uint    TGID;   //!< Thread Group (Process)
+       Uint    UID, GID;       //!< User and Group
+       char    *ThreadName;    //!< Name of thread
+       
+       Uint    ESP, EBP, EIP;  //!< State on switch
+       #if USE_PAE
+       Uint64  PML4[3];        //!< Address Space
+       #else
+       Uint    CR3;    //!< Memory Space
+       #endif
+       
+       Uint    KernelStack;    //!< Thread's Kernel Stack
+       
+       tMsg    *Messages;      //!< Message Queue
+       tMsg    *LastMessage;   //!< Last Message (speeds up insertion)
+       
+        int    Quantum, Remaining;     //!< Quantum Size and remaining timesteps
+        int    NumTickets;     //!< Priority - Chance of gaining CPU
+       
+       Uint    Config[NUM_CFG_ENTRIES];        //!< Per-process configuration
+} tThread;     // sizeof = 68
+
+enum {
+       THREAD_STAT_NULL,
+       THREAD_STAT_ACTIVE,
+       THREAD_STAT_SLEEPING,
+       THREAD_STAT_WAITING,
+       THREAD_STAT_DEAD
+};
+
+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
+} tTSS;
+
+// === GLOBALS ===
+extern tThread *gCurrentThread;
+
+// === FUNCTIONS ===
+extern void    Proc_Start();
+extern int     Proc_Clone(Uint *Err, Uint Flags);
+extern void Proc_Exit();
+extern void Proc_Yield();
+extern void Proc_Sleep();
+extern void Proc_SetTickets(int Num);
+extern tThread *Proc_GetThread(Uint TID);
+extern void    Thread_Wake(tThread *Thread);
+
+#endif
diff --git a/Kernel/arch/x86/irq.c b/Kernel/arch/x86/irq.c
new file mode 100644 (file)
index 0000000..848e7e9
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * AcessOS Microkernel Version
+ * irq.c
+ */
+#include <common.h>
+
+// === CONSTANTS ===
+#define        MAX_CALLBACKS_PER_IRQ   4
+
+// === TYPES ===
+typedef void (*tIRQ_Callback)(void);
+
+// === GLOBALS ===
+tIRQ_Callback  gIRQ_Handlers[16][MAX_CALLBACKS_PER_IRQ];
+
+// === CODE ===
+/**
+ * \fn void IRQ_Handler(tRegs *Regs)
+ * \brief Handle an IRQ
+ */
+void IRQ_Handler(tRegs *Regs)
+{
+        int    i;
+       
+       Regs->int_num -= 0xF0;  // Adjust
+       
+       //Log("IRQ_Handler: (Regs={int_num:%i})", Regs->int_num);
+       
+       for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
+       {
+               //Log(" IRQ_Handler: Call %p", gIRQ_Handlers[Regs->int_num][i]);
+               if( gIRQ_Handlers[Regs->int_num][i] )
+                       gIRQ_Handlers[Regs->int_num][i]();
+       }
+       
+       outb(0x20, 0x20);       // ACK IRQ
+       if(Regs->int_num >= 8)
+               outb(0xA0, 0x20);       // ACK IRQ (Secondary PIC)
+}
+
+/**
+ * \fn int IRQ_AddHandler( int Num, void (*Callback)(void) )
+ */
+int IRQ_AddHandler( int Num, void (*Callback)(void) )
+{
+        int    i;
+       for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
+       {
+               if( gIRQ_Handlers[Num][i] == NULL ) {
+                       gIRQ_Handlers[Num][i] = Callback;
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
diff --git a/Kernel/arch/x86/lib.c b/Kernel/arch/x86/lib.c
new file mode 100644 (file)
index 0000000..2334417
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * AcessOS Microkernel Version
+ * lib.c
+ */
+#include <common.h>
+
+// === CODE ===
+void Spinlock(int *lock)
+{
+        int    v = 1;
+       while(v)        __asm__ __volatile__ ("lock xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(lock));
+}
+
+void Release(int *lock)
+{
+       __asm__ __volatile__ ("lock andl $0, (%0)"::"r"(lock));
+}
+
+// === 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, Uint Num)
+ * \brief Do a byte set of Dest
+ */
+void *memset(void *Dest, int Val, Uint Num)
+{
+       __asm__ __volatile__ ("rep stosb" :: "D" (Dest), "a" (Val), "c" (Num));
+       return Dest;
+}
+/**
+ * \fn void *memsetd(void *Dest, Uint Val, Uint Num)
+ */
+void *memsetd(void *Dest, Uint Val, Uint Num)
+{
+       __asm__ __volatile__ ("rep stosl" :: "D" (Dest), "a" (Val), "c" (Num));
+       return Dest;
+}
+
+
+/**
+ * \fn void *memcpy(void *Dest, void *Src, Uint Num)
+ */
+void *memcpy(void *Dest, void *Src, Uint Num)
+{
+       __asm__ __volatile__ ("rep movsb" :: "D" (Dest), "S" (Src), "c" (Num));
+       return Dest;
+}
+/**
+ * \fn void *memcpyd(void *Dest, void *Src, Uint Num)
+ */
+void *memcpyd(void *Dest, void *Src, Uint Num)
+{
+       __asm__ __volatile__ ("rep movsl" :: "D" (Dest), "S" (Src), "c" (Num));
+       return Dest;
+}
+
+/**
+ * \fn Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+ * \brief Divide two 64-bit integers
+ */
+Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+{
+       Uint64  ret = 0;
+       
+       if(Den == 0)    __asm__ __volatile__ ("int $0x0");      // Call Div by Zero Error
+       if(Den == 1)    return Num;     // Speed Hacks
+       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(Num >> 32 == 0 && Den >> 32 == 0)
+               return (Uint32)Num / (Uint32)Den;
+       
+       //Log("__udivdi3: (Num={0x%x:%x}, Den={0x%x:%x})",
+       //      Num>>32, Num&0xFFFFFFFF,
+       //      Den>>32, Den&0xFFFFFFFF);
+       
+       while(Num > Den) {
+               ret ++;
+               Num -= Den;
+       }
+       return ret;
+}
+
+/**
+ * \fn Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+ * \brief Get the modulus of two 64-bit integers
+ */
+Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+{
+       if(Den == 0)    __asm__ __volatile__ ("int $0x0");      // Call Div by Zero Error
+       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(Num >> 32 == 0 && Den >> 32 == 0)
+               return (Uint32)Num % (Uint32)Den;
+       
+       while(Num > Den)
+               Num -= Den;
+       return Num;
+}
+
+// --- EXPORTS ---
+EXPORT(memcpy);        EXPORT(memset);
+//EXPORT(memcpyw);     EXPORT(memsetw);
+EXPORT(memcpyd);       EXPORT(memsetd);
+EXPORT(inb);   EXPORT(inw);    EXPORT(ind);
+EXPORT(outb);  EXPORT(outw);   EXPORT(outd);
+EXPORT(__udivdi3);     EXPORT(__umoddi3);
diff --git a/Kernel/arch/x86/link.ld b/Kernel/arch/x86/link.ld
new file mode 100644 (file)
index 0000000..93066bc
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * AcessMicro Kernel
+ * Linker Script
+ */
+
+lowStart = start - 0xC0000000;
+ENTRY(lowStart)
+OUTPUT_FORMAT(elf32-i386)
+
+SECTIONS {
+       . = 0x100000;
+       .multiboot : AT(ADDR(.multiboot)) {
+               *(.multiboot)
+       }
+       
+       . += 0xC0000000;
+       
+       .text ALIGN(0x1000): AT(ADDR(.text) - 0xC0000000) {
+               *(.text)
+       }
+       
+       .usertext ALIGN(0x1000): AT(ADDR(.usertext) - 0xC0000000) {
+               _UsertextBase = .;
+               *(.usertext)
+       }
+       
+       .rodata ALIGN(0x1000): AT(ADDR(.rodata) - 0xC0000000) {
+               *(.initpd)
+               *(.rodata)
+               *(.rdata)
+               _gKernelModules = .;
+               *(KMODULES)
+               _gKernelModulesEnd = .;
+               . = ALIGN(4);
+               _gKernelSymbols = .;
+               *(KEXPORT)
+               _gKernelSymbolsEnd = .;
+
+       }
+       
+       .padata ALIGN (0x1000) : AT(ADDR(.padata) - 0xC0000000) {
+               *(.padata)
+       }
+       
+       .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
+               *(.data)
+       }
+
+       .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
new file mode 100644 (file)
index 0000000..710923d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Acess 2
+ * x86 Kernel Main
+ * arch/x86/main.c
+ */
+#include <common.h>
+#include <mboot.h>
+#include <init.h>
+#include <mm_virt.h>
+#include <mp.h>
+
+#define        VGA_ERRORS      0
+
+// === IMPORTS ===
+extern void    Heap_Install();
+extern void    Desctab_Install();
+extern void    MM_PreinitVirtual();
+extern void    MM_Install(tMBoot_Info *MBoot);
+extern void MM_InstallVirtual();
+extern void    Proc_Start();
+extern Uint    Proc_Clone(Uint *Err, Uint Flags);
+extern void    Proc_Sleep();
+extern void    Proc_Exit();
+
+// === GLOBALS ===
+
+// === CODE ===
+int kmain(Uint MbMagic, tMBoot_Info *MbInfo)
+{
+        int    i;
+       tMBoot_Module   *mods;
+       
+       // Adjust Multiboot structure address
+       MbInfo = (void*)( (Uint)MbInfo + KERNEL_BASE );
+       
+       Desctab_Install();      // Set up GDT and IDT
+       MM_PreinitVirtual();    // Initialise vital mappings
+       MM_Install( MbInfo );   // Set up physical memory manager
+       MM_InstallVirtual();    // Clean up virtual address space
+       Heap_Install();         // Create initial heap
+       
+       Log("Starting Multitasking...");
+       // Start Multitasking
+       Proc_Start();
+       
+       Log("Starting VFS...");
+       // Load Virtual Filesystem
+       VFS_Init();
+       
+       Log("Loading Modules...");
+       
+       // Load initial modules
+       mods = (void*)( MbInfo->Modules + KERNEL_BASE );
+       for(i=0;i<MbInfo->ModuleCount;i++)
+       {
+               // Adjust into higher half
+               mods[i].Start += KERNEL_BASE;
+               mods[i].End += KERNEL_BASE;
+               mods[i].String += KERNEL_BASE;
+               
+               Log("Loading '%s'", mods[i].String);
+               
+               if( !Module_LoadMem( (void *)mods[i].Start, mods[i].End-mods[i].Start, (char *)mods[i].String ) )
+               {
+                       Warning("Unable to load module\n");
+               }
+       }
+       
+       // Pass on to Independent Loader
+       Log("Loading Configuration...");
+       System_Init( (char*)(MbInfo->CommandLine + KERNEL_BASE) );
+       
+       // Sleep forever (sleeping beauty)
+       for(;;) Proc_Sleep();
+       return 0;
+}
diff --git a/Kernel/arch/x86/mm_phys.c b/Kernel/arch/x86/mm_phys.c
new file mode 100644 (file)
index 0000000..80e92fe
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ AcessOS Microkernel Version
+ mm_phys.c
+*/
+#include <common.h>
+#include <mboot.h>
+#include <mm_virt.h>
+
+#define        REFERENCE_BASE  0xE0400000
+
+// === IMPORTS ===
+extern void    gKernelEnd;
+
+// === PROTOTYPES ===
+Uint32 MM_AllocPhys();
+void   MM_RefPhys(Uint32 Addr);
+void   MM_DerefPhys(Uint32 Addr);
+
+// === GLOBALS ===
+ int   giPhysAlloc = 0;
+Uint   giPageCount = 0;
+Uint32 gaSuperBitmap[1024];    // Blocks of 1024 Pages
+Uint32 gaPageBitmap[1024*1024/32];     // Individual pages
+Uint32 *gaPageReferences;
+
+// === CODE ===
+void MM_Install(tMBoot_Info *MBoot)
+{
+       Uint    kernelPages, num;
+       Uint    i;
+       tMBoot_Module   *mods;
+       
+       // Initialise globals
+       giPageCount = (MBoot->HighMem >> 2) + 256;      // HighMem is a kByte value
+       Log("giPageCount = %i", giPageCount);
+       
+       // Get used page count
+       kernelPages = (Uint)&gKernelEnd - KERNEL_BASE;
+       kernelPages += 0xFFF;   // Page Align
+       kernelPages >>= 12;
+       
+       // Fill page bitmap
+       num = kernelPages/32;
+       memsetd(gaPageBitmap, -1, num);
+       gaPageBitmap[ num ] = (1 << (kernelPages & 31)) - 1;
+       
+       // Fill Superpage bitmap
+       num = kernelPages/(32*32);
+       memsetd(gaSuperBitmap, -1, num);
+       gaSuperBitmap[ 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) );
+       }
+       
+       // Allocate References
+       Log("Reference Pages %i", (giPageCount*4+0xFFF)>>12);
+       for(num = 0; num < (giPageCount*4+0xFFF)>>12; num++)
+       {
+               MM_Allocate( REFERENCE_BASE + (num<<12) );
+       }
+       
+       // Fill references
+       gaPageReferences = (void*)REFERENCE_BASE;
+       memsetd(gaPageReferences, 1, kernelPages);
+       for( num = kernelPages; num < giPageCount; num++ )
+       {
+               //if(gaPageBitmap[ num2 / 32 ] == 0) {
+               //      memsetd(&gaPageReferences[num2], 0, 31-(num2&31));
+               //      num2 = (num2 + 32) & ~31;
+               //} else
+                       gaPageReferences[num] = (gaPageBitmap[ num / 32 ] >> (num&31)) & 1;
+       }
+}
+
+/**
+ * \fn Uint32 MM_AllocPhys()
+ * \brief Allocates a physical page
+ */
+tPAddr MM_AllocPhys()
+{
+        int    num = giPageCount / 32 / 32;
+        int    a, b, c;
+       Uint32  ret;
+       
+       LOCK( &giPhysAlloc );
+       
+       // Find free page
+       for(a=0;gaSuperBitmap[a]==-1&&a<num;a++);
+       if(a == num) {
+               RELEASE( &giPhysAlloc );
+               return 0;
+       }
+       for(b=0;gaSuperBitmap[a]&(1<<b);b++);
+       for(c=0;gaPageBitmap[a*32+b]&(1<<c);c++);
+       //for(c=0;gaPageReferences[a*32*32+b*32+c]>0;c++);
+       
+       // Mark page used
+       if(gaPageReferences)
+               gaPageReferences[a*32*32+b*32+c] = 1;
+       gaPageBitmap[ a*32+b ] |= 1 << c;
+       
+       // Get address
+       ret = (a << 22) + (b << 17) + (c << 12);
+       
+       // Mark used block
+       if(gaPageBitmap[ a*32+b ] == -1)        gaSuperBitmap[a] |= 1 << b;
+
+       // Release Spinlock
+       RELEASE( &giPhysAlloc );
+       //LOG("ret = %x", ret);
+       return ret;
+}
+
+/**
+ * \fn void MM_RefPhys(tPAddr Addr)
+ */
+void MM_RefPhys(tPAddr Addr)
+{
+       // Get page number
+       Addr >>= 12;
+       
+       // We don't care about non-ram pages
+       if(Addr >= giPageCount) return;
+       
+       // Lock Structures
+       LOCK( &giPhysAlloc );
+       
+       // Reference the page
+       if(gaPageReferences)
+               gaPageReferences[ Addr ] ++;
+       
+       // Mark as used
+       gaPageBitmap[ Addr / 32 ] |= 1 << (Addr&31);
+       
+       // Mark used block
+       if(gaPageBitmap[ Addr / 32 ] == -1)     gaSuperBitmap[Addr/1024] |= 1 << ((Addr/32)&31);
+       
+       // Release Spinlock
+       RELEASE( &giPhysAlloc );
+}
+
+/**
+ * \fn void MM_DerefPhys(Uint32 Addr)
+ */
+void MM_DerefPhys(Uint32 Addr)
+{
+       // Get page number
+       Addr >>= 12;
+       
+       // We don't care about non-ram pages
+       if(Addr >= giPageCount) return;
+       
+       // Check if it is freed
+       if(gaPageReferences[ Addr ] == 0) {
+               Warning("MM_DerefPhys - Non-referenced memory dereferenced");
+               return;
+       }
+       
+       // Lock Structures
+       LOCK( &giPhysAlloc );
+       
+       // Dereference
+       gaPageReferences[ Addr ] --;
+       
+       // Mark as free in bitmaps
+       if( gaPageReferences[ Addr ] == 0 )
+       {
+               gaPageBitmap[ Addr / 32 ] &= ~(1 << (Addr&31));
+               if(gaPageReferences[ Addr ] == 0)
+                       gaSuperBitmap[ Addr >> 10 ] &= ~(1 << ((Addr >> 5)&31));
+       }
+       
+       // Release spinlock
+       RELEASE( &giPhysAlloc );
+}
diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c
new file mode 100644 (file)
index 0000000..985dc14
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * 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
+ */
+#include <common.h>
+#include <mm_phys.h>
+#include <proc.h>
+
+#define KERNEL_STACKS  0xF0000000
+#define        KERNEL_STACK_SIZE       0x00002000
+#define KERNEL_STACK_END       0xFD000000
+#define PAGE_TABLE_ADDR        0xFD000000
+#define PAGE_DIR_ADDR  0xFD3F4000
+//#define PAGE_CR3_ADDR        0xFD3F47F4
+//#define TMP_CR3_ADDR 0xFD3F47F8      // Part of core instead of temp
+#define PAGE_CR3_ADDR  0xFD3F4FD0
+#define TMP_CR3_ADDR   0xFD3F4FD4      // Part of core instead of temp
+#define TMP_DIR_ADDR   0xFD3F5000      // Same
+#define TMP_TABLE_ADDR 0xFD400000
+#define        HW_MAP_ADDR             0xFD800000
+#define        HW_MAP_MAX              0xFEFF0000
+#define        NUM_HW_PAGES    ((HW_MAP_MAX-HW_MAP_ADDR)/0x1000)
+#define        TEMP_MAP_ADDR   0xFEFF0000      // Allows 16 "temp" pages
+#define        NUM_TEMP_PAGES  16
+
+#define        USE_COW 1
+
+#define        PF_PRESENT      0x1
+#define        PF_WRITE        0x2
+#define        PF_USER         0x4
+#define        PF_COW          0x200
+#define        PF_PAGED        0x400
+
+#define INVLPG(addr)   __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
+
+// === IMPORTS ===
+extern Uint32  gaInitPageDir[1024];
+extern Uint32  gaInitPageTable[1024];
+
+// === PROTOTYPES ===
+void   MM_PreinitVirtual();
+void   MM_InstallVirtual();
+void   MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
+void   MM_DumpTables(tVAddr Start, tVAddr End);
+tPAddr MM_DuplicatePage(Uint VAddr);
+
+// === GLOBALS ===
+tPAddr *gaPageTable = (void*)PAGE_TABLE_ADDR;
+tPAddr *gaPageDir = (void*)PAGE_DIR_ADDR;
+tPAddr *gaPageCR3 = (void*)PAGE_CR3_ADDR;
+tPAddr *gaTmpTable = (void*)TMP_TABLE_ADDR;
+tPAddr *gaTmpDir = (void*)TMP_DIR_ADDR;
+tPAddr *gTmpCR3 = (void*)TMP_CR3_ADDR;
+ int   gilTempMappings = 0;
+
+// === CODE ===
+/**
+ * \fn void MM_PreinitVirtual()
+ */
+void MM_PreinitVirtual()
+{
+       gaInitPageDir[ 0 ] = 0;
+       gaInitPageDir[ PAGE_TABLE_ADDR >> 22 ] = ((Uint)&gaInitPageDir - KERNEL_BASE) | 3;
+}
+/**
+ * \fn void MM_InstallVirtual()
+ */
+void MM_InstallVirtual()
+{
+        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 > KERNEL_STACKS >> 22 && i < KERNEL_STACK_END >> 22) {
+                       gaPageDir[ i ] = 0;
+                       continue;
+               }
+               // Preallocate table
+               gaPageDir[ i ] = MM_AllocPhys() | 3;
+               INVLPG( &gaPageTable[i*1024] );
+               memset( &gaPageTable[i*1024], 0, 0x1000 );
+       }
+}
+
+/**
+ * \fn void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs)
+ * \brief Called on a page fault
+ */
+void MM_PageFault(Uint 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;
+               paddr = MM_DuplicatePage( Addr );
+               MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
+               gaPageTable[Addr>>12] &= PF_USER;
+               gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
+               INVLPG( Addr & ~0xFFF );
+       }
+       
+       // -- Check Error Code --
+       if(ErrorCode & 8)
+               Warning("Reserved Bits Trashed!");
+       else
+       {
+               Warning("%s %s %s memory%s",
+                       (ErrorCode&4?"User":"Kernel"),
+                       (ErrorCode&2?"write to":"read from"),
+                       (ErrorCode&1?"bad/locked":"non-present"),
+                       (ErrorCode&16?" (Instruction Fetch)":"")
+                       );
+       }
+       
+       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]);
+       
+       MM_DumpTables(0, -1);   
+       
+       Panic("Page Fault at 0x%x\n", Regs->eip);
+       LEAVE('-');
+}
+
+/**
+ * \fn void MM_DumpTables(Uint Start, Uint End)
+ * \brief Dumps the layout of the page tables
+ */
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+       tVAddr  rangeStart = 0;
+       tPAddr  expected = 0;
+       tVAddr  curPos;
+       Uint    page;
+       const tPAddr    MASK = ~0xF98;
+       
+       Start >>= 12;   End >>= 12;
+       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)
+               {
+                       if(expected) {
+                               Log("0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)",
+                                       rangeStart, curPos - 1,
+                                       gaPageTable[rangeStart>>12] & ~0xFFF,
+                                       (expected & ~0xFFF) - 1,
+                                       (expected & PF_PAGED ? "p" : "-"),
+                                       (expected & PF_COW ? "C" : "-"),
+                                       (expected & PF_USER ? "U" : "-"),
+                                       (expected & PF_WRITE ? "W" : "-")
+                                       );
+                               expected = 0;
+                       }
+                       if( !(gaPageDir[curPos>>22] & PF_PRESENT) )     continue;
+                       if( !(gaPageTable[curPos>>12] & PF_PRESENT) )   continue;
+                       
+                       expected = (gaPageTable[page] & MASK);
+                       rangeStart = curPos;
+               }
+               if(expected)    expected += 0x1000;
+       }
+       
+       if(expected) {
+               Log("0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)",
+                       rangeStart, curPos - 1,
+                       gaPageTable[rangeStart>>12] & ~0xFFF,
+                       (expected & ~0xFFF) - 1,
+                       (expected & PF_PAGED ? "p" : "-"),
+                       (expected & PF_COW ? "C" : "-"),
+                       (expected & PF_USER ? "U" : "-"),
+                       (expected & PF_WRITE ? "W" : "-")
+                       );
+               expected = 0;
+       }
+}
+
+/**
+ * \fn tPAddr MM_Allocate(Uint VAddr)
+ */
+tPAddr MM_Allocate(Uint VAddr)
+{
+       // Check if the directory is mapped
+       if( gaPageDir[ VAddr >> 22 ] == 0 )
+       {
+               // Allocate directory
+               gaPageDir[ VAddr >> 22 ] = MM_AllocPhys() | 3;
+               // Mark as user
+               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");
+               return gaPageTable[ VAddr >> 12 ] & ~0xFFF;
+       }
+       
+       // Allocate
+       gaPageTable[ VAddr >> 12 ] = MM_AllocPhys() | 3;
+       // Mark as user
+       if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
+       // Invalidate Cache for address
+       INVLPG( VAddr & ~0xFFF );
+       
+       return gaPageTable[ VAddr >> 12 ] & ~0xFFF;
+}
+
+/**
+ * \fn void MM_Deallocate(Uint VAddr)
+ */
+void MM_Deallocate(Uint 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(Uint Addr)
+ * \brief Checks if the passed address is accesable
+ */
+tPAddr MM_GetPhysAddr(Uint 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__ __volatile__ ("mov %0, %%cr3"::"r"(CR3));
+}
+
+/**
+ * \fn int MM_Map(Uint VAddr, tPAddr PAddr)
+ * \brief Map a physical page to a virtual one
+ */
+int MM_Map(Uint VAddr, tPAddr PAddr)
+{
+       //ENTER("xVAddr xPAddr", VAddr, PAddr);
+       // Sanity check
+       if( PAddr & 0xFFF || VAddr & 0xFFF ) {
+               Warning("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 )
+       {
+               gaPageDir[ VAddr >> 22 ] = MM_AllocPhys() | 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;
+}
+
+/**
+ * \fn Uint MM_ClearUser()
+ * \brief Clear user's address space
+ */
+Uint MM_ClearUser()
+{
+       Uint    i, j;
+       
+       // Copy Directories
+       for( i = 0; i < (MM_USER_MAX>>22); i ++ )
+       {
+               // Check if directory is not allocated
+               if( !(gaPageDir[i] & PF_PRESENT) ) {
+                       gaPageDir[i] = 0;
+                       continue;
+               }
+               
+               
+               for( j = 0; j < 1024; j ++ )
+               {
+                       if( gaPageTable[i*1024+j] & 1 )
+                               MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF );
+                       gaPageTable[i*1024+j] = 0;
+               }
+               
+               MM_DerefPhys( gaPageDir[i] & ~0xFFF );
+       }
+       
+       
+       return *gTmpCR3;
+}
+
+/**
+ * \fn Uint MM_Clone()
+ * \brief Clone the current address space
+ */
+Uint MM_Clone()
+{
+       Uint    i, j;
+       Uint    kStackBase = gCurrentThread->KernelStack - KERNEL_STACK_SIZE;
+       void    *tmp;
+       
+       //ENTER("");
+       
+       // Create Directory Table
+       *gTmpCR3 = MM_AllocPhys() | 3;
+       INVLPG( gaTmpDir );
+       //LOG("Allocated Directory (%x)", *gTmpCR3);
+       memsetd( gaTmpDir, 0, 1024 );
+       
+       // Copy Tables
+       for(i=0;i<768;i++)
+       {
+               // Check if table is allocated
+               if( !(gaPageDir[i] & PF_PRESENT) ) {
+                       gaTmpDir[i] = 0;
+                       continue;
+               }
+               
+               // Allocate new table
+               gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7);
+               INVLPG( &gaTmpTable[i*1024] );
+               // Fill
+               for( j = 0; j < 1024; j ++ )
+               {
+                       if( !(gaPageTable[i*1024+j] & PF_PRESENT) ) {
+                               gaTmpTable[i*1024+j] = 0;
+                               continue;
+                       }
+                       
+                       #if USE_COW
+                       // Refrence old page
+                       MM_RefPhys( gaPageTable[i*1024+j] & ~0xFFF );
+                       // Add to new table
+                       if(gaPageTable[i*1024+j] & PF_WRITE) {
+                               gaTmpTable[i*1024+j] = (gaPageTable[i*1024+j] & ~PF_WRITE) | PF_COW;
+                               gaPageTable[i*1024+j] = (gaPageTable[i*1024+j] & ~PF_WRITE) | PF_COW;
+                       }
+                       else
+                               gaTmpTable[i*1024+j] = gaPageTable[i*1024+j];
+                       LOG("gaTmpTable[0x%x] = 0x%x", i*1024+j, gaTmpTable[i*1024+j]);
+                       #else
+                       gaTmpTable[i*1024+j] = MM_DuplicatePage( (i*1024+j)<<12 ) | (gaPageTable[i*1024+j]&7);
+                       #endif
+               }
+       }
+       
+       // 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 ] = *gTmpCR3;
+                       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 = KERNEL_STACKS >> 22;
+               i < KERNEL_STACK_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 & ~(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 );
+               }
+       }
+       
+       //LEAVE('x', *gTmpCR3 & ~0xFFF);
+       return *gTmpCR3 & ~0xFFF;
+}
+
+/**
+ * \fn Uint MM_NewKStack()
+ * \brief Create a new kernel stack
+ */
+Uint MM_NewKStack()
+{
+       Uint    base = KERNEL_STACKS;
+       Uint    i;
+       for(;base<KERNEL_STACK_END;base+=KERNEL_STACK_SIZE)
+       {
+               if(MM_GetPhysAddr(base) != 0)   continue;
+               for(i=0;i<KERNEL_STACK_SIZE;i+=0x1000) {
+                       MM_Allocate(base+i);
+               }
+               return base+KERNEL_STACK_SIZE;
+       }
+       Warning("MM_NewKStack - No address space left\n");
+       return 0;
+}
+
+/**
+ * \fn void MM_SetFlags(Uint VAddr, Uint Flags, Uint Mask)
+ * \brief Sets the flags on a page
+ */
+void MM_SetFlags(Uint VAddr, Uint Flags, Uint Mask)
+{
+       tPAddr  *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    *ent |= PF_WRITE;
+       }
+       
+       // Kernel
+       if( Mask & MM_PFLAG_KERNEL )
+       {
+               if( Flags & MM_PFLAG_KERNEL )   *ent &= ~PF_USER;
+               else    *ent |= PF_USER;
+       }
+}
+
+/**
+ * \fn tPAddr MM_DuplicatePage(Uint VAddr)
+ * \brief Duplicates a virtual page to a physical one
+ */
+tPAddr MM_DuplicatePage(Uint VAddr)
+{
+       tPAddr  ret;
+       Uint    temp;
+        int    wasRO = 0;
+       
+       // 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();
+       
+       // 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);
+       
+       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
+ */
+Uint MM_MapTemp(tPAddr PAddr)
+{
+        int    i;
+       
+       //ENTER("XPAddr", PAddr);
+       
+       PAddr &= ~0xFFF;
+       
+       //LOG("gilTempMappings = %i", gilTempMappings);
+       
+       for(;;)
+       {
+               LOCK( &gilTempMappings );
+               
+               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));
+                       RELEASE( &gilTempMappings );
+                       return TEMP_MAP_ADDR + (i << 12);
+               }
+               RELEASE( &gilTempMappings );
+               Proc_Yield();
+       }
+}
+
+/**
+ * \fn void MM_FreeTemp(Uint PAddr)
+ * \brief Free's a temp mapping
+ */
+void MM_FreeTemp(Uint VAddr)
+{
+        int    i = VAddr >> 12;
+       //ENTER("xVAddr", VAddr);
+       
+       if(i >= (TEMP_MAP_ADDR >> 12))
+               gaPageTable[ i ] = 0;
+       
+       //LEAVE('-');
+}
+
+/**
+ * \fn Uint MM_MapHWPage(tPAddr PAddr, Uint Number)
+ * \brief Allocates a contigous number of pages
+ */
+Uint MM_MapHWPage(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 void MM_UnmapHWPage(Uint VAddr, Uint Number)
+ * \brief Unmap a hardware page
+ */
+void MM_UnmapHWPage(Uint VAddr, Uint Number)
+{
+        int    i, j;
+       // Sanity Check
+       if(VAddr < HW_MAP_ADDR || VAddr-Number*0x1000 > HW_MAP_MAX)     return;
+       
+       i = VAddr >> 12;
+       
+       LOCK( &gilTempMappings );       // Temp and HW share a directory, so they share a lock
+       
+       for( j = 0; j < Number; j++ )
+       {
+               MM_DerefPhys( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] );
+               gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = 0;
+       }
+       
+       RELEASE( &gilTempMappings );
+}
+
+// --- EXPORTS ---
+EXPORT(MM_GetPhysAddr);
+EXPORT(MM_Map);
+//EXPORT(MM_Unmap);
+EXPORT(MM_MapHWPage);
+EXPORT(MM_UnmapHWPage);
diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c
new file mode 100644 (file)
index 0000000..d7af3e3
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ * AcessOS Microkernel Version
+ * proc.c
+ */
+#include <common.h>
+#include <proc.h>
+#include <mm_virt.h>
+#include <errno.h>
+#if USE_MP
+# include <mp.h>
+#endif
+
+// === CONSTANTS ===
+#define        RANDOM_SEED     0xACE55052
+#define        SWITCH_MAGIC    0xFFFACE55      // There is no code in this area
+#define        DEFAULT_QUANTUM 10
+#define        DEFAULT_TICKETS 5
+#define MAX_TICKETS            10
+#define TIMER_DIVISOR  11931   //~100Hz
+
+// === IMPORTS ===
+extern tGDT    gGDT[];
+extern Uint    GetEIP();       // start.asm
+extern Uint32  gaInitPageDir[1024];    // start.asm
+extern void    Kernel_Stack_Top;
+
+// === PROTOTYPES ===
+void   Proc_Start();
+void   Proc_ChangeStack();
+ int   Proc_Clone(Uint *Err, Uint Flags);
+void   Proc_Exit();
+void   Proc_Yield();
+void   Proc_Sleep();
+static tThread *Proc_int_GetPrevThread(tThread **List, tThread *Thread);
+void   Proc_Scheduler();
+Sint64 now();
+Uint   rand();
+
+// === GLOBALS ===
+// -- Core Thread --
+tThread        gThreadZero = {
+       NULL, 0,        // Next, Lock
+       THREAD_STAT_ACTIVE,     // Status
+       0, 0,   // TID, TGID
+       0, 0,   // UID, GID
+       "ThreadZero",   // Name
+       0, 0, 0,        // ESP, EBP, EIP (Set on switch)
+       #if USE_PAE
+       {0,0,0},        // PML4 Entries
+       #else
+       (Uint)&gaInitPageDir-KERNEL_BASE,       // CR3
+       #endif
+       (Uint)&Kernel_Stack_Top,        // Kernel Stack (Unused as it is PL0)
+       NULL, NULL,     // Messages, Last Message
+       DEFAULT_QUANTUM, DEFAULT_QUANTUM,       // Quantum, Remaining
+       DEFAULT_TICKETS,
+       {0}     // Default config to zero
+       };
+// -- Processes --
+// --- Locks ---
+volatile int   giThreadListLock = 0;   ///\note NEVER use a heap function while locked
+// --- Current State ---
+#if USE_MP
+tThread        **gCurrentThread = NULL;
+# define CUR_THREAD    gCurrentThread[0]
+#else
+tThread        *gCurrentThread = NULL;
+# define CUR_THREAD    gCurrentThread
+#endif
+volatile int   giNumActiveThreads = 0;
+volatile int   giTotalTickets = 0;
+volatile Uint  giNextTID = 1;
+// --- Thread Lists ---
+tThread        *gActiveThreads = NULL;         // Currently Running Threads
+tThread        *gSleepingThreads = NULL;       // Sleeping Threads
+tThread        *gDeleteThreads = NULL;         // Threads to delete
+// --- Multiprocessing ---
+ int   giNumCPUs = 1;
+#if USE_MP
+tMPInfo        *gMPTable = NULL;
+#endif
+#if USE_PAE
+Uint32 *gPML4s[4] = NULL;
+#endif
+tTSS   *gTSSs = NULL;
+#if !USE_MP
+tTSS   gTSS0 = {0};
+#endif
+
+// === CODE ===
+/**
+ * \fn void Proc_Start()
+ * \brief Starts the process scheduler
+ */
+void Proc_Start()
+{
+       Uint    pos = 0;
+       
+       #if USE_MP
+       // -- Initialise Multiprocessing
+       // Find MP Floating Table
+       // - EBDA
+       for(pos = KERNEL_BASE|0x9FC00; pos < (KERNEL_BASE|0xA0000); pos += 16) {
+               if( *(Uint*)(pos) == MPTABLE_IDENT ) {
+                       if(ByteSum( (void*)pos, sizeof(tMPInfo) ) != 0) continue;
+                       gMPTable = (void*)pos;
+                       break;
+               }
+       }
+       // - Last KiB
+       if(!gMPTable) {
+               
+       }
+       // - BIOS ROM
+       if(!gMPTable) {
+               for(pos = KERNEL_BASE|0xF0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
+                       if( *(Uint*)(pos) == MPTABLE_IDENT ) {
+                               if(ByteSum( (void*)pos, sizeof(tMPInfo) ) != 0) continue;
+                               gMPTable = (void*)pos;
+                               break;
+                       }
+               }
+       }
+       
+       // If the MP Table Exists, parse it
+       if(gMPTable)
+       {
+               Panic("Uh oh... MP Table Parsing is unimplemented\n");
+       } else {
+       #endif
+               giNumCPUs = 1;
+               gTSSs = &gTSS0;
+       #if USE_MP
+       }
+       
+       // Initialise TSS
+       for(pos=0;pos<giNumCPUs;pos++)
+       {
+       #else
+       pos = 0;
+       #endif
+               gTSSs[pos].SS0 = 0x10;
+               gTSSs[pos].ESP0 = 0;    // Set properly by scheduler
+               gGDT[5+pos].LimitLow = sizeof(tTSS);
+               gGDT[5+pos].LimitHi = 0;
+               gGDT[5+pos].Access = 0x89;      // Type
+               gGDT[5+pos].Flags = 0x4;
+               gGDT[5+pos].BaseLow = (Uint)&gTSSs[pos] & 0xFFFF;
+               gGDT[5+pos].BaseMid = (Uint)&gTSSs[pos] >> 16;
+               gGDT[5+pos].BaseHi = (Uint)&gTSSs[pos] >> 24;
+       #if USE_MP
+       }
+       for(pos=0;pos<giNumCPUs;pos++) {
+       #endif
+               __asm__ __volatile__ ("ltr %%ax"::"a"(0x28+pos*8));
+       #if USE_MP
+       }
+       #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
+       
+       // Create Initial Task
+       gActiveThreads = &gThreadZero;
+       gCurrentThread = &gThreadZero;
+       giTotalTickets = gThreadZero.NumTickets;
+       giNumActiveThreads = 1;
+       
+       // Create Per-Process Data Block
+       MM_Allocate(MM_PPD_CFG);
+       
+       // Change Stacks
+       Proc_ChangeStack();
+       
+       #if 1
+       // Create Idle Task
+       if(Proc_Clone(0, 0) == 0)
+       {
+               gCurrentThread->ThreadName = "Idle Thread";
+               Proc_SetTickets(0);     // Never called randomly
+               gCurrentThread->Quantum = 1;    // 1 slice quantum
+               for(;;) __asm__ __volatile__ ("hlt");   // Just yeilds
+       }
+       #endif
+       
+       // Start Interrupts (and hence scheduler)
+       __asm__ __volatile__("sti");
+}
+
+/**
+ * \fn void Proc_ChangeStack()
+ * \brief Swaps the current stack for a new one (in the proper stack reigon)
+ */
+void Proc_ChangeStack()
+{
+       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 = gCurrentThread->KernelStack;
+       
+       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;
+       }
+       
+       gCurrentThread->KernelStack = newBase;
+       
+       __asm__ __volatile__ ("mov %0, %%esp"::"r"(esp));
+       __asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
+}
+
+/**
+ * \fn int Proc_Clone(Uint *Err, Uint Flags)
+ * \brief Clone the current process
+ */
+int Proc_Clone(Uint *Err, Uint Flags)
+{
+       tThread *newThread;
+       Uint    eip, esp, ebp;
+       
+       __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp));
+       __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp));
+       
+       // Create new thread structure
+       newThread = malloc( sizeof(tThread) );
+       if(!newThread) {
+               Warning("Proc_Clone - Out of memory when creating thread\n");
+               *Err = -ENOMEM;
+               return -1;
+       }
+       // Base new thread on old
+       memcpy(newThread, gCurrentThread, sizeof(tThread));
+       // Initialise Memory Space (New Addr space or kernel stack)
+       if(Flags & CLONE_VM) {
+               newThread->TGID = newThread->TID;
+               newThread->CR3 = MM_Clone();
+       } else {
+               Uint    tmpEbp, oldEsp = esp;
+
+               // Create new KStack
+               newThread->KernelStack = MM_NewKStack();
+               // Check for errors
+               if(newThread->KernelStack == 0) {
+                       free(newThread);
+                       return -1;
+               }
+
+               // Get ESP as a used size
+               esp = gCurrentThread->KernelStack - esp;
+               // Copy used stack
+               memcpy( (void*)(newThread->KernelStack - esp), (void*)(gCurrentThread->KernelStack - esp), esp );
+               // Get ESP as an offset in the new stack
+               esp = newThread->KernelStack - esp;
+               // Adjust EBP
+               ebp = newThread->KernelStack - (gCurrentThread->KernelStack - ebp);
+
+               // Repair EBPs & Stack Addresses
+               // Catches arguments also, but may trash stack-address-like values
+               for(tmpEbp = esp; tmpEbp < newThread->KernelStack; tmpEbp += 4)
+               {
+                       if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < gCurrentThread->KernelStack)
+                               *(Uint*)tmpEbp += newThread->KernelStack - gCurrentThread->KernelStack;
+               }
+       }
+
+       // Set Pointer, Spinlock and TID
+       newThread->Next = NULL;
+       newThread->IsLocked = 0;
+       newThread->TID = giNextTID++;
+
+       // Clear message list (messages are not inherited)
+       newThread->Messages = NULL;
+       newThread->LastMessage = NULL;
+       
+       // Set remaining (sheduler expects remaining to be correct)
+       newThread->Remaining = newThread->Quantum;
+       
+       // Save core machine state
+       newThread->ESP = esp;
+       newThread->EBP = ebp;
+       eip = GetEIP();
+       if(eip == SWITCH_MAGIC) {
+               outb(0x20, 0x20);       // ACK Timer and return as child
+               return 0;
+       }
+       
+       // Set EIP as parent
+       newThread->EIP = eip;
+       
+       //Log(" Proc_Clone: giTimestamp = %i.%07i", (Uint)giTimestamp, (Uint)giPartMiliseconds/214);
+       
+       // Lock list and add to active
+       LOCK( &giThreadListLock );
+       newThread->Next = gActiveThreads;
+       gActiveThreads = newThread;
+       giNumActiveThreads ++;
+       giTotalTickets += newThread->NumTickets;
+       RELEASE( &giThreadListLock );
+       
+       return newThread->TID;
+}
+
+/**
+ * \fn void Proc_SetThreadName()
+ * \brief Sets the thread's name
+ */
+void Proc_SetThreadName(char *NewName)
+{
+       if( (Uint)CUR_THREAD->ThreadName > 0xC0400000 )
+               free( CUR_THREAD->ThreadName );
+       CUR_THREAD->ThreadName = malloc(strlen(NewName)+1);
+       strcpy(CUR_THREAD->ThreadName, NewName);
+}
+
+/**
+ * \fn Uint Proc_MakeUserStack()
+ */
+Uint Proc_MakeUserStack()
+{
+        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/4069; i++ )
+               MM_Allocate( base + (i<<12) );
+       
+       return base + USER_STACK_SZ;
+}
+
+
+/**
+ * \fn void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, char **EnvP, int DataSize)
+ * \brief Starts a user task
+ */
+void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
+{
+       Uint    *stack = (void*)Proc_MakeUserStack();
+        int    i;
+       Uint    delta;
+       Uint16  ss, cs;
+       
+       LOG("stack = 0x%x", stack);
+       
+       // Copy Arguments
+       stack = (void*)( (Uint)stack - DataSize );
+       memcpy( stack, ArgV, DataSize );
+       
+       // Adjust Arguments and environment
+       delta = (Uint)stack - (Uint)ArgV;
+       ArgV = (char**)stack;
+       for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
+       i ++;
+       EnvP = &ArgV[i];
+       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;
+       while(*Bases)
+               *--stack = *Bases++;
+       *--stack = 0;   // Return Address
+       delta = (Uint)stack;    // Reuse delta to save SP
+       
+       *--stack = ss;          //Stack Segment
+       *--stack = delta;       //Stack Pointer
+       *--stack = 0x0202;      //EFLAGS (Resvd (0x2) and IF (0x20))
+       *--stack = cs;          //Code Segment
+       *--stack = Entrypoint;  //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 void Proc_Exit()
+ * \brief Kill the current process
+ */
+void Proc_Exit()
+{
+       tThread *thread;
+       tMsg    *msg;
+       
+       ///\note Double lock is needed due to overlap of locks
+       
+       // Lock thread (stop us recieving messages)
+       LOCK( &gCurrentThread->IsLocked );
+       
+       // Lock thread list
+       LOCK( &giThreadListLock );
+       
+       // Get previous thread on list
+       thread = Proc_int_GetPrevThread( &gActiveThreads, gCurrentThread );
+       if(!thread) {
+               Warning("Proc_Exit - Current thread is not on the active queue");
+               return;
+       }
+       
+       // Clear Message Queue
+       while( gCurrentThread->Messages )
+       {
+               msg = gCurrentThread->Messages->Next;
+               free( gCurrentThread->Messages );
+               gCurrentThread->Messages = msg;
+       }
+       
+       gCurrentThread->Remaining = 0;  // Clear Remaining Quantum
+       gCurrentThread->Quantum = 0;    // Clear Quantum to indicate dead thread
+       thread->Next = gCurrentThread->Next;    // Remove from active
+       
+       // Add to delete queue
+       if(gDeleteThreads) {
+               gCurrentThread->Next = gDeleteThreads;
+               gDeleteThreads = gCurrentThread;
+       } else {
+               gCurrentThread->Next = NULL;
+               gDeleteThreads = gCurrentThread;
+       }
+       
+       giNumActiveThreads --;
+       giTotalTickets -= gCurrentThread->NumTickets;
+       
+       // Mark thread as sleeping
+       gCurrentThread->Status = THREAD_STAT_DEAD;
+       
+       // Release spinlocks
+       RELEASE( &gCurrentThread->IsLocked );   // Released first so that it IS released
+       RELEASE( &giThreadListLock );
+       __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Proc_Yield()
+ * \brief Yield remainder of timeslice
+ */
+void Proc_Yield()
+{
+       gCurrentThread->Quantum = 0;
+       __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Proc_Sleep()
+ * \brief Take the current process off the run queue
+ */
+void Proc_Sleep()
+{
+       tThread *thread;
+       
+       //Log("Proc_Sleep: %i going to sleep", gCurrentThread->TID);
+       
+       // Acquire Spinlock
+       LOCK( &giThreadListLock );
+       
+       // Get thread before current thread
+       thread = Proc_int_GetPrevThread( &gActiveThreads, gCurrentThread );
+       if(!thread) {
+               Warning("Proc_Sleep - Current thread is not on the active queue");
+               return;
+       }
+       
+       // Don't sleep if there is a message waiting
+       if( gCurrentThread->Messages ) {
+               RELEASE( &giThreadListLock );
+               return;
+       }
+       
+       // Unset remaining timeslices (force a task switch on timer fire)
+       gCurrentThread->Remaining = 0;
+       
+       // Remove from active list
+       thread->Next = gCurrentThread->Next;
+       
+       // Add to Sleeping List (at the top)
+       gCurrentThread->Next = gSleepingThreads;
+       gSleepingThreads = gCurrentThread;
+       
+       // Reduce the active count & ticket count
+       giNumActiveThreads --;
+       giTotalTickets -= gCurrentThread->NumTickets;
+       
+       // Mark thread as sleeping
+       gCurrentThread->Status = THREAD_STAT_SLEEPING;
+       
+       // Release Spinlock
+       RELEASE( &giThreadListLock );
+       
+       __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Thread_Wake( tThread *Thread )
+ * \brief Wakes a sleeping/waiting thread up
+ */
+void Thread_Wake(tThread *Thread)
+{
+       tThread *prev;
+       switch(Thread->Status)
+       {
+       case THREAD_STAT_ACTIVE:        break;
+       case THREAD_STAT_SLEEPING:
+               LOCK( &giThreadListLock );
+               prev = Proc_int_GetPrevThread(&gSleepingThreads, Thread);
+               prev->Next = Thread->Next;      // Remove from sleeping queue
+               Thread->Next = gActiveThreads;  // Add to active queue
+               gActiveThreads = Thread;
+               Thread->Status = THREAD_STAT_ACTIVE;
+               RELEASE( &giThreadListLock );
+               break;
+       case THREAD_STAT_WAITING:
+               Warning("Thread_Wake - Waiting threads are not currently supported");
+               break;
+       case THREAD_STAT_DEAD:
+               Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
+               break;
+       default:
+               Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
+               break;
+       }
+}
+
+/**
+ * \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
+ */
+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;
+}
+
+/**
+ * \fn void Proc_SetTickets(int Num)
+ * \brief Sets the 'priority' of a task
+ */
+void Proc_SetTickets(int Num)
+{
+       if(Num < 0)     return;
+       if(Num > MAX_TICKETS)   Num = MAX_TICKETS;
+       
+       LOCK( &giThreadListLock );
+       giTotalTickets -= gCurrentThread->NumTickets;
+       gCurrentThread->NumTickets = Num;
+       giTotalTickets += Num;
+       //LOG("giTotalTickets = %i", giTotalTickets);
+       RELEASE( &giThreadListLock );
+}
+
+/**
+ * \fn tThread *Proc_GetThread(Uint TID)
+ * \brief Gets a thread given its TID
+ */
+tThread *Proc_GetThread(Uint TID)
+{
+       tThread *thread;
+       
+       // Search Active List
+       for(thread = gActiveThreads;
+               thread;
+               thread = thread->Next)
+       {
+               if(thread->TID == TID)
+                       return thread;
+       }
+       
+       // Search Sleeping List
+       for(thread = gSleepingThreads;
+               thread;
+               thread = thread->Next)
+       {
+               if(thread->TID == TID)
+                       return thread;
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn static tThread *Proc_int_GetPrevThread(tThread *List, tThread *Thread)
+ * \brief Gets the previous entry in a thead linked list
+ */
+static tThread *Proc_int_GetPrevThread(tThread **List, tThread *Thread)
+{
+       tThread *ret;
+       // First Entry
+       if(*List == Thread) {
+               return (tThread*)List;
+       } else {
+               for(ret = *List;
+                       ret->Next && ret->Next != Thread;
+                       ret = ret->Next
+                       );
+               // Error if the thread is not on the list
+               if(!ret->Next || ret->Next != Thread) {
+                       return NULL;
+               }
+       }
+       return ret;
+}
+
+/**
+ * \fn void Proc_DumpThreads()
+ */
+void Proc_DumpThreads()
+{
+       tThread *thread;
+       
+       Log("Active Threads:");
+       for(thread=gActiveThreads;thread;thread=thread->Next)
+       {
+               Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
+               Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
+               Log("  CR3 0x%x, KStack 0x%x", thread->CR3, thread->KernelStack);
+       }
+       Log("Sleeping Threads:");
+       for(thread=gSleepingThreads;thread;thread=thread->Next)
+       {
+               Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
+               Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
+               Log("  CR3 0x%x, KStack 0x%x", thread->CR3, thread->KernelStack);
+       }
+}
+
+/**
+ * \fn void Proc_Scheduler(int CPU)
+ * \brief Swap current task
+ */
+void Proc_Scheduler(int CPU)
+{
+       Uint    esp, ebp, eip;
+       Uint    number, ticket;
+       tThread *thread;
+       
+       // If the spinlock is set, let it complete
+       if(giThreadListLock)    return;
+       
+       // Clear Delete Queue
+       while(gDeleteThreads)
+       {
+               thread = gDeleteThreads->Next;
+               if(gDeleteThreads->IsLocked) {  // Only free if structure is unused
+                       gDeleteThreads->Status = THREAD_STAT_NULL;
+                       free( gDeleteThreads );
+               }
+               gDeleteThreads = thread;
+       }
+       
+       // Check if there is any tasks running
+       if(giNumActiveThreads == 0) {
+               Log("No Active threads, sleeping\n");
+               __asm__ __volatile__ ("hlt");
+               return;
+       }
+       
+       // Reduce remaining quantum
+       if(gCurrentThread->Remaining--) return;
+       // Reset quantum for next call
+       gCurrentThread->Remaining = gCurrentThread->Quantum;
+       
+       // Get machine state
+       __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
+       __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
+       eip = GetEIP();
+       if(eip == SWITCH_MAGIC) return; // Check if a switch happened
+       
+       // Save machine state
+       gCurrentThread->ESP = esp;
+       gCurrentThread->EBP = ebp;
+       gCurrentThread->EIP = eip;
+       
+       // Special case: 1 thread
+       if(giNumActiveThreads == 1)
+       {
+               // Check if a switch is needed (NumActive can be 1 after a sleep)
+               if(gActiveThreads == gCurrentThread)    return;
+               // Switch processes
+               gCurrentThread = gActiveThreads;
+               goto performSwitch;
+       }
+       
+       // Get the ticket number
+       ticket = number = rand() % giTotalTickets;
+       
+       // Find the next thread
+       for(thread=gActiveThreads;thread;thread=thread->Next)
+       {
+               if(thread->NumTickets > number) break;
+               number -= thread->NumTickets;
+       }
+       
+       // Error Check
+       if(thread == NULL)
+       {
+               number = 0;
+               for(thread=gActiveThreads;thread;thread=thread->Next)
+                       number += thread->NumTickets;
+               Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
+                       giTotalTickets, number);
+       }
+       
+       // Set current thread
+       gCurrentThread = thread;
+       
+       // Update Kernel Stack pointer
+       gTSSs[CPU].ESP0 = thread->KernelStack;
+       
+performSwitch:
+       // Set address space
+       //MM_SetCR3( gCurrentThread->CR3 );
+       __asm__ __volatile__ ("mov %0, %%cr3"::"a"(gCurrentThread->CR3));
+       // Switch threads
+       __asm__ __volatile__ (
+               "mov %1, %%esp\n\t"
+               "mov %2, %%ebp\n\t"
+               "jmp *%3" : :
+               "a"(SWITCH_MAGIC), "b"(gCurrentThread->ESP),
+               "d"(gCurrentThread->EBP), "c"(gCurrentThread->EIP));
+       for(;;);        // Shouldn't reach here
+}
+
+// --- Process Structure Access Functions ---
+int Proc_GetPID()
+{
+       return gCurrentThread->TGID;
+}
+int Proc_GetTID()
+{
+       return gCurrentThread->TID;
+}
+int Proc_GetUID()
+{
+       return gCurrentThread->UID;
+}
+int Proc_GetGID()
+{
+       return gCurrentThread->GID;
+}
+
+/**
+ * \fn Uint rand()
+ * \brief Pseudo random number generator
+ * \note Unknown effectiveness (made up on the spot)
+ */
+Uint rand()
+{
+       static Uint     randomState = RANDOM_SEED;
+       Uint    ret = randomState;
+        int    roll = randomState & 31;
+       randomState = (randomState << roll) | (randomState >> (32-roll));
+       randomState ^= 0x9A3C5E78;
+       return ret;
+}
diff --git a/Kernel/arch/x86/start.asm b/Kernel/arch/x86/start.asm
new file mode 100644 (file)
index 0000000..e1cc70a
--- /dev/null
@@ -0,0 +1,105 @@
+; AcessOS Microkernel Version\r
+; Start.asm\r
+\r
+[bits 32]\r
+\r
+KERNEL_BASE    equ 0xC0000000\r
+\r
+[section .multiboot]\r
+mboot:\r
+    ; Multiboot macros to make a few lines later more readable\r
+    MULTIBOOT_PAGE_ALIGN       equ 1<<0\r
+    MULTIBOOT_MEMORY_INFO      equ 1<<1\r
+    MULTIBOOT_HEADER_MAGIC     equ 0x1BADB002\r
+    MULTIBOOT_HEADER_FLAGS     equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO\r
+    MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)\r
+       \r
+    ; This is the GRUB Multiboot header. A boot signature\r
+    dd MULTIBOOT_HEADER_MAGIC\r
+    dd MULTIBOOT_HEADER_FLAGS\r
+    dd MULTIBOOT_CHECKSUM\r
+       dd mboot - KERNEL_BASE  ;Location of Multiboot Header\r
+       \r
+[section .text]\r
+[extern _kmain]\r
+[global start]\r
+start:\r
+       ; Set up stack\r
+       mov esp, _Kernel_Stack_Top\r
+       \r
+       ; Start Paging\r
+       mov ecx, _gaInitPageDir - KERNEL_BASE\r
+       mov cr3, ecx\r
+       \r
+       mov ecx, cr0\r
+       or      ecx, 0x80000000\r
+       mov cr0, ecx\r
+       \r
+       lea ecx, [.higherHalf]\r
+       jmp ecx\r
+.higherHalf:\r
+\r
+       mov DWORD [_gaInitPageDir], 0\r
+\r
+       ; Call the kernel\r
+       push ebx        ; Multiboot Info\r
+       push eax        ; Multiboot Magic Value\r
+       call _kmain
+
+       ; Halt the Machine\r
+       cli\r
+.hlt:\r
+       hlt\r
+       jmp .hlt\r
+\r
+[global _GetEIP]\r
+_GetEIP:\r
+       mov eax, [esp]\r
+       ret\r
+\r
+[extern _Proc_Clone]\r
+[extern _Proc_Exit]\r
+[global _SpawnTask]\r
+_SpawnTask:\r
+       ; Call Proc_Clone with Flags=0\r
+       xor eax, eax\r
+       push eax
+       push eax\r
+       call _Proc_Clone\r
+       add esp, 8      ; Remove arguments from stack\r
+       \r
+       test eax, eax\r
+       jnz .parent\r
+       \r
+       ; In child, so now set up stack frame\r
+       mov ebx, [esp+4]        ; Child Function\r
+       mov edx, [esp+8]        ; Argument\r
+       ; Child\r
+       push edx        ; Argument\r
+       call ebx        ; Function\r
+       call _Proc_Exit ; Kill Thread\r
+       \r
+.parent:\r
+       ret\r
+\r
+[section .initpd]\r
+[global _gaInitPageDir]\r
+[global _gaInitPageTable]\r
+align 0x1000\r
+_gaInitPageDir:\r
+       dd      _gaInitPageTable-KERNEL_BASE+3  ; 0x00\r
+       times 1024-256-1        dd      0\r
+       dd      _gaInitPageTable-KERNEL_BASE+3  ; 0xC0\r
+       times 256-1     dd      0\r
+align 0x1000\r
+_gaInitPageTable:\r
+       %assign i 0\r
+       %rep 1024\r
+       dd      i*0x1000+3\r
+       %assign i i+1\r
+       %endrep\r
+[global _Kernel_Stack_Top]\r
+ALIGN 0x1000\r
+       times 1024      dd      0\r
+_Kernel_Stack_Top:\r
+       
diff --git a/Kernel/arch/x86/time.c b/Kernel/arch/x86/time.c
new file mode 100644 (file)
index 0000000..3a13904
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Acess2 Kernel
+ * Timekeeping
+ * arch/x86/time.c
+ */
+#include <common.h>
+
+// === MACROS ===
+#define TIMER_FREQ     1024    //Hz
+#define MS_PER_TICK_WHOLE      (1000/(TIMER_FREQ))
+#define MS_PER_TICK_FRACT      ((Uint64)(1000*TIMER_FREQ-((Uint64)MS_PER_TICK_WHOLE)*0x80000000/TIMER_FREQ))
+
+// === PROTOTYPES ===
+void   Time_Interrupt();
+
+// === GLOBALS ===
+Uint64 giTicks = 0;
+Sint64 giTimestamp = 0;
+Uint64 giPartMiliseconds = 0;
+
+// === CODE ===
+/**
+ * \fn int Time_Setup()
+ * \brief Sets the system time from the Realtime-Clock
+ */
+int Time_Setup()
+{
+       Uint8   val;
+       
+       outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
+       __asm__ __volatile__ ("cli");   // Disable normal interrupts
+       
+       // 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");   // Disable normal interrupts
+       outb(0x70, inb(0x70)|0x80);     // Disable NMIs
+       
+       // Install IRQ Handler
+       IRQ_AddHandler(8, Time_Interrupt);
+       return 0;
+}
+
+/**
+ * \fn void Time_Interrupt()
+ * \brief Called on the timekeeping IRQ
+ */
+void Time_Interrupt()
+{
+       giTicks ++;
+       giTimestamp += MS_PER_TICK_WHOLE;
+       giPartMiliseconds += MS_PER_TICK_FRACT;
+       if(giPartMiliseconds > 0x80000000) {
+               giTimestamp ++;
+               giPartMiliseconds -= 0x80000000;
+       }
+}
+
+/**
+ * \fn Sint64 now()
+ * \brief Return the current timestamp
+ */
+Sint64 now()
+{
+       return giTimestamp;
+}
diff --git a/Kernel/bin/bin_elf.h b/Kernel/bin/bin_elf.h
new file mode 100644 (file)
index 0000000..fbbfebc
--- /dev/null
@@ -0,0 +1,215 @@
+/**\r
+ Acess v1\r
+ \file bin_elf.h\r
+ \brief ELF Exeutable Loader\r
+*/\r
+#ifndef _BIN_ELF_H\r
+#define _BIN_ELF_H\r
+\r
+/**\r
+ \struct elf_header_s\r
+ \brief ELF File Header\r
+*/\r
+struct sElf32_Ehdr {\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
+};\r
+\r
+/**\r
+ \name Executable Types\r
+ \{\r
+*/\r
+#define        ET_NONE         0       //!< NULL Type\r
+#define        ET_REL          1       //!< Relocatable (Object)\r
+#define ET_EXEC                2       //!< Executable\r
+#define ET_DYN         3       //!< Dynamic Library\r
+#define ET_CORE                4       //!< Core?\r
+#define ET_LOPROC      0xFF00  //!< Low Impl Defined\r
+#define 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
+};     //sizeof = 40\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
+};\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
+       Uint    Offset;\r
+       Uint    VAddr;\r
+       Uint    PAddr;\r
+       Uint32  FileSize;\r
+       Uint32  MemSize;\r
+       Uint32  Flags;\r
+       Uint32  Align;\r
+};\r
+\r
+struct elf32_rel_s {\r
+       Uint32  r_offset;\r
+       Uint32  r_info;\r
+};\r
+\r
+struct elf32_rela_s {\r
+       Uint32  r_offset;\r
+       Uint32  r_info;\r
+       Sint32  r_addend;\r
+};\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
+       Uint16  d_tag;\r
+       Uint32  d_val;  //Also d_ptr\r
+};\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/elf.c b/Kernel/bin/elf.c
new file mode 100644 (file)
index 0000000..dbd38d2
--- /dev/null
@@ -0,0 +1,587 @@
+/*\r
+Acess v0.1\r
+ELF Executable Loader Code\r
+*/\r
+#include <common.h>\r
+#include <binary.h>\r
+#include "bin_elf.h"\r
+\r
+#define DEBUG  1\r
+#define DEBUG_WARN     1\r
+\r
+#if DEBUG\r
+# define DEBUGS(v...)  Log(v)\r
+#else\r
+# define DEBUGS(v...)\r
+# undef ENTER\r
+# undef LOG\r
+# undef LEAVE\r
+# define ENTER(...)\r
+# define LOG(...)\r
+# define LEAVE(...)\r
+#endif\r
+\r
+\r
+// === PROTOTYPES ===\r
+tBinary        *Elf_Load(int fp);\r
+ int   Elf_Relocate(void *Base);\r
+ int   Elf_GetSymbol(void *Base, 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(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
+       tBinary *ret;\r
+       Elf32_Ehdr      hdr;\r
+       Elf32_Phdr      *phtab;\r
+        int    i, j, k;\r
+        int    iPageCount;\r
+        int    count;\r
+       \r
+       ENTER("ifp", fp);\r
+       \r
+       // Read ELF Header\r
+       VFS_Read(fp, sizeof(hdr), &hdr);\r
+       \r
+       // Check the file type\r
+       if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') {\r
+               Warning("Non-ELF File was passed to the ELF loader\n");\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Check for a program header\r
+       if(hdr.phoff == 0) {\r
+               #if DEBUG_WARN\r
+               Warning("ELF File does not contain a program header\n");\r
+               #endif\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Read Program Header Table\r
+       phtab = malloc(sizeof(Elf32_Phdr)*hdr.phentcount);\r
+       VFS_Seek(fp, hdr.phoff, SEEK_SET);\r
+       VFS_Read(fp, sizeof(Elf32_Phdr)*hdr.phentcount, phtab);\r
+       \r
+       // Count Pages\r
+       iPageCount = 0;\r
+       LOG("hdr.phentcount = %i", hdr.phentcount);\r
+       for( i = 0; i < hdr.phentcount; i++ )\r
+       {\r
+               // Ignore Non-LOAD types\r
+               if(phtab[i].Type != PT_LOAD)\r
+                       continue;\r
+               iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;\r
+               LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
+       }\r
+       \r
+       LOG("iPageCount = %i", iPageCount);\r
+       \r
+       // Allocate Information Structure\r
+       ret = malloc( sizeof(tBinary) + 3*sizeof(Uint)*iPageCount );\r
+       // Fill Info Struct\r
+       ret->Entry = hdr.entrypoint;\r
+       ret->Base = -1;         // Set Base to maximum value\r
+       ret->NumPages = iPageCount;\r
+       ret->Interpreter = NULL;\r
+       \r
+       // Load Pages\r
+       j = 0;\r
+       for( i = 0; i < hdr.phentcount; i++ )\r
+       {\r
+                int    lastSize;\r
+               LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\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(fp, phtab[i].Offset, 1);\r
+                       VFS_Read(fp, 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
+               k = 0;\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
+               if( (phtab[i].FileSize & 0xFFF) < 0x1000 - (phtab[i].VAddr & 0xFFF) )\r
+                       lastSize = phtab[i].FileSize;\r
+               else\r
+                       lastSize = (phtab[i].FileSize & 0xFFF) + (phtab[i].VAddr & 0xFFF);\r
+               lastSize &= 0xFFF;\r
+               \r
+               LOG("lastSize = 0x%x", lastSize);\r
+               \r
+               // Get Pages\r
+               count = ( (phtab[i].VAddr&0xFFF) + phtab[i].FileSize + 0xFFF) >> 12;\r
+               for(;k<count;k++)\r
+               {\r
+                       ret->Pages[j+k].Virtual = phtab[i].VAddr + (k<<12);\r
+                       ret->Pages[j+k].Physical = phtab[i].Offset + (k<<12);   // Store the offset in the physical address\r
+                       if(k != 0) {\r
+                               ret->Pages[j+k].Physical -= ret->Pages[j+k].Virtual&0xFFF;\r
+                               ret->Pages[j+k].Virtual &= ~0xFFF;\r
+                       }\r
+                       if(k == count-1)\r
+                               ret->Pages[j+k].Size = lastSize;        // Byte count in page\r
+                       else if(k == 0)\r
+                               ret->Pages[j+k].Size = 4096 - (phtab[i].VAddr&0xFFF);\r
+                       else\r
+                               ret->Pages[j+k].Size = 4096;\r
+                       LOG("ret->Pages[%i].Size = 0x%x", j+k, ret->Pages[j+k].Size);\r
+                       ret->Pages[j+k].Flags = 0;\r
+               }\r
+               count = (phtab[i].MemSize + 0xFFF) >> 12;\r
+               for(;k<count;k++)\r
+               {\r
+                       ret->Pages[j+k].Virtual = phtab[i].VAddr + (k<<12);\r
+                       ret->Pages[j+k].Physical = -1;  // -1 = Fill with zeros\r
+                       if(k != 0)      ret->Pages[j+k].Virtual &= ~0xFFF;\r
+                       if(k == count-1 && (phtab[i].MemSize & 0xFFF))\r
+                               ret->Pages[j+k].Size = phtab[i].MemSize & 0xFFF;        // Byte count in page\r
+                       else\r
+                               ret->Pages[j+k].Size = 4096;\r
+                       ret->Pages[j+k].Flags = 0;\r
+                       LOG("%i - 0x%x => 0x%x - 0x%x", j+k,\r
+                               ret->Pages[j+k].Physical, ret->Pages[j+k].Virtual, ret->Pages[j+k].Size);\r
+               }\r
+               j += count;\r
+       }\r
+       \r
+       #if 0\r
+       LOG("Cleaning up overlaps");\r
+       // Clear up Overlaps\r
+       {\r
+               struct {\r
+                       Uint    V;\r
+                       Uint    P;\r
+                       Uint    S;\r
+                       Uint    F;\r
+               } *tmpRgns;\r
+               count = j;\r
+               tmpRgns = malloc(sizeof(*tmpRgns)*count);\r
+               // Copy\r
+               for(i=0;i<count;i++) {\r
+                       tmpRgns[i].V = ret->Pages[i].Virtual;\r
+                       tmpRgns[i].P = ret->Pages[i].Physical;\r
+                       tmpRgns[i].S = ret->Pages[i].Size;\r
+                       tmpRgns[i].F = ret->Pages[i].Flags;\r
+               }\r
+               // Compact\r
+               for(i=1,j=0; i < count; i++)\r
+               {                       \r
+                       if(     tmpRgns[j].F == tmpRgns[i].F\r
+                       &&      tmpRgns[j].V + tmpRgns[j].S == tmpRgns[i].V\r
+                       &&      ((tmpRgns[j].P == -1 && tmpRgns[i].P == -1)\r
+                       || (tmpRgns[j].P + tmpRgns[j].S == tmpRgns[i].P)) )\r
+                       {\r
+                               tmpRgns[j].S += tmpRgns[i].S;\r
+                       } else {\r
+                               j ++;\r
+                               tmpRgns[j].V = tmpRgns[i].V;\r
+                               tmpRgns[j].P = tmpRgns[i].P;\r
+                               tmpRgns[j].F = tmpRgns[i].F;\r
+                               tmpRgns[j].S = tmpRgns[i].S;\r
+                       }\r
+               }\r
+               j ++;\r
+               // Count\r
+               count = j;      j = 0;\r
+               for(i=0;i<count;i++) {\r
+                       //LogF(" Elf_Load: %i - 0x%x => 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S);\r
+                       tmpRgns[i].S += tmpRgns[i].V & 0xFFF;\r
+                       if(tmpRgns[i].P != -1)  tmpRgns[i].P -= tmpRgns[i].V & 0xFFF;\r
+                       tmpRgns[i].V &= ~0xFFF;\r
+                       j += (tmpRgns[i].S + 0xFFF) >> 12;\r
+                       //LogF(" Elf_Load: %i - 0x%x => 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S);\r
+               }\r
+               // Reallocate\r
+               ret = realloc( ret, sizeof(tBinary) + 3*sizeof(Uint)*j );\r
+               if(!ret) {\r
+                       Warning("BIN", "ElfLoad: Unable to reallocate return structure");\r
+                       return NULL;\r
+               }\r
+               ret->NumPages = j;\r
+               // Split\r
+               k = 0;\r
+               for(i=0;i<count;i++) {\r
+                       for( j = 0; j < (tmpRgns[i].S + 0xFFF) >> 12; j++,k++ ) {\r
+                               ret->Pages[k].Flags = tmpRgns[i].F;\r
+                               ret->Pages[k].Virtual = tmpRgns[i].V + (j<<12);\r
+                               if(tmpRgns[i].P != -1) {\r
+                                       ret->Pages[k].Physical = tmpRgns[i].P + (j<<12);\r
+                               } else\r
+                                       ret->Pages[k].Physical = -1;\r
+                               ret->Pages[k].Size = tmpRgns[i].S - (j << 12);\r
+                               // Clamp to page size\r
+                               if(ret->Pages[k].Size > 0x1000) ret->Pages[k].Size = 0x1000;\r
+                       }\r
+               }\r
+               // Free Temp\r
+               free(tmpRgns);\r
+       }\r
+       #endif\r
+       \r
+       // Clean Up\r
+       free(phtab);\r
+       // Return\r
+       LEAVE('p', ret);\r
+       return ret;\r
+}\r
+\r
+// --- ELF RELOCATION ---\r
+// Taken from 'ld-acess.so'\r
+/**\r
+ \fn int Elf_Relocate(void *Base)\r
+ \brief Relocates a loaded ELF Executable\r
+*/\r
+int Elf_Relocate(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
+       \r
+       ENTER("pBase", Base);\r
+       \r
+       // Parse Program Header to get Dynamic Table\r
+       phtab = 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
+                               Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
+                               continue;\r
+                       }\r
+                       dynamicTab = (void *) 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
+               Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
+               LEAVE('x', hdr->entrypoint);\r
+               return hdr->entrypoint;\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*)(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*)(dynamicTab[j].d_val);\r
+                       break;\r
+               \r
+               // --- Hash Table --\r
+               case DT_HASH:\r
+                       dynamicTab[j].d_val += iBaseDiff;\r
+                       iSymCount = ((Uint*)(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
+\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("Required Library '%s' (IGNORED in kernel mode)\n", 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
+               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
+                               LEAVE('x', 0);\r
+                               return 0;\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(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
+                               LEAVE('x', 0);\r
+                               return 0;\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
+                       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
+                                       LEAVE('x', 0);\r
+                                       return 0;\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       Elf32_Rela      *pltRela = plt;\r
+                       j = pltSz / sizeof(Elf32_Rela);\r
+                       for(i=0;i<j;i++)\r
+                       {\r
+                               ptr = (void*)((Uint)Base + pltRela[i].r_offset);\r
+                               if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
+                                       LEAVE('x', 0);\r
+                                       return 0;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       LEAVE('x', hdr->entrypoint);\r
+       return hdr->entrypoint;\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("R_386_32 *0x%x += 0x%x('%s')", 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("R_386_PC32 *0x%x = 0x%x + 0x%x('%s') - 0x%x", 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("R_386_GLOB_DAT *0x%x = 0x%x (%s)", 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("R_386_JMP_SLOT *0x%x = 0x%x (%s)", ptr, val, sSymName);\r
+               *ptr = val;\r
+               break;\r
+\r
+       // Base Address (B+A)\r
+       case R_386_RELATIVE:\r
+               //LOG("R_386_RELATIVE *0x%x = 0x%x + 0x%x", 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, char *name, Uint *ret)\r
+ * \brief Get a symbol from the loaded binary\r
+ */\r
+int Elf_GetSymbol(void *Base, 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
+               *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
+                       *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(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/binary.c b/Kernel/binary.c
new file mode 100644 (file)
index 0000000..7175799
--- /dev/null
@@ -0,0 +1,813 @@
+/*\r
+ * Acess2\r
+ * Common Binary Loader\r
+ */\r
+#include <common.h>\r
+#include <binary.h>\r
+\r
+#define DEBUG  1\r
+\r
+#if DEBUG\r
+#else\r
+# undef ENTER\r
+# undef LOG\r
+# undef LEAVE\r
+# define ENTER(...)\r
+# define LOG(...)\r
+# define LEAVE(...)\r
+#endif\r
+\r
+// === CONSTANTS ===\r
+#define BIN_LOWEST     MM_USER_MIN             // 1MiB\r
+#define BIN_GRANUALITY 0x10000         // 64KiB\r
+#define BIN_HIGHEST    (0xBC000000-BIN_GRANUALITY)             // Just below the kernel\r
+#define        KLIB_LOWEST     MM_MODULE_MIN\r
+#define KLIB_GRANUALITY        0x8000          // 32KiB\r
+#define        KLIB_HIGHEST    (MM_MODULE_MAX-KLIB_GRANUALITY)\r
+\r
+// === TYPES ===\r
+typedef struct sKernelBin {\r
+       struct sKernelBin       *Next;\r
+       void    *Base;\r
+       tBinary *Info;\r
+} tKernelBin;\r
+\r
+// === IMPORTS ===\r
+extern int     Proc_Clone(Uint *Err, Uint Flags);\r
+extern void    Proc_SetThreadName(char *Name);\r
+extern Uint    MM_ClearUser();\r
+extern void    Proc_Exit();\r
+extern void    Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);\r
+extern tKernelSymbol   gKernelSymbols[];\r
+extern void            gKernelSymbolsEnd;\r
+extern tBinaryType     gELF_Info;\r
+\r
+// === PROTOTYPES ===\r
+ int   Proc_Execve(char *File, char **ArgV, char **EnvP);\r
+Uint   Binary_Load(char *file, Uint *entryPoint);\r
+tBinary *Binary_GetInfo(char *truePath);\r
+Uint   Binary_MapIn(tBinary *binary);\r
+Uint   Binary_IsMapped(tBinary *binary);\r
+tBinary *Binary_DoLoad(char *truePath);\r
+void   Binary_Dereference(tBinary *Info);\r
+Uint   Binary_Relocate(void *Base);\r
+Uint   Binary_GetSymbolEx(char *Name, Uint *Value);\r
+Uint   Binary_FindSymbol(void *Base, char *Name, Uint *val);\r
+\r
+// === GLOBALS ===\r
+ int   glBinListLock = 0;\r
+tBinary        *glLoadedBinaries = NULL;\r
+char   **gsaRegInterps = NULL;\r
+ int   giRegInterps = 0;\r
+ int   glKBinListLock = 0;\r
+tKernelBin     *glLoadedKernelLibs;\r
+tBinaryType    *gRegBinTypes = &gELF_Info;\r
\r
+// === FUNCTIONS ===\r
+/**\r
+ * \fn int Proc_Spawn(char *Path)\r
+ */\r
+int Proc_Spawn(char *Path)\r
+{\r
+       char    stackPath[strlen(Path)+1];\r
+       \r
+       strcpy(stackPath, Path);\r
+       \r
+       LOG("stackPath = '%s'\n", stackPath);\r
+       \r
+       if(Proc_Clone(NULL, CLONE_VM) == 0)\r
+       {\r
+               // CHILD\r
+               char    *args[2] = {stackPath, NULL};\r
+               LOG("stackPath = '%s'\n", stackPath);\r
+               Proc_Execve(stackPath, args, &args[1]);\r
+               for(;;);\r
+       }\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)\r
+ * \brief Replace the current user image with another\r
+ * \param File File to load as the next image\r
+ * \param ArgV Arguments to pass to user\r
+ * \param EnvP User's environment\r
+ * \note Called Proc_ for historical reasons\r
+ */\r
+int Proc_Execve(char *File, char **ArgV, char **EnvP)\r
+{\r
+        int    argc, envc, i;\r
+        int    argenvBytes;\r
+       char    *argenvBuf, *strBuf;\r
+       char    **argvSaved, **envpSaved;\r
+       char    *savedFile;\r
+       Uint    entry;\r
+       Uint    bases[2] = {0};\r
+       \r
+       ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);\r
+       \r
+       // --- Save File, ArgV and EnvP (also get argc)\r
+       \r
+       // Count Arguments, Environment Variables and total string sizes\r
+       argenvBytes = 0;\r
+       for( argc = 0; ArgV && ArgV[argc]; argc++ )\r
+               argenvBytes += strlen(ArgV[argc])+1;\r
+       for( envc = 0; EnvP && EnvP[envc]; envc++ )\r
+               argenvBytes += strlen(EnvP[envc])+1;\r
+       argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);\r
+       argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);\r
+       \r
+       // Allocate\r
+       argenvBuf = malloc(argenvBytes);\r
+       if(argenvBuf == NULL) {\r
+               Warning("Proc_Execve - What the hell? The kernel is out of heap space");\r
+               return 0;\r
+       }\r
+       strBuf = argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);\r
+       \r
+       // Populate\r
+       argvSaved = (char **) argenvBuf;\r
+       for( i = 0; i < argc; i++ )\r
+       {\r
+               argvSaved[i] = strBuf;\r
+               strcpy(argvSaved[i], ArgV[i]);\r
+               strBuf += strlen(ArgV[i])+1;\r
+       }\r
+       argvSaved[i] = NULL;\r
+       envpSaved = &argvSaved[i+1];\r
+       for( i = 0; i < envc; i++ )\r
+       {\r
+               envpSaved[i] = strBuf;\r
+               strcpy(envpSaved[i], EnvP[i]);\r
+               strBuf += strlen(EnvP[i])+1;\r
+       }\r
+       \r
+       savedFile = malloc(strlen(File)+1);\r
+       strcpy(savedFile, File);\r
+       \r
+       // --- Set Process Name\r
+       Proc_SetThreadName(File);\r
+       \r
+       // --- Clear User Address space\r
+       MM_ClearUser();\r
+       \r
+       // --- Load new binary\r
+       bases[0] = Binary_Load(savedFile, &entry);\r
+       free(savedFile);\r
+       if(bases[0] == 0)\r
+       {\r
+               Warning("Proc_Execve - Unable to load '%s'", File);\r
+               Proc_Exit();\r
+               for(;;);\r
+       }\r
+       \r
+       LOG("entry = 0x%x, bases[0] = 0x%x", entry, bases[0]);\r
+       LEAVE('-');\r
+       // --- And... Jump to it\r
+       Proc_StartUser(entry, bases, argc, argvSaved, envpSaved, argenvBytes);\r
+       for(;;);        // Tell GCC that we never return\r
+}\r
+\r
+/**\r
+ * \fn Uint Binary_Load(char *file, Uint *entryPoint)\r
+ */\r
+Uint Binary_Load(char *file, Uint *entryPoint)\r
+{\r
+       char    *sTruePath;\r
+       tBinary *pBinary;\r
+       Uint    base = -1;\r
+\r
+       ENTER("sfile", file);\r
+       \r
+       // Sanity Check Argument\r
+       if(file == NULL) {\r
+               LEAVE('x', 0);\r
+               return 0;\r
+       }\r
+\r
+       // Get True File Path\r
+       sTruePath = VFS_GetTruePath(file);\r
+       \r
+       if(sTruePath == NULL) {\r
+               Warning("[BIN ] '%s' does not exist.", file);\r
+               LEAVE('x', 0);\r
+               return 0;\r
+       }\r
+       \r
+       LOG("sTruePath = '%s'", sTruePath);\r
+\r
+       // Check if the binary has already been loaded\r
+       if( !(pBinary = Binary_GetInfo(sTruePath)) )\r
+               pBinary = Binary_DoLoad(sTruePath);     // Else load it\r
+       \r
+       // Clean Up\r
+       free(sTruePath);\r
+       \r
+       // Error Check\r
+       if(pBinary == NULL) {\r
+               LEAVE('x', 0);\r
+               return 0;\r
+       }\r
+       \r
+       #if 0\r
+       if( (base = Binary_IsMapped(pBinary)) ) {\r
+               LEAVE('x', base);\r
+               return base;\r
+       }\r
+       #endif\r
+       \r
+       // Map into process space\r
+       base = Binary_MapIn(pBinary);   // If so then map it in\r
+       \r
+       // Check for errors\r
+       if(base == 0) {\r
+               LEAVE('x', 0);\r
+               return 0;\r
+       }\r
+       \r
+       // Interpret\r
+       if(pBinary->Interpreter) {\r
+               Uint start;\r
+               if( Binary_Load(pBinary->Interpreter, &start) == 0 ) {\r
+                       LEAVE('x', 0);\r
+                       return 0;\r
+               }\r
+               *entryPoint = start;\r
+       }\r
+       else\r
+               *entryPoint = pBinary->Entry - pBinary->Base + base;\r
+       \r
+       // Return\r
+       LOG("*entryPoint = 0x%x", *entryPoint);\r
+       LEAVE('x', base);\r
+       return base;    // Pass the base as an argument to the user if there is an interpreter\r
+}\r
+\r
+/**\r
+ \fn tBinary *Binary_GetInfo(char *truePath)\r
+ \brief Finds a matching binary entry\r
+ \param truePath       File Identifier (True path name)\r
+*/\r
+tBinary *Binary_GetInfo(char *truePath)\r
+{\r
+       tBinary *pBinary;\r
+       pBinary = glLoadedBinaries;\r
+       while(pBinary)\r
+       {\r
+               if(strcmp(pBinary->TruePath, truePath) == 0)\r
+                       return pBinary;\r
+               pBinary = pBinary->Next;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+/**\r
+ \fn Uint Binary_MapIn(tBinary *binary)\r
+ \brief Maps an already-loaded binary into an address space.\r
+ \param binary Pointer to globally stored data.\r
+*/\r
+Uint Binary_MapIn(tBinary *binary)\r
+{\r
+       Uint    base;\r
+       Uint    addr;\r
+        int    i;\r
+       \r
+       // Reference Executable (Makes sure that it isn't unloaded)\r
+       binary->ReferenceCount ++;\r
+       \r
+       // Get Binary Base\r
+       base = binary->Base;\r
+       \r
+       // Check if base is free\r
+       if(base != 0)\r
+       {\r
+               for(i=0;i<binary->NumPages;i++)\r
+               {\r
+                       if( MM_GetPhysAddr( binary->Pages[i].Virtual & ~0xFFF ) ) {\r
+                               base = 0;\r
+                               LOG("Address 0x%x is taken\n", binary->Pages[i].Virtual & ~0xFFF);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       // Check if the executable has no base or it is not free\r
+       if(base == 0)\r
+       {\r
+               // If so, give it a base\r
+               base = BIN_HIGHEST;\r
+               while(base >= BIN_LOWEST)\r
+               {\r
+                       for(i=0;i<binary->NumPages;i++)\r
+                       {\r
+                               addr = binary->Pages[i].Virtual & ~0xFFF;\r
+                               addr -= binary->Base;\r
+                               addr += base;\r
+                               if( MM_GetPhysAddr( addr ) )    break;\r
+                       }\r
+                       // If space was found, break\r
+                       if(i == binary->NumPages)               break;\r
+                       // Else decrement pointer and try again\r
+                       base -= BIN_GRANUALITY;\r
+               }\r
+       }\r
+       \r
+       // Error Check\r
+       if(base < BIN_LOWEST) {\r
+               Warning("[BIN ] Executable '%s' cannot be loaded, no space", binary->TruePath);\r
+               return 0;\r
+       }\r
+       \r
+       // Map Executable In\r
+       for(i=0;i<binary->NumPages;i++)\r
+       {\r
+               addr = binary->Pages[i].Virtual & ~0xFFF;\r
+               addr -= binary->Base;\r
+               addr += base;\r
+               LOG("%i - 0x%x to 0x%x", i, addr, binary->Pages[i].Physical);\r
+               MM_Map( addr, (Uint) (binary->Pages[i].Physical) );\r
+               if( binary->Pages[i].Physical & 1)      // Read-Only\r
+                       MM_SetFlags( addr, MM_PFLAG_RO, -1 );\r
+               else\r
+                       MM_SetFlags( addr, MM_PFLAG_COW, -1 );\r
+       }\r
+       \r
+       //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);\r
+       \r
+       return base;\r
+}\r
+\r
+#if 0\r
+/**\r
+ * \fn Uint Binary_IsMapped(tBinary *binary)\r
+ * \brief Check if a binary is already mapped into the address space\r
+ * \param binary       Binary information to check\r
+ * \return Current Base or 0\r
+ */\r
+Uint Binary_IsMapped(tBinary *binary)\r
+{\r
+       Uint    iBase;\r
+       \r
+       // Check prefered base\r
+       iBase = binary->Base;\r
+       if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))\r
+               return iBase;\r
+       \r
+       for(iBase = BIN_HIGHEST;\r
+               iBase >= BIN_LOWEST;\r
+               iBase -= BIN_GRANUALITY)\r
+       {\r
+               if(MM_GetPage( iBase ) == (binary->Pages[0].Physical & ~0xFFF))\r
+                       return iBase;\r
+       }\r
+       \r
+       return 0;\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn tBinary *Binary_DoLoad(char *truePath)\r
+ * \brief Loads a binary file into memory\r
+ * \param truePath     Absolute filename of binary\r
+ */\r
+tBinary *Binary_DoLoad(char *truePath)\r
+{\r
+       tBinary *pBinary;\r
+        int    fp, i;\r
+       Uint    ident;\r
+       tBinaryType     *bt = gRegBinTypes;\r
+       \r
+       ENTER("struePath", truePath);\r
+       \r
+       // Open File\r
+       fp = VFS_Open(truePath, VFS_OPENFLAG_READ);\r
+       if(fp == -1) {\r
+               LOG("Unable to load file, access denied");\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Read File Type\r
+       VFS_Read(fp, 4, &ident);\r
+       VFS_Seek(fp, 0, SEEK_SET);\r
+       \r
+       for(; bt; bt = bt->Next)\r
+       {\r
+               if( (ident & bt->Mask) != (Uint)bt->Ident )\r
+                       continue;\r
+               pBinary = bt->Load(fp);\r
+               break;\r
+       }\r
+       if(!bt) {\r
+               Warning("[BIN ] '%s' is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
+                       truePath, ident&0xFF, (ident>>8)&0xFF, (ident>>16)&0xFF, (ident>>24)&0xFF);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Error Check\r
+       if(pBinary == NULL) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Initialise Structure\r
+       pBinary->ReferenceCount = 0;\r
+       pBinary->TruePath = malloc( strlen(truePath) + 1 );\r
+       strcpy(pBinary->TruePath, truePath);\r
+       \r
+       // Debug Information\r
+       LOG("Interpreter: '%s'", pBinary->Interpreter);\r
+       LOG("Base: 0x%x, Entry: 0x%x", pBinary->Base, pBinary->Entry);\r
+       LOG("NumPages: %i", pBinary->NumPages);\r
+       \r
+       // Read Data\r
+       for(i=0;i<pBinary->NumPages;i++)\r
+       {\r
+               Uint    dest;\r
+               tPAddr  paddr;\r
+               paddr = (Uint)MM_AllocPhys();\r
+               MM_RefPhys( paddr );    // Make sure it is _NOT_ freed until we want it to be\r
+               dest = MM_MapTemp( paddr );\r
+               dest += pBinary->Pages[i].Virtual & 0xFFF;\r
+               LOG("dest = 0x%x, paddr = 0x%x", dest, paddr);\r
+               LOG("Pages[%i]={Physical:0x%x,Virtual:0x%x,Size:0x%x}",\r
+                       i, pBinary->Pages[i].Physical, pBinary->Pages[i].Virtual, pBinary->Pages[i].Size);\r
+               \r
+               // Pure Empty Page\r
+               if(pBinary->Pages[i].Physical == -1) {\r
+                       LOG("%i - ZERO", i);\r
+                       memsetd( (void*)dest, 0, 1024 );\r
+               }\r
+               else\r
+               {\r
+                       VFS_Seek( fp, pBinary->Pages[i].Physical, 1 );\r
+                       if(pBinary->Pages[i].Size != 0x1000) {\r
+                               LOG("%i - 0x%x - 0x%x bytes",\r
+                                       i, pBinary->Pages[i].Physical, pBinary->Pages[i].Size);\r
+                               memset( (void*)dest, 0, 0x1000 -(dest&0xFFF) );\r
+                               VFS_Read( fp, pBinary->Pages[i].Size, (void*)dest );\r
+                       } else {\r
+                               LOG("%i - 0x%x", i, pBinary->Pages[i].Physical);\r
+                               VFS_Read( fp, 0x1000, (void*)dest );\r
+                       }\r
+               }\r
+               pBinary->Pages[i].Physical = paddr;\r
+               MM_FreeTemp( dest );\r
+       }\r
+       LOG("Page Count: %i", pBinary->NumPages);\r
+       \r
+       // Close File\r
+       VFS_Close(fp);\r
+       \r
+       // Add to the list\r
+       LOCK(&glBinListLock);\r
+       pBinary->Next = glLoadedBinaries;\r
+       glLoadedBinaries = pBinary;\r
+       RELEASE(&glBinListLock);\r
+       \r
+       // Return\r
+       LEAVE('p', pBinary);\r
+       return pBinary;\r
+}\r
+\r
+/**\r
+ * \fn void Binary_Unload(void *Base)\r
+ * \brief Unload / Unmap a binary\r
+ * \param Base Loaded Base\r
+ * \note Currently used only for kernel libaries\r
+ */\r
+void Binary_Unload(void *Base)\r
+{\r
+       tKernelBin      *pKBin;\r
+       tKernelBin      *prev = NULL;\r
+        int    i;\r
+       \r
+       if((Uint)Base < 0xC0000000)\r
+       {\r
+               // TODO: User Binaries\r
+               Warning("[BIN ] Unloading user binaries is currently unimplemented");\r
+               return;\r
+       }\r
+       \r
+       // Kernel Libraries\r
+       for(pKBin = glLoadedKernelLibs;\r
+               pKBin;\r
+               prev = pKBin, pKBin = pKBin->Next)\r
+       {\r
+               // Check the base\r
+               if(pKBin->Base != Base) continue;\r
+               // Deallocate Memory\r
+               for(i = 0; i < pKBin->Info->NumPages; i++) {\r
+                       MM_Deallocate( (Uint)Base + (i << 12) );\r
+               }\r
+               // Dereference Binary\r
+               Binary_Dereference( pKBin->Info );\r
+               // Remove from list\r
+               if(prev)        prev->Next = pKBin->Next;\r
+               else            glLoadedKernelLibs = pKBin->Next;\r
+               // Free Kernel Lib\r
+               free(pKBin);\r
+               return;\r
+       }\r
+}\r
+\r
+/**\r
+ * \fn void Binary_Dereference(tBinary *Info)\r
+ * \brief Dereferences and if nessasary, deletes a binary\r
+ * \param Info Binary information structure\r
+ */\r
+void Binary_Dereference(tBinary *Info)\r
+{\r
+       // Decrement reference count\r
+       Info->ReferenceCount --;\r
+       \r
+       // Check if it is still in use\r
+       if(Info->ReferenceCount)        return;\r
+       \r
+       /// \todo Implement binary freeing\r
+}\r
+\r
+/**\r
+ \fn char *Binary_RegInterp(char *path)\r
+ \brief Registers an Interpreter\r
+ \param path   Path to interpreter provided by executable\r
+*/\r
+char *Binary_RegInterp(char *path)\r
+{\r
+        int    i;\r
+       // NULL Check Argument\r
+       if(path == NULL)        return NULL;\r
+       // NULL Check the array\r
+       if(gsaRegInterps == NULL)\r
+       {\r
+               giRegInterps = 1;\r
+               gsaRegInterps = malloc( sizeof(char*) );\r
+               gsaRegInterps[0] = malloc( strlen(path) );\r
+               strcpy(gsaRegInterps[0], path);\r
+               return gsaRegInterps[0];\r
+       }\r
+       \r
+       // Scan Array\r
+       for( i = 0; i < giRegInterps; i++ )\r
+       {\r
+               if(strcmp(gsaRegInterps[i], path) == 0)\r
+                       return gsaRegInterps[i];\r
+       }\r
+       \r
+       // Interpreter is not in list\r
+       giRegInterps ++;\r
+       gsaRegInterps = malloc( sizeof(char*)*giRegInterps );\r
+       gsaRegInterps[i] = malloc( strlen(path) );\r
+       strcpy(gsaRegInterps[i], path);\r
+       return gsaRegInterps[i];\r
+}\r
+\r
+// ============\r
+// Kernel Binary Handling\r
+// ============\r
+/**\r
+ * \fn void *Binary_LoadKernel(char *path)\r
+ * \brief Load a binary into kernel space\r
+ * \note This function shares much with #Binary_Load, but does it's own mapping\r
+ */\r
+void *Binary_LoadKernel(char *file)\r
+{\r
+       char    *sTruePath;\r
+       tBinary *pBinary;\r
+       tKernelBin      *pKBinary;\r
+       Uint    base = -1;\r
+       Uint    addr;\r
+        int    i;\r
+\r
+       ENTER("sfile", file);\r
+       \r
+       // Sanity Check Argument\r
+       if(file == NULL) {\r
+               LEAVE('n');\r
+               return 0;\r
+       }\r
+\r
+       // Get True File Path\r
+       sTruePath = VFS_GetTruePath(file);\r
+       if(sTruePath == NULL) {\r
+               LEAVE('n');\r
+               return 0;\r
+       }\r
+       \r
+       // Check if the binary has already been loaded\r
+       if( (pBinary = Binary_GetInfo(sTruePath)) )\r
+       {\r
+               for(pKBinary = glLoadedKernelLibs;\r
+                       pKBinary;\r
+                       pKBinary = pKBinary->Next )\r
+               {\r
+                       if(pKBinary->Info == pBinary) {\r
+                               LEAVE('p', pKBinary->Base);\r
+                               return pKBinary->Base;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+               pBinary = Binary_DoLoad(sTruePath);     // Else load it\r
+       \r
+       // Error Check\r
+       if(pBinary == NULL) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // --------------\r
+       // Now pBinary is valid (either freshly loaded or only user mapped)\r
+       // So, map it into kernel space\r
+       // --------------\r
+       \r
+       // Reference Executable (Makes sure that it isn't unloaded)\r
+       pBinary->ReferenceCount ++;\r
+       \r
+       // Check compiled base\r
+       base = pBinary->Base;\r
+       // - Sanity Check\r
+       if(base < KLIB_LOWEST || base > KLIB_HIGHEST || base + (pBinary->NumPages<<12) > KLIB_HIGHEST) {\r
+               base = 0;\r
+       }\r
+       // - Check if it is a valid base address\r
+       if(base != 0)\r
+       {\r
+               for(i=0;i<pBinary->NumPages;i++)\r
+               {\r
+                       if( MM_GetPhysAddr( pBinary->Pages[i].Virtual & ~0xFFF ) ) {\r
+                               base = 0;\r
+                               LOG("Address 0x%x is taken\n", pBinary->Pages[i].Virtual & ~0xFFF);\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       // Check if the executable has no base or it is not free\r
+       if(base == 0)\r
+       {\r
+               // If so, give it a base\r
+               base = KLIB_LOWEST;\r
+               while(base < KLIB_HIGHEST)\r
+               {\r
+                       for(i = 0; i < pBinary->NumPages; i++)\r
+                       {\r
+                               addr = pBinary->Pages[i].Virtual & ~0xFFF;\r
+                               addr -= pBinary->Base;\r
+                               addr += base;\r
+                               if( MM_GetPhysAddr( addr ) )    break;\r
+                       }\r
+                       // If space was found, break\r
+                       if(i == pBinary->NumPages)              break;\r
+                       // Else decrement pointer and try again\r
+                       base += KLIB_GRANUALITY;\r
+               }\r
+       }\r
+       \r
+       // - Error Check\r
+       if(base >= KLIB_HIGHEST) {\r
+               Warning("[BIN ] Executable '%s' cannot be loaded into kernel, no space", pBinary->TruePath);\r
+               Binary_Dereference( pBinary );\r
+               LEAVE('n');\r
+               return 0;\r
+       }\r
+       \r
+       LOG("base = 0x%x", base);\r
+       \r
+       // - Map binary in\r
+       LOG("pBinary = {NumPages:%i, Pages=%p}", pBinary->NumPages, pBinary->Pages);\r
+       for(i = 0; i < pBinary->NumPages; i++)\r
+       {\r
+               addr = pBinary->Pages[i].Virtual & ~0xFFF;\r
+               addr -= pBinary->Base;\r
+               addr += base;\r
+               LOG("%i - 0x%x to 0x%x", i, addr, pBinary->Pages[i].Physical);\r
+               MM_Map( addr, (Uint) (pBinary->Pages[i].Physical) );\r
+               MM_SetFlags( addr, MM_PFLAG_KERNEL, MM_PFLAG_KERNEL );\r
+               #if 0   // Why was this here? It's the kernel\r
+               if( pBinary->Pages[i].Physical & 1)     // Read-Only\r
+                       MM_SetFlags( addr, MM_PFLAG_RO, MM_PFLAG_KERNEL );\r
+               else\r
+                       MM_SetFlags( addr, MM_PFLAG_COW, MM_PFLAG_KERNEL );\r
+                       //MM_SetCOW( addr );\r
+               #endif\r
+       }
+\r
+       // Relocate Library\r
+       if( !Binary_Relocate( (void*)base ) )\r
+       {\r
+               Warning("[BIN ] Relocation of '%s' failed, unloading", sTruePath);\r
+               Binary_Unload( (void*)base );\r
+               Binary_Dereference( pBinary );\r
+               LEAVE('n');\r
+               return 0;\r
+       }\r
+       \r
+       // Add to list (relocator must look at itself manually, not via Binary_GetSymbol)\r
+       pKBinary = malloc(sizeof(*pKBinary));\r
+       pKBinary->Base = (void*)base;\r
+       pKBinary->Info = pBinary;\r
+       LOCK( &glKBinListLock );\r
+       pKBinary->Next = glLoadedKernelLibs;\r
+       glLoadedKernelLibs = pKBinary;\r
+       RELEASE( &glKBinListLock );\r
+       \r
+       LEAVE('p', base);\r
+       return (void*)base;\r
+}\r
+\r
+/**\r
+ * \fn Uint Binary_Relocate(void *Base)\r
+ * \brief Relocates a loaded binary (used by kernel libraries)\r
+ * \param Base Loaded base address of binary\r
+ * \return Boolean Success\r
+ */\r
+Uint Binary_Relocate(void *Base)\r
+{\r
+       Uint32  ident = *(Uint32*) Base;\r
+       tBinaryType     *bt = gRegBinTypes;\r
+       \r
+       for(; bt; bt = bt->Next)\r
+       {\r
+               if( (ident & bt->Mask) == (Uint)bt->Ident )\r
+                       return bt->Relocate( (void*)Base);\r
+       }\r
+       \r
+       Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
+               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn int Binary_GetSymbol(char *Name, Uint *Val)\r
+ * \brief Get a symbol value\r
+ * \return Value of symbol or -1 on error\r
+ * \r
+ * Gets the value of a symbol from either the currently loaded\r
+ * libraries or the kernel's exports.\r
+ */\r
+int Binary_GetSymbol(char *Name, Uint *Val)\r
+{\r
+       if( Binary_GetSymbolEx(Name, Val) )     return 1;\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn Uint Binary_GetSymbolEx(char *Name, Uint *Value)\r
+ * \brief Get a symbol value\r
+ * \r
+ * Gets the value of a symbol from either the currently loaded\r
+ * libraries or the kernel's exports.\r
+ */\r
+Uint Binary_GetSymbolEx(char *Name, Uint *Value)\r
+{\r
+        int    i;\r
+       tKernelBin      *pKBin;\r
+        int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);\r
+       \r
+       // Scan Kernel\r
+       for( i = 0; i < numKSyms; i++ )\r
+       {\r
+               if(strcmp(Name, gKernelSymbols[i].Name) == 0) {\r
+                       *Value = gKernelSymbols[i].Value;\r
+                       return 1;\r
+               }\r
+       }\r
+       \r
+       // Scan Loaded Libraries\r
+       for(pKBin = glLoadedKernelLibs;\r
+               pKBin;\r
+               pKBin = pKBin->Next )\r
+       {\r
+               if( Binary_FindSymbol(pKBin->Base, Name, Value) ) {\r
+                       return 1;\r
+               }\r
+       }\r
+       
+       Warning("[BIN ] Unable to find symbol '%s'", Name);\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn Uint Binary_GetSymbolBin(void *Base, char *Name, Uint *val)\r
+ * \brief Get a symbol from the specified library\r
+ * \param Base Base address\r
+ * \param Name Name of symbol to find\r
+ * \param val  Pointer to place final value\r
+ */\r
+Uint Binary_FindSymbol(void *Base, char *Name, Uint *val)\r
+{\r
+       Uint32  ident = *(Uint32*) Base;\r
+       tBinaryType     *bt = gRegBinTypes;\r
+       \r
+       for(; bt; bt = bt->Next)\r
+       {\r
+               if( (ident & bt->Mask) == (Uint)bt->Ident )\r
+                       return bt->GetSymbol(Base, Name, val);\r
+       }\r
+       \r
+       Warning("[BIN ] 0x%x is an unknown file type. (0x%x 0x%x 0x%x 0x%x)",\r
+               Base, ident&0xFF, ident>>8, ident>>16, ident>>24);\r
+       return 0;\r
+}\r
diff --git a/Kernel/debug.c b/Kernel/debug.c
new file mode 100644 (file)
index 0000000..8df3609
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * AcessOS Microkernel Version
+ * debug.c
+ */
+#include <common.h>
+#include <stdarg.h>
+
+// === MACROS ===
+#define E9(ch) __asm__ __volatile__ ("outb %%al, $0xe9"::"a"(((Uint8)ch)))
+
+// === IMPORTS ===
+extern void Proc_DumpThreads();
+
+// === GLOBALS ===
+ int   gDebug_Level = 0;
+
+// === CODE ===
+static void E9_Str(char *Str)
+{
+       while(*Str)     E9(*Str++);
+}
+
+void E9_Fmt(const char *format, va_list *args)
+{
+       char    c, pad = ' ';
+        int    minSize = 0;
+       char    tmpBuf[34];     // For Integers
+       char    *p = NULL;
+        int    isLongLong = 0;
+       Uint64  arg;
+  
+       while((c = *format++) != 0)
+       {
+               // Non control character
+               if( c != '%' ) {
+                       E9(c);
+                       continue;
+               }
+               
+               c = *format++;
+               
+               // Literal %
+               if(c == '%') {
+                       E9('%');
+                       continue;
+               }
+               
+               // Pointer
+               if(c == 'p') {
+                       Uint    ptr = va_arg(*args, Uint);
+                       E9('*');        E9('0');        E9('x');
+                       p = tmpBuf;
+                       itoa(p, ptr, 16, BITS/4, '0');
+                       goto printString;
+               }
+               
+               // Get Argument
+               arg = va_arg(*args, Uint);
+               
+               // Padding
+               if(c == '0') {
+                       pad = '0';
+                       c = *format++;
+               } else
+                       pad = ' ';
+               
+               // Minimum length
+               minSize = 1;
+               if('1' <= c && c <= '9')
+               {
+                       minSize = 0;
+                       while('0' <= c && c <= '9')
+                       {
+                               minSize *= 10;
+                               minSize += c - '0';
+                               c = *format++;
+                       }
+               }
+               
+               // Long (default)
+               isLongLong = 0;
+               if(c == 'l') {
+                       c = *format++;
+                       if(c == 'l') {
+                               #if BITS == 32
+                               arg |= va_arg(*args, Uint);
+                               #endif
+                               c = *format++;
+                               isLongLong = 1;
+                       }
+               }
+               
+               p = tmpBuf;
+               switch (c) {
+               case 'd':
+               case 'i':
+                       if( (isLongLong && arg >> 63) || (!isLongLong && arg >> 31) ) {
+                               E9('-');
+                               arg = -arg;
+                       }
+                       itoa(p, arg, 10, minSize, pad);
+                       goto printString;
+               case 'u':
+                       itoa(p, arg, 10, minSize, pad);
+                       goto printString;
+               case 'x':
+                       itoa(p, arg, 16, minSize, pad);
+                       goto printString;
+               case 'o':
+                       itoa(p, arg, 8, minSize, pad);
+                       goto printString;
+               case 'b':
+                       itoa(p, arg, 2, minSize, pad);
+                       goto printString;
+
+               case 'B':       //Boolean
+                       if(arg) E9_Str("True");
+                       else    E9_Str("False");
+                       break;
+               
+               case 's':
+                       p = (char*)(Uint)arg;
+               printString:
+                       if(!p)          p = "(null)";
+                       while(*p)       E9(*p++);
+                       break;
+                       
+               default:        E9(arg);        break;
+               }
+    }
+}
+
+/**
+ * \fn void LogV(char *Fmt, va_list Args)
+ */
+void LogV(char *Fmt, va_list Args)
+{
+       E9_Str("Log: ");
+       E9_Fmt(Fmt, &Args);
+       E9('\n');
+}
+/**
+ * \fn void LogF(char *Msg, ...)
+ */
+void LogF(char *Fmt, ...)
+{
+       va_list args;
+       
+       va_start(args, Fmt);
+       
+       E9_Fmt(Fmt, &args);
+       
+       va_end(args);
+}
+/**
+ * \fn void Log(char *Msg, ...)
+ */
+void Log(char *Fmt, ...)
+{
+       va_list args;
+       
+       E9_Str("Log: ");
+       va_start(args, Fmt);
+       E9_Fmt(Fmt, &args);
+       va_end(args);
+       E9('\n');
+}
+void Warning(char *Fmt, ...)
+{
+       va_list args;
+       E9_Str("Warning: ");
+       va_start(args, Fmt);
+       E9_Fmt(Fmt, &args);
+       va_end(args);
+       E9('\n');
+}
+void Panic(char *Fmt, ...)
+{
+       va_list args;
+       E9_Str("Panic: ");
+       va_start(args, Fmt);
+       E9_Fmt(Fmt, &args);
+       va_end(args);
+       E9('\n');
+       
+       Proc_DumpThreads();
+       
+       __asm__ __volatile__ ("xchg %bx, %bx");
+       __asm__ __volatile__ ("cli;\n\thlt");
+       for(;;) __asm__ __volatile__ ("hlt");
+}
+
+void Debug_Enter(char *FuncName, char *ArgTypes, ...)
+{
+       va_list args;
+        int    i = gDebug_Level ++;
+        int    pos;
+       
+       va_start(args, ArgTypes);
+       
+       while(i--)      E9(' ');
+       
+       E9_Str(FuncName);       E9_Str(": (");
+       
+       while(*ArgTypes)
+       {
+               pos = strpos(ArgTypes, ' ');
+               if(pos != -1)   ArgTypes[pos] = '\0';
+               if(pos == -1 || pos > 1) {
+                       E9_Str(ArgTypes+1);
+                       E9('=');
+               }
+               if(pos != -1)   ArgTypes[pos] = ' ';
+               switch(*ArgTypes)
+               {
+               case 'p':       E9_Fmt("%p", &args);    break;
+               case 's':       E9_Fmt("'%s'", &args);  break;
+               case 'i':       E9_Fmt("%i", &args);    break;
+               case 'u':       E9_Fmt("%u", &args);    break;
+               case 'x':       E9_Fmt("0x%x", &args);  break;
+               case 'b':       E9_Fmt("0b%b", &args);  break;
+               // Extended (64-Bit)
+               case 'X':       E9_Fmt("0x%llx", &args);        break;
+               case 'B':       E9_Fmt("0b%llb", &args);        break;
+               }
+               if(pos != -1) {
+                       E9(',');        E9(' ');
+               }
+               
+               if(pos == -1)   break;
+               ArgTypes = &ArgTypes[pos+1];
+       }
+       
+       va_end(args);
+       E9(')');        E9('\n');
+}
+
+void Debug_Log(char *FuncName, char *Fmt, ...)
+{
+       va_list args;
+        int    i = gDebug_Level;
+       
+       va_start(args, Fmt);
+       
+       while(i--)      E9(' ');
+       
+       E9_Str(FuncName);       E9_Str(": ");
+       E9_Fmt(Fmt, &args);
+       
+       va_end(args);
+       E9('\n');
+}
+
+void Debug_Leave(char *FuncName, char RetType, ...)
+{
+       va_list args;
+        int    i = --gDebug_Level;
+       
+       va_start(args, RetType);
+       
+       // Indenting
+       while(i--)      E9(' ');
+       
+       E9_Str(FuncName);       E9_Str(": RETURN");
+       
+       // No Return
+       if(RetType == '-') {
+               E9('\n');
+               return;
+       }
+       
+       E9(' ');
+       switch(RetType)
+       {
+       case 'n':       E9_Str("NULL"); break;
+       case 'p':       E9_Fmt("%p", &args);    break;
+       case 's':       E9_Fmt("'%s'", &args);  break;
+       case 'i':       E9_Fmt("%i", &args);    break;
+       case 'u':       E9_Fmt("%u", &args);    break;
+       case 'x':       E9_Fmt("0x%x", &args);  break;
+       // Extended (64-Bit)
+       case 'X':       E9_Fmt("0x%llx", &args);        break;
+       }
+       E9('\n');
+       
+       va_end(args);
+}
+
+void Debug_HexDump(char *Header, void *Data, Uint Length)
+{
+       Uint8   *cdat = Data;
+       Uint    pos = 0;
+       E9_Str(Header);
+       LogF(" (Hexdump of %p)\n", Data);
+       
+       while(Length >= 16)
+       {
+               Log("%04x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+                       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]
+                       );
+               Length -= 16;
+               cdat += 16;
+               pos += 16;
+       }
+       
+       LogF("Log: %04x: ", pos);
+       while(Length)
+       {
+               Uint    byte = *cdat;
+               LogF("%02x ", byte);
+               Length--;
+               cdat --;
+       }
+       E9('\n');
+       
+}
+
+// --- EXPORTS ---
+EXPORT(Warning);
+EXPORT(Debug_Enter);
+EXPORT(Debug_Log);
+EXPORT(Debug_Leave);
diff --git a/Kernel/drv/Makefile b/Kernel/drv/Makefile
new file mode 100644 (file)
index 0000000..5a55d93
--- /dev/null
@@ -0,0 +1,22 @@
+# Acess2 Module/Driver Templater Makefile
+# Makefile.tpl
+ARCH = i386
+
+CC = gcc
+LD = ld
+
+CPPFLAGS = -I../include -I../arch/$(ARCH)/include -DARCH=$(ARCH) -DBUILD_MODULE
+CFLAGS = -Wall -Werror $(CPPFLAGS)
+
+.PHONY: all clean
+
+all: ata_x86.kmd
+
+%.kmd:
+       $(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/ata_x86.c b/Kernel/drv/ata_x86.c
new file mode 100644 (file)
index 0000000..a4c5306
--- /dev/null
@@ -0,0 +1,877 @@
+/*
+ * Acess2 IDE Harddisk Driver
+ * drv/ide.c
+ */
+#include <common.h>
+#include <modules.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include <tpl_drv_common.h>
+
+// === CONSTANTS ===
+#define        MAX_ATA_DISKS   4
+#define        SECTOR_SIZE             512
+#define        MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
+
+#define        IDE_PRI_BASE    0x1F0
+#define        IDE_SEC_BASE    0x170
+
+#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,
+};
+
+// === STRUCTURES ===
+typedef struct {
+       Uint32  PBufAddr;
+       Uint16  Bytes;
+       Uint16  Flags;
+} tPRDT_Ent;
+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 - and with 0xFF to get true value;
+       Uint16  Unused3;        // 49
+       Uint16  Capabilities[2];        // 51
+       Uint16  Unused4[2];     // 53
+       Uint16  ValidExtData;   // 54
+       Uint16  Unused5[5];      // 59
+       Uint16  SizeOfRWMultiple;       // 60
+       Uint32  Sectors28;      // 62
+       Uint16  Unused6[100-62];
+       Uint64  Sectors48;
+       Uint16  Unused7[256-104];
+} tIdentify;
+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;
+
+// === PROTOTYPES ===
+ int   ATA_Install();
+ int   ATA_SetupIO();
+static void    ATA_SetupPartitions();
+ void  ATA_SetupVFS();
+ int   ATA_ScanDisk(int Disk);
+void   ATA_ParseGPT(int Disk);
+void   ATA_ParseMBR(int Disk);
+void   ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
+Uint16 ATA_GetBasePort(int Disk);
+char   *ATA_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *ATA_FindDir(tVFS_Node *Node, char *Name);
+Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
+ int   ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer);
+ int   ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
+void   ATA_IRQHandlerPri(void);
+void   ATA_IRQHandlerSec(void);
+Uint8  ATA_int_BusMasterReadByte(int Ofs);
+void   ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
+void   ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL);
+tDevFS_Driver  gATA_DriverInfo = {
+       NULL, "ata",
+       {
+               .NumACLs = 1,
+               .Flags = VFS_FFLAG_DIRECTORY,
+               .ACLs = &gVFS_ACL_EveryoneRX,
+               .ReadDir = ATA_ReadDir,
+               .FindDir = ATA_FindDir
+       }
+};
+tATA_Disk      gATA_Disks[MAX_ATA_DISKS];
+ int   giATA_NumNodes;
+tVFS_Node      **gATA_Nodes;
+Uint16 gATA_BusMasterBase = 0;
+Uint8  *gATA_BusMasterBasePtr = 0;
+ int   gATA_IRQPri = 14;
+ int   gATA_IRQSec = 15;
+ int   giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
+Uint8  gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
+ int   gaATA_IRQs[2] = {0};
+tPRDT_Ent      gATA_PRDTs[2] = {
+       {0, 512, IDE_PRDT_LAST},
+       {0, 512, IDE_PRDT_LAST}
+};
+
+// === CODE ===
+/**
+ * \fn int ATA_Install()
+ */
+int ATA_Install()
+{
+       int     ret;
+       
+       ret = ATA_SetupIO();
+       if(ret != 1)    return ret;
+       
+       ATA_SetupPartitions();
+       
+       ATA_SetupVFS();
+       
+       if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
+               return 0;
+       
+       return 1;
+}
+
+/**
+ * \fn int ATA_SetupIO()
+ * \brief Sets up the ATA controller's DMA mode
+ */
+int ATA_SetupIO()
+{
+        int    ent;
+       Uint    addr;
+       
+       ENTER("");
+       
+       // Get IDE Controller's PCI Entry
+       ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
+       LOG("ent = %i\n", ent);
+       gATA_BusMasterBase = PCI_GetBAR4( ent );
+       LOG("gATA_BusMasterBase = 0x%x\n", gATA_BusMasterBase);
+       if( gATA_BusMasterBase == 0 ) {
+               Warning("It seems that there is no Bus Master Controller on this machine, get one");
+               LEAVE('i', 0);
+               return 0;
+       }
+       if( !(gATA_BusMasterBase & 1) )
+       {
+               if( gATA_BusMasterBase < 0x100000 )
+                       gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
+               else
+                       gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
+       }
+       
+       IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
+       IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
+       
+       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
+       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
+       
+       LOG("gATA_PRDTs = {0x%x, 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
+       
+       addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
+       ATA_int_BusMasterWriteDWord(4, addr);
+       addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
+       ATA_int_BusMasterWriteDWord(12, addr);
+       
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \fn static void     ATA_SetupPartitions()
+ */
+static void    ATA_SetupPartitions()
+{
+        int    i;
+       for( i = 0; i < MAX_ATA_DISKS; i ++ )
+       {
+               if( !ATA_ScanDisk(i) ) {
+                       gATA_Disks[i].Name[0] = '\0';   // Mark as unused
+                       continue;
+               }
+       }
+}
+
+/**
+ * \fn void ATA_SetupVFS()
+ * \brief Sets up the ATA drivers VFS information and registers with DevFS
+ */
+void ATA_SetupVFS()
+{
+        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;
+       }
+}
+
+/**
+ * \fn int ATA_ScanDisk(int Disk)
+ */
+int ATA_ScanDisk(int Disk)
+{
+       Uint16  buf[256];
+       tIdentify       *identify = (void*)buf;
+       tMBR    *mbr = (void*)buf;
+       Uint16  base;
+       Uint8   val;
+        int    i;
+       tVFS_Node       *node;
+       
+       base = ATA_GetBasePort( Disk );
+       
+       // Send Disk Selector
+       if(Disk == 1 || Disk == 3)
+               outb(base+6, 0xB0);
+       else
+               outb(base+6, 0xA0);
+       
+       // Send IDENTIFY
+       outb(base+7, 0xEC);
+       val = inb(base+7);      // Read status
+       if(val == 0)    return 0;       // Disk does not exist
+       
+       // Poll until BSY clears and DRQ sets or ERR is set
+       while( ((val & 0x80) || !(val & 0x08)) && !(val & 1))   val = inb(base+7);
+       
+       if(val & 1)     return 0;       // Error occured, so return false
+       
+       // Read Data
+       for(i=0;i<256;i++)      buf[i] = inw(base);
+       
+       // Populate Disk Structure
+       if(identify->Sectors48 != 0)
+               gATA_Disks[ Disk ].Sectors = identify->Sectors48;
+       else
+               gATA_Disks[ Disk ].Sectors = identify->Sectors28;
+       
+       
+       if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
+               Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
+                       gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
+       else if( gATA_Disks[ Disk ].Sectors / 2048 )
+               Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
+                       gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
+       else
+               Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
+                       gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
+       
+       // Create Name
+       gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
+       gATA_Disks[ Disk ].Name[1] = '\0';
+       
+       // 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->Read = ATA_ReadFS;
+       //node->Write = ATA_WriteFS;
+       node->IOCtl = ATA_IOCtl;
+
+
+       // --- Scan Partitions ---
+       // Read Boot Sector
+       ATA_ReadDMA( Disk, 0, 1, mbr );
+       
+       // Check for a GPT table
+       if(mbr->Parts[0].SystemID == 0xEE)
+               ATA_ParseGPT(Disk);
+       else    // No? Just parse the MBR
+               ATA_ParseMBR(Disk);
+       
+       return 1;
+}
+
+/**
+ * \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");
+}
+
+/**
+ * \fn void ATA_ParseMBR(int Disk)
+ */
+void ATA_ParseMBR(int Disk)
+{
+        int    i, j = 0, k = 4;
+       tMBR    mbr;
+       Uint64  extendedLBA;
+       
+       // Read Boot Sector
+       ATA_ReadDMA( Disk, 0, 1, &mbr );
+       
+       // 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 ) {
+                               if(extendedLBA != 0) {
+                                       Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+                                       continue;
+                               }
+                               extendedLBA = mbr.Parts[i].LBAStart;
+                               continue;
+                       }
+                       
+                       gATA_Disks[Disk].NumPartitions ++;
+                       continue;
+               }
+               // Invalid Partition, so don't count it
+       }
+       while(extendedLBA != 0)
+       {
+               if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
+                       break;  // Stop on Errors
+               
+               extendedLBA = 0;
+               
+               if( mbr.Parts[0].SystemID == 0 )        continue;
+               if(     mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80   // LBA 28
+               ||      mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81   // LBA 48
+                       )
+               {
+                       if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
+                               extendedLBA = mbr.Parts[0].LBAStart;
+                       else
+                               gATA_Disks[Disk].NumPartitions ++;
+               }
+               
+               if( mbr.Parts[1].SystemID == 0 )        continue;
+               if(     mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80   // LBA 28
+               ||      mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81   // LBA 48
+                       )
+               {
+                       if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
+                               if(extendedLBA == 0) {
+                                       Warning("Disk %i has twp forward link in the extended partition",
+                                               Disk);
+                                       break;
+                               }
+                               extendedLBA = mbr.Parts[1].LBAStart;
+                       }
+                       else {
+                               if(extendedLBA != 0) {
+                                       Warning("Disk %i lacks a forward link in the extended partition",
+                                               Disk);
+                                       break;
+                               }
+                               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( 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
+               {
+                       if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
+                               if(extendedLBA != 0) {
+                                       Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+                                       continue;
+                               }
+                               extendedLBA = mbr.Parts[1].LBAStart;
+                               continue;
+                       }
+                       // Create Partition
+                       ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
+                               mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
+                               );
+                       j ++;
+                       continue;
+               }
+               if(     mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
+               {
+                       if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
+                               if(extendedLBA != 0) {
+                                       Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
+                                       continue;
+                               }
+                               extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
+                               continue;
+                       }
+                       ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
+                               (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
+                               (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
+                               );
+                       j ++;
+               }
+               // Invalid Partition, so don't count it
+       }
+       // Scan extended partition
+       while(extendedLBA != 0)
+       {
+               if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
+                       break;  // Stop on Errors
+               
+               extendedLBA = 0;
+               
+               // Check first entry (should be partition)
+               if( mbr.Parts[0].SystemID != 0)
+               {
+                       if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 )     // LBA 28
+                       {
+                               // Forward Link to next Extended partition entry
+                               if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
+                                       extendedLBA = mbr.Parts[0].LBAStart;
+                               else {
+                                       ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+                                               mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
+                                               );
+                                       j ++;   k ++;
+                               }
+                       }
+                       else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 )        // LBA 48
+                       {
+                               if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
+                                       extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
+                               else {
+                                       ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+                                               (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
+                                               (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
+                                               );
+                                       j ++;   k ++;
+                               }
+                       }
+               }
+               
+               // Check second entry (should be forward link)
+               if( mbr.Parts[1].SystemID != 0)
+               {
+                       if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 )      // LBA 28
+                       {
+                               if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
+                                       if(extendedLBA == 0) {
+                                               Warning("Disk %i has twp forward link in the extended partition",
+                                                       Disk);
+                                               break;
+                                       }
+                                       extendedLBA = mbr.Parts[1].LBAStart;
+                               }
+                               else
+                               {
+                                       if(extendedLBA != 0) {
+                                               Warning("Disk %i lacks a forward link in the extended partition",
+                                                       Disk);
+                                               break;
+                                       }
+                                       ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+                                               mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
+                                               );
+                                       j ++;   k ++;
+                               }
+                               
+                       }
+                       else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 )        // LBA 48
+                       {
+                               if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
+                                       if(extendedLBA == 0) {
+                                               Warning("Disk %i has twp forward link in the extended partition",
+                                                       Disk);
+                                               break;
+                                       }
+                                       extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
+                               }
+                               else
+                               {
+                                       if(extendedLBA != 0) {
+                                               Warning("Disk %i lacks a forward link in the extended partition",
+                                                       Disk);
+                                               break;
+                                       }
+                                       ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
+                                               (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
+                                               (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
+                                               );
+                                       j ++;   k ++;
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * \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.Read = ATA_ReadFS;
+       Part->Node.IOCtl = ATA_IOCtl;
+       LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
+       LEAVE('-');
+}
+
+/**
+ * \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 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
+ */
+char *ATA_ReadDir(tVFS_Node *Node, int Pos)
+{
+       if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
+       return gATA_Nodes[Pos]->ImplPtr;
+}
+
+/**
+ * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
+ */
+tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
+{
+        int    part;
+       // Check first character
+       if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
+               return NULL;
+       // Raw Disk
+       if(Name[1] == '\0')     return &gATA_Disks[Name[0]-'A'].Node;
+       
+       // Partitions
+       if(Name[1] < '0' || '9' < Name[1])      return NULL;
+       if(Name[2] == '\0') {   // <= 9
+               part = Name[1] - '0';
+               part --;
+               return &gATA_Disks[Name[0]-'A'].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 &gATA_Disks[Name[0]-'A'].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    ret;
+        int    disk, part;
+       Uint64  sector, count;
+       
+       disk = Node->Inode >> 8;
+       part = Node->Inode & 0xFF;
+       
+       // Aligned Read
+       if(Offset % SECTOR_SIZE == 0 && Length % SECTOR_SIZE == 0)
+       {
+               sector = Offset / SECTOR_SIZE;
+               count = Length / SECTOR_SIZE;
+               // Raw Disk?
+               if(part == 0xFF)
+               {
+                       // Bounds Check
+                       if( sector >= gATA_Disks[disk].Sectors )        return 0;
+                       if( sector + count > gATA_Disks[disk].Sectors )
+                               count = gATA_Disks[disk].Sectors - sector;
+                       // Read Data
+                       ret = ATA_Read(disk, sector, count, Buffer);
+               }
+               else    // Or a partition
+               {
+                       //Log(" ATA_ReadFS: %i:%i 0x%llx + 0x%llx\n", disk, part,
+                       //      gATA_Disks[disk].Partitions[part].Start,
+                       //      gATA_Disks[disk].Partitions[part].Length );
+                       
+                       // Bounds Check
+                       if( sector >= gATA_Disks[disk].Partitions[part].Length )        return 0;
+                       if( sector + count > gATA_Disks[disk].Partitions[part].Length )
+                               count = gATA_Disks[disk].Partitions[part].Length - sector;
+                       // Read Disk
+                       ret = ATA_Read(disk,
+                               gATA_Disks[disk].Partitions[part].Start + sector,
+                               count,
+                               Buffer);
+               }
+               // Check return value
+               if(ret == 1)
+                       return count * SECTOR_SIZE;
+               else {
+                       Warning("ATA_ReadFS: RETURN 0 (Read failed with ret = %i)", ret);
+                       return 0;
+               }
+       }
+       Warning("ATA_ReadFS: RETURN 0 (Non-Aligned Read 0x%llx 0x%llx)", Offset, Length);
+       return 0;
+}
+
+/**
+ * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ */
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       return 0;
+}
+
+/**
+ * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief IO Control Funtion
+ */
+int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       switch(Id)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;
+       }
+       return 0;
+}
+
+// --- Disk Access ---
+/**
+ * \fn int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
+ */
+int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
+{
+        int    ret;
+       Uint    offset;
+        
+       // Pass straight on to ATA_ReadDMAPage if we can
+       if(Count <= MAX_DMA_SECTORS)
+               return ATA_ReadDMA(Disk, Address, Count, Buffer);
+       
+       // 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 ret;
+               // Change Position
+               Count -= MAX_DMA_SECTORS;
+               offset += MAX_DMA_SECTORS*SECTOR_SIZE;
+       }
+       
+       return ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
+}
+
+/**
+ * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ */
+int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+        int    cont = (Disk>>1)&1;     // Controller ID
+        int    disk = Disk & 1;
+       Uint16  base;
+       
+       // Check if the count is small enough
+       if(Count > MAX_DMA_SECTORS)     return -1;
+       
+       // Get exclusive access to the disk controller
+       LOCK( &giaATA_ControllerLock[ cont ] );
+       
+       // Set Size
+       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+       
+       // Get Port Base
+       base = ATA_GetBasePort(Disk);
+       
+       // 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
+       {
+               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
+       }
+       
+       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_R48);   // Read Command (LBA48)
+       else
+               outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
+       
+       // Reset IRQ Flag
+       gaATA_IRQs[cont] = 0;
+       
+       // Start transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 9 );     // Read and start
+       
+       // Wait for transfer to complete
+       while( gaATA_IRQs[cont] == 0 )  Proc_Yield();
+       
+       // Complete Transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
+       
+       // Copy to destination buffer
+       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
+       
+       // Release controller lock
+       RELEASE( &giaATA_ControllerLock[ cont ] );
+       
+       return 1;
+}
+
+/**
+ * \fn void ATA_IRQHandlerPri(void)
+ */
+void ATA_IRQHandlerPri(void)
+{
+       Uint8   val;
+       
+       // IRQ bit set for Primary Controller
+       val = ATA_int_BusMasterReadByte( 0x2 );
+       if(val & 4) {
+               //Log(" ATA_IRQHandlerPri: IRQ hit (val = 0x%x)", val);
+               ATA_int_BusMasterWriteByte( 0x2, 4 );
+               gaATA_IRQs[0] = 1;
+               return ;
+       }
+}
+
+/**
+ * \fn void ATA_IRQHandlerSec(void)
+ */
+void ATA_IRQHandlerSec(void)
+{
+       Uint8   val;
+       // IRQ bit set for Secondary Controller
+       val = ATA_int_BusMasterReadByte( 0xA );
+       if(val & 4) {
+               //Log(" ATA_IRQHandlerSec: IRQ hit (val = 0x%x)", val);
+               ATA_int_BusMasterWriteByte( 0xA, 4 );
+               gaATA_IRQs[1] = 1;
+               return ;
+       }
+}
+
+/**
+ * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
+ */
+Uint8 ATA_int_BusMasterReadByte(int Ofs)
+{
+       if( gATA_BusMasterBase & 1 )
+               return inb( (gATA_BusMasterBase & ~1) + Ofs );
+       else
+               return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
+}
+
+/**
+ * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
+ * \brief Writes a byte to a Bus Master Register
+ */
+void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
+{
+       if( gATA_BusMasterBase & 1 )
+               outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
+       else
+               *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
+}
+
+/**
+ * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
+ * \brief Writes a dword to a Bus Master Register
+ */
+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/Kernel/drv/bochsvbe.c b/Kernel/drv/bochsvbe.c
new file mode 100644 (file)
index 0000000..2aed670
--- /dev/null
@@ -0,0 +1,390 @@
+/**\r
+ * \file drv_bochsvbe.c\r
+ * \brief BGA (Bochs Graphic Adapter) Driver\r
+ * \note for AcessOS Version 1\r
+ * \warning This driver does NOT support the Bochs PCI VGA driver\r
+*/\r
+#include <common.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <tpl_drv_video.h>\r
+\r
+#define DEBUG  0\r
+#if DEBUG\r
+# define DEBUGS(v...)  SysDebug(v)\r
+#else\r
+# define DEBUGS(v...)\r
+#endif\r
+\r
+//#define INT  static\r
+#define INT\r
+\r
+// === TYPEDEFS ===\r
+typedef struct {\r
+       Uint16  width;\r
+       Uint16  height;\r
+       Uint16  bpp;\r
+       Uint16  flags;\r
+       Uint32  fbSize;\r
+} t_bga_mode;\r
+\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, Uint16 bpp);\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, void *buffer);\r
+ int   BGA_Ioctl(tVFS_Node *node, int id, void *data);\r
+\r
+// === CONSTANTS ===\r
+const t_bga_mode       BGA_MODES[] = {\r
+       {640,480,8, 0, 640*480},\r
+       {640,480,32, 0, 640*480*4},\r
+       {800,600,8, 0, 800*600},\r
+       {800,600,32, 0, 800*600*4},\r
+};\r
+#define        BGA_MODE_COUNT  (sizeof(BGA_MODES)/sizeof(BGA_MODES[0]))\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
+// GLOBALS\r
+MODULE_DEFINE(0, 0x0032, BochsVBE, BGA_Install, NULL, NULL);\r
+tDevFS_Driver  gBGA_DriverStruct = {\r
+       NULL, "BochsGA",\r
+       {\r
+       .Read = BGA_Read,\r
+       .Write = BGA_Write,\r
+       .IOCtl = BGA_Ioctl\r
+       }\r
+};\r
+ int   giBGA_CurrentMode = -1;\r
+ int   giBGA_DriverId = -1;\r
+Uint   *gBGA_Framebuffer;\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int BGA_Install(char **Arguments)\r
+ */\r
+int BGA_Install(char **Arguments)\r
+{\r
+        int    bga_version = 0;\r
+       \r
+       // Check BGA Version\r
+       bga_version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
+       // NOTE: This driver was written for 0xB0C4, but they seem to be backwards compatable\r
+       if(bga_version < 0xB0C4 || bga_version > 0xB0C5) {\r
+               Warning("[BGA ] Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", bga_version);\r
+               return 0;\r
+       }\r
+       \r
+       // Install Device\r
+       giBGA_DriverId = DevFS_AddDevice( &gBGA_DriverStruct );\r
+       if(giBGA_DriverId == -1) {\r
+               Warning("[BGA ] Unable to register with DevFS, maybe already loaded?");\r
+               return 0;\r
+       }\r
+       \r
+       // Map Framebuffer to hardware address\r
+       gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768);  // 768 pages (3Mb)\r
+       \r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn void BGA_Uninstall()\r
+ */\r
+void BGA_Uninstall()\r
+{\r
+       //DevFS_DelDevice( giBGA_DriverId );\r
+       MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 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 > BGA_MODES[giBGA_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
+ * \fn Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       Uint8   *destBuf;\r
+       \r
+       DEBUGS("BGA_Write: (off=%i, len=0x%x)\n", off, len);\r
+       \r
+       // Check Mode\r
+       if(giBGA_CurrentMode == -1)\r
+               return -1;\r
+       // Check Input against Frambuffer Size\r
+       if(off+len > BGA_MODES[giBGA_CurrentMode].fbSize)\r
+               return -1;\r
+       \r
+       destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off);\r
+       \r
+       DEBUGS(" BGA_Write: *buffer = 0x%x\n", *(Uint*)buffer);\r
+       DEBUGS(" BGA_Write: Updating Framebuffer (0x%x - 0x%x bytes)\n", \r
+               destBuf, destBuf + (Uint)len);\r
+       \r
+       \r
+       // Copy to Frambuffer\r
+       memcpy(destBuf, buffer, len);\r
+       \r
+       DEBUGS("BGA_Write: BGA Framebuffer updated\n");\r
+       \r
+       return len;\r
+}\r
+\r
+/**\r
+ * \fn INT int BGA_Ioctl(tVFS_Node *node, int id, void *data)\r
+ * \brief Handle messages to the device\r
+ */\r
+INT 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
+       case DRV_IOCTL_TYPE:\r
+               ret = DRV_TYPE_VIDEO;\r
+               break;\r
+       case DRV_IOCTL_IDENT:\r
+               memcpy(data, "BGA1", 4);\r
+               ret = 1;\r
+               break;\r
+       case DRV_IOCTL_VERSION:\r
+               ret = 0x100;\r
+               break;\r
+       case DRV_IOCTL_LOOKUP:  // TODO: Implement\r
+               ret = 0;\r
+               break;\r
+               \r
+       case VIDEO_IOCTL_SETMODE:\r
+               ret = BGA_int_UpdateMode(*(int*)(data));\r
+               break;\r
+               \r
+       case VIDEO_IOCTL_GETMODE:\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
+       // Request Access to LFB\r
+       case VIDEO_IOCTL_REQLFB:\r
+               ret = BGA_int_MapFB( *(void**)data );\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
+ * \fn void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\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
+INT Uint16 BGA_int_ReadRegister(Uint16 reg)\r
+{\r
+       outw(VBE_DISPI_IOPORT_INDEX, reg);\r
+       return inw(VBE_DISPI_IOPORT_DATA);\r
+}\r
+\r
+#if 0\r
+INT void BGA_int_SetBank(Uint16 bank)\r
+{\r
+       BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank);\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
+ * \brief Sets the video mode from the dimensions and bpp given\r
+ */\r
+void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
+{\r
+       DEBUGS("BGA_int_SetMode: (width=%i, height=%i, bpp=%i)\n", width, height, bpp);\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, bpp);\r
+    BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
+    //BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM);\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
+       if(id < 0 || id >= BGA_MODE_COUNT)      return -1;\r
+       BGA_int_SetMode(BGA_MODES[id].width, BGA_MODES[id].height, BGA_MODES[id].bpp);\r
+       giBGA_CurrentMode = 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 = -1, bestFactor = 1000;\r
+        int    factor, tmp;\r
+        int    rqdProduct = info->width * info->height * info->bpp;\r
+       \r
+       DEBUGS("BGA_int_FindMode: (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
+               LogF("Mode %i (%ix%ix%i), ", i, BGA_MODES[i].width, BGA_MODES[i].height, BGA_MODES[i].bpp);\r
+               #endif\r
+       \r
+               if(BGA_MODES[i].width == info->width\r
+               && BGA_MODES[i].height == info->height\r
+               && BGA_MODES[i].bpp == info->bpp)\r
+               {\r
+                       #if DEBUG >= 2\r
+                       LogF("Perfect!\n");\r
+                       #endif\r
+                       best = i;\r
+                       break;\r
+               }\r
+               \r
+               tmp = BGA_MODES[i].width * BGA_MODES[i].height * BGA_MODES[i].bpp;\r
+               tmp -= rqdProduct;\r
+               tmp = tmp < 0 ? -tmp : tmp;\r
+               factor = tmp * 100 / rqdProduct;\r
+               \r
+               #if DEBUG >= 2\r
+               LogF("factor = %i\n", factor);\r
+               #endif\r
+               \r
+               if(factor < bestFactor)\r
+               {\r
+                       bestFactor = factor;\r
+                       best = i;\r
+               }\r
+       }\r
+       info->id = best;\r
+       info->width = BGA_MODES[best].width;\r
+       info->height = BGA_MODES[best].height;\r
+       info->bpp = BGA_MODES[best].bpp;\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
+       if(!info)       return -1;\r
+       if(MM_GetPhysAddr((Uint)info) == 0)\r
+               return -1;\r
+       \r
+       if(info->id < 0 || info->id >= BGA_MODE_COUNT)  return -1;\r
+       \r
+       info->width = BGA_MODES[info->id].width;\r
+       info->height = BGA_MODES[info->id].height;\r
+       info->bpp = BGA_MODES[info->id].bpp;\r
+       \r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_MapFB(void *Dest)\r
+ * \brief Map the framebuffer into a process's space\r
+ * \param Dest User address to load to\r
+ */\r
+int BGA_int_MapFB(void *Dest)\r
+{\r
+       Uint    i;\r
+       Uint    pages;\r
+       \r
+       // Sanity Check\r
+       if((Uint)Dest > 0xC0000000)     return 0;\r
+       if(BGA_MODES[giBGA_CurrentMode].bpp < 15)       return 0;       // Only non-pallete modes are supported\r
+       \r
+       // Count required pages\r
+       pages = (BGA_MODES[giBGA_CurrentMode].fbSize + 0xFFF) >> 12;\r
+       \r
+       // Check if there is space\r
+       for( i = 0; i < pages; i++ )\r
+       {\r
+               if(MM_GetPhysAddr( (Uint)Dest + (i << 12) ))\r
+                       return 0;\r
+       }\r
+       \r
+       // Map\r
+       for( i = 0; i < pages; i++ )\r
+               MM_Map( (Uint)Dest + (i<<12), VBE_DISPI_LFB_PHYSICAL_ADDRESS + (i<<12) );\r
+       \r
+       return 1;\r
+}\r
diff --git a/Kernel/drv/kb.c b/Kernel/drv/kb.c
new file mode 100644 (file)
index 0000000..013e953
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Acess2
+ * PS2 Keyboard Driver
+ */
+#include <common.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <tpl_drv_common.h>
+#include <tpl_drv_keyboard.h>
+#include "kb_kbdus.h"
+
+// === CONSTANTS ===
+#define        KB_BUFFER_SIZE  1024
+
+// === PROTOTYPES ===
+ int   KB_Install(char **Arguments);
+void   KB_IRQHandler();
+void   KB_AddBuffer(char ch);
+Uint64 KB_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Dest);
+void   KB_UpdateLEDs();
+ int   KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0100, PS2Keybard, KB_Install, NULL, NULL);
+tDevFS_Driver  gKB_DevInfo = {
+       NULL, "PS2Kb",
+       {
+       .NumACLs = 0,
+       .Size = -1,
+       .Read = KB_Read,
+       .IOCtl = KB_IOCtl
+       }
+};
+tKeybardCallback       gKB_Callback = NULL;
+Uint8  **gpKB_Map = gpKBDUS;
+Uint8  gbaKB_States[256];
+ int   gbKB_ShiftState = 0;
+ int   gbKB_CapsState = 0;
+ int   gbKB_KeyUp = 0;
+ int   giKB_KeyLayer = 0;
+//Uint64       giKB_ReadBase = 0;
+Uint8  gaKB_Buffer[KB_BUFFER_SIZE];    //!< Keyboard Ring Buffer
+volatile int   giKB_InsertPoint = 0;   //!< Writing location marker
+volatile int   giKB_ReadPoint = 0;     //!< Reading location marker
+volatile int   giKB_InUse = 0;         //!< Lock marker
+
+// === CODE ===
+/**
+ * \fn int KB_Install(char **Arguments)
+ */
+int KB_Install(char **Arguments)
+{
+       IRQ_AddHandler(1, KB_IRQHandler);
+       DevFS_AddDevice( &gKB_DevInfo );
+       return 1;
+}
+
+/**
+ * \fn void KB_IRQHandler()
+ * \brief Called on a keyboard IRQ
+ */
+void KB_IRQHandler()
+{
+       Uint8   scancode;
+       Uint32  ch;
+        int    keyNum;
+
+       //if( inportb(0x64) & 0x20 )    return;
+       
+       scancode = inb(0x60); // Read from the keyboard's data buffer
+
+       // Ignore ACKs
+       if(scancode == 0xFA) {
+               //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
+       
+       // Translate
+       ch = gpKB_Map[giKB_KeyLayer][scancode];
+       keyNum = giKB_KeyLayer * 256 + scancode;
+       // Check for unknown key
+       if(!ch && !gbKB_KeyUp)
+               Warning("UNK %i %x", giKB_KeyLayer, scancode);
+       
+       // Reset Layer
+       giKB_KeyLayer = 0;
+       
+       // Key Up?
+       if (gbKB_KeyUp)
+       {
+               gbKB_KeyUp = 0;
+               gbaKB_States[ keyNum ] = 0;     // Unset key state flag
+               
+               if( !gbaKB_States[KEY_LSHIFT] && !gbaKB_States[KEY_RSHIFT] )
+                       gbKB_ShiftState = 0;
+               
+               KB_AddBuffer(KEY_KEYUP);
+               KB_AddBuffer(ch);
+               
+               return;
+       }
+
+       // Set the bit relating to the key
+       gbaKB_States[keyNum] = 1;
+       if(ch == KEY_LSHIFT || ch == KEY_RSHIFT)
+               gbKB_ShiftState = 1;
+       
+       // Check for Caps Lock
+       if(ch == KEY_CAPSLOCK) {
+               gbKB_CapsState = !gbKB_CapsState;
+               KB_UpdateLEDs();
+       }
+
+       // Ignore Non-Printable Characters
+       if(ch == 0 || ch & 0x80)                return;
+               
+       // Is shift pressed
+       if(gbKB_ShiftState ^ gbKB_CapsState)
+       {
+               switch(ch)
+               {
+               case '`':       ch = '~';       break;
+               case '1':       ch = '!';       break;
+               case '2':       ch = '@';       break;
+               case '3':       ch = '#';       break;
+               case '4':       ch = '$';       break;
+               case '5':       ch = '%';       break;
+               case '6':       ch = '^';       break;
+               case '7':       ch = '&';       break;
+               case '8':       ch = '*';       break;
+               case '9':       ch = '(';       break;
+               case '0':       ch = ')';       break;
+               case '-':       ch = '_';       break;
+               case '=':       ch = '+';       break;
+               case '[':       ch = '{';       break;
+               case ']':       ch = '}';       break;
+               case '\\':      ch = '|';       break;
+               case ';':       ch = ':';       break;
+               case '\'':      ch = '"';       break;
+               case ',':       ch = '<';       break;
+               case '.':       ch = '>';       break;
+               case '/':       ch = '?';       break;
+               default:
+                       if('a' <= ch && ch <= 'z')
+                               ch -= 0x20;
+                       break;
+               }
+       }
+       
+       // --- Check for Kernel Magic Combos
+       if(gbaKB_States[KEY_LSHIFT] && gbaKB_States[KEY_RSHIFT])
+       {
+               switch(ch)
+               {
+               case 'D':       __asm__ __volatile__ ("xchg %bx, %bx"); break;
+               }
+       }
+       
+       if(gKB_Callback)
+               gKB_Callback(ch);
+}
+
+/**
+ * \fn void KB_AddBuffer(char ch)
+ * \brief Add to the keyboard ring buffer
+ */
+void KB_AddBuffer(char ch)
+{
+       // Add to buffer
+       gaKB_Buffer[ giKB_InsertPoint++ ] = ch;
+       // - Wrap
+       if( giKB_InsertPoint == KB_BUFFER_SIZE )        giKB_InsertPoint = 0;
+       // - Force increment read pointer
+       if( giKB_InsertPoint == giKB_ReadPoint )        giKB_ReadPoint ++;
+}
+
+/**
+ * \fn Uint64 KB_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Dest)
+ * \brief Read from the ring buffer
+ * \param Node Unused
+ * \param Offset       Unused (Character Device)
+ * \param Length       Number of bytes to read
+ * \param Dest Destination
+ */
+Uint64 KB_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Dest)
+{
+        int    pos = 0;
+       char    *dstbuf = Dest;
+       
+       if(giKB_InUse)  return -1;
+       giKB_InUse = 1;
+       
+       while(giKB_ReadPoint != giKB_InsertPoint && pos < Length)
+       {
+               dstbuf[pos++] = gaKB_Buffer[ giKB_ReadPoint++ ];
+               if( giKB_ReadPoint == KB_BUFFER_SIZE )  giKB_InsertPoint = 0;
+       }
+       
+       giKB_InUse = 0;
+       
+       return Length;
+}
+
+/**
+ * \fn void KB_UpdateLEDs()
+ * \brief Updates the status of the keyboard LEDs
+ */
+void KB_UpdateLEDs()
+{
+       Uint8   leds;
+       
+       leds = (gbKB_CapsState ? 4 : 0);
+       
+       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);
+}
+
+/**
+ * \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)
+       {
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_KEYBOARD;
+       case DRV_IOCTL_IDENT:   memcpy(Data, "KB\0\0", 4);      return 1;
+       case DRV_IOCTL_VERSION: return 0x100;
+       case DRV_IOCTL_LOOKUP:  return 0;
+       
+       // 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/Kernel/drv/kb_kbdus.h b/Kernel/drv/kb_kbdus.h
new file mode 100644 (file)
index 0000000..5f85ab1
--- /dev/null
@@ -0,0 +1,39 @@
+\r
+#ifndef _KBDUS_H\r
+#define _KBDUS_H\r
+\r
+// - BASE (NO PREFIX)\r
+Uint8  gpKBDUS1[256] = {\r
+       // 00\r
+       0,  KEY_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t',\r
+       // 10\r
+       'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', KEY_LCTRL, 'a', 's',\r
+       // 20\r
+       'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`', KEY_LSHIFT,'\\', 'z', 'x', 'c', 'v',\r
+       // 30\r
+       'b','n','m',',','.','/',KEY_RSHIFT,KEY_KPSTAR,KEY_LALT,' ',KEY_CAPSLOCK,KEY_F1,KEY_F2,KEY_F3,KEY_F4, KEY_F5,\r
+       // 40\r
+       KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_KPHOME, KEY_KPUP, KEY_KPPGUP, KEY_KPMINUS, KEY_KPLEFT, KEY_KP5, KEY_KPRIGHT, KEY_KPPLUS, KEY_KPEND,   /* 4F9 - Keypad End key*/\r
+       // 50\r
+    KEY_KPDOWN, KEY_KPPGDN, KEY_KPINS, KEY_KPDEL, 0, 0, 0, KEY_F11, KEY_F12, 0\r
+};\r
+// - 0xE0 Prefixed\r
+Uint8  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, KEY_WIN, 0, 0, KEY_MENU\r
+};\r
+Uint8  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\r
+};\r
+\r
+\r
+Uint8  *gpKBDUS[3] = { gpKBDUS1, gpKBDUS2, gpKBDUS3 };\r
+\r
+#endif\r
diff --git a/Kernel/drv/pci.c b/Kernel/drv/pci.c
new file mode 100644 (file)
index 0000000..e0a25b5
--- /dev/null
@@ -0,0 +1,556 @@
+/*\r
+AcessOS/AcessBasic v0.1\r
+PCI Bus Driver\r
+*/\r
+#include <common.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+\r
+#define DEBUG  0\r
+#define        LIST_DEVICES    1\r
+\r
+// === STRUCTURES ===\r
+typedef struct s_pciDevice {\r
+       Uint16  bus, slot, fcn;\r
+       Uint16  vendor, device;\r
+       union {\r
+               struct {Uint8 class, subclass;};\r
+               Uint16  oc;\r
+       };\r
+       Uint16  revision;\r
+       Uint32  ConfigCache[256/4];\r
+       char    Name[8];\r
+       tVFS_Node       Node;\r
+} t_pciDevice;\r
+\r
+// === CONSTANTS ===\r
+#define SPACE_STEP     5\r
+#define MAX_RESERVED_PORT      0xD00\r
+\r
+// === PROTOTYPES ===\r
+ int   PCI_Install(char **Arguments);\r
+char   *PCI_ReadDirRoot(tVFS_Node *node, int pos);\r
+tVFS_Node      *PCI_FindDirRoot(tVFS_Node *node, char *filename);\r
+Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);\r
\r
+ int   PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);\r
+ int   PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);\r
+ int   PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);\r
+Uint8  PCI_GetIRQ(int id);\r
+Uint32 PCI_GetBAR0(int id);\r
+Uint32 PCI_GetBAR1(int id);\r
+Uint32 PCI_GetBAR3(int id);\r
+Uint32 PCI_GetBAR4(int id);\r
+Uint32 PCI_GetBAR5(int id);\r
+Uint16 PCI_AssignPort(int id, int bar, int count);\r
+\r
+ int   PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, t_pciDevice *info);\r
+Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
+void   PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);\r
+Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
+Uint8  PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
+\r
+// === GLOBALS ===\r
+//MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL);\r
+ int   giPCI_BusCount = 1;\r
+ int   giPCI_InodeHandle = -1;\r
+ int   giPCI_DeviceCount = 0;\r
+t_pciDevice    *gPCI_Devices = NULL;\r
+tDevFS_Driver  gPCI_DriverStruct = {\r
+       NULL, "pci",\r
+       {\r
+       .Flags = VFS_FFLAG_DIRECTORY,\r
+       .NumACLs = 1,\r
+       .ACLs = &gVFS_ACL_EveryoneRX,\r
+       .ReadDir = PCI_ReadDirRoot,\r
+       .FindDir = PCI_FindDirRoot\r
+       }\r
+};\r
+ Uint32        *gaPCI_PortBitmap = NULL;\r
\r
+// === CODE ===\r
+/**\r
+ * \fn int PCI_Install()\r
+ * \brief Scan the PCI Bus for devices\r
+ */\r
+int PCI_Install(char **Arguments)\r
+{\r
+        int    bus, dev, fcn, i;\r
+        int    space = 0;\r
+       t_pciDevice     devInfo;\r
+       void    *tmpPtr = NULL;\r
+       \r
+       // Build Portmap\r
+       gaPCI_PortBitmap = malloc( 1 << 13 );\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
+       //LogF("Done.\n");\r
+       \r
+       // Scan Busses\r
+       for( bus = 0; bus < giPCI_BusCount; bus++ )\r
+       {\r
+               for( dev = 0; dev < 10; dev++ ) // 10 Devices per bus\r
+               {\r
+                       for( fcn = 0; fcn < 8; fcn++ )  // 8 functions per device\r
+                       {\r
+                               // Check if the device/function exists\r
+                               if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))\r
+                               {\r
+                                       continue;\r
+                               }\r
+                               \r
+                               if(giPCI_DeviceCount == space)\r
+                               {\r
+                                       space += SPACE_STEP;\r
+                                       tmpPtr = realloc(gPCI_Devices, space*sizeof(t_pciDevice));\r
+                                       if(tmpPtr == NULL)\r
+                                               break;\r
+                                       gPCI_Devices = tmpPtr;\r
+                               }\r
+                               if(devInfo.oc == PCI_OC_PCIBRIDGE)\r
+                               {\r
+                                       #if LIST_DEVICES\r
+                                       Log("[PCI ] Bridge @ %i,%i:%i (0x%x:0x%x)",\r
+                                               bus, dev, fcn, devInfo.vendor, devInfo.device);\r
+                                       #endif\r
+                                       giPCI_BusCount++;\r
+                               }\r
+                               devInfo.Node.Inode = giPCI_DeviceCount;\r
+                               memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(t_pciDevice));\r
+                               giPCI_DeviceCount ++;\r
+                               #if LIST_DEVICES\r
+                               Log("[PCI ] Device %i,%i:%i => 0x%x:0x%x",\r
+                                       bus, dev, fcn, devInfo.vendor, devInfo.device);\r
+                               #endif\r
+                               \r
+                               // WTF is this for?\r
+                               if(fcn == 0) {\r
+                                       if( !(devInfo.ConfigCache[3] & 0x800000) )\r
+                                               break;\r
+                               }\r
+                       }\r
+                       if(tmpPtr != gPCI_Devices)\r
+                               break;\r
+               }\r
+               if(tmpPtr != gPCI_Devices)\r
+                       break;\r
+       }\r
+       tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(t_pciDevice));\r
+       if(tmpPtr == NULL)\r
+               return 0;\r
+       gPCI_Devices = tmpPtr;\r
+       //LogF("Done.\n");\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 1;\r
+}\r
+\r
+/**\r
+ * \fn char *PCI_ReadDirRoot(tVFS_Node *node, int pos)\r
+ * \brief Read from Root of PCI Driver\r
+*/\r
+char *PCI_ReadDirRoot(tVFS_Node *node, int pos)\r
+{      \r
+       if(pos < 0 || pos >= giPCI_DeviceCount)\r
+               return NULL;\r
+       \r
+       return gPCI_Devices[pos].Name;\r
+}\r
+/**\r
+ * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, char *filename)\r
+ */\r
+tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, 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
+ * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
+ */\r
+Uint64 PCI_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
+ \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)\r
+ \brief Counts the devices with the specified codes\r
+ \param vendor Vendor ID\r
+ \param device Device ID\r
+ \param fcn    Function ID\r
+*/\r
+int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)\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
+               if(gPCI_Devices[i].fcn != fcn)  continue;\r
+               ret ++;\r
+       }\r
+       return ret;\r
+}\r
+\r
+/**\r
+ \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)\r
+ \brief Gets the ID of the specified PCI device\r
+ \param vendor Vendor ID\r
+ \param device Device ID\r
+ \param fcn    Function IDs\r
+ \param idx    Number of matching entry wanted\r
+*/\r
+int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, 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(gPCI_Devices[i].fcn != fcn)  continue;\r
+               if(j == idx)    return i;\r
+               j ++;\r
+       }\r
+       return -1;\r
+}\r
+\r
+/**\r
+ * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)\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
+int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int 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].oc & mask) != class)        continue;\r
+               return i;\r
+       }\r
+       return -1;\r
+}\r
+\r
+/**\r
+ \fn Uint8 PCI_GetIRQ(int id)\r
+*/\r
+Uint8 PCI_GetIRQ(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[15];\r
+       //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);\r
+}\r
+\r
+/**\r
+ \fn Uint32 PCI_GetBAR0(int id)\r
+*/\r
+Uint32 PCI_GetBAR0(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[4];\r
+}\r
+\r
+/**\r
+ \fn Uint32 PCI_GetBAR1(int id)\r
+*/\r
+Uint32 PCI_GetBAR1(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[5];\r
+}\r
+\r
+/**\r
+ \fn Uint32 PCI_GetBAR2(int id)\r
+*/\r
+Uint32 PCI_GetBAR2(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[6];\r
+}\r
+\r
+/**\r
+ \fn Uint32 PCI_GetBAR3(int id)\r
+*/\r
+Uint32 PCI_GetBAR3(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[7];\r
+}\r
+\r
+/**\r
+ \fn Uint32 PCI_GetBAR4(int id)\r
+*/\r
+Uint32 PCI_GetBAR4(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[8];\r
+}\r
+\r
+/**\r
+ \fn Uint32 PCI_GetBAR5(int id)\r
+*/\r
+Uint32 PCI_GetBAR5(int id)\r
+{\r
+       if(id < 0 || id >= giPCI_DeviceCount)\r
+               return 0;\r
+       return gPCI_Devices[id].ConfigCache[9];\r
+}\r
+\r
+Uint16 PCI_AssignPort(int id, int bar, int count)\r
+{\r
+       Uint16  portVals;\r
+        int    gran=0;\r
+        int    i, j;\r
+       t_pciDevice     *dev;\r
+       \r
+       //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);\r
+       \r
+       if(id < 0 || id >= giPCI_DeviceCount)   return 0;\r
+       if(bar < 0 || bar > 5)  return 0;\r
+       \r
+       dev = &gPCI_Devices[id];\r
+       \r
+       PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );\r
+       portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );\r
+       dev->ConfigCache[4+bar] = portVals;\r
+       //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);\r
+       \r
+       // Check for IO port\r
+       if( !(portVals & 1) )   return 0;\r
+       \r
+       // Mask out final bit\r
+       portVals &= ~1;\r
+       \r
+       // Get Granuality\r
+       __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );\r
+       gran = 1 << gran;\r
+       //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);\r
+       \r
+       // Find free space\r
+       portVals = 0;\r
+       for( i = 0; i < 1<<16; i += gran )\r
+       {\r
+               for( j = 0; j < count; j ++ )\r
+               {\r
+                       if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )\r
+                               break;\r
+               }\r
+               if(j == count) {\r
+                       portVals = i;\r
+                       break;\r
+               }\r
+       }\r
+       \r
+       if(portVals)\r
+       {\r
+               for( j = 0; j < count; j ++ )\r
+               {\r
+                       if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )\r
+                               break;\r
+               }\r
+               PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );\r
+               dev->ConfigCache[4+bar] = portVals|1;\r
+       }\r
+       \r
+       // Return\r
+       //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);\r
+       return portVals;\r
+}\r
+\r
+/**\r
+ * \fn int     PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)\r
+ */\r
+int    PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)\r
+{\r
+       Uint16  vendor;\r
+        int    i;\r
+       Uint32  addr;\r
+       \r
+       vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);\r
+       if(vendor == 0xFFFF)    // Invalid Device\r
+               return 0;\r
+               \r
+       info->bus = bus;\r
+       info->slot = slot;\r
+       info->fcn = fcn;\r
+       info->vendor = vendor;\r
+       info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);\r
+       info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);\r
+       info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);\r
+       \r
+       // Load Config Bytes\r
+       addr = 0x80000000 | ((Uint)bus<<16) | ((Uint)slot<<11) | ((Uint)fcn<<8);\r
+       for(i=0;i<256/4;i++)\r
+       {\r
+               #if 1\r
+               outd(0xCF8, addr);\r
+               info->ConfigCache[i] = ind(0xCFC);\r
+               addr += 4;\r
+               #else\r
+               info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);\r
+               #endif\r
+       }\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%04x", info->oc);\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.Read = PCI_ReadDevice;\r
+       \r
+       return 1;\r
+}\r
+\r
+Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)\r
+{\r
+       Uint32  address;\r
+       Uint32  data;\r
+       \r
+       bus &= 0xFF;    // 8 Bits\r
+       dev &= 0x1F;    // 5 Bits\r
+       func &= 0x7;    // 3 Bits\r
+       offset &= 0xFF; // 8 Bits\r
+       \r
+       address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);\r
+       outd(0xCF8, address);\r
+       \r
+       data = ind(0xCFC);\r
+       return (Uint32)data;\r
+}\r
+void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data)\r
+{\r
+       Uint32  address;\r
+       \r
+       bus &= 0xFF;    // 8 Bits\r
+       dev &= 0x1F;    // 5 Bits\r
+       func &= 0x7;    // 3 Bits\r
+       offset &= 0xFF; // 8 Bits\r
+       \r
+       address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);\r
+       outd(0xCF8, address);\r
+       outd(0xCFC, data);\r
+}\r
+Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)\r
+{\r
+       Uint32  data;\r
+       \r
+       bus &= 0xFF;    // 8 Bits\r
+       dev &= 0x1F;    // 5 Bits\r
+       func &= 0x7;    // 3 Bits\r
+       offset &= 0xFF; // 8 Bits\r
+       \r
+       //LogF("PCI_CfgReadWord: (bus=0x%x,dev=0x%x,func=%x,offset=0x%x)\n", bus, dev, func, offset);\r
+       \r
+       outd(0xCF8,\r
+               0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC) );\r
+       \r
+       data = ind(0xCFC);\r
+       data >>= (offset&2)*8;  //Allow Access to Upper Word\r
+       //LogF("PCI_CfgReadWord: RETURN 0x%x\n", data&0xFFFF);\r
+       return (Uint16)data;\r
+}\r
+\r
+Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset)\r
+{\r
+       Uint32  address;\r
+       Uint32  data;\r
+       \r
+       bus &= 0xFF;    // 8 Bits\r
+       dev &= 0x1F;    // 4 Bits\r
+       func &= 0x7;    // 3 Bits\r
+       offset &= 0xFF; // 8 Bits\r
+       \r
+       address = 0x80000000 | ((Uint)bus<<16) | ((Uint)dev<<11) | ((Uint)func<<8) | (offset&0xFC);\r
+       outd(0xCF8, address);\r
+       \r
+       data = ind(0xCFC);\r
+       data >>= (offset&3)*8;  //Allow Access to Upper Word\r
+       return (Uint8)data;\r
+}\r
+\r
+\r
+// === EXPORTS ===\r
+/*\r
+EXPORT(PCI_CountDevices);\r
+EXPORT(PCI_GetDevice);\r
+EXPORT(PCI_AssignPort);\r
+EXPORT(PCI_GetIRQ);\r
+*/\r
diff --git a/Kernel/drv/vga.c b/Kernel/drv/vga.c
new file mode 100644 (file)
index 0000000..93f44f0
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Acess2 VGA Controller Driver
+ */
+#include <common.h>
+#include <fs_devfs.h>
+#include <tpl_drv_video.h>
+#include <modules.h>
+
+// === PROTOTYPES ===
+ int   VGA_Install(char **Arguments);
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   VGA_IOCtl(tVFS_Node *Node, int Id, void *Data);
+Uint16 VGA_int_GetWord(tVT_Char *Char);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x000A, VGA, VGA_Install, NULL, NULL);
+tDevFS_Driver  gVGA_DevInfo = {
+       NULL, "VGA",
+       {
+       .NumACLs = 0,
+       .Size = 80*25*sizeof(tVT_Char),
+       //.Read = VGA_Read,
+       .Write = VGA_Write,
+       .IOCtl = VGA_IOCtl
+       }
+};
+Uint16 *gVGA_Framebuffer = (void*)( KERNEL_BASE|0xB8000 );
+
+// === 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 1;
+}
+
+/**
+ * \fn Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Writes a string of bytes to the VGA controller
+ */
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+        int    num = Length / sizeof(tVT_Char);
+        int    ofs = Offset / sizeof(tVT_Char);
+        int    i = 0;
+       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;
+}
+
+/**
+ * \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)
+{
+       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_SETMODE:       return 0;       // Ignored (Text Only ATM)
+       case VIDEO_IOCTL_GETMODE:       return 0;       // Mode 0 only
+       case VIDEO_IOCTL_FINDMODE:      return 0;       // Text Only!
+       case VIDEO_IOCTL_MODEINFO:
+               if( ((tVideo_IOCtl_Mode*)Data)->id != 0)        return 0;
+               ((tVideo_IOCtl_Mode*)Data)->width = 80;
+               ((tVideo_IOCtl_Mode*)Data)->height = 25;
+               ((tVideo_IOCtl_Mode*)Data)->bpp = 4;
+               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(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;
+}
diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c
new file mode 100644 (file)
index 0000000..9244619
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Acess2 Virtual Terminal Driver
+ */
+#include <common.h>
+#include <fs_devfs.h>
+#include <modules.h>
+#include <tpl_drv_video.h>
+
+// === CONSTANTS ===
+#define        NUM_VTS 4
+#define MAX_INPUT_BYTES        64
+#define VT_SCROLLBACK  4       // 4 Screens of text
+#define DEFAULT_OUTPUT "/Devices/VGA"
+#define DEFAULT_INPUT  "/Devices/PS2Keyboard"
+#define        DEFAULT_WIDTH   80
+#define        DEFAULT_HEIGHT  25
+#define        DEFAULT_COLOUR  (VT_COL_BLACK|(VT_COL_WHITE<<16))
+
+enum eVT_Modes {
+       VT_MODE_TEXT,
+       VT_MODE_8BPP,
+       VT_MODE_16BPP,
+       VT_MODE_24BPP,
+       VT_MODE_32BPP,
+       NUM_VT_MODES
+};
+
+// === TYPES ===
+typedef struct {
+        int    Mode;
+        int    Width, Height;
+        int    ViewPos, WritePos;
+       Uint32  CurColour;
+       char    Name[2];
+        int    NumInputBytes;
+       Uint8   InputBuffer[MAX_INPUT_BYTES];
+       union {
+               tVT_Char        *Text;
+               Uint32          *Buffer;
+       };
+       tVFS_Node       Node;
+} tVTerm;
+
+// === PROTOTYPES ===
+ int   VT_Install(char **Arguments);
+char   *VT_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *VT_FindDir(tVFS_Node *Node, char *Name);
+Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int   VT_IOCtl(tVFS_Node *Node, int Id, void *Data);
+void   VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count);
+ int   VT_int_ParseEscape(tVTerm *Term, char *Buffer);
+void   VT_int_PutChar(tVTerm *Term, Uint32 Ch);
+void   VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
+
+// === CONSTANTS ===
+const Uint16   caVT100Colours[] = {
+               VT_COL_BLACK, 0, 0, 0, 0, 0, 0, VT_COL_LTGREY,
+               VT_COL_GREY, 0, 0, 0, 0, 0, 0, VT_COL_WHITE
+       };
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0032, VTerm, VT_Install, NULL, NULL);
+tDevFS_Driver  gVT_DrvInfo = {
+       NULL, "VTerm",
+       {
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .Inode = -1,
+       .NumACLs = 0,
+       .ReadDir = VT_ReadDir,
+       .FindDir = VT_FindDir
+       }
+};
+tVTerm gVT_Terminals[NUM_VTS];
+char   *gsVT_OutputDevice = NULL;
+char   *gsVT_InputDevice = NULL;
+ int   giVT_OutputDevHandle = -2;
+ int   giVT_InputDevHandle = -2;
+ int   giVT_CurrentTerminal = 0;
+
+// === CODE ===
+/**
+ * \fn int VT_Install(char **Arguments)
+ */
+int VT_Install(char **Arguments)
+{
+       char    **args = Arguments;
+       char    *arg;
+        int    i;
+       
+       // Scan Arguments
+       if(Arguments)
+       {
+               for( ; (arg = *args); args++ )
+               {
+                       if(arg[0] != '-')       continue;
+                       
+                       switch(arg[1])
+                       {
+                       // Set output device
+                       case 'o':
+                               if(args[1] ==  NULL)    break;
+                               if(gsVT_OutputDevice)   free(gsVT_OutputDevice);
+                               gsVT_OutputDevice = malloc(strlen(args[1])+1);
+                               strcpy(gsVT_OutputDevice, args[1]);
+                               args ++;
+                               break;
+                       
+                       // Set input device
+                       case 'i':
+                               if(args[1] == NULL)     break;
+                               if(gsVT_InputDevice)    free(gsVT_InputDevice);
+                               gsVT_InputDevice = malloc(strlen(args[1])+1);
+                               strcpy(gsVT_InputDevice, args[1]);
+                               args ++;
+                               break;
+                       
+                       }
+               }
+       }
+       
+       // Apply Defaults
+       if(!gsVT_OutputDevice)  gsVT_OutputDevice = DEFAULT_OUTPUT;
+       if(!gsVT_InputDevice)   gsVT_InputDevice = DEFAULT_INPUT;
+       
+       LOG("Using '%s' as output", gsVT_OutputDevice);
+       LOG("Using '%s' as input", gsVT_InputDevice);
+       
+       // Create Nodes
+       for( i = 0; i < NUM_VTS; i++ )
+       {
+               gVT_Terminals[i].Mode = VT_MODE_TEXT;
+               gVT_Terminals[i].Width = DEFAULT_WIDTH;
+               gVT_Terminals[i].Height = DEFAULT_HEIGHT;
+               gVT_Terminals[i].CurColour = DEFAULT_COLOUR;
+               gVT_Terminals[i].WritePos = 0;
+               gVT_Terminals[i].ViewPos = 0;
+               
+               gVT_Terminals[i].Buffer = malloc( DEFAULT_WIDTH*DEFAULT_HEIGHT*sizeof(tVT_Char) );
+               memset( gVT_Terminals[i].Buffer, 0, DEFAULT_WIDTH*DEFAULT_HEIGHT*sizeof(tVT_Char) );
+               
+               gVT_Terminals[i].Name[0] = '0'+i;
+               gVT_Terminals[i].Name[1] = '\0';
+               gVT_Terminals[i].Node.Inode = i;
+               gVT_Terminals[i].Node.NumACLs = 0;      // Only root can open virtual terminals
+               
+               gVT_Terminals[i].Node.Read = VT_Read;
+               gVT_Terminals[i].Node.Write = VT_Write;
+               gVT_Terminals[i].Node.IOCtl = VT_IOCtl;
+       }
+       
+       // Add to DevFS
+       DevFS_AddDevice( &gVT_DrvInfo );
+       
+       return 0;
+}
+
+/**
+ * \fn void VT_InitOutput()
+ * \brief Initialise Video Output
+ */
+void VT_InitOutput()
+{
+       giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
+       LOG("giVT_OutputDevHandle = %x\n", giVT_OutputDevHandle);
+}
+
+/**
+ * \fn void VT_InitInput()
+ * \brief Initialises the input
+ */
+void VT_InitInput()
+{
+       giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
+       LOG("giVT_InputDevHandle = %x\n", giVT_InputDevHandle);
+}
+
+/**
+ * \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 gVT_Terminals[Pos].Name;
+}
+
+/**
+ * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Find an item in the VTerm directory
+ */
+tVFS_Node *VT_FindDir(tVFS_Node *Node, 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 Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a virtual terminal
+ */
+Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       ENTER("pNode XOffset XLength pBuffer",  Node, Offset, Length, Buffer);
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a virtual terminal
+ */
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+       tVTerm  *term = &gVT_Terminals[ Node->Inode ];
+       
+       //ENTER("pNode XOffset XLength pBuffer",  Node, Offset, Length, Buffer);
+       
+       // Write
+       switch( term->Mode )
+       {
+       case VT_MODE_TEXT:
+               VT_int_PutString(term, Buffer, Length);
+               break;
+       }
+       //LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn int VT_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Call an IO Control on a virtual terminal
+ */
+int VT_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+       return 0;
+}
+
+/**
+ * \fn void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count)
+ * \brief Print a string to the Virtual Terminal
+ */
+void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count)
+{
+       Uint32  val;
+        int    i;
+       for( i = 0; i < Count; i++ )
+       {
+               if( Buffer[i] == 0x1B ) // Escape Sequence
+               {
+                       i += VT_int_ParseEscape(Term, (char*)&Buffer[i]);
+                       continue;
+               }
+               
+               if( Buffer[i] < 128 )   // Plain ASCII
+                       VT_int_PutChar(Term, Buffer[i]);
+               else {  // UTF-8
+                       i += ReadUTF8(&Buffer[i], &val);
+                       VT_int_PutChar(Term, val);
+               }
+       }
+}
+
+/**
+ * \fn int VT_int_ParseEscape(tVTerm *Term, char *Buffer)
+ * \brief Parses a VT100 Escape code
+ */
+int VT_int_ParseEscape(tVTerm *Term, char *Buffer)
+{
+       char    c;
+        int    argc = 0, j = 1;
+        int    args[4] = {0,0,0,0};
+       
+       switch(Buffer[0]) {
+       //Large Code
+       case '[':
+               // Get Arguments
+               c = Buffer[1];
+               do {
+                       while('0' <= c && c <= '9') {
+                               args[argc] *= 10;
+                               args[argc] += c-'0';
+                               c = Buffer[++j];
+                       }
+                       argc ++;
+               } while(c == ';');
+               
+               // Get string (what does this do?)
+               if(c == '"') {
+                       c = Buffer[++j];
+                       while(c != '"')
+                               c = Buffer[++j];
+               }
+               
+               // Get Command
+               if(     ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+               {
+                       switch(c) {
+                       //Clear By Line
+                       case 'J':
+                               // Clear Screen
+                               if(args[0] == 2) {
+                                       memset(Term->Text, 0, Term->Width*Term->Height*VT_SCROLLBACK*sizeof(tVT_Char));
+                                       Term->WritePos = 0;
+                                       Term->ViewPos = 0;
+                               }
+                               break;
+                       // Set Font flags
+                       case 'm':
+                               for( ; argc--; )
+                               {
+                                       // 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) {
+                                               Term->CurColour &= 0xF000FFFF;
+                                               Term->CurColour |= (Uint32)caVT100Colours[ args[argc]-30+(Term->CurColour>>28) ] << 16;
+                                       }
+                                       // Background Colour
+                                       else if(40 <= args[argc] && args[argc] <= 47) {
+                                               Term->CurColour &= 0xFFFF8000;
+                                               Term->CurColour |= caVT100Colours[ args[argc]-40+((Term->CurColour>>12)&15) ];
+                                       }
+                               }
+                               break;
+                       }
+               }
+               break;
+               
+       default:
+               break;
+       }
+       
+       return j + 1;
+}
+
+/**
+ * \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;
+       //ENTER("pTerm xCh", Term, Ch);
+       //LOG("Term = {WritePos:%i, ViewPos:%i}\n", Term->WritePos, Term->ViewPos);
+       
+       switch(Ch)
+       {
+       case '\n':
+               Term->WritePos += Term->Width;
+       case '\r':
+               Term->WritePos -= Term->WritePos % Term->Width;
+               break;
+       
+       case '\t':
+               do {
+                       Term->Text[ Term->WritePos ].Ch = '\t';
+                       Term->Text[ Term->WritePos ].Colour = Term->CurColour;
+                       Term->WritePos ++;
+               } while(Term->WritePos & 7);
+               break;
+       
+       case '\b':
+               // Backspace is invalid at Offset 0
+               if(Term->WritePos == 0) break;
+               
+               Term->WritePos --;
+               // Singe Character
+               if(Term->Text[ Term->WritePos ].Ch != '\t') {
+                       Term->Text[ Term->WritePos ].Ch = 0;
+                       Term->Text[ Term->WritePos ].Colour = Term->CurColour;
+                       break;
+               }
+               // Tab
+               i = 7;  // Limit it to 8
+               do {
+                       Term->Text[ Term->WritePos ].Ch = 0;
+                       Term->Text[ Term->WritePos ].Colour = Term->CurColour;
+                       Term->WritePos --;
+               } while(Term->WritePos && i-- && Term->Text[ Term->WritePos ].Ch == '\t');
+               break;
+       
+       default:
+               Term->Text[ Term->WritePos ].Ch = Ch;
+               Term->Text[ Term->WritePos ].Colour = Term->CurColour;
+               Term->WritePos ++;
+               break;
+       }
+       
+       if(Term->WritePos >= Term->Width*Term->Height*VT_SCROLLBACK)
+       {
+                int    base, i;
+               Term->WritePos -= Term->Width;
+               
+               // Update view position
+               base = Term->Width*Term->Height*(VT_SCROLLBACK-1);
+               if(Term->ViewPos < base)        Term->ViewPos += Term->Width;
+               if(Term->ViewPos > base)        Term->ViewPos = base;
+               
+               // Scroll terminal cache
+               base = Term->Width*(Term->Height*VT_SCROLLBACK-1);
+               
+               // Scroll Back
+               memcpy( Term->Text, &Term->Text[Term->Width], base*sizeof(tVT_Char) );
+               
+               // Clear last row
+               for( i = 0; i < Term->Width; i ++ )
+               {
+                       Term->Text[ base + i ].Ch = 0;
+                       Term->Text[ base + i ].Colour = Term->CurColour;
+               }
+               
+               VT_int_UpdateScreen( Term, 1 );
+       }
+       else
+               VT_int_UpdateScreen( Term, 0 );
+       
+       //LEAVE('-');
+}
+
+/**
+ * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+ * \brief Updates the video framebuffer
+ */
+void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+{
+       if(UpdateAll) {
+               VFS_WriteAt(
+                       giVT_OutputDevHandle,
+                       0,
+                       Term->Width*Term->Height*sizeof(tVT_Char),
+                       &Term->Text[Term->ViewPos]
+                       );
+       } else {
+               VFS_WriteAt(
+                       giVT_OutputDevHandle,
+                       Term->ViewPos*sizeof(tVT_Char),
+                       Term->Width*sizeof(tVT_Char),
+                       &Term->Text[Term->ViewPos]
+                       );
+       }
+}
+
+// ---
+// 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
+
+
+int VT_Font_GetWidth(Uint32 Codepoint)
+{
+       return FONT_WIDTH;
+}
+int VT_Font_GetHeight(Uint32 Codepoint)
+{
+       return FONT_HEIGHT;
+}
+
+void VT_Font_Render(Uint32 Codepoint, void *Buffer, Uint32 BGC, Uint32 FGC)
+{
+//     Uint8   *font;
+       
+}
+
+/**
+ * \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];
+}
diff --git a/Kernel/drv/vterm_font_8x16.h b/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/Kernel/drv/vterm_font_8x8.h b/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/Kernel/heap.c b/Kernel/heap.c
new file mode 100644 (file)
index 0000000..fce510c
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * AcessOS Microkernel Version
+ * heap.c
+ */
+#include <common.h>
+#include <mm_virt.h>
+#include <heap.h>
+
+#define WARNINGS       1
+
+// === CONSTANTS ===
+#define HEAP_BASE      0xE0800000
+#define HEAP_MAX       0xF0000000      // 120MiB, Plenty
+#define        HEAP_INIT_SIZE  0x8000  // 32 KiB
+#define        BLOCK_SIZE      (sizeof(void*)) // 8 Machine Words
+#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
+
+// === PROTOTYPES ===
+void   Heap_Install();
+void   *Heap_Extend(int Bytes);
+void   *Heap_Merge(tHeapHead *Head);
+void   *malloc(size_t Bytes);
+void   free(void *Ptr);
+void   Heap_Dump();
+
+// === GLOBALS ===
+ int   giHeapSpinlock;
+void   *gHeapStart;
+void   *gHeapEnd;
+
+// === CODE ===
+void Heap_Install()
+{
+       gHeapStart      = (void*)MM_KHEAP_BASE;
+       gHeapEnd        = (void*)MM_KHEAP_BASE;
+       Heap_Extend(HEAP_INIT_SIZE);
+}
+
+/**
+ * \fn void *Heap_Extend(int Bytes)
+ * \brief Extend the size of the heap
+ */
+void *Heap_Extend(int Bytes)
+{
+       Uint    i;
+       tHeapHead       *head = gHeapEnd;
+       tHeapFoot       *foot;
+       
+       // Bounds Check
+       if( (Uint)gHeapEnd == MM_KHEAP_MAX )
+               return NULL;
+       
+       // Bounds Check
+       if( (Uint)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
+               Bytes = MM_KHEAP_MAX - (Uint)gHeapEnd;
+               return NULL;
+       }
+       
+       // Heap expands in pages
+       for(i=0;i<(Bytes+0xFFF)>>12;i++)
+               MM_Allocate( (Uint)gHeapEnd+(i<<12) );
+       
+       // Increas heap end
+       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;
+       
+       //Log(" Heap_Extend: head = %p", head);
+       return Heap_Merge(head);        // Merge with previous block
+}
+
+/**
+ * \fn void *Heap_Merge(tHeapHead *Head)
+ * \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 > HEAP_BASE)
+       && 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;
+}
+
+/**
+ * \fn void *malloc(size_t Bytes)
+ * \brief Allocate memory from the heap
+ */
+void *malloc(size_t Bytes)
+{
+       tHeapHead       *head, *newhead;
+       tHeapFoot       *foot, *newfoot;
+       tHeapHead       *best = NULL;
+       Uint    bestSize = 0;   // Speed hack
+       
+       // Get required size
+       Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1);
+       
+       // Lock Heap
+       LOCK(&giHeapSpinlock);
+       
+       // Traverse Heap
+       for( head = gHeapStart;
+               (Uint)head < (Uint)gHeapEnd;
+               head = (void*)((Uint)head + head->Size)
+               )
+       {
+               // Alignment Check
+               if( head->Size & (BLOCK_SIZE-1) ) {
+                       #if WARNINGS
+                       Warning("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)   {
+                       #if WARNINGS
+                       Warning("Magic of heap address %p is invalid (0x%x)", head, head->Magic);
+                       Heap_Dump();
+                       #endif
+                       RELEASE(&giHeapSpinlock);       // Release spinlock
+                       return NULL;
+               }
+               
+               // Size check
+               if(head->Size < Bytes)  continue;
+               
+               // Perfect fit
+               if(head->Size == Bytes) {
+                       head->Magic = MAGIC_USED;
+                       RELEASE(&giHeapSpinlock);       // Release spinlock
+                       return best->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) {
+                       RELEASE(&giHeapSpinlock);       // Release spinlock
+                       return NULL;
+               }
+               // Check size
+               if(best->Size == Bytes) {
+                       RELEASE(&giHeapSpinlock);       // Release spinlock
+                       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->Magic = MAGIC_USED;       // Mark block as used
+       
+       RELEASE(&giHeapSpinlock);       // Release spinlock
+       return best->Data;
+}
+
+/**
+ * \fn void free(void *Ptr)
+ * \brief Free an allocated memory block
+ */
+void free(void *Ptr)
+{
+       tHeapHead       *head;
+       tHeapFoot       *foot;
+       
+       // Alignment Check
+       if( (Uint)Ptr & (sizeof(Uint)-1) ) {
+               Warning("free - Passed a non-aligned address (%p)\n", Ptr);
+               return;
+       }
+       
+       // Sanity check
+       if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
+       {
+               Warning("free - Passed a non-heap address (%p)\n", Ptr);
+               return;
+       }
+       
+       // Check memory block - Header
+       head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
+       if(head->Magic == MAGIC_FREE) {
+               Warning("free - Passed a freed block (%p)\n", head);
+               return;
+       }
+       if(head->Magic != MAGIC_USED) {
+               Warning("free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
+               return;
+       }
+       
+       // Check memory block - Footer
+       foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
+       if(foot->Head != head) {
+               Warning("free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
+               return;
+       }
+       if(foot->Magic != MAGIC_FOOT) {
+               Warning("free - Footer magic is invalid (%p, 0x%x)\n", head, foot->Magic);
+               return;
+       }
+       
+       // Lock
+       LOCK( &giHeapSpinlock );
+       
+       // Mark as free
+       head->Magic = MAGIC_FREE;
+       // Merge blocks
+       Heap_Merge( head );
+       
+       // Release
+       RELEASE( &giHeapSpinlock );
+}
+
+/**
+ */
+void *realloc(void *__ptr, size_t __size)
+{
+       tHeapHead       *head = (void*)( (Uint)__ptr-8 );
+       tHeapHead       *nextHead;
+       tHeapFoot       *foot;
+       Uint    newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1);
+       
+       // Check for reallocating NULL
+       if(__ptr == NULL)       return malloc(__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;
+                       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
+               // 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;
+               // Exact fit
+               if(size == newSize)
+               {
+                       Uint    oldDataSize;
+                       // Set 1st (new/lower) header
+                       nextHead->Magic = MAGIC_USED;
+                       nextHead->Size = newSize;
+                       // 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;
+                       memcpy(nextHead->Data, __ptr, oldDataSize);
+               }
+       }
+       
+       return NULL;
+}
+
+#if WARNINGS
+void Heap_Dump()
+{
+       tHeapHead       *head;
+       tHeapFoot       *foot;
+       
+       head = gHeapStart;
+       while( (Uint)head < (Uint)gHeapEnd )
+       {               
+               foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
+               Log("%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
+               Log("%p 0x%lx", foot->Head, foot->Magic);
+               Log("");
+               
+               // Sanity Check Header
+               if(head->Size == 0) {
+                       Log("HALTED - Size is zero");
+                       break;
+               }
+               if(head->Size & (BLOCK_SIZE-1)) {
+                       Log("HALTED - Size is malaligned");
+                       break;
+               }
+               if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
+                       Log("HALTED - Head Magic is Bad");
+                       break;
+               }
+               
+               // Check footer
+               if(foot->Magic != MAGIC_FOOT) {
+                       Log("HALTED - Foot Magic is Bad");
+                       break;
+               }
+               if(head != foot->Head) {
+                       Log("HALTED - Footer backlink is invalid");
+                       break;
+               }
+               
+               // All OK? Go to next
+               head = foot->NextHead;
+       }
+}
+#endif
diff --git a/Kernel/include/binary.h b/Kernel/include/binary.h
new file mode 100644 (file)
index 0000000..e02fc2d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ */
+#ifndef _BINARY_H
+#define _BINARY_H
+
+// === TYPES ===
+/**
+ * \struct sBinary
+ * \brief Defines a binary file
+ */
+typedef struct sBinary {
+       struct sBinary  *Next;
+       char    *TruePath;
+       char    *Interpreter;
+       Uint    Entry;
+       Uint    Base;
+        int    NumPages;
+        int    ReferenceCount;
+       struct {
+               Uint    Physical;
+               Uint    Virtual;
+               Uint16  Size, Flags;
+       }       Pages[];
+} tBinary;
+
+/**
+ * \struct sBinaryType
+ */
+typedef struct sBinaryType {
+       struct sBinaryType      *Next;
+       Uint32  Ident;
+       Uint32  Mask;
+       char    *Name;
+       tBinary *(*Load)(int FD);
+        int    (*Relocate)(void *Base);
+        int    (*GetSymbol)(void *Base, char *Name, Uint *Dest);
+} tBinaryType;
+
+extern char    *Binary_RegInterp(char *Path);
+
+#endif
diff --git a/Kernel/include/binary_ext.h b/Kernel/include/binary_ext.h
new file mode 100644 (file)
index 0000000..8b8a6df
--- /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(char *Path);
+extern void    *Binary_LoadKernel(char *Path);
+extern Uint    Binary_Relocate(void *Mem);
+extern void    Binary_Unload(void *Base);
+extern int     Binary_GetSymbol(char *Name, Uint *Dest);
+extern Uint    Binary_FindSymbol(void *Base, char *Name, Uint *Dest);
+
+#endif
diff --git a/Kernel/include/common.h b/Kernel/include/common.h
new file mode 100644 (file)
index 0000000..f199ef5
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * AcessOS Microkernel Version
+ * common.h
+ */
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#define NULL   ((void*)0)
+
+#include <arch.h>
+#include <stdarg.h>
+
+enum eConfigs {
+       CFG_VFS_CWD,
+       CFG_VFS_MAXFILES,
+       NUM_CFG_ENTRIES
+};
+#define CFGINT(_idx)   (*(Uint*)(MM_PPD_CFG+(_idx)*sizeof(void*)))
+#define CFGPTR(_idx)   (*(void**)(MM_PPD_CFG+(_idx)*sizeof(void*)))
+
+// === CONSTANTS ===
+// --- Memory Flags --
+#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)
+
+// === Kernel Export Macros ===
+typedef struct sKernelSymbol {
+       char    *Name;
+       unsigned int    Value;
+} tKernelSymbol;
+#define        EXPORT(_name)   tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (Uint)_name}
+#define        EXPORTAS(_sym,_name)    tKernelSymbol _kexp_##_name __attribute__((section ("KEXPORT"),unused))={#_name, (Uint)_sym}
+
+// === FUNCTIONS ===
+// --- Core ---
+extern void    System_Init(char *ArgString);
+extern int     IRQ_AddHandler(int Num, void (*Callback)(void));
+// --- Debug ---
+extern void    Panic(char *Msg, ...);
+extern void    Warning(char *Msg, ...);
+extern void    Log(char *Fmt, ...);
+extern void    LogV(char *Fmt, va_list Args);
+extern void    Debug_Enter(char *FuncName, char *ArgTypes, ...);
+extern void    Debug_Log(char *FuncName, char *Fmt, ...);
+extern void    Debug_Leave(char *FuncName, char RetType, ...);
+extern void    Debug_HexDump(char *Header, void *Data, Uint Length);
+#define ENTER(_types...)       Debug_Enter((char*)__func__, _types)
+#define LOG(_fmt...)   Debug_Log((char*)__func__, _fmt)
+#define LEAVE(_t...)   Debug_Leave((char*)__func__, _t)
+// --- IO ---
+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);
+// --- Memory ---
+extern tPAddr  MM_Allocate(Uint VAddr);
+extern void    MM_Deallocate(Uint VAddr);
+extern int     MM_Map(Uint VAddr, tPAddr PAddr);
+extern tPAddr  MM_GetPhysAddr(Uint VAddr);
+extern void    MM_SetFlags(Uint VAddr, Uint Flags, Uint Mask);
+extern Uint    MM_MapTemp(tPAddr PAddr);
+extern void    MM_FreeTemp(Uint PAddr);
+extern Uint    MM_MapHWPage(tPAddr PAddr, Uint Number);
+extern void    MM_UnmapHWPage(Uint VAddr, Uint Number);
+extern tPAddr  MM_AllocPhys();
+extern void    MM_RefPhys(tPAddr Addr);
+extern void    MM_DerefPhys(tPAddr Addr);
+extern void *memcpy(void *dest, void *src, Uint count);
+extern void *memcpyd(void *dest, void *src, Uint count);
+extern void *memset(void *dest, int val, Uint count);
+extern void *memsetd(void *dest, Uint val, Uint count);
+// --- Strings ---
+extern Uint    strlen(char *Str);
+extern char    *strcpy(char *__dest, char *__src);
+extern int     strcmp(char *__dest, char *__src);
+extern int     strncmp(char *Str1, char *Str2, size_t num);
+extern int     strucmp(char *Str1, char *Str2);
+extern int     strpos(char *Str, char Ch);
+extern int     strpos8(char *str, Uint32 search);
+extern void    itoa(char *buf, Uint num, int base, int minLength, char pad);
+extern int     ReadUTF8(Uint8 *str, Uint32 *Val);
+// --- Heap ---
+extern void *malloc(size_t size);
+extern void    *realloc(void *ptr, size_t size);
+extern void free(void *Ptr);
+// --- Modules ---
+extern int     Module_LoadMem(void *Buffer, Uint Length, char *ArgStr);
+extern int     Module_LoadFile(char *Path, char *ArgStr);
+// --- Timing ---
+extern Sint64  timestamp(int sec, int mins, int hrs, int day, int month, int year);
+extern Sint64  now();
+// --- Threads ---
+extern  int    Proc_Spawn(char *Path);
+extern void    Proc_Exit();
+extern void    Proc_Yield();
+extern int     Proc_GetCfg(int Index);
+extern int     Proc_GetUID();
+extern int     Proc_GetGID();
+extern int     SpawnTask(tThreadFunction Function, void *Arg);
+
+#include <binary_ext.h>
+#include <vfs_ext.h>
+
+#endif
diff --git a/Kernel/include/drv_pci.h b/Kernel/include/drv_pci.h
new file mode 100644 (file)
index 0000000..b6a1b07
--- /dev/null
@@ -0,0 +1,41 @@
+/*\r
+ * Acess 2\r
+ * PCI Bus Driver\r
+ * drv_pci.h\r
+ */\r
+#ifndef _DRV_PCI_H\r
+#define _DRV_PCI_H\r
+\r
+enum e_PciClasses {\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
+enum e_PciOverClasses {\r
+       PCI_OC_PCIBRIDGE = 0x0604,\r
+       PCI_OC_SCSI = 0x0100\r
+};\r
+\r
+\r
+extern int     PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);\r
+extern int     PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);\r
+extern int     PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);\r
+extern Uint8   PCI_GetIRQ(int id);\r
+extern Uint32  PCI_GetBAR0(int id);\r
+extern Uint32  PCI_GetBAR1(int id);\r
+extern Uint32  PCI_GetBAR3(int id);\r
+extern Uint32  PCI_GetBAR4(int id);\r
+extern Uint32  PCI_GetBAR5(int id);\r
+\r
+#endif\r
diff --git a/Kernel/include/errno.h b/Kernel/include/errno.h
new file mode 100644 (file)
index 0000000..8bf83d8
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * AcessOS Microkernel Version
+ * errno.h
+ */
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+enum eErrorNums {
+       EOK,
+       ENOSYS,
+       EINVAL,
+       ENOMEM,
+       EACCES
+};
+
+#endif
diff --git a/Kernel/include/fs_devfs.h b/Kernel/include/fs_devfs.h
new file mode 100644 (file)
index 0000000..4b29cf1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Acess 2
+ * Device Filesystem (DevFS)
+ * - vfs/fs/devfs.c
+ */
+#ifndef _FS_DEVFS_H
+#define _FS_DEVFS_H
+#include <vfs.h>
+
+// === TYPES ===
+typedef struct sDevFS_Driver {
+       struct sDevFS_Driver    *Next;
+       char    *Name;
+       tVFS_Node       RootNode;
+} tDevFS_Driver;
+
+// === FUNCTIONS ===
+extern int     DevFS_AddDevice(tDevFS_Driver *Dev);
+
+#endif
diff --git a/Kernel/include/heap.h b/Kernel/include/heap.h
new file mode 100644 (file)
index 0000000..c793c87
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * AcessOS Microkernel Version
+ * heap.h
+ */
+#ifndef _HEAP_H
+#define _HEAP_H
+
+typedef struct {
+       Uint    Size;
+       Uint    Magic;
+       char    Data[];
+} tHeapHead;
+
+typedef struct {
+       Uint    Magic;
+       tHeapHead       *Head;
+       tHeapHead       NextHead[];     // Array to make it act like a pointer, but have no size
+} tHeapFoot;
+
+#endif
diff --git a/Kernel/include/init.h b/Kernel/include/init.h
new file mode 100644 (file)
index 0000000..a16acfd
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * AcessOS Microkernel Version
+ * init.h
+ */
+#ifndef _INIT_H
+#define _INIT_H
+
+#define INIT_SRV_MAGIC (0xE6|('S'<<8)|('R'<<16)|('V'<<24))
+
+typedef struct sInitServ {
+       Uint32  Magic;
+       Uint32  LoadBase;
+       Uint32  MemSize;
+        int    (*Entrypoint)(char **Args);
+} tInitServ;
+
+#endif
diff --git a/Kernel/include/mboot.h b/Kernel/include/mboot.h
new file mode 100644 (file)
index 0000000..764120f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * AcessOS Microkernel Version
+ * mboot.h
+ */
+#ifndef _MBOOT_H
+#define _MBOOT_H
+
+// === TYPES ===
+typedef struct {
+       Uint32  Flags;
+       Uint32  LowMem;
+       Uint32  HighMem;
+       Uint32  BootDevice;
+       Uint32  CommandLine;
+       Uint32  ModuleCount;
+       Uint32  Modules;
+} tMBoot_Info;
+
+typedef struct {
+       Uint32  Start;
+       Uint32  End;
+       char    *String;
+       Uint32  Resvd;
+} tMBoot_Module;
+
+#endif
diff --git a/Kernel/include/modules.h b/Kernel/include/modules.h
new file mode 100644 (file)
index 0000000..dcf3465
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * AcessOS 2
+ * - Module Loader
+ */
+#ifndef _MODULE_H
+#define _MODULE_H
+
+#define MODULE_MAGIC   ('A'|('M'<<8)|('D'<<16)|('\2'<<24))
+
+// IA32 - Architecture 1
+#if ARCH == i386 || ARCH == i586
+# define MODULE_ARCH_ID        1
+// IA64 - Architecture 2
+#elif ARCH == x64 || ARCH == x86_64
+# define MODULE_ARCH_ID        2
+#else
+# error "Unknown architecture when determining MODULE_ARCH_ID ('" #ARCH "')"
+#endif
+
+#if BUILD_MODULE
+# define MODULE_DEFINE(_flags,_ver,_ident,_entry,_deps...)     char *_DriverDeps[]={_deps};\
+       tModule DriverInfo=\
+       {MODULE_MAGIC,MODULE_ARCH_ID,_flags,_ver,NULL,#_ident,_entry,_DriverDeps}
+#else
+# define MODULE_DEFINE(_flags,_ver,_ident,_entry,_deps...)     char *_DriverDeps_##_ident[]={_deps};\
+       tModule __attribute__ ((section ("KMODULES"),unused)) _DriverInfo_##_ident=\
+       {MODULE_MAGIC,MODULE_ARCH_ID,_flags,_ver,NULL,#_ident,_entry,_DriverDeps_##_ident}
+#endif
+
+typedef struct sModule {
+       Uint32  Magic;
+       Uint8   Arch;
+       Uint8   Flags;
+       Uint16  Version;
+       struct sModule  *Next;
+       char    *Name;
+        int    (*Init)(char **Arguments);
+       char    **Dependencies; // NULL Terminated List
+} __attribute__((packed)) tModule;
+
+#endif
diff --git a/Kernel/include/syscalls.h b/Kernel/include/syscalls.h
new file mode 100644 (file)
index 0000000..b2c13cf
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * AcessOS Microkernel Version
+ * syscalls.h
+ */
+#ifndef _SYSCALLS_H
+#define _SYSCALLS_H
+
+enum eSyscalls {
+       SYS_EXIT,       // 0 - Kill this thread
+       SYS_CLONE,      // 1 - Create a new thread
+       SYS_KILL,       // 2 - Send a signal
+       SYS_SIGNAL,     // 3 - Set signal Handler
+       SYS_YIELD,      // 4 - Yield remainder of timestamp
+       SYS_SLEEP,      // 5 - Sleep until messaged or signaled
+       SYS_WAIT,       // 6 - Wait for a time or a message
+       SYS_WAITTID,    // 7 - Wait for a thread to do something
+       SYS_SETNAME,    // 8 - Set's the name of the current thread
+       SYS_GETNAME,    // 9 - Get's the name of a thread
+       SYS_GETTID,     // 10 - Get current thread ID
+       SYS_GETPID,     // 11 - Get current thread group ID
+       SYS_SETPRI,     // 12 - Set process priority
+       SYS_SENDMSG,    // 13 - Send an IPC message
+       SYS_GETMSG,     // 14 - Recieve an IPC message
+       SYS_GETTIME,    // 15 - Get the current timestamp
+       SYS_SPAWN,      // 16 - Spawn a new process
+       SYS_EXECVE,     // 17 - Replace the current process
+       SYS_LOADBIN,    // 18 - Load a binary into the current address space
+       SYS_UNLOADBIN,  // 19 - Unload a loaded binary
+
+       SYS_GETPHYS = 32,       // 32 - Get the physical address of a page
+       SYS_MAP,        // 33 -         Map a physical address
+       SYS_ALLOCATE,   // 34 - Allocate a page
+       SYS_UNMAP,      // 35 - Unmap a page
+       SYS_PREALLOC,   // 36 - Preallocate a page
+       SYS_SETFLAGS,   // 37 - Set a page's flags
+       SYS_SHAREWITH,  // 38 - Share a page with another thread
+       SYS_GETUID,     // 39 - Get current User ID
+       SYS_GETGID,     // 40 - Get current Group ID
+       SYS_SETUID,     // 41 - Set current user ID
+       SYS_SETGID,     // 42 - Set current Group ID
+
+       SYS_OPEN = 64,  // 64 - Open a file
+       SYS_REOPEN,     // 65 - Close a file and reuse its handle
+       SYS_CLOSE,      // 66 - Close a file
+       SYS_READ,       // 67 - Read from an open file
+       SYS_WRITE,      // 68 - Write to an open file
+       SYS_IOCTL,      // 69 - Perform an IOCtl Call
+       SYS_READDIR,    // 70 - Read from an open directory
+       SYS_MKDIR,      // 71 - Create a new directory
+       SYS_SYMLINK,    // 72 - Create a symbolic link
+       SYS_GETACL,     // 73 - Get an ACL Value
+       SYS_SETACL,     // 74 - Set an ACL Value
+       SYS_FINFO,      // 75 - Get file information
+       SYS_SEEK,       // 76 - Seek to a new position in the file
+       SYS_TELL,       // 77 - Return the current file position
+       NUM_SYSCALLS,
+       SYS_DEBUG = 0x100       // 0x100 - Print a debug string
+};
+
+static const char *cSYSCALL_NAMES[] = {
+       "SYS_EXIT","SYS_CLONE","SYS_KILL","SYS_SIGNAL","SYS_YIELD","SYS_SLEEP",
+       "SYS_WAIT","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_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_READDIR","SYS_MKDIR",
+       "SYS_SYMLINK","SYS_GETACL","SYS_SETACL","SYS_FINFO","SYS_SEEK","SYS_TELL",
+       ""
+};
+#endif
diff --git a/Kernel/include/syscalls.inc.asm b/Kernel/include/syscalls.inc.asm
new file mode 100644 (file)
index 0000000..39b8193
--- /dev/null
@@ -0,0 +1,51 @@
+; 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_SIGNAL     3       ; Set signal Handler
+%define SYS_YIELD      4       ; Yield remainder of timestamp
+%define SYS_SLEEP      5       ; Sleep until messaged or signaled
+%define SYS_WAIT       6       ; Wait for a time or a message
+%define SYS_WAITTID    7       ; Wait for a thread to do something
+%define SYS_SETNAME    8       ; Set's the name of the current thread
+%define SYS_GETNAME    9       ; Get's 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_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_READDIR    70      ; Read from an open directory
+%define SYS_MKDIR      71      ; Create a new directory
+%define SYS_SYMLINK    72      ; Create a symbolic link
+%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_SEEK       76      ; Seek to a new position in the file
+%define SYS_TELL       77      ; Return the current file position
diff --git a/Kernel/include/syscalls_old.h b/Kernel/include/syscalls_old.h
new file mode 100644 (file)
index 0000000..6a9d038
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * AcessOS Microkernel Version
+ * syscalls.h
+ */
+#ifndef _SYSCALLS_H
+#define _SYSCALLS_H
+
+enum eSyscalls {
+       SYS_EXIT,       // 0 - Kill Current Thread
+       SYS_CLONE,      // 1 - Create a new thread
+       SYS_KILL,       // 2 - Send a signal
+       SYS_SIGNAL,     // 3 - Set a signal handler
+       SYS_YIELD,      // 4 - Yield remainder of timestamp
+       SYS_SLEEP,      // 5 - Sleep until messaged or signaled
+       SYS_WAIT,       // 6 - Wait for a time or a message
+       SYS_WAITTID,    // 7 - Wait for a thread to terminate
+       
+       SYS_SETNAME,    // 8 - Set thread's name
+       SYS_GETNAME,    // 9 - Get a thread's name
+       SYS_GETTID,     // 10 - Get current thread ID
+       SYS_GETPID,     // 11 - Get current thread group ID
+       
+       SYS_SETPRI,             // 12 - Set Priority
+       
+       SYS_SENDMSG,    // 13 - Send an IPC message
+       SYS_GETMSG,             // 14 - Recieve an IPC message
+       
+       SYS_GETTIME,    // 15 - Get the current timestamp
+
+       SYS_SPAWN,              // 16 - Fork and Execve
+       SYS_EXECVE,             // 17 - Replace the current process image with another
+       SYS_LOADBIN,    // 18 - Load a binary image into memory
+       SYS_UNLOADBIN,  // 19 - Unload a loaded binary image
+       
+       // Address Space & Permissions (001x xxxx)
+       SYS_GETPHYS=32, // 32 - Gets the physical address of a page
+       SYS_MAP,                // 33 - Map a physical page
+       SYS_ALLOCATE,   // 34 - Allocate a page
+       SYS_UNMAP,              // 35 - Unmap a page
+       SYS_PREALLOC,   // 36 - Preallocates a page
+       SYS_SETFLAGS,   // 37 - Sets a page's flags
+       SYS_SHAREWITH,  // 38 - Share a page with another thread
+       // Permissions
+       SYS_GETUID,     // 39 - Get current User ID
+       SYS_GETGID,     // 40 - Get current Group ID
+       SYS_SETUID,     // 41 - Set the current User ID
+       SYS_SETGID,     // 42 - Set the current Group ID
+       
+       // VFS (010x xxxx)
+       SYS_OPEN = 64,  // 64 - Open a file
+       SYS_REOPEN,             // 65 - Close a file and reuse its handle
+       SYS_CLOSE,              // 66 - Close and open file
+       SYS_READ,               // 67 - Read from a file
+       SYS_WRITE,              // 68 - Write to a file
+       SYS_IOCTL,              // 69 - Call a file's IOCtl method
+       SYS_READDIR,    // 70 - Read from a directory
+       SYS_MKDIR,              // 71 - Make new directory
+       SYS_SYMLINK,    // 72 - Create a symbolic link
+       SYS_GETACL,             // 73 - Get an ACL
+       SYS_SETACL,             // 74 - Set an ACL
+       SYS_FINFO,              // 75 - Get a file's information
+       
+       NUM_SYSCALLS,
+       
+       SYS_DEBUG = 0x100               // Print a debug string
+};
+
+static const char *cSYSCALL_NAMES[] = {
+       "SYS_EXIT", "SYS_CLONE", "SYS_KILL", "SYS_SIGNAL", "SYS_YIELD", "SYS_SLEEP", "SYS_WAIT",
+       "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_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_READDIR", "SYS_MKDIR", "SYS_SYMLINK",
+       "SYS_GETACL", "SYS_SETACL", "SYS_FINFO"
+       };
+
+#endif
diff --git a/Kernel/include/tpl_drv_common.h b/Kernel/include/tpl_drv_common.h
new file mode 100644 (file)
index 0000000..31ad97a
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ AcessOS Version 1
+ \file tpl_drv_common.h
+ \brief Common Driver Interface Definitions
+*/
+#ifndef _TPL_COMMON_H
+#define _TPL_COMMON_H
+
+/**
+ * \enum eTplDrv_IOCtl
+ * \brief Common IOCtl Calls
+ */
+enum eTplDrv_IOCtl {
+       /// \brief Driver Type - Return an ::eTplDrv_Type value
+       DRV_IOCTL_TYPE,
+       /// \brief Get driver identifier - (char *dest[4])
+       DRV_IOCTL_IDENT,
+       /// \brief Get driver version - (int *ver)
+       DRV_IOCTL_VERSION,
+       /// \brief Get a IOCtl from a symbolic name
+       DRV_IOCTL_LOOKUP,
+};
+
+/**
+ * \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
+       DRV_TYPE_VIDEO,         //!< Video - LFB
+       DRV_TYPE_SOUND,         //!< Audio
+       DRV_TYPE_DISK,          //!< Disk
+       DRV_TYPE_KEYBOARD,      //!< Keyboard
+       DRV_TYPE_MOUSE,         //!< Mouse
+       DRV_TYPE_JOYSTICK,      //!< Joystick / Gamepad
+       DRV_TYPE_NETWORK        //!< Network Device
+};
+
+// === FUNCTIONS ===
+extern int     GetIOCtlId(int Class, char *Name);
+
+#endif
diff --git a/Kernel/include/tpl_drv_keyboard.h b/Kernel/include/tpl_drv_keyboard.h
new file mode 100644 (file)
index 0000000..9d3e5dc
--- /dev/null
@@ -0,0 +1,50 @@
+/**\r
+ * \file tpl_drv_keyboard.h\r
+ * \brief Keyboard Driver Interface Definitions\r
+*/\r
+#ifndef _TPL_KEYBOARD_H\r
+#define _TPL_KEYBOARD_H\r
+\r
+#include <tpl_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
+       //! \brief Get/Set Repeat Rate - (int Rate)\r
+       KB_IOCTL_REPEATRATE = 4,\r
+       //! \brief Get/Set Repeat Delay - (int Delay)\r
+       KB_IOCTL_REPEATDELAY,\r
+       //! \brief Sets the callback\r
+       KB_IOCTL_SETCALLBACK\r
+};\r
+\r
+typedef void (*tKeybardCallback)(Uint32);\r
+\r
+enum {\r
+       KEY_ESC = 0x1B,\r
+       \r
+       KEY_NP_MASK = 0x80,     //End of ASCII Range\r
+       KEY_LCTRL, KEY_RCTRL,\r
+       KEY_LALT, KEY_RALT,\r
+       KEY_LSHIFT, KEY_RSHIFT,\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_WIN, KEY_MENU,\r
+       \r
+       KEY_KEYUP = 0xFF\r
+};\r
+\r
+\r
+#endif\r
diff --git a/Kernel/include/tpl_drv_video.h b/Kernel/include/tpl_drv_video.h
new file mode 100644 (file)
index 0000000..23d3907
--- /dev/null
@@ -0,0 +1,77 @@
+/**\r
+ * \file tpl_drv_video.h\r
+ * \brief Video Driver Interface Definitions\r
+ * \note For AcessOS Version 1\r
+ * \r
+ * Video drivers extend the common driver interface tpl_drv_common.h\r
+ * and must support _at least_ the IOCtl numbers defined in this file\r
+ * to be compatable with Acess.\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
+ * Reads and 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
+ * In pallete colour modes the LFB is preceded by a 1024 byte pallete (allowing\r
+ * room for 256 entries of 32-bits each)\r
+*/\r
+#ifndef _TPL_VIDEO_H\r
+#define _TPL_VIDEO_H\r
+\r
+#include <tpl_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
+       //! \brief Set Mode - (int mode)\r
+       VIDEO_IOCTL_SETMODE = 4,\r
+       //! \brief Get Mode - (int *mode)\r
+       VIDEO_IOCTL_GETMODE,\r
+       //! \brief Find a matching mode - (tVideo_IOCtl_Mode *info)\r
+       VIDEO_IOCTL_FINDMODE,\r
+       //! \brief Get mode info - (tVideo_IOCtl_Mode *info)\r
+       VIDEO_IOCTL_MODEINFO,\r
+       //! \brief Request access to Framebuffer - (void *dest), Return Boolean Success\r
+       VIDEO_IOCTL_REQLFB\r
+};\r
+\r
+/**\r
+ \struct sVideo_IOCtl_Mode\r
+ \brief Mode Structure used in IOCtl Calls\r
+*/\r
+struct sVideo_IOCtl_Mode {\r
+       short   id;             //!< Mide ID\r
+       Uint16  width;  //!< Width\r
+       Uint16  height; //!< Height\r
+       Uint16  bpp;    //!< Bits per Pixel\r
+};\r
+typedef struct sVideo_IOCtl_Mode       tVideo_IOCtl_Mode;      //!< Mode Type\r
+\r
+/**\r
+ * \struct sVT_Char\r
+ * \brief Virtual Terminal Representation of a character\r
+ */\r
+struct sVT_Char {\r
+       Uint32  Ch;\r
+       union {\r
+               struct {\r
+                       Uint16  BGCol;\r
+                       Uint16  FGCol;\r
+               };\r
+               Uint32  Colour;\r
+       };\r
+};\r
+typedef struct sVT_Char        tVT_Char;\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
+#endif\r
diff --git a/Kernel/include/vfs.h b/Kernel/include/vfs.h
new file mode 100644 (file)
index 0000000..12cc8a4
--- /dev/null
@@ -0,0 +1,106 @@
+/* 
+ * Acess Micro - VFS Server Ver 1
+ */
+#ifndef _VFS_H
+#define _VFS_H
+
+#include <common.h>
+
+#define VFS_PERM_READ  0x00000001
+#define VFS_PERM_WRITE 0x00000002
+#define VFS_PERM_APPEND        0x00000004
+#define VFS_PERM_EXECUTE       0x00000008
+#define VFS_PERM_ALL   0x7FFFFFFF      // Mask for permissions
+#define VFS_PERM_DENY  0x80000000      // Inverts permissions
+
+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;
+
+#define VFS_FFLAG_READONLY     0x01
+#define VFS_FFLAG_DIRECTORY    0x02
+#define VFS_FFLAG_SYMLINK      0x04
+
+typedef struct sVFS_Node {
+       //char  *Name;  //!< Node's Name (UTF-8)
+       
+       Uint64  Inode;  //!< Inode ID
+       Uint    ImplInt;        //!< Implementation Usable Integer
+       void    *ImplPtr;       //!< Implementation Usable Pointer
+       
+        int    ReferenceCount; //!< Number of times the node is used
+       
+       Uint64  Size;   //!< File Size
+       
+       Uint32  Flags;  //!< File Flags
+       
+       Sint64  ATime;  //!< Last Accessed Time
+       Sint64  MTime;  //!< Last Modified Time
+       Sint64  CTime;  //!< Creation Time
+       
+       Uint    UID;    //!< Owning User
+       Uint    GID;    //!< Owning Group
+       
+        int    NumACLs;        //!< Number of ACL entries
+       tVFS_ACL        *ACLs;  //!< ACL Entries
+       
+       //! Reference the node
+       void    (*Reference)(struct sVFS_Node *Node);
+       //! Close (dereference) the node
+       void    (*Close)(struct sVFS_Node *Node);
+       //! Send an IO Control
+        int    (*IOCtl)(struct sVFS_Node *Node, int Id, void *Data);
+       
+       Uint64  (*Read)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+       Uint64  (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+       
+       //! Find an directory entry by name
+       struct sVFS_Node        *(*FindDir)(struct sVFS_Node *Node, char *Name);
+       //! Read from a directory
+       char    *(*ReadDir)(struct sVFS_Node *Node, int Pos);
+       //! Create a node in a directory
+        int    (*MkNod)(struct sVFS_Node *Node, char *Name, Uint Flags);
+       //! Relink (Rename/Remove) a file/directory
+        int    (*Relink)(struct sVFS_Node *Node, char *OldName, char *NewName);
+       
+       //!< \todo Complete
+} tVFS_Node;
+
+/**
+ * \brief VFS Driver (Filesystem) Definition
+ */
+typedef struct sVFS_Driver {
+       char    *Name;
+       Uint    Flags;
+       tVFS_Node       *(*InitDevice)(char *Device, char *Options);
+       struct sVFS_Driver      *Next;
+} tVFS_Driver;
+
+// === GLOBALS ===
+#define        VFS_SKIP        ((void*)1)
+#define        VFS_SKIPN(n)    ((void*)(n))
+extern tVFS_Node       NULLNode;
+extern tVFS_ACL        gVFS_ACL_EveryoneRWX;
+extern tVFS_ACL        gVFS_ACL_EveryoneRW;
+extern tVFS_ACL        gVFS_ACL_EveryoneRX;
+extern tVFS_ACL        gVFS_ACL_EveryoneRO;
+
+// === FUNCTIONS ===
+extern int     VFS_AddDriver(tVFS_Driver *Info);
+extern tVFS_Driver     *VFS_GetFSByName(char *Name);
+
+// --- Node Cache --
+extern int     Inode_GetHandle();
+extern tVFS_Node       *Inode_GetCache(int Handle, Uint64 Inode);
+extern tVFS_Node       *Inode_CacheNode(int Handle, tVFS_Node *Node);
+extern void    Inode_UncacheNode(int Handle, Uint64 Inode);
+extern void    Inode_ClearCache(int Handle);
+
+#endif
diff --git a/Kernel/include/vfs_ext.h b/Kernel/include/vfs_ext.h
new file mode 100644 (file)
index 0000000..6390f84
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Acess 2
+ * vfs_ext.h
+ * - Exported Symbols from the VFS
+ */
+#ifndef _VFS_EXT_H
+#define _VFS_EXT_H
+
+// === CONSTANTS ===
+#define        VFS_MEMPATH_SIZE        (3 + (BITS/8)*2)
+#define VFS_OPENFLAG_EXEC      0x01
+#define VFS_OPENFLAG_READ      0x02
+#define VFS_OPENFLAG_WRITE     0x04
+#define        VFS_OPENFLAG_NOLINK     0x40
+#define        VFS_OPENFLAG_USER       0x80
+#define VFS_KERNEL_FLAG        0x40000000
+
+#define SEEK_SET       1
+#define SEEK_CUR       0
+#define SEEK_END       -1
+
+// === FUNCTIONS ===
+extern int     VFS_Init();
+
+extern int     VFS_Open(char *Path, Uint Flags);
+extern void    VFS_Close(int FD);
+
+extern int     VFS_Seek(int FD, Sint64 Offset, int Direction);
+extern Uint64  VFS_Tell(int FD);
+
+extern Uint64  VFS_Read(int FD, Uint64 Length, void *Buffer);
+extern Uint64  VFS_Write(int FD, Uint64 Length, void *Buffer);
+
+extern Uint64  VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
+extern Uint64  VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
+
+extern void    VFS_GetMemPath(void *Base, Uint Length, char *Dest);
+extern char    *VFS_GetTruePath(char *Path);
+
+extern int     VFS_Mount(char *Device, char *MountPoint, char *Filesystem, char *Options);
+extern int     VFS_MkDir(char *Path);
+extern int     VFS_Symlink(char *Link, char *Dest);
+
+#endif
diff --git a/Kernel/include/vfs_int.h b/Kernel/include/vfs_int.h
new file mode 100644 (file)
index 0000000..f227b23
--- /dev/null
@@ -0,0 +1,49 @@
+/* 
+ * 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;
+        int    MountPointLen;
+       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;
+
+// === GLOBALS ===
+extern tVFS_Mount      *gMounts;
+
+// === PROTOTYPES ===
+// --- OPEN.C ---
+extern char    *VFS_GetAbsPath(char *Path);
+extern tVFS_Node       *VFS_ParsePath(char *Path, char **TruePath);
+extern tVFS_Handle     *VFS_GetHandle(int FD);
+// --- ACLS.C ---
+extern int     VFS_CheckACL(tVFS_Node *Node, Uint Permissions);
+
+#endif
diff --git a/Kernel/include/vfs_ramfs.h b/Kernel/include/vfs_ramfs.h
new file mode 100644 (file)
index 0000000..5bb7f31
--- /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;
+       tVFS_Node       Node;
+       union {
+               struct sRamFS_File      *FirstChild;
+               char    *Bytes;
+       } Data;
+} tRamFS_File;
+
+#endif 
diff --git a/Kernel/lib.c b/Kernel/lib.c
new file mode 100644 (file)
index 0000000..ee9f24e
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Acess2
+ * Common Library Functions
+ */
+#include <common.h>
+
+// === CONSTANTS ===
+//                          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 ===
+ int   ReadUTF8(Uint8 *str, Uint32 *Val);
+
+// === CODE ===
+static const char cUCDIGITS[] = "0123456789ABCDEF";
+/**
+ * \fn static void itoa(char *buf, Uint num, int base, int minLength, char pad)
+ * \brief Convert an integer into a character string
+ */
+void itoa(char *buf, Uint num, int base, int minLength, char pad)
+{
+       char    tmpBuf[BITS];
+        int    pos=0, i;
+
+       // Sanity check
+       if(!buf)        return;
+       
+       // Sanity Check
+       if(base > 16 || base < 2) {
+               buf[0] = 0;
+               return;
+       }
+       
+       // Convert 
+       while(num > base-1) {
+               tmpBuf[pos] = cUCDIGITS[ num % base ];
+               num /= (Uint)base;              // Shift `num` right 1 digit
+               pos++;
+       }
+       tmpBuf[pos++] = cUCDIGITS[ num % base ];                // 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;
+}
+
+/**
+ * \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(char *Str1, char *Str2)
+ * \brief Compare \a Str1 and \a Str2 case-insensitively
+ */
+int strucmp(char *Str1, char *Str2)
+{
+       while(*Str1 && tolower(*Str1) == tolower(*Str2))
+               Str1++, Str2++;
+       return tolower(*Str1) - tolower(*Str2);
+}
+
+/**
+ * \fn int strpos(char *Str, char Ch)
+ * \brief Search a string for an ascii character
+ */
+int strpos(char *Str, char Ch)
+{
+        int    pos;
+       for(pos=0;Str[pos];pos++)
+       {
+               if(Str[pos] == Ch)      return pos;
+       }
+       return -1;
+}
+
+/**
+ */
+int ByteSum(void *Ptr, int Size)
+{
+        int    sum = 0;
+       while(Size--)   sum += *(Uint8*)Ptr++;
+       return sum;
+}
+
+/**
+ * \fn Uint strlen(char *__str)
+ * \brief Get the length of string
+ */
+Uint strlen(char *__str)
+{
+       Uint    ret = 0;
+       while(*__str++) ret++;
+       return ret;
+}
+
+/**
+ * \fn char *strcpy(char *__str1, char *__str2)
+ * \brief Copy a string to a new location
+ */
+char *strcpy(char *__str1, char *__str2)
+{
+       while(*__str2)
+               *__str1++ = *__str2++;
+       *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \fn int strcmp(char *str1, char *str2)
+ * \brief Compare two strings return the difference between
+ *        the first non-matching characters.
+ */
+int strcmp(char *str1, char *str2)
+{
+       while(*str1 && *str1 == *str2)
+               str1++, str2++;
+       return *str1 - *str2;
+}
+
+/**
+ * \fn int strncmp(char *Str1, char *Str2, size_t num)
+ * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
+ */
+int strncmp(char *Str1, char *Str2, size_t num)
+{
+       while(num-- && *Str1 && *Str1 == *Str2)
+               Str1++, Str2++;
+       return *Str1-*Str2;
+}
+
+/**
+ * \fn int strpos8(char *str, Uint32 search)
+ * \brief Search a string for a UTF-8 character
+ */
+int strpos8(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(Uint8 *str, Uint32 *Val)
+{
+       // ASCII
+       if( !(*str & 0x80) ) {
+               *Val = *str;
+               return 1;
+       }
+       
+       // Middle of a sequence
+       if( (*str & 0xC0) == 0x80 ) {
+               *Val = -1;
+               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
+       *Val = -1;
+       return 4;
+}
+
+/**
+ * \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 mins, int hrs, int day, int month, int year)
+{
+       Sint64  stamp;
+       stamp = sec;
+       stamp += mins*60;
+       stamp += hrs*3600;
+       
+       stamp += day*3600*24;
+       stamp += month*DAYS_BEFORE[month]*3600*24;
+       if(     (
+               ((year&3) == 0 || year%100 != 0)
+               || (year%100 == 0 && ((year/100)&3) == 0)
+               ) && month > 1) // Leap year and after feb
+               stamp += 3600*24;
+       
+       stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
+       stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
+       stamp += UNIX_TO_2K;
+       
+       return stamp * 1000;
+}
+
+EXPORT(timestamp);
+EXPORT(ReadUTF8);
diff --git a/Kernel/messages.c b/Kernel/messages.c
new file mode 100644 (file)
index 0000000..31ae8f3
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * AcessOS Microkernel Version
+ * messages.c
+ */
+#include <common.h>
+#include <proc.h>
+#include <errno.h>
+
+// === CODE ===
+/**
+ * \fn int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
+ * \brief Send an IPC message
+ * \param Err  Pointer to the errno variable
+ * \param Dest Destination Thread
+ */
+int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
+{
+       tThread *thread;
+       tMsg    *msg;
+       
+       Log("Proc_SendMessage: (Err=%p, Dest=%i, Length=%i, Data=%p)", Err, Dest, Length, Data);
+       
+       if(Length <= 0 || !Data) {
+               *Err = -EINVAL;
+               return -1;
+       }
+       
+       // Get thread
+       thread = Proc_GetThread( Dest );
+       
+       // Error check
+       if(!thread) {   return -1;      }
+       
+       // Get Spinlock
+       LOCK( &thread->IsLocked );
+       
+       // Check if thread is still alive
+       if(thread->Status == THREAD_STAT_DEAD)  return -1;
+       
+       // Create message
+       msg = malloc( sizeof(tMsg)+Length );
+       msg->Next = NULL;
+       msg->Source = gCurrentThread->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;
+       }
+       
+       RELEASE(&thread->IsLocked);
+       
+       Thread_Wake( thread );
+       
+       return 0;
+}
+
+/**
+ * \fn int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
+ * \brief Gets a message
+ */
+int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
+{
+        int    ret;
+       void *tmp;
+       
+       // Check if queue has any items
+       if(!gCurrentThread->Messages) {
+               return 0;
+       }
+
+       LOCK( &gCurrentThread->IsLocked );
+       
+       if(Source)
+               *Source = gCurrentThread->Messages->Source;
+       
+       // Get message length
+       if( !Buffer ) {
+               ret = gCurrentThread->Messages->Length;
+               RELEASE( &gCurrentThread->IsLocked );
+               return ret;
+       }
+       
+       // Get message
+       if(Buffer != GETMSG_IGNORE)
+               memcpy(Buffer, gCurrentThread->Messages->Data, gCurrentThread->Messages->Length);
+       ret = gCurrentThread->Messages->Length;
+       
+       // Remove from list
+       tmp = gCurrentThread->Messages->Next;
+       free(gCurrentThread->Messages);
+       gCurrentThread->Messages = tmp;
+       
+       RELEASE( &gCurrentThread->IsLocked );
+       
+       return ret;
+}
diff --git a/Kernel/modules.c b/Kernel/modules.c
new file mode 100644 (file)
index 0000000..91afc26
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Acess2
+ * - Module Loader
+ */
+#include <common.h>
+#include <modules.h>
+
+// === PROTOTYPES ===
+ 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(char *Name);
+
+// === IMPORTS ===
+extern tModule gKernelModules[];
+extern void            gKernelModulesEnd;
+
+// === GLOBALS ===
+ int   giNumBuiltinModules = 0;
+ int   giModuleSpinlock = 0;
+tModule        *gLoadedModules = NULL;
+
+// === CODE ===
+int Modules_LoadBuiltins()
+{
+        int    i;
+       giNumBuiltinModules = (Uint)&gKernelModulesEnd - (Uint)&gKernelModules;
+       giNumBuiltinModules /= sizeof(tModule);
+       
+       for( i = 0; i < giNumBuiltinModules; i++ )
+       {
+               Log("Initialising %p '%s' v%i.%i...",
+                       &gKernelModules[i],
+                       gKernelModules[i].Name,
+                       gKernelModules[i].Version>>8, gKernelModules[i].Version & 0xFF
+                       );
+               gKernelModules[i].Init(NULL);
+       }
+       
+       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, char *ArgString)
+{
+       char    path[VFS_MEMPATH_SIZE];
+       
+       VFS_GetMemPath(Buffer, Length, path);
+       
+       return Module_LoadFile( path, ArgString );
+}
+
+/**
+ * \fn int Module_LoadFile(char *Path, char *ArgString)
+ * \brief Load a module from a file
+ */
+int Module_LoadFile(char *Path, char *ArgString)
+{
+       void    *base;
+       tModule *info;
+       
+       // Load Binary
+       base = Binary_LoadKernel(Path);
+       
+       // Error check
+       if(base == NULL)        return 0;
+       
+       // Check for Acess Driver
+       if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
+       {
+               #if USE_EDI
+               // Check for EDI Driver
+               if( Binary_FindSymbol(base, "driver_init", NULL ) == 0 )
+               {
+                       Binary_Relocate(base);  // Relocate
+                       return Module_InitEDI( base );  // And intialise
+               }
+               #endif
+               
+               // Unknown module type?, return error
+               Binary_Unload(base);
+               #if USE_EDI
+               Warning("Module_LoadMem: Module has neither a Module Info struct, nor an EDI entrypoint");
+               #else
+               Warning("Module_LoadMem: Module does not have a Module Info struct");
+               #endif
+               return 0;
+       }
+       
+       LOG("info = %p\n", info);
+       Debug_HexDump("info", info, 6*4);
+       
+       // Check magic number
+       if(info->Magic != MODULE_MAGIC)
+       {
+               Warning("Module_LoadMem: Module's magic value is invalid (0x%x != 0x%x)", info->Magic, MODULE_MAGIC);
+               return 0;
+       }
+       
+       // Check Architecture
+       if(info->Arch != MODULE_ARCH_ID)
+       {
+               Warning("Module_LoadMem: Module is for a different architecture");
+               return 0;
+       }
+       
+       // Resolve Dependencies
+       if( !Module_int_ResolveDeps(info) ) {
+               Binary_Unload(base);
+               return 0;
+       }
+       
+       // Call Initialiser
+       //if( info->Init( ArgString ) != 0 )
+       if( info->Init( NULL ) == 0 )
+       {
+               Binary_Unload(base);
+               return 0;
+       }
+       
+       // Add to list
+       LOCK( &giModuleSpinlock );
+       info->Next = gLoadedModules;
+       gLoadedModules = info;
+       RELEASE( &giModuleSpinlock );
+       
+       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)
+{
+       char    **names = Info->Dependencies;
+       
+       // Walk dependencies array
+       for( ; *names; names++ )
+       {
+               // Check if the module is loaded
+               if( !Module_IsLoaded(*names) ) {
+                       Warning("Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+/**
+ * \fn int Module_IsLoaded(char *Name)
+ * \brief Checks if a module is loaded
+ * \param Name Name of module to find
+ */
+int Module_IsLoaded(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;
+}
diff --git a/Kernel/proc.c b/Kernel/proc.c
new file mode 100644 (file)
index 0000000..e5d9f8f
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * AcessOS Microkernel Version
+ * proc.c
+ */
+#include <common.h>
+#include <proc.h>
+#include <mm_virt.h>
+#include <errno.h>
+#include <mp.h>
+
+// === CONSTANTS ===
+#define        RANDOM_SEED     0xACE55051
+#define        SWITCH_MAGIC    0xFFFACE55      // There is no code in this area
+#define        DEFAULT_QUANTUM 10
+#define        DEFAULT_TICKETS 5
+#define MAX_TICKETS            10
+#define TIMER_DIVISOR  11931   //~100Hz
+
+// === MACROS ===
+#define TIMER_BASE     1193182 //Hz
+#define MS_PER_TICK_WHOLE      (1000*(TIMER_DIVISOR)/(TIMER_BASE))
+#define MS_PER_TICK_FRACT      ((Uint64)(1000*TIMER_DIVISOR-((Uint64)MS_PER_TICK_WHOLE)*TIMER_BASE)*(0x80000000/TIMER_BASE))
+
+// === IMPORTS ===
+extern Uint    GetEIP();       // start.asm
+extern Uint32  gaInitPageDir[1024];    // start.asm
+extern void    Kernel_Stack_Top;
+
+// === PROTOTYPES ===
+void   Proc_Start();
+static tThread *Proc_int_GetPrevThread(tThread **List, tThread *Thread);
+void   Proc_Scheduler();
+Uint   rand();
+
+// === GLOBALS ===
+// -- Core Thread --
+tThread        gThreadZero = {
+       NULL, 0,        // Next, Lock
+       THREAD_STAT_ACTIVE,     // Status
+       0, 0,   // TID, TGID
+       0, 0,   // UID, GID
+       "ThreadZero",   // Name
+       0, 0, 0,        // ESP, EBP, EIP (Set on switch)
+       (Uint)&gaInitPageDir-KERNEL_BASE,       // CR3
+       (Uint)&Kernel_Stack_Top,        // Kernel Stack (Unused as it it PL0)
+       NULL, NULL,     // Messages, Last Message
+       DEFAULT_QUANTUM, DEFAULT_QUANTUM,       // Quantum, Remaining
+       DEFAULT_TICKETS
+       };
+// -- Processes --
+// --- Locks ---
+ int   giThreadListLock = 0;   ///\note NEVER use a heap function while locked
+// --- Current State ---
+tThread        *gCurrentThread = NULL;
+ int   giNumActiveThreads = 0;
+ int   giTotalTickets = 0;
+Uint   giNextTID = 1;
+// --- Thread Lists ---
+tThread        *gActiveThreads = NULL;         // Currently Running Threads
+tThread        *gSleepingThreads = NULL;       // Sleeping Threads
+tThread        *gDeleteThreads = NULL;         // Threads to delete
+// --- Timekeeping ---
+Uint64 giTicks = 0;
+Uint64 giTimestamp = 0;
+Uint64 giPartMiliseconds = 0;
+// --- Multiprocessing ---
+ int   giNumCPUs = 1;
+tMPInfo        *gMPTable = NULL;
+tTSS   *gTSSs = NULL;
+tTSS   gTSS0 = {0};
+
+// === CODE ===
+/**
+ * \fn void Proc_Start()
+ * \brief Starts the process scheduler
+ */
+void Proc_Start()
+{
+       Uint    pos;
+       // -- Initialise Multiprocessing
+       // Find MP Floating Table
+       // - EBDA
+       for(pos = KERNEL_BASE|0x9FC00; pos < (KERNEL_BASE|0xA0000); pos += 16) {
+               if( *(Uint*)(pos) == MPTABLE_IDENT ) {
+                       if(ByteSum( (void*)pos, sizeof(tMPInfo) ) != 0) continue;
+                       gMPTable = (void*)pos;
+                       break;
+               }
+       }
+       // - Last KiB
+       if(!gMPTable) {
+               
+       }
+       // - BIOS ROM
+       if(!gMPTable) {
+               for(pos = KERNEL_BASE|0xF0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
+                       if( *(Uint*)(pos) == MPTABLE_IDENT ) {
+                               if(ByteSum( (void*)pos, sizeof(tMPInfo) ) != 0) continue;
+                               gMPTable = (void*)pos;
+                               break;
+                       }
+               }
+       }
+       
+       // If the MP Table Exists, parse it
+       if(gMPTable)
+       {
+               Panic("Uh oh... MP Table Parsing is unimplemented\n");
+       } else {
+               giNumCPUs = 1;
+               gTSSs = &gTSS0;
+       }
+       
+       // Initialise TSS
+       for(pos=0;pos<giNumCPUs;pos++)
+       {
+               gTSSs[pos].SS0 = 0x10;
+               gTSSs[pos].ESP0 = 0;    // Set properly by scheduler
+               gGDT[9+pos].LimitLow = sizeof(tTSS);
+               gGDT[9+pos].LimitHi = 0;
+               gGDT[9+pos].Access = 0x89;      // Type
+               gGDT[9+pos].Flags = 0x4;
+               gGDT[9+pos].BaseLow = (Uint)&gTSSs[pos] & 0xFFFF;
+               gGDT[9+pos].BaseMid = (Uint)&gTSSs[pos] >> 16;
+               gGDT[9+pos].BaseHi = (Uint)&gTSSs[pos] >> 24;
+       }
+       for(pos=0;pos<giNumCPUs;pos++) {
+               __asm__ __volatile__ ("ltr %%ax"::"a"(0x48+pos*8));
+       }
+       
+       // 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
+       
+       // Clear timestamp
+       giTimestamp = 0;
+       giPartMiliseconds = 0;
+       giTicks = 0;
+       
+       // Create Initial Task
+       gActiveThreads = &gThreadZero;
+       gCurrentThread = &gThreadZero;
+       giTotalTickets = gThreadZero.NumTickets;
+       giNumActiveThreads = 1;
+       
+       // Create Idle Task
+       if(Proc_Clone(0, 0) == 0)
+       {
+               gCurrentThread->ThreadName = "Idle Thread";
+               Proc_SetTickets(0);     // Never called randomly
+               gCurrentThread->Quantum = 1;    // 1 slice quantum
+               for(;;) __asm__ __volatile__ ("hlt");   // Just yeilds
+       }
+       
+       // Start Interrupts (and hence scheduler)
+       __asm__ __volatile__("sti");
+}
+
+/**
+ * \fn int Proc_Clone(Uint *Err, Uint Flags)
+ * \brief Clone the current process
+ */
+int Proc_Clone(Uint *Err, Uint Flags)
+{
+       tThread *newThread;
+       Uint    eip, esp, ebp;
+       
+       __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp));
+       __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp));
+       
+       // Create new thread structure
+       newThread = malloc( sizeof(tThread) );
+       if(!newThread) {
+               Warning("Proc_Clone - Out of memory when creating thread\n");
+               *Err = -ENOMEM;
+               return -1;
+       }
+       // Base new thread on old
+       memcpy(newThread, gCurrentThread, sizeof(tThread));
+       // Initialise Memory Space (New Addr space or kernel stack)
+       if(Flags & CLONE_VM) {
+               newThread->TGID = newThread->TID;
+               newThread->CR3 = MM_Clone();
+       } else {
+               Uint    tmpEbp, oldEsp = esp;
+
+               // Create new KStack
+               newThread->KernelStack = MM_NewKStack();
+               // Check for errors
+               if(newThread->KernelStack == 0) {
+                       free(newThread);
+                       return -1;
+               }
+
+               // Get ESP as a used size
+               esp = gCurrentThread->KernelStack - esp;
+               // Copy used stack
+               memcpy( (void*)(newThread->KernelStack - esp), (void*)(gCurrentThread->KernelStack - esp), esp );
+               // Get ESP as an offset in the new stack
+               esp = newThread->KernelStack - esp;
+               // Adjust EBP
+               ebp = newThread->KernelStack - (gCurrentThread->KernelStack - ebp);
+
+               // Repair EBPs & Stack Addresses
+               #if 0
+               tmpEbp = ebp;
+               while(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < gCurrentThread->KernelStack)
+               {
+                       *(Uint*)tmpEbp += newThread->KernelStack - gCurrentThread->KernelStack;
+                       tmpEbp = *(Uint*)tmpEbp;
+               }
+               #else   // Catches arguments also, but may trash stack-address-like values
+               for(tmpEbp = esp; tmpEbp < newThread->KernelStack; tmpEbp += 4)
+               {
+                       if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < gCurrentThread->KernelStack)
+                               *(Uint*)tmpEbp += newThread->KernelStack - gCurrentThread->KernelStack;
+               }
+               #endif
+       }
+
+       // Set Pointer, Spinlock and TID
+       newThread->Next = NULL;
+       newThread->IsLocked = 0;
+       newThread->TID = giNextTID++;
+
+       // Clear message list (messages are not inherited)
+       newThread->Messages = NULL;
+       newThread->LastMessage = NULL;
+       
+       // Set remaining (sheduler expects remaining to be correct)
+       newThread->Remaining = newThread->Quantum;
+       
+       // Save core machine state
+       newThread->ESP = esp;
+       newThread->EBP = ebp;
+       eip = GetEIP();
+       if(eip == SWITCH_MAGIC) {
+               outb(0x20, 0x20);       // ACK Timer and return as child
+               return 0;
+       }
+       
+       // Set EIP as parent
+       newThread->EIP = eip;
+       
+       //Log(" Proc_Clone: giTimestamp = %i.%07i", (Uint)giTimestamp, (Uint)giPartMiliseconds/214);
+       
+       // Lock list and add to active
+       LOCK( &giThreadListLock );
+       newThread->Next = gActiveThreads;
+       gActiveThreads = newThread;
+       giNumActiveThreads ++;
+       giTotalTickets += newThread->NumTickets;
+       RELEASE( &giThreadListLock );
+       
+       return newThread->TID;
+}
+
+/**
+ * \fn void Proc_Exit()
+ * \brief Kill the current process
+ */
+void Proc_Exit()
+{
+       tThread *thread;
+       tMsg    *msg;
+       
+       ///\note Double lock is needed due to overlap of locks
+       
+       // Lock thread (stop us recieving messages)
+       LOCK( &gCurrentThread->IsLocked );
+       
+       // Lock thread list
+       LOCK( &giThreadListLock );
+       
+       // Get previous thread on list
+       thread = Proc_int_GetPrevThread( &gActiveThreads, gCurrentThread );
+       if(!thread) {
+               Warning("Proc_Exit - Current thread is not on the active queue");
+               return;
+       }
+       
+       // Clear Message Queue
+       while( gCurrentThread->Messages )
+       {
+               msg = gCurrentThread->Messages->Next;
+               free( gCurrentThread->Messages );
+               gCurrentThread->Messages = msg;
+       }
+       
+       gCurrentThread->Remaining = 0;  // Clear Remaining Quantum
+       gCurrentThread->Quantum = 0;    // Clear Quantum to indicate dead thread
+       thread->Next = gCurrentThread->Next;    // Remove from active
+       
+       // Add to delete queue
+       if(gDeleteThreads) {
+               gCurrentThread->Next = gDeleteThreads;
+               gDeleteThreads = gCurrentThread;
+       } else {
+               gCurrentThread->Next = NULL;
+               gDeleteThreads = gCurrentThread;
+       }
+       
+       giNumActiveThreads --;
+       giTotalTickets -= gCurrentThread->NumTickets;
+       
+       // Mark thread as sleeping
+       gCurrentThread->Status = THREAD_STAT_DEAD;
+       
+       // Release spinlocks
+       RELEASE( &gCurrentThread->IsLocked );   // Released first so that it IS released
+       RELEASE( &giThreadListLock );
+       __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Proc_Yield()
+ * \brief Yield remainder of timeslice
+ */
+void Proc_Yield()
+{
+       gCurrentThread->Quantum = 0;
+       __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Proc_Sleep()
+ * \brief Take the current process off the run queue
+ */
+void Proc_Sleep()
+{
+       tThread *thread;
+       
+       //Log("Proc_Sleep: %i going to sleep", gCurrentThread->TID);
+       
+       // Acquire Spinlock
+       LOCK( &giThreadListLock );
+       
+       // Get thread before current thread
+       thread = Proc_int_GetPrevThread( &gActiveThreads, gCurrentThread );
+       if(!thread) {
+               Warning("Proc_Sleep - Current thread is not on the active queue");
+               return;
+       }
+       
+       // Don't sleep if there is a message waiting
+       if( gCurrentThread->Messages ) {
+               RELEASE( &giThreadListLock );
+               return;
+       }
+       
+       // Unset remaining timeslices (force a task switch on timer fire)
+       gCurrentThread->Remaining = 0;
+       
+       // Remove from active list
+       thread->Next = gCurrentThread->Next;
+       
+       // Add to Sleeping List (at the top)
+       gCurrentThread->Next = gSleepingThreads;
+       gSleepingThreads = gCurrentThread;
+       
+       // Reduce the active count & ticket count
+       giNumActiveThreads --;
+       giTotalTickets -= gCurrentThread->NumTickets;
+       
+       // Mark thread as sleeping
+       gCurrentThread->Status = THREAD_STAT_SLEEPING;
+       
+       // Release Spinlock
+       RELEASE( &giThreadListLock );
+       
+       __asm__ __volatile__ ("hlt");
+}
+
+/**
+ * \fn void Thread_Wake( tThread *Thread )
+ * \brief Wakes a sleeping/waiting thread up
+ */
+void Thread_Wake(tThread *Thread)
+{
+       tThread *prev;
+       switch(Thread->Status)
+       {
+       case THREAD_STAT_ACTIVE:        break;
+       case THREAD_STAT_SLEEPING:
+               LOCK( &giThreadListLock );
+               prev = Proc_int_GetPrevThread(&gSleepingThreads, Thread);
+               prev->Next = Thread->Next;      // Remove from sleeping queue
+               Thread->Next = gActiveThreads;  // Add to active queue
+               gActiveThreads = Thread;
+               Thread->Status = THREAD_STAT_ACTIVE;
+               RELEASE( &giThreadListLock );
+               break;
+       case THREAD_STAT_WAITING:
+               Warning("Thread_Wake - Waiting threads are not currently supported");
+               break;
+       case THREAD_STAT_DEAD:
+               Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
+               break;
+       default:
+               Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
+               break;
+       }
+}
+
+/**
+ * \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
+ */
+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;
+}
+
+/**
+ * \fn void Proc_SetTickets(int Num)
+ * \brief Sets the 'priority' of a task
+ */
+void Proc_SetTickets(int Num)
+{
+       if(Num < 0)     return;
+       if(Num > MAX_TICKETS)   Num = MAX_TICKETS;
+       
+       Log("Proc_SetTickets: (Num=%i)", Num);
+       Log(" Proc_SetTickets: giTotalTickets = %i", giTotalTickets);
+       LOCK( &giThreadListLock );
+       giTotalTickets -= gCurrentThread->NumTickets;
+       gCurrentThread->NumTickets = Num;
+       giTotalTickets += Num;
+       RELEASE( &giThreadListLock );
+       Log(" Proc_SetTickets: giTotalTickets = %i", giTotalTickets);
+       Log("Proc_SetTickets: RETURN", giTotalTickets);
+}
+
+/**
+ * \fn tThread *Proc_GetThread(Uint TID)
+ * \brief Gets a thread given its TID
+ */
+tThread *Proc_GetThread(Uint TID)
+{
+       tThread *thread;
+       
+       // Search Active List
+       for(thread = gActiveThreads;
+               thread;
+               thread = thread->Next)
+       {
+               if(thread->TID == TID)
+                       return thread;
+       }
+       
+       // Search Sleeping List
+       for(thread = gSleepingThreads;
+               thread;
+               thread = thread->Next)
+       {
+               if(thread->TID == TID)
+                       return thread;
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn static tThread *Proc_int_GetPrevThread(tThread *List, tThread *Thread)
+ * \brief Gets the previous entry in a thead linked list
+ */
+static tThread *Proc_int_GetPrevThread(tThread **List, tThread *Thread)
+{
+       tThread *ret;
+       // First Entry
+       if(*List == Thread) {
+               return (tThread*)List;
+       } else {
+               for(ret = *List;
+                       ret->Next && ret->Next != Thread;
+                       ret = ret->Next
+                       );
+               // Error if the thread is not on the list
+               if(!ret->Next || ret->Next != Thread) {
+                       return NULL;
+               }
+       }
+       return ret;
+}
+
+/**
+ * \fn void Proc_DumpThreads()
+ */
+void Proc_DumpThreads()
+{
+       tThread *thread;
+       
+       Log("Active Threads:");
+       for(thread=gActiveThreads;thread;thread=thread->Next)
+       {
+               Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
+               Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
+               Log("  CR3 0x%x, KStack 0x%x", thread->CR3, thread->KernelStack);
+       }
+       Log("Sleeping Threads:");
+       for(thread=gSleepingThreads;thread;thread=thread->Next)
+       {
+               Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
+               Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
+               Log("  CR3 0x%x, KStack 0x%x", thread->CR3, thread->KernelStack);
+       }
+}
+
+/**
+ * \fn void Proc_Scheduler(int CPU)
+ * \brief Swap current task
+ */
+void Proc_Scheduler(int CPU)
+{
+       Uint    esp, ebp, eip;
+       Uint    number, ticket;
+       tThread *thread;
+       
+       // Increment Timestamps
+       giTicks ++;
+       giTimestamp += MS_PER_TICK_WHOLE;
+       giPartMiliseconds += MS_PER_TICK_FRACT;
+       if(giPartMiliseconds > 0x80000000) {
+               giTimestamp ++;
+               giPartMiliseconds -= 0x80000000;
+       }
+       
+       // If the spinlock is set, let it complete
+       if(giThreadListLock)    return;
+       
+       // Clear Delete Queue
+       while(gDeleteThreads)
+       {
+               thread = gDeleteThreads->Next;
+               if(gDeleteThreads->IsLocked) {  // Only free if structure is unused
+                       gDeleteThreads->Status = THREAD_STAT_NULL;
+                       free( gDeleteThreads );
+               }
+               gDeleteThreads = thread;
+       }
+       
+       // Check if there is any tasks running
+       if(giNumActiveThreads == 0) {
+               Log("No Active threads, sleeping\n");
+               __asm__ __volatile__ ("hlt");
+               return;
+       }
+       
+       // Reduce remaining quantum
+       if(gCurrentThread->Remaining--) return;
+       // Reset quantum for next call
+       gCurrentThread->Remaining = gCurrentThread->Quantum;
+       
+       // Get machine state
+       __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
+       __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
+       eip = GetEIP();
+       if(eip == SWITCH_MAGIC) return; // Check if a switch happened
+       
+       // Save machine state
+       gCurrentThread->ESP = esp;
+       gCurrentThread->EBP = ebp;
+       gCurrentThread->EIP = eip;
+       
+       // Special case: 1 thread
+       if(giNumActiveThreads == 1)
+       {
+               // Check if a switch is needed (NumActive can be 1 after a sleep)
+               if(gActiveThreads == gCurrentThread)    return;
+               // Switch processes
+               gCurrentThread = gActiveThreads;
+               goto performSwitch;
+       }
+       
+       // Get the ticket number
+       ticket = number = rand() % giTotalTickets;
+       
+       //Log(" Proc_Scheduler: number = 0x%x\n", number);
+       
+       // Find the next thread
+       for(thread=gActiveThreads;thread;thread=thread->Next)
+       {
+               if(thread->NumTickets > number) break;
+               number -= thread->NumTickets;
+       }
+       
+       // Error Check
+       if(thread == NULL)
+       {
+               number = 0;
+               for(thread=gActiveThreads;thread;thread=thread->Next)
+                       number += thread->NumTickets;
+               Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
+                       giTotalTickets, number);
+       }
+       
+       // Set current thread
+       gCurrentThread = thread;
+       
+       // Update Kernel Stack pointer
+       gTSSs[CPU].ESP0 = thread->KernelStack;
+       
+performSwitch:
+       // Set address space
+       MM_SetCR3( gCurrentThread->CR3 );
+       // Switch threads
+       __asm__ __volatile__ (
+               "mov %1, %%esp\n\t"
+               "mov %2, %%ebp\n\t"
+               "jmp *%3" : :
+               "a"(SWITCH_MAGIC), "b"(gCurrentThread->ESP),
+               "d"(gCurrentThread->EBP), "c"(gCurrentThread->EIP));
+       for(;;);        // Shouldn't reach here
+}
+
+/**
+ * \fn Uint rand()
+ * \brief Pseudo random number generator
+ * \note Unknown effectiveness (made up on the spot)
+ */
+Uint rand()
+{
+       static Uint     randomState = RANDOM_SEED;
+       Uint    ret = randomState;
+        int    roll = randomState & 31;
+       randomState = (randomState << roll) | (randomState >> (32-roll));
+       randomState ^= 0x9A3C5E78;
+       return ret;
+}
diff --git a/Kernel/syscalls.c b/Kernel/syscalls.c
new file mode 100644 (file)
index 0000000..d89d6e6
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * AcessOS Microkernel Version
+ * syscalls.c
+ */
+#define DEBUG  1
+
+#include <common.h>
+#include <syscalls.h>
+#include <proc.h>
+#include <errno.h>
+
+// === IMPORTS ===
+extern int     Proc_Clone(Uint *Err, Uint Flags);
+extern Uint    Proc_SendMessage(Uint *Err, Uint Dest, Uint Length, void *Data);
+extern int     Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer);
+extern int     Proc_Execve(char *File, char **ArgV, char **EnvP);
+extern Uint    Binary_Load(char *file, Uint *entryPoint);
+
+// === CODE ===
+void SyscallHandler(tSyscallRegs *Regs)
+{
+       Uint    ret=0, err=0;
+       #if DEBUG
+       ENTER("iThread iNum", gCurrentThread->TID, Regs->Num);
+       if(Regs->Num < NUM_SYSCALLS)
+               LOG("Syscall %s", cSYSCALL_NAMES[Regs->Num]);
+       LOG("Arg1: 0x%x, Arg2: 0x%x, Arg3: 0x%x", Regs->Arg1, Regs->Arg2, Regs->Arg3);
+       #endif
+       switch(Regs->Num)
+       {
+       // -- Exit the current thread
+       case SYS_EXIT:  Proc_Exit();    break;
+       
+       // -- Put the current thread to sleep
+       case SYS_SLEEP: Proc_Sleep();   Log(" SyscallHandler: %i is alive", gCurrentThread->TID);       break;
+       
+       // -- Yield current timeslice
+       case SYS_YIELD: Proc_Yield();   break;
+       
+       // -- Clone the current thread
+       case SYS_CLONE:
+               // Call clone system call
+               ret = Proc_Clone(&err, Regs->Arg1);
+               // Change user stack if requested
+               if(ret == 0 && Regs->Arg2)
+                       Regs->StackPointer = Regs->Arg2;
+               break;
+       
+       // -- Send a signal
+       case SYS_KILL:
+               err = -ENOSYS;
+               ret = -1;
+               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 = gCurrentThread->TID;      break;
+       case SYS_GETPID:        ret = gCurrentThread->TGID;     break;
+       // -- Get User/Group IDs
+       case SYS_GETUID:        ret = gCurrentThread->UID;      break;
+       case SYS_GETGID:        ret = gCurrentThread->GID;      break;
+       
+       // -- Send Message
+       case SYS_SENDMSG:
+               ret = Proc_SendMessage(&err, Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
+               break;
+       // -- Check for messages
+       case SYS_GETMSG:
+               ret = Proc_GetMessage(&err, (Uint*)Regs->Arg1, (void*)Regs->Arg2);
+               break;
+       
+       // -- Set the thread's name
+       case SYS_SETNAME:
+               // Sanity Check
+               if(!Regs->Arg1) {       ret = -1;       err = -EINVAL;  break;  }
+               // Lock Process
+               LOCK( &gCurrentThread->IsLocked );
+               // Free old name
+               if(gCurrentThread->ThreadName && (Uint)gCurrentThread->ThreadName > 0xE0800000)
+                       free(gCurrentThread->ThreadName);
+               // Change name
+               gCurrentThread->ThreadName = malloc( strlen( (char*)Regs->Arg1 ) + 1 );
+               strcpy(gCurrentThread->ThreadName, (char*)Regs->Arg1);
+               // Unlock
+               RELEASE( &gCurrentThread->IsLocked );
+               break;
+       
+       // ---
+       // Binary Control
+       // ---
+       case SYS_EXECVE:
+               ret = Proc_Execve((char*)Regs->Arg1, (char**)Regs->Arg2, (char**)Regs->Arg3);
+               break;
+       case SYS_LOADBIN:
+               ret = Binary_Load((char*)Regs->Arg1, (Uint*)Regs->Arg2);
+               break;
+       
+       // ---
+       // Virtual Filesystem
+       // ---
+       case SYS_OPEN:
+               ret = VFS_Open((char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
+               break;
+       
+       case SYS_CLOSE:
+               VFS_Close( Regs->Arg1 );
+               break;
+       
+       case SYS_WRITE:
+               #if BITS < 64
+               VFS_Write( Regs->Arg1, Regs->Arg2|((Uint64)Regs->Arg3<<32), (void*)Regs->Arg4 );
+               #else
+               VFS_Write( Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3 );
+               #endif
+               break;
+       
+       
+       // -- Debug
+       case SYS_DEBUG:
+               Log((char*)Regs->Arg1,
+                       Regs->Arg2, Regs->Arg3, Regs->Arg4, Regs->Arg5, Regs->Arg6);
+               break;
+       
+       // -- Default (Return Error)
+       default:
+               Warning("SyscallHandler: Unknown System Call %i", Regs->Num);
+               if(Regs->Num < NUM_SYSCALLS)
+                       Warning(" Syscall %s", cSYSCALL_NAMES[Regs->Num]);
+               err = -ENOSYS;
+               ret = -1;
+               break;
+       }
+       Regs->Return = ret;
+       Regs->Error = err;
+       #if DEBUG
+       LOG("SyscallHandler: err = %i", err);
+       LEAVE('x', ret);
+       #endif
+}
+
diff --git a/Kernel/syscalls.lst b/Kernel/syscalls.lst
new file mode 100644 (file)
index 0000000..280656e
--- /dev/null
@@ -0,0 +1,56 @@
+
+0
+SYS_EXIT       Kill this thread
+SYS_CLONE      Create a new thread
+SYS_KILL       Send a signal
+SYS_SIGNAL     Set signal Handler
+SYS_YIELD      Yield remainder of timestamp
+SYS_SLEEP      Sleep until messaged or signaled
+SYS_WAIT       Wait for a time or a message
+SYS_WAITTID    Wait for a thread to do something
+
+SYS_SETNAME    Set's the name of the current thread
+SYS_GETNAME    Get's 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
+
+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_READDIR    Read from an open directory
+SYS_MKDIR      Create a new directory
+SYS_SYMLINK    Create a symbolic link
+SYS_GETACL     Get an ACL Value
+SYS_SETACL     Set an ACL Value
+SYS_FINFO      Get file information
+SYS_SEEK       Seek to a new position in the file
+SYS_TELL       Return the current file position
diff --git a/Kernel/system.c b/Kernel/system.c
new file mode 100644 (file)
index 0000000..a736c46
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Acess 2
+ * Architecture Independent System Init
+ * system.c
+ */
+#include <common.h>
+
+// === IMPORTS ===
+extern int     Modules_LoadBuiltins();
+extern int     PCI_Install();
+
+// === PROTOTYPES ===
+void   System_Init(char *ArgString);
+void   System_ParseCommandLine(char *ArgString);
+void   System_ParseVFS(char *Arg);
+void   System_ParseSetting(char *Arg);
+void   System_ExecuteScript();
+ int   System_Int_GetString(char *Str, char **Dest);
+
+// === GLOBALS ===
+char   *gsInitPath = "/Acess/Bin/init";
+char   *gsConfigScript = "/Acess/BootConf.cfg";
+
+// === CODE ===
+void System_Init(char *ArgString)
+{
+       // - Start Builtin Drivers & Filesystems
+       PCI_Install();
+       //ATA_Install();
+       Modules_LoadBuiltins();
+       
+       // - Parse Kernel's Command Line
+       System_ParseCommandLine(ArgString);
+       
+       // - Execute the Config Script
+       Log("Executing config script...");
+       System_ExecuteScript();
+}
+
+/**
+ * \fn void System_ParseCommandLine(char *ArgString)
+ * \brief Parses the kernel's command line and sets the environment
+ */
+void System_ParseCommandLine(char *ArgString)
+{
+       char    *argv[32];
+        int    argc;
+        int    i;
+       char    *str;
+       
+       Log("Kernel Command Line: \"%s\"", ArgString);
+       
+       // --- Get Arguments ---
+       str = ArgString;
+       for( argc = 0; argc < 32; argc++ )
+       {
+               while(*str == ' ')      str++;  // Eat Whitespace
+               if(*str == '\0') {      argc--; break;} // End of string
+               argv[argc] = str;
+               while(*str && *str != ' ')
+               {
+                       /*if(*str == '"') {
+                               while(*str && !(*str == '"' && str[-1] != '\\'))
+                                       str ++;
+                       }*/
+                       str++;
+               }
+               if(*str == '\0')        break;  // End of string
+               *str = '\0';    // Cap off argument string
+               str ++; // and increment the string pointer
+       }
+       if(argc < 32)
+               argc ++;        // Count last argument
+       
+       // --- Parse Arguments ---
+       for( i = 1; i < argc; i++ )
+       {
+               if( argv[i][0] == '/' )
+                       System_ParseVFS( argv[i] );
+               else
+                       System_ParseSetting( argv[i] );
+       }
+}
+
+/**
+ * \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' ) {
+               Warning("Expected '=' in the string '%s'", Arg);
+               return ;
+       }
+       
+       // Edit string
+       *value = '\0';  value ++;
+       
+       // Check assignment type
+       // - Symbolic Link <link>=<destination>
+       if(value[0] == '/')
+       {
+               Log("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("Creating directory '%s'", Arg, value);
+                       VFS_MkDir( Arg );
+               } else {
+                       VFS_Close(fd);
+               }
+               // Mount
+               Log("Mounting '%s' to '%s' ('%s')", dev, Arg, value);
+               VFS_Mount(dev, Arg, value, "");
+       }
+}
+
+/**
+ * \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 {
+                       Warning("Kernel flag '%s' is not recognised", Arg);
+               }
+       }
+       else
+       {
+               *value = '\0';  // Remove '='
+               value ++;       // and eat it's position
+               
+               if(strcmp(Arg, "SCRIPT") == 0) {
+                       Log("Config Script: '%s'", value);
+                       gsConfigScript = value;
+               } else {
+                       Warning("Kernel config setting '%s' is not recognised", Arg);
+               }
+               
+       }
+}
+
+/**
+ * \fn void System_ExecuteScript()
+ */
+void System_ExecuteScript()
+{
+        int    fp;
+        int    fLen = 0;
+        int    i = 0, lineStart;
+       char    *sArg1, *sArg2, *sArg3;
+       char    *fData;
+       
+       // Open Script
+       fp = VFS_Open(gsConfigScript, VFS_OPENFLAG_READ);
+       if(fp == -1) {
+               Warning("[CFG] Passed script '%s' does not exist", gsConfigScript);
+               return;
+       }
+       
+       // Read into memory buffer
+       VFS_Seek(fp, 0, SEEK_END);
+       fLen = VFS_Tell(fp);
+       VFS_Seek(fp, 0, SEEK_SET);
+       fData = malloc(fLen+1);
+       VFS_Read(fp, fLen, fData);
+       fData[fLen] = '\0';
+       VFS_Close(fp);
+       
+       // Read Script
+       while(i < fLen)
+       {
+               sArg1 = sArg2 = sArg3 = NULL;
+               
+               lineStart = i;
+               // Clear leading whitespace and find empty lines
+               while(i < fLen && (fData[i] == ' ' || fData[i]=='\t'))  i ++;
+               if(i == fLen)   break;
+               if(fData[i] == '\n') {
+                       i++;
+                       continue;
+               }
+               
+               // Comment
+               if(fData[i] == ';' || fData[i] == '#') {
+                       while(i < fLen && fData[i] != '\n')     i ++;
+                       i ++;
+                       continue;
+               }
+               
+               // Commands
+               // - Mount
+               if(strncmp("mount ", fData+i, 6) == 0) {
+                       i += 6;
+                       i += System_Int_GetString(fData+i, &sArg1);
+                       if(!sArg1)      goto read2eol;
+                       i += System_Int_GetString(fData+i, &sArg2);
+                       if(!sArg2)      goto read2eol;
+                       i += System_Int_GetString(fData+i, &sArg3);
+                       if(!sArg3)      goto read2eol;
+                       //Log("[CFG ] Mount '%s' to '%s' (%s)\n", sArg1, sArg2, sArg3);
+                       VFS_Mount(sArg1, sArg2, sArg3, "");
+               }
+               // - Load Module
+               else if(strncmp("module ", fData+i, 6) == 0) {
+                       i += 7;
+                       i += System_Int_GetString(fData+i, &sArg1);
+                       if(!sArg1)      goto read2eol;
+                       //Log("[CFG ] Load Module '%s'\n", sArg1);
+                       Module_LoadFile(sArg1, "");     //!\todo Use the rest of the line as the argument string
+               }
+               // - Load Module
+               else if(strncmp("edimod ", fData+i, 6) == 0) {
+                       i += 7;
+                       i += System_Int_GetString(fData+i, &sArg1);
+                       if(!sArg1)      goto read2eol;
+                       Log("[CFG ] Load EDI Module '%s'\n", sArg1);
+                       Module_LoadFile(sArg1, "");
+               }
+               // - Symlink
+               else if(strncmp("symlink ", fData+i, 7) == 0) {
+                       i += 8;
+                       i += System_Int_GetString(fData+i, &sArg1);
+                       if(!sArg1)      goto read2eol;
+                       i += System_Int_GetString(fData+i, &sArg2);
+                       if(!sArg2)      goto read2eol;
+                       Log("[CFG ] Symlink '%s' pointing to '%s'\n", sArg1, sArg2);
+                       VFS_Symlink(sArg1, sArg2);
+               }
+               // - New Directory
+               else if(strncmp("mkdir ", fData+i, 5) == 0) {
+                       i += 6;
+                       i += System_Int_GetString(fData+i, &sArg1);
+                       if(!sArg1)      goto read2eol;
+                       Log("[CFG ] New Directory '%s'\n", sArg1);
+                       VFS_MkDir(sArg1);
+               }
+               // - Spawn a task
+               else if(strncmp("spawn ", fData+i, 5) == 0) {
+                       i += 6;
+                       i += System_Int_GetString(fData+i, &sArg1);
+                       if(!sArg1)      goto read2eol;
+                       Log("[CFG ] Starting '%s' as a new task\n", sArg1);
+                       Proc_Spawn(sArg1);
+               }
+               else {
+                       Warning("Unknown configuration command, Line: '%s'", fData+i);
+                       goto read2eol;
+               }
+       read2eol:
+               if(sArg1)       free(sArg1);
+               if(sArg2)       free(sArg2);
+               if(sArg3)       free(sArg3);
+               // Skip to EOL
+               while(i < fLen && fData[i] != '\n')     i++;
+               i ++;   // Skip \n
+       }
+       free(fData);
+}
+
+/**
+ * \fn int System_Int_GetString(char *Str, char **Dest)
+ * \brief Gets a string from another
+ * \note Destructive
+ * \param Str  Input String
+ * \param Dest Pointer to output pointer
+ * \return Characters eaten from input
+ */
+int System_Int_GetString(char *Str, char **Dest)
+{
+        int    pos = 0;
+        int    start = 0;
+        int    len;
+        
+       //LogF("GetString: (Str='%s', Dest=0x%x)\n", Str, Dest);
+        
+       while(Str[pos] == ' ' || Str[pos] == '\t')      pos++;
+       if(Str[pos] == '\n' || Str[pos] == '\0') {
+               *Dest = NULL;
+               return pos;
+       }
+       
+       // Quoted String
+       if(Str[pos] == '"')
+       {
+               pos ++;
+               start = pos;
+               while(Str[pos] != '"')  pos++;
+               
+               len = pos - start;
+               *Dest = malloc( len + 1 );
+               memcpy( *Dest, Str+start, len );
+               (*Dest)[len] = '\0';
+               
+               //LogF("GetString: RETURN *Dest = '%s'\n", *Dest);
+               
+               pos++;
+               return pos;
+       }
+       
+       // Non-Quoted String - Whitespace deliminated
+       start = pos;
+       while(Str[pos] != ' ' && Str[pos] != '\t' && Str[pos] != '\n')  pos++;
+       
+       len = pos - start;
+       //LogF(" GetString: len = %i\n", len);
+       *Dest = malloc( len + 1 );
+       memcpy( *Dest, Str+start, len );
+       (*Dest)[len] = '\0';
+       
+       //LogF("GetString: RETURN *Dest = '%s'\n", *Dest);
+       
+       return pos;
+}
diff --git a/Kernel/vfs.c b/Kernel/vfs.c
new file mode 100644 (file)
index 0000000..c1d6eef
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Acess 2
+ * binary.c
+ * - Binary File Loader
+ */
+#include <common.h>
+#include <vfs.h>
+
+// === GLOBALS ===
+
+
+// === CODE ===
diff --git a/Kernel/vfs/acls.c b/Kernel/vfs/acls.c
new file mode 100644 (file)
index 0000000..52c802c
--- /dev/null
@@ -0,0 +1,58 @@
+/* 
+ * Acess Micro VFS
+ */
+#include <common.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === GLOBALS ===
+tVFS_ACL       gVFS_ACL_EveryoneRWX = { {0,-1}, {0,VFS_PERM_ALL} };
+tVFS_ACL       gVFS_ACL_EveryoneRW = { {0,-1}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE} };
+tVFS_ACL       gVFS_ACL_EveryoneRX = { {0,-1}, {0,VFS_PERM_READ|VFS_PERM_EXECUTE} };
+tVFS_ACL       gVFS_ACL_EveryoneRO = { {0,-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 = Proc_GetUID();
+        int    gid = Proc_GetGID();
+       
+       // Root can do anything
+       if(uid == 0)    return 1;
+       
+       // Root only file?, fast return
+       if( Node->NumACLs == 0 )        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 != -1)
+               {
+                       if(!Node->ACLs[i].Group && Node->ACLs[i].ID != uid)     continue;
+                       if(Node->ACLs[i].Group && Node->ACLs[i].ID != gid)      continue;
+               }
+               
+               if(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 != -1)
+               {
+                       if(!Node->ACLs[i].Group && Node->ACLs[i].ID != uid)     continue;
+                       if(Node->ACLs[i].Group && Node->ACLs[i].ID != gid)      continue;
+               }
+               
+               if((Node->ACLs[i].Perms & Permissions) == Permissions)  return 1;
+       }
+       
+       return 0;
+}
diff --git a/Kernel/vfs/dir.c b/Kernel/vfs/dir.c
new file mode 100644 (file)
index 0000000..aeda00e
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ */
+#include "vfs.h"
+#include "vfs_int.h"
+
+// === IMPORTS ===
+extern tVFS_Mount      *gRootMount;
+
+// === PROTOTYPES ===
+ int   VFS_MkDir(char *Path);
+ int   VFS_MkNod(char *Path, Uint Flags);
+
+// === CODE ===
+/**
+ * \fn int VFS_MkDir(char *Path)
+ * \brief Create a new node
+ * \param Path Path of directory to create
+ */
+int VFS_MkDir(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(char *Path, Uint Flags)
+{
+       char    *absPath, *name;
+        int    pos=0, oldpos = 0;
+       tVFS_Node       *parent;
+        int    ret;
+       
+       Debug_Enter("VFS_MkNod", "sPath xFlags", Path, Flags);
+       
+       absPath = VFS_GetAbsPath(Path);
+       
+       while( (pos = strpos8(&absPath[pos+1], '/')) != -1 )    oldpos = pos;
+       absPath[oldpos] = '\0'; // Mutilate path
+       name = &absPath[oldpos+1];
+       
+       // Check for root
+       if(absPath[0] == '\0')
+               parent = VFS_ParsePath("/", NULL);
+       else
+               parent = VFS_ParsePath(absPath, NULL);
+       
+       if(!parent)     return -1;      // Error Check
+       
+       // Permissions Check
+       if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
+               if(parent->Close)       parent->Close( parent );
+               free(absPath);
+               Debug_Leave("VFS_MkNod", 'i', -1);
+               return -1;
+       }
+       
+       Debug_Log("VFS_MkNod", "parent = %p\n", parent);
+       
+       if(parent->MkNod == NULL) {
+               Warning("VFS_MkNod - Directory has no MkNod method");
+               Debug_Leave("VFS_MkNod", 'i', -1);
+               return -1;
+       }
+       
+       // Create node
+       ret = parent->MkNod(parent, name, Flags);
+       
+       // Free allocated string
+       free(absPath);
+       
+       // Free Parent
+       if(parent->Close)       parent->Close( parent );
+       
+       // Error Check
+       if(ret == 0)    return -1;
+       
+       Debug_Leave("VFS_MkNod", 'i', 0);
+       return 0;
+}
+
+/**
+ * \fn int VFS_Symlink(char *Name, 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(char *Name, char *Link)
+{
+       char    *realLink;
+        int    fp;
+       tVFS_Node       *destNode;
+       
+       //LogF("vfs_symlink: (name='%s', link='%s')\n", name, link);
+       
+       // Get absolue path name
+       Link = VFS_GetAbsPath( Link );
+       if(!Link) {
+               Warning("Path '%s' is badly formed", Link);
+               return -1;
+       }
+       
+       // Get true path and node
+       destNode = VFS_ParsePath( Link, &realLink );
+       free(Link);
+       
+       // Check if destination exists
+       if(!destNode) {
+               Warning("File '%s' does not exist, symlink not created", Link);
+               return -1;
+       }
+       
+       // Derefence the destination
+       if(destNode->Close)     destNode->Close(destNode);
+       
+       // Make node
+       if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
+               Warning("Unable to create link node '%s'", Name);
+               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);
+       
+       return 1;
+}
diff --git a/Kernel/vfs/fs/devfs.c b/Kernel/vfs/fs/devfs.c
new file mode 100644 (file)
index 0000000..25be490
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Acess 2
+ * Device Filesystem (DevFS)
+ * - vfs/fs/devfs.c
+ */
+#include <common.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+
+// === PROTOTYPES ===
+ int   DevFS_AddDevice(tDevFS_Driver *Dev);
+tVFS_Node      *DevFS_InitDevice(char *Device, char *Options);
+char   *DevFS_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node      *DevFS_FindDir(tVFS_Node *Node, char *Name);
+
+// === GLOBALS ===
+tVFS_Driver    gDevFS_Info = {
+       "devfs", 0, DevFS_InitDevice, NULL
+       };
+tVFS_Node      gDevFS_RootNode = {
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       .ReadDir = DevFS_ReadDir,
+       .FindDir = DevFS_FindDir
+       };
+tDevFS_Driver  *gDevFS_Drivers = NULL;
+ int   giDevFS_NextID = 1;
+
+// === CODE ===
+/**
+ * \fn int DevFS_AddDevice(tDevFS_Driver *Dev)
+ */
+int DevFS_AddDevice(tDevFS_Driver *Dev)
+{
+       Dev->Next = gDevFS_Drivers;
+       gDevFS_Drivers = Dev;
+       
+       return giDevFS_NextID++;
+}
+
+/**
+ * \fn tVFS_Node *DevFS_InitDevice(char *Device, char *Options)
+ * \brief Initialise the DevFS and detect double-mounting, or just do nothing
+ * \stub
+ */
+tVFS_Node *DevFS_InitDevice(char *Device, 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
+               );
+       
+       return dev->Name;
+}
+
+/**
+ * \fn tVFS_Node *DevFS_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Get an entry from the devices directory
+ */
+tVFS_Node *DevFS_FindDir(tVFS_Node *Node, 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);
diff --git a/Kernel/vfs/fs/fat.c b/Kernel/vfs/fs/fat.c
new file mode 100644 (file)
index 0000000..c4f6671
--- /dev/null
@@ -0,0 +1,920 @@
+/*\r
+ * Acess2\r
+ * FAT12/16/32 Driver Version (Incl LFN)\r
+ */\r
+//INCLUDES\r
+#include <common.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include "fs_fat.h"\r
+\r
+#define DEBUG  0\r
+#define VERBOSE        1\r
+\r
+#if DEBUG\r
+# define DEBUGS(v...)  Log(v)\r
+#else\r
+# define DEBUGS(v...)\r
+# undef ENTER\r
+# undef LOG\r
+# undef LEAVE\r
+# define ENTER(...)\r
+# define LOG(...)\r
+# define LEAVE(...)\r
+#endif\r
+\r
+#define CACHE_FAT      1       //!< Caches the FAT in memory\r
+#define USE_LFN                1       //!< Enables the use of Long File Names\r
+\r
+// === TYPES ===\r
+#if USE_LFN\r
+typedef struct s_lfncache {\r
+       Uint    Inode, Impl;\r
+        int    id;\r
+       char    Name[256];\r
+       struct s_lfncache       *Next;\r
+}      t_lfncache;\r
+#endif\r
+\r
+// === PROTOTYPES ===\r
+ int   FAT_Install(char **Arguments);\r
+tVFS_Node      *FAT_InitDevice(char *device, char *options);\r
+void   FAT_CloseDevice(tVFS_Node *node);\r
+Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
+Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
+char   *FAT_ReadDir(tVFS_Node *dirNode, int dirpos);\r
+tVFS_Node      *FAT_FindDir(tVFS_Node *dirNode, char *file);\r
+ int   FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags);\r
+ int   FAT_Relink(tVFS_Node *node, char *OldName, char *NewName);\r
+void   FAT_CloseFile(tVFS_Node *node);\r
+\r
+// === SEMI-GLOBALS ===\r
+MODULE_DEFINE(0, 0x5B /*v0.90*/, FAT32, FAT_Install, NULL);\r
+tFAT_VolInfo   gFAT_Disks[8];\r
+ int   giFAT_PartCount = 0;\r
+#if CACHE_FAT\r
+Uint32 *fat_cache[8];\r
+#endif\r
+#if USE_LFN\r
+t_lfncache     *fat_lfncache;\r
+#endif\r
+tVFS_Driver    gFAT_FSInfo = {\r
+       "fat", 0, FAT_InitDevice, NULL\r
+       };\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int FAT_Install(char **Arguments)\r
+ * \brief \r
+ */\r
+int FAT_Install(char **Arguments)\r
+{\r
+       VFS_AddDriver( &gFAT_FSInfo );\r
+       return 0;\r
+}\r
+\r
+/* Reads the boot sector of a disk and prepares the structures for it\r
+ */\r
+tVFS_Node *FAT_InitDevice(char *Device, char *options)\r
+{\r
+       fat_bootsect *bs;\r
+        int    i;\r
+       Uint32  FATSz, RootDirSectors, TotSec, CountofClusters;\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
+               Warning("FAT_InitDisk - 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
+               Warning("FAT_InitDisk - Error in FAT Boot Sector\n");\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)            FATSz = bs->fatSz16;\r
+       else                                    FATSz = bs->spec.fat32.fatSz32;\r
+       \r
+       if(bs->totalSect16 != 0)                TotSec = bs->totalSect16;\r
+       else                                            TotSec = bs->totalSect32;\r
+       \r
+       CountofClusters = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
+       \r
+       if(CountofClusters < 4085)\r
+               diskInfo->type = FAT12;\r
+       else if(CountofClusters < 65525)\r
+               diskInfo->type = FAT16;\r
+       else\r
+               diskInfo->type = FAT32;\r
+       \r
+       #if VERBOSE\r
+       {\r
+               char    *sFatType, *sSize;\r
+               Uint    iSize = CountofClusters * bs->spc / 2;\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
+               }\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("[FAT ] '%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
+       }\r
+       #endif\r
+       \r
+       //Get Name\r
+       //puts(" 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
+       //puts(diskInfo->name); putch('\n');\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->clusterCount = CountofClusters;\r
+       \r
+       diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;\r
+       \r
+       //Allow for Caching the FAT\r
+       #if CACHE_FAT\r
+       {\r
+       Uint32  Ofs;\r
+       fat_cache[ giFAT_PartCount ] = (Uint32*)malloc(sizeof(Uint32)*CountofClusters);\r
+       if(fat_cache[giFAT_PartCount] == NULL) {\r
+               Warning("FAT_InitDisk - Heap Exhausted\n");\r
+               return NULL;\r
+       }\r
+       Ofs = bs->resvSectCount*512;\r
+       if(diskInfo->type == FAT12) {\r
+               Uint32  val;\r
+                int    j;\r
+               char    buf[1536];\r
+               for(i=0;i<CountofClusters/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
+                       fat_cache[giFAT_PartCount][i*2] = val & 0xFFF;\r
+                       fat_cache[giFAT_PartCount][i*2+1] = (val>>12) & 0xFFF;\r
+               }\r
+       }\r
+       if(diskInfo->type == FAT16) {\r
+               Uint16  buf[256];\r
+               for(i=0;i<CountofClusters;i++) {\r
+                       if( (i & 255) == 0 ) {\r
+                               VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
+                               Ofs += 512;\r
+                       }\r
+                       fat_cache[giFAT_PartCount][i] = buf[i&255];\r
+               }\r
+       }\r
+       if(diskInfo->type == FAT32) {\r
+               Uint32  buf[128];\r
+               for(i=0;i<CountofClusters;i++) {\r
+                       if( (i & 127) == 0 ) {\r
+                               VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
+                               Ofs += 512;\r
+                       }\r
+                       fat_cache[giFAT_PartCount][i] = buf[i&127];\r
+               }\r
+       }\r
+       DEBUGS(" FAT_InitDisk: FAT Fully Cached\n");\r
+       }\r
+       #endif /*CACHE_FAT*/\r
+       \r
+       //Initalise inode cache for FAT\r
+       gFAT_Disks[giFAT_PartCount].inodeHandle = Inode_GetHandle();\r
+       \r
+       #if DEBUG\r
+               Log(" FAT_InitDisk: Inode Cache handle is %i\n", gFAT_Disks[giFAT_PartCount].inodeHandle);\r
+       #endif\r
+       \r
+       //== VFS Interface\r
+       node = &gFAT_Disks[giFAT_PartCount].rootNode;\r
+       //node->Name = gFAT_Disks[giFAT_PartCount].name;\r
+       node->Inode = diskInfo->rootOffset;\r
+       node->Size = bs->files_in_root; //Unknown - To be set on readdir\r
+       node->ImplInt = giFAT_PartCount;\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->Read = node->Write = NULL;\r
+       node->ReadDir = FAT_ReadDir;\r
+       node->FindDir = FAT_FindDir;\r
+       node->Relink = FAT_Relink;\r
+       node->MkNod = FAT_Mknod;\r
+       node->Close = FAT_CloseDevice;\r
+       \r
+       giFAT_PartCount ++;\r
+       return node;\r
+}\r
+\r
+/**\r
+ * \fn void FAT_CloseDevice(tVFS_Node *node)\r
+ * \brief Closes a mount and marks it as free\r
+ */\r
+void FAT_CloseDevice(tVFS_Node *node)\r
+{\r
+       node->ReferenceCount --;\r
+       \r
+       if(node->ReferenceCount > 0)    return;\r
+       \r
+       // Close Disk Handle\r
+       VFS_Close( gFAT_Disks[node->ImplInt].fileHandle );\r
+       Inode_ClearCache(gFAT_Disks[node->ImplInt].inodeHandle);\r
+       gFAT_Disks[node->ImplInt].fileHandle = -2;\r
+       return;\r
+}\r
+\r
+/**\r
+ * \fn static Uint32 FAT_int_GetFatValue(int handle, Uint32 cluster)\r
+ * \brief Fetches a value from the FAT\r
+ */\r
+static Uint32 FAT_int_GetFatValue(int handle, Uint32 cluster)\r
+{\r
+       Uint32  val;\r
+       ENTER("iHandle xCluster", handle, cluster);\r
+       #if CACHE_FAT\r
+       val = fat_cache[handle][cluster];\r
+       #else\r
+       if(gFAT_Disks[handle].type == FAT12) {\r
+               VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+(cluster&~1)*3, 3, &val);\r
+               val = (cluster&1 ? val&0xFFF : val>>12);\r
+       } else if(gFAT_Disks[handle].type == FAT16) {\r
+               VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+cluster*2, 2, &val);\r
+       } else {\r
+               VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+cluster*4, 4, &val);\r
+       }\r
+       #endif /*CACHE_FAT*/\r
+       LEAVE('x', val);\r
+       return val;\r
+}\r
+\r
+/* Reads a cluster's data\r
+ */\r
+static void FAT_int_ReadCluster(int Handle, Uint32 Cluster, int Length, void *Buffer)\r
+{\r
+       #if DEBUG\r
+       ENTER("iHandle xCluster iLength pBuffer", Handle, Cluster, Length, Buffer);\r
+       #endif\r
+       VFS_ReadAt(\r
+               gFAT_Disks[Handle].fileHandle,\r
+               (gFAT_Disks[Handle].firstDataSect + (Cluster-2)*gFAT_Disks[Handle].bootsect.spc )\r
+                       * gFAT_Disks[Handle].bootsect.bps,\r
+               Length,\r
+               Buffer\r
+               );\r
+       #if DEBUG\r
+       LEAVE('-');\r
+       #endif\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
+        int    handle = node->ImplInt;\r
+        int    i, cluster, pos;\r
+        int    bpc;\r
+       void    *tmpBuf;\r
+       Uint    eocMarker;\r
+       tFAT_VolInfo    *disk = &gFAT_Disks[node->ImplInt];\r
+       \r
+       ENTER("Xoffset Xlength pbuffer", offset, length, buffer);\r
+       \r
+       // Calculate and Allocate Bytes Per Cluster\r
+       bpc = disk->bootsect.spc * disk->bootsect.bps;\r
+       tmpBuf = (void*) malloc(bpc);\r
+       LOG("malloc'd %i bytes", bpc);\r
+       \r
+       // Cluster is stored in Inode Field\r
+       cluster = node->Inode;\r
+       \r
+       // Get EOC Marker\r
+       if     (disk->type == FAT12)    eocMarker = EOC_FAT12;\r
+       else if(disk->type == FAT16)    eocMarker = EOC_FAT16;\r
+       else if(disk->type == FAT32)    eocMarker = EOC_FAT32;\r
+       else {\r
+               Log("ERROR: Unsupported FAT Variant.\n");\r
+               free(tmpBuf);\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       \r
+       // Single Cluster including offset\r
+       if(length + offset < bpc)\r
+       {\r
+               FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
+               memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length );\r
+               free(tmpBuf);\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       preSkip = offset / bpc;\r
+       \r
+       //Skip previous clusters\r
+       for(i=preSkip;i--;)     {\r
+               cluster = FAT_int_GetFatValue(handle, cluster);\r
+               if(cluster == eocMarker) {\r
+                       Warning("FAT_Read - Offset is past end of cluster chain mark");\r
+               }\r
+       }\r
+       \r
+       // Get Count of Clusters to read\r
+       count = ((offset%bpc+length) / bpc) + 1;\r
+       \r
+       // Get buffer Position after 1st cluster\r
+       pos = bpc - offset%bpc;\r
+       \r
+       // Read 1st Cluster\r
+       FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
+       memcpy(\r
+               buffer,\r
+               (void*)( tmpBuf + (bpc-pos) ),\r
+               (pos < length ? pos : length)\r
+               );\r
+       \r
+       if (count == 1) {\r
+               free(tmpBuf);\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       cluster = FAT_int_GetFatValue(handle, cluster);\r
+       \r
+       #if DEBUG\r
+       LOG("pos=%i\n", pos);\r
+       LOG("Reading the rest of the clusters\n");\r
+       #endif\r
+       \r
+       \r
+       //Read the rest of the cluster data\r
+       for( i = 1; i < count-1; i++ )\r
+       {\r
+               FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
+               memcpy((void*)(buffer+pos), tmpBuf, bpc);\r
+               pos += bpc;\r
+               cluster = FAT_int_GetFatValue(handle, cluster);\r
+               if(cluster == eocMarker) {\r
+                       Warning("FAT_Read - Read past End of Cluster Chain");\r
+                       free(tmpBuf);\r
+                       LEAVE('i', 0);\r
+                       return 0;\r
+               }\r
+       }\r
+       \r
+       FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
+       memcpy((void*)(buffer+pos), tmpBuf, length-pos);\r
+       \r
+       #if DEBUG\r
+       LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf);\r
+       #endif\r
+       \r
+       free(tmpBuf);\r
+       LEAVE('X', length);\r
+       return length;\r
+}\r
+\r
+/**\r
+ * \fn Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
+ */\r
+Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
+{\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn static void FAT_int_ProperFilename(char *dest, char *src)\r
+ * \brief Converts a FAT directory entry name into a proper filename\r
+ */\r
+static void FAT_int_ProperFilename(char *dest, char *src)\r
+{\r
+        int    a, b;\r
+       \r
+       for( a = 0; a < 8; a++) {\r
+               if(src[a] == ' ')       break;\r
+               dest[a] = src[a];\r
+       }\r
+       b = a;\r
+       a = 8;\r
+       if(src[8] != ' ')\r
+               dest[b++] = '.';\r
+       for( ; a < 11; a++, b++)        {\r
+               if(src[a] == ' ')       break;\r
+               dest[b] = src[a];\r
+       }\r
+       dest[b] = '\0';\r
+       #if DEBUG\r
+       //Log("FAT_int_ProperFilename: dest='%s'", dest);\r
+       #endif\r
+}\r
+\r
+/**\r
+ * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
+ * \brief Converts either a LFN or a 8.3 Name into a proper name\r
+ */\r
+char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
+{\r
+       char    *ret;\r
+        int    len;\r
+       #if USE_LFN\r
+       if(LongFileName && LongFileName[0] != '\0')\r
+       {       \r
+               len = strlen(LongFileName);\r
+               ret = malloc(len+1);\r
+               strcpy(ret, LongFileName);\r
+       }\r
+       else\r
+       {\r
+       #endif\r
+               ret = (char*) malloc(13);\r
+               memset(ret, 13, '\0');\r
+               FAT_int_ProperFilename(ret, ft->name);\r
+       #if USE_LFN\r
+       }\r
+       #endif\r
+       return ret;\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
+ * \brief Creates a tVFS_Node structure for a given file entry\r
+ */\r
+tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
+{\r
+       tVFS_Node       node = {0};\r
+       tVFS_Node       *ret;\r
+       \r
+       ENTER("pParent pFT sLongFileName", parent, ft, LongFileName);\r
+       \r
+       // Get Name\r
+       //node.Name = FAT_int_CreateName(parent, ft, LongFileName);\r
+       // Set Other Data\r
+       node.Inode = ft->cluster | (ft->clusterHi<<16);\r
+       node.Size = ft->size;\r
+       node.ImplInt = parent->ImplInt;\r
+       node.UID = 0;   node.GID = 0;\r
+       node.NumACLs = 1;\r
+       node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX\r
+       \r
+       node.Flags = 0;\r
+       if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY;\r
+       if(ft->attrib & ATTR_READONLY)  node.Flags |= VFS_FFLAG_READONLY;\r
+       \r
+       node.ATime = timestamp(0,0,0,\r
+                       ((ft->adate&0x1F)-1),   //Days\r
+                       ((ft->adate&0x1E0)-1),          //Months\r
+                       1980+((ft->adate&0xFF00)>>8));  //Years\r
+       \r
+       node.CTime = ft->ctimems * 10;  //Miliseconds\r
+       node.CTime += timestamp(\r
+                       (ft->ctime&0x1F)<<1,    //Seconds\r
+                       ((ft->ctime&0x3F0)>>5), //Minutes\r
+                       ((ft->ctime&0xF800)>>11),       //Hours\r
+                       ((ft->cdate&0x1F)-1),           //Days\r
+                       ((ft->cdate&0x1E0)-1),          //Months\r
+                       1980+((ft->cdate&0xFF00)>>8));  //Years\r
+                       \r
+       node.MTime = timestamp(\r
+                       (ft->mtime&0x1F)<<1,    //Seconds\r
+                       ((ft->mtime&0x3F0)>>5), //Minuites\r
+                       ((ft->mtime&0xF800)>>11),       //Hours\r
+                       ((ft->mdate&0x1F)-1),           //Days\r
+                       ((ft->mdate&0x1E0)-1),          //Months\r
+                       1980+((ft->mdate&0xFF00)>>8));  //Years\r
+       \r
+       if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
+               node.ReadDir = FAT_ReadDir;\r
+               node.FindDir = FAT_FindDir;\r
+               node.MkNod = FAT_Mknod;\r
+       } else {\r
+               node.Read = FAT_Read;\r
+               node.Write = FAT_Write;\r
+       }\r
+       node.Close = FAT_CloseFile;\r
+       node.Relink = FAT_Relink;\r
+       \r
+       ret = Inode_CacheNode(gFAT_Disks[parent->ImplInt].inodeHandle, &node);\r
+       LEAVE('p', ret);\r
+       return ret;\r
+}\r
+\r
+#if USE_LFN\r
+/**\r
+ \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
+ \brief Return pointer to LFN cache entry\r
+ */\r
+char *FAT_int_GetLFN(tVFS_Node *node)\r
+{\r
+       t_lfncache      *tmp;\r
+       tmp = fat_lfncache;\r
+       while(tmp)\r
+       {\r
+               if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt)\r
+                       return tmp->Name;\r
+               tmp = tmp->Next;\r
+       }\r
+       tmp = malloc(sizeof(t_lfncache));\r
+       tmp->Inode = node->Inode;\r
+       tmp->Impl = node->ImplInt;\r
+       memset(tmp->Name, 0, 256);\r
+       \r
+       tmp->Next = fat_lfncache;\r
+       fat_lfncache = tmp;\r
+       \r
+       return tmp->Name;\r
+}\r
+\r
+/**\r
+ \fn void FAT_int_DelLFN(tVFS_Node *node)\r
+ \brief Delete a LFN cache entry\r
+*/\r
+void FAT_int_DelLFN(tVFS_Node *node)\r
+{\r
+       t_lfncache      *tmp;\r
+       \r
+       if(!fat_lfncache)       return;\r
+       \r
+       if(!fat_lfncache->Next)\r
+       {\r
+               tmp = fat_lfncache;\r
+               fat_lfncache = tmp->Next;\r
+               free(tmp);\r
+               return;\r
+       }\r
+       tmp = fat_lfncache;\r
+       while(tmp && tmp->Next)\r
+       {\r
+               if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt)\r
+               {\r
+                       free(tmp->Next);\r
+                       tmp->Next = tmp->Next->Next;\r
+                       return;\r
+               }\r
+               tmp = tmp->Next;\r
+       }\r
+}\r
+#endif\r
+\r
+/**\r
+ \fn char *FAT_ReadDir(tVFS_Node *dirNode, int dirPos)\r
+ \param dirNode        Node structure of directory\r
+ \param dirPos Directory position\r
+**/\r
+char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos)\r
+{\r
+       fat_filetable   fileinfo[16];   //Sizeof=32, 16 per sector\r
+        int    a=0;\r
+       tFAT_VolInfo    *disk = &gFAT_Disks[dirNode->ImplInt&7];\r
+       Uint32  cluster, offset;\r
+        int    preSkip;\r
+       char    *ret;\r
+       #if USE_LFN\r
+       char    *lfn = NULL;\r
+       #endif\r
+       \r
+       ENTER("pDirNode iDirPos", dirNode, dirpos);\r
+       \r
+       // Get Byte Offset and skip\r
+       offset = dirpos * sizeof(fat_filetable);\r
+       preSkip = (offset >> 9) / disk->bootsect.spc;   // >>9 == /512\r
+       cluster = dirNode->Inode;       // Cluster ID\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 previous clusters\r
+               for(a=preSkip;a--;)     {\r
+                       cluster = FAT_int_GetFatValue(dirNode->ImplInt, cluster);\r
+               }\r
+       }\r
+       \r
+       // Check for end of cluster chain\r
+       if((disk->type == FAT12 && cluster == EOC_FAT12)\r
+       || (disk->type == FAT16 && cluster == EOC_FAT16)\r
+       || (disk->type == FAT32 && cluster == EOC_FAT32))\r
+               return NULL;\r
+       \r
+       // Bounds Checking (Used to spot heap overflows)\r
+       if(cluster > disk->clusterCount + 2)\r
+       {\r
+               Warning("FAT_ReadDir - Cluster ID is over cluster count (0x%x>0x%x)",\r
+                       cluster, disk->clusterCount+2);\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       LOG("cluster=0x%x, dirpos=%i\n", cluster, dirpos);\r
+       \r
+       // Compute Offsets\r
+       // - Pre FAT32 cluster base (in sectors)\r
+       if( cluster == disk->rootOffset && disk->type != FAT32 )\r
+               offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc;\r
+       else\r
+       {       // FAT32 cluster base (in sectors)\r
+               offset = disk->firstDataSect;\r
+               offset += (cluster - 2) * disk->bootsect.spc;\r
+       }\r
+       // Sector in cluster\r
+       if(disk->bootsect.spc == 1)\r
+               offset += (dirpos / 16);\r
+       else\r
+               offset += (dirpos / 16) % disk->bootsect.spc;\r
+       // Offset in sector\r
+       a = dirpos & 0xF;\r
+\r
+       LOG("offset=%i, a=%i\n", (Uint)offset, a);\r
+       \r
+       // Read Sector\r
+       VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo);        // Read Dir Data\r
+       \r
+       LOG("name[0] = 0x%x\n", (Uint8)fileinfo[a].name[0]);\r
+       //Check if this is the last entry\r
+       if(fileinfo[a].name[0] == '\0') {\r
+               dirNode->Size = dirpos;\r
+               LOG("End of list\n");\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\n");\r
+               LEAVE('p', VFS_SKIP);\r
+               return VFS_SKIP;        // Skip\r
+       }\r
+       \r
+       #if USE_LFN\r
+       // Get Long File Name Cache\r
+       lfn = FAT_int_GetLFN(dirNode);\r
+       if(fileinfo[a].attrib == ATTR_LFN)\r
+       {\r
+               fat_longfilename        *lfnInfo;\r
+                int    len;\r
+               \r
+               lfnInfo = (fat_longfilename *) &fileinfo[a];\r
+               if(lfnInfo->id & 0x40)  memset(lfn, 0, 256);\r
+               // Get the current length\r
+               len = strlen(lfn);\r
+               \r
+               // Sanity Check (FAT implementations do not allow >255 bytes)\r
+               if(len + 13 > 255)      return VFS_SKIP;\r
+               // Rebase all bytes\r
+               for(a=len+1;a--;)       lfn[a+13] = lfn[a];\r
+               \r
+               // Append new bytes\r
+               lfn[ 0] = lfnInfo->name1[0];    lfn[ 1] = lfnInfo->name1[1];\r
+               lfn[ 2] = lfnInfo->name1[2];    lfn[ 3] = lfnInfo->name1[3];\r
+               lfn[ 4] = lfnInfo->name1[4];    \r
+               lfn[ 5] = lfnInfo->name2[0];    lfn[ 6] = lfnInfo->name2[1];\r
+               lfn[ 7] = lfnInfo->name2[2];    lfn[ 8] = lfnInfo->name2[3];\r
+               lfn[ 9] = lfnInfo->name2[4];    lfn[10] = lfnInfo->name2[5];\r
+               lfn[11] = lfnInfo->name3[0];    lfn[12] = lfnInfo->name3[1];\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 . and ..\r
+       if(fileinfo[a].name[0] == '.') {\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'\n",\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
+       //node = FAT_int_CreateNode(dirNode, &fileinfo[a], lfn);\r
+       ret = FAT_int_CreateName(dirNode, &fileinfo[a], lfn);\r
+       lfn[0] = '\0';\r
+       #else\r
+       //node = FAT_int_CreateNode(dirNode, &fileinfo[a], NULL);\r
+       ret = FAT_int_CreateName(dirNode, &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, char *name)\r
+{\r
+       fat_filetable   fileinfo[16];\r
+       char    tmpName[11];\r
+       #if USE_LFN\r
+       fat_longfilename        *lfnInfo;\r
+       char    *lfn = NULL;\r
+        int    lfnPos=255, lfnId = -1;\r
+       #endif\r
+        int    i=0;\r
+       tVFS_Node       *tmpNode;\r
+       Uint64  diskOffset;\r
+       tFAT_VolInfo    *disk = &gFAT_Disks[node->ImplInt];\r
+       Uint32  dirCluster;\r
+       Uint32  cluster;\r
+       \r
+       ENTER("pnode sname", node, name);\r
+       \r
+       // Fast Returns\r
+       if(!name)       return NULL;\r
+       if(name[0] == '\0')     return NULL;\r
+       \r
+       #if USE_LFN\r
+       lfn = FAT_int_GetLFN(node);\r
+       #endif\r
+       \r
+       dirCluster = node->Inode;\r
+       // Seek to Directory\r
+       if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
+               diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9;\r
+       else\r
+               diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9;\r
+       \r
+       for(;;i++)\r
+       {\r
+               // Load sector\r
+               if((i & 0xF) == 0) {\r
+                       VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo);\r
+                       diskOffset += 512;\r
+               }\r
+               \r
+               //Check if the files are free\r
+               if(fileinfo[i&0xF].name[0] == '\0')     break;          //Free and last\r
+               if(fileinfo[i&0xF].name[0] == '\xE5')   goto loadCluster;       //Free\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 = 255;\r
+                       }\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
+                               memcpy(lfn, lfn+lfnPos+1, 256-lfnPos);\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
+               #endif\r
+                       // Get Real Filename\r
+                       FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
+               \r
+                       LOG("tmpName = '%s'\n", tmpName);\r
+               \r
+                       //Only 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
+                               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
+                                       #if USE_LFN\r
+                                       tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], lfn);\r
+                                       #else\r
+                                       tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], NULL);\r
+                                       #endif\r
+                               }\r
+                               #if USE_LFN\r
+                               lfn[0] = '\0';\r
+                               #endif\r
+                               LEAVE('p', tmpNode);\r
+                               return tmpNode;\r
+                       }\r
+               #if USE_LFN\r
+               }\r
+               #endif\r
+               \r
+       loadCluster:\r
+               //Load Next cluster?\r
+               if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0)\r
+               {\r
+                       if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
+                               continue;\r
+                       dirCluster = FAT_int_GetFatValue(node->ImplInt, dirCluster);\r
+                       diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512;\r
+               }\r
+       }\r
+       \r
+       LEAVE('n');\r
+       return NULL;\r
+}\r
+\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
+       return 0;\r
+}\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
+       if(Node == NULL)        return ;\r
+       \r
+       Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode);\r
+       #if USE_LFN\r
+       if(     !Inode_GetCache(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode)\r
+       &&      Node->Flags & VFS_FFLAG_DIRECTORY)\r
+               FAT_int_DelLFN(Node);\r
+       else    // Get Cache references the node, so dereference it\r
+               Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode);\r
+       #endif\r
+       return ;\r
+}\r
+\r
+/**\r
+ * \fn void fat_install()\r
+ * \brief Add the FAT Filesystem to the VFS\r
+ */\r
+void fat_install()\r
+{\r
+       VFS_AddDriver( &gFAT_FSInfo );\r
+}\r
diff --git a/Kernel/vfs/fs/fs_fat.h b/Kernel/vfs/fs/fs_fat.h
new file mode 100644 (file)
index 0000000..67feb61
--- /dev/null
@@ -0,0 +1,135 @@
+/*\r
+ * Acess2\r
+ * FAT12/16/32 Driver\r
+ * vfs/fs/fs_fat.h\r
+ */\r
+\r
+// === On Disk Structures ===\r
+/**\r
+ \struct fat_bootsect_s\r
+ \brief Bootsector format\r
+*/\r
+struct fat_bootsect_s {\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
+       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
+       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
+       //char  ext[3]; //!< Extention\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 Data. 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
+#define ATTR_READONLY  0x01\r
+#define ATTR_HIDDEN            0x02\r
+#define ATTR_SYSTEM            0x04\r
+#define ATTR_VOLUMEID  0x08\r
+#define ATTR_DIRECTORY 0x10\r
+#define ATTR_ARCHIVE   0x20\r
+#define        ATTR_LFN                (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID)\r
+\r
+/**\r
+ \enum eFatType\r
+ \brief Internal Ids for FAT types\r
+*/\r
+enum eFatType {\r
+//     FAT_NULL,       //!< NULL Entry\r
+       FAT12,  //!< FAT12 Volume\r
+       FAT16,  //!< FAT16 Volume\r
+       FAT32,  //!< FAT32 Volume\r
+//     FAT_LAST        //!< LAST Entry. Unused\r
+};\r
+\r
+#define        EOC_FAT12       0x0FFF\r
+#define        EOC_FAT16       0xFFFF\r
+#define        EOC_FAT32       0x0FFFFFF\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
+        int    fileHandle;     //!< File Handle\r
+        int    type;   //!< FAT Type. See eFatType\r
+       char    name[12];       //!< Volume Name (With NULL Terminator)\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            inodeHandle;    //!< Inode Cache Handle\r
+};\r
+\r
+typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
diff --git a/Kernel/vfs/fs/root.c b/Kernel/vfs/fs/root.c
new file mode 100644 (file)
index 0000000..95e308a
--- /dev/null
@@ -0,0 +1,208 @@
+/* 
+ * AcessMicro VFS
+ * - Root Filesystem Driver
+ */
+#include <vfs.h>
+#include <vfs_ramfs.h>
+
+// === CONSTANTS ===
+#define MAX_FILES      64
+
+// === PROTOTYPES ===
+tVFS_Node      *Root_InitDevice(char *Device, char *Options);
+ int   Root_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
+tVFS_Node      *Root_FindDir(tVFS_Node *Node, 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, void *Buffer);
+tRamFS_File    *Root_int_AllocFile();
+
+// === GLOBALS ===
+tVFS_Driver    gRootFS_Info = {
+       "rootfs", 0, Root_InitDevice,
+       NULL
+};
+tRamFS_File    RootFS_Files[MAX_FILES];
+tVFS_ACL       RootFS_ACLs[3] = {
+       {{0,0}, {0,VFS_PERM_ALL}},      // Owner (Root)
+       {{1,0}, {0,VFS_PERM_ALL}},      // Group (Root)
+       {{0,-1}, {0,VFS_PERM_ALL}}      // World (Nobody)
+};
+
+// === CODE ===
+/**
+ * \fn tVFS_Node *Root_InitDevice(char *Device, char *Options)
+ * \brief Initialise the root filesystem
+ */
+tVFS_Node *Root_InitDevice(char *Device, 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_ACLs;
+       
+       //root->Node.Close = Root_CloseFile;    // Not Needed (It's a RAM Disk!)
+       //root->Node.Relink = Root_RelinkRoot;  // Not Needed (Why relink the root of the tree)
+       root->Node.FindDir = Root_FindDir;
+       root->Node.ReadDir = Root_ReadDir;
+       root->Node.MkNod = Root_MkNod;
+       
+       return &root->Node;
+}
+
+/**
+ * \fn int Root_MkNod(tVFS_Node *Node, char *Name, Uint Flags)
+ * \brief Create an entry in the root directory
+ */
+int Root_MkNod(tVFS_Node *Node, char *Name, Uint Flags)
+{
+       tRamFS_File     *parent = Node->ImplPtr;
+       tRamFS_File     *child = parent->Data.FirstChild;
+       tRamFS_File     *prev = (tRamFS_File *) &parent->Data.FirstChild;
+       
+       Log("Root_MkNod: (Node=%p, Name='%s', Flags=0x%x)", Node, Name, Flags);
+       
+       // Find last child, while we're at it, check for duplication
+       for( ; child; prev = child, child = child->Next )
+       {
+               if(strcmp(child->Name, Name) == 0)      return 0;
+       }
+       
+       child = Root_int_AllocFile();
+       memset(child, 0, sizeof(tRamFS_File));
+       
+       child->Name = malloc(strlen(Name)+1);
+       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 = 0;
+       child->Node.Size = 0;
+       
+       if(Flags & VFS_FFLAG_DIRECTORY)
+       {
+               child->Node.ReadDir = Root_ReadDir;
+               child->Node.FindDir = Root_FindDir;
+               child->Node.MkNod = Root_MkNod;
+       } else {
+               child->Node.Read = Root_Read;
+               child->Node.Write = Root_Write;
+       }
+       
+       prev->Next = child;
+       
+       return 1;
+}
+
+/**
+ * \fn tVFS_Node *Root_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Find an entry in the filesystem
+ */
+tVFS_Node *Root_FindDir(tVFS_Node *Node, 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(Pos) return child->Name;
+       
+       return child->Name;
+}
+
+/**
+ * \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;
+       
+       if(Offset > Node->Size) return 0;
+       if(Length > Node->Size) return 0;
+       
+       if(Offset+Length > Node->Size)
+               Length = Node->Size - Offset;
+       
+       memcpy(Buffer, file->Data.Bytes+Offset, 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, void *Buffer)
+{
+       tRamFS_File     *file = Node->ImplPtr;
+       
+       // 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\n");
+                       return -1;
+               }
+               file->Data.Bytes = tmp;
+               Node->Size = Offset + Length;
+               Log(" Root_Write: Expanded buffer to %i bytes\n", Node->Size);
+       }
+       
+       memcpy(file->Data.Bytes+Offset, Buffer, Length);
+       
+       return Length;
+}
+
+/**
+ * \fn tRamFS_File *Root_int_AllocFile()
+ * \brief Allocates a file from the pool
+ */
+tRamFS_File *Root_int_AllocFile()
+{
+        int    i;
+       for( i = 0; i < MAX_FILES; i ++ )
+       {
+               if( RootFS_Files[i].Name == NULL )
+               {
+                       return &RootFS_Files[i];
+               }
+       }
+       return NULL;
+}
diff --git a/Kernel/vfs/io.c b/Kernel/vfs/io.c
new file mode 100644 (file)
index 0000000..57d3f84
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * AcessMicro VFS
+ * - File IO Passthru's
+ */
+#include <common.h>
+#include "vfs.h"
+#include "vfs_int.h"
+
+#define DEBUG  0
+
+#if DEBUG
+#else
+# undef ENTER
+# undef LOG
+# undef LEAVE
+# define ENTER(...)
+# define LOG(...)
+# define LEAVE(...)
+#endif
+
+// === 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)  return -1;
+       
+       if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY ) {
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       if(!h->Node->Read) {
+               LEAVE('i', 0);
+               return 0;
+       }
+       
+       ret = h->Node->Read(h->Node, h->Position, Length, Buffer);
+       if(ret == -1) {
+               LEAVE('i', -1);
+               return -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->Read) {
+               Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
+               return 0;
+       }
+       ret = h->Node->Read(h->Node, Offset, Length, Buffer);
+       if(ret == -1)   return -1;
+       return ret;
+}
+
+/**
+ * \fn Uint64 VFS_Write(int FD, Uint64 Length, void *Buffer)
+ * \brief Read data from a node (file)
+ */
+Uint64 VFS_Write(int FD, Uint64 Length, 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->Write)     return 0;
+       
+       ret = h->Node->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, void *Buffer)
+ * \brief Write data to a file at a given offset (atomic)
+ */
+Uint64 VFS_WriteAt(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_WRITE) )   return -1;
+       if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
+
+       if(!h->Node->Write)     return 0;
+       ret = h->Node->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 Distance, int Whence)
+ * \brief Seek to a new location
+ * \param FD   File descriptor
+ * \param Distance     Where to go
+ * \param Whence       From where
+ */
+int VFS_Seek(int FD, Sint64 Distance, int Whence)
+{
+       tVFS_Handle     *h;
+       
+       h = VFS_GetHandle(FD);
+       if(!h)  return -1;
+       
+       // Set relative to current position
+       if(Whence == 0) {
+               h->Position += Distance;
+               return 0;
+       }
+       
+       // Set relative to end of file
+       if(Whence < 0) {
+               h->Position = h->Node->Size - Distance;
+               return 0;
+       }
+       
+       // Set relative to start of file
+       h->Position = Distance;
+       return 0;
+}
diff --git a/Kernel/vfs/main.c b/Kernel/vfs/main.c
new file mode 100644 (file)
index 0000000..bfa1fc1
--- /dev/null
@@ -0,0 +1,100 @@
+/* 
+ * Acess 2
+ * Virtual File System
+ */
+#include <common.h>
+#include "vfs.h"
+#include "vfs_int.h"
+#include "vfs_ext.h"
+
+// === IMPORTS ===
+extern tVFS_Driver     gRootFS_Info;
+extern tVFS_Driver     gDevFS_Info;
+
+// === GLOBALS ===
+tVFS_Node      NULLNode = {0};
+static int     siDriverListLock = 0;
+tVFS_Driver    *gVFS_Drivers = NULL;
+
+// === CODE ===
+/**
+ * \fn int VFS_Init()
+ * \brief Initialises the VFS for use by the kernel and user
+ */
+int VFS_Init()
+{
+       // Core Drivers
+       gVFS_Drivers = &gRootFS_Info;
+       gVFS_Drivers->Next = &gDevFS_Info;
+       
+       VFS_Mount("root", "/", "rootfs", "");
+       VFS_MkDir("/Devices");
+       VFS_MkDir("/Mount");
+       VFS_Mount("dev", "/Devices", "devfs", "");
+       
+       CFGINT(CFG_VFS_MAXFILES) = 32;
+       return 0;
+}
+
+/**
+ * \fn char *VFS_GetTruePath(char *Path)
+ * \brief Gets the true path (non-symlink) of a file
+ */
+char *VFS_GetTruePath(char *Path)
+{
+       tVFS_Node       *node;
+       char    *ret;
+       
+       node = VFS_ParsePath(Path, &ret);
+       
+       if(!node)       return NULL;
+       if(node->Close) node->Close(node);
+       
+       return ret;
+}
+
+/**
+ * \fn void VFS_GetMemPath(void *Base, Uint Length, char *Dest)
+ * \brief Create a VFS memory pointer path
+ */
+void VFS_GetMemPath(void *Base, Uint Length, char *Dest)
+{
+       Log("VFS_GetMemPath: (Base=%p, Length=0x%x, Dest=%p)", Base, Length, Dest);
+       Dest[0] = '$';
+       itoa( &Dest[1], (Uint)Base, 16, BITS/4, '0' );
+       Dest[BITS/4+1] = ':';
+       itoa( &Dest[BITS/4+2], Length, 16, BITS/4, '0' );
+       
+       Log("VFS_GetMemPath: Dest = \"%s\"", Dest);
+}
+
+/**
+ * \fn tVFS_Driver *VFS_GetFSByName(char *Name)
+ * \brief Gets a filesystem structure given a name
+ */
+tVFS_Driver *VFS_GetFSByName(char *Name)
+{
+       tVFS_Driver     *drv = gVFS_Drivers;
+       
+       for(;drv;drv=drv->Next)
+       {
+               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;
+       
+       LOCK( &siDriverListLock );
+       Info->Next = gVFS_Drivers;
+       gVFS_Drivers = Info;
+       RELEASE( &siDriverListLock );
+       
+       return 0;
+}
diff --git a/Kernel/vfs/memfile.c b/Kernel/vfs/memfile.c
new file mode 100644 (file)
index 0000000..2fc38e7
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ */
+#include <common.h>
+#include <vfs.h>
+
+// === PROTOTYPES ===
+tVFS_Node      *VFS_MemFile_Create(tVFS_Node *Unused, 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, void *Buffer);
+
+// === GLOBALS ===
+tVFS_Node      gVFS_MemRoot = {
+       .Flags = VFS_FFLAG_DIRECTORY,
+       .NumACLs = 0,
+       .FindDir = VFS_MemFile_Create
+       };
+
+// === CODE ===
+/**
+ * \fn tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, char *Path)
+ * \note Treated as finddir by VFS_ParsePath
+ */
+tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, char *Path)
+{
+       Uint    base, size;
+       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;
+       
+       Log(" VFS_MemFile_Create: base=0x%x, size=0x%x", base, size);
+       
+       // 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->Close = VFS_MemFile_Close;
+       ret->Read = VFS_MemFile_Read;
+       ret->Write = VFS_MemFile_Write;
+       
+       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, 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, 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(Node->ImplPtr+Offset, Buffer, Length);
+       
+       return Length;
+}
diff --git a/Kernel/vfs/mount.c b/Kernel/vfs/mount.c
new file mode 100644 (file)
index 0000000..f49c721
--- /dev/null
@@ -0,0 +1,81 @@
+/* 
+ * Acess Micro - VFS Server version 1
+ */
+#include <common.h>
+#include <vfs.h>
+#include <vfs_int.h>
+
+// === GLOBALS ===
+ int   glVFS_MountList = 0;
+tVFS_Mount     *gMounts;
+tVFS_Mount     *gRootMount = NULL;
+
+// === CODE ===
+/**
+ * \fn int VFS_Mount(char *Device, char *MountPoint, char *Filesystem, char *ArgString)
+ * \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 ArgString            Options to be passed to the filesystem
+ * \return -1 on Invalid FS, -2 on No Mem, 0 on success
+ */
+int VFS_Mount(char *Device, char *MountPoint, char *Filesystem, char *ArgString)
+{
+       tVFS_Mount      *mnt;
+       tVFS_Driver     *fs;
+        int    deviceLen = strlen(Device);
+        int    mountLen = strlen(MountPoint);
+        int    argLen = strlen(ArgString);
+       
+       // Get the filesystem
+       fs = VFS_GetFSByName(Filesystem);
+       if(!fs) {
+               Warning("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, ArgString, argLen+1 );
+       
+       // Initialise Volume
+       mnt->RootNode = fs->InitDevice(Device, ArgString);
+       if(!mnt->RootNode) {
+               free(mnt);
+               return -2;
+       }
+       
+       // Set root
+       if(!gRootMount) gRootMount = mnt;
+       
+       // Add to mount list
+       LOCK( &glVFS_MountList );
+       mnt->Next = gMounts;
+       gMounts = mnt;
+       RELEASE( &glVFS_MountList );
+       
+       Log("VFS_Mount: Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
+       
+       return 0;
+}
diff --git a/Kernel/vfs/nodecache.c b/Kernel/vfs/nodecache.c
new file mode 100644 (file)
index 0000000..983f3f7
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * AcessMicro VFS
+ * - File IO Passthru's
+ */
+#include <common.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;
+ int   gilVFS_InodeCache = 0;
+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
+       LOCK( &gilVFS_InodeCache );
+       ent->Next = gVFS_InodeCache;
+       gVFS_InodeCache = ent;
+       RELEASE( &gilVFS_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;
+       }
+}
+
+/**
+ * \fn void Inode_ClearCache(int Handle)
+ * \brief Removes a cache
+ */
+void Inode_ClearCache(int Handle)
+{
+       tInodeCache     *cache;
+       tInodeCache     *prev = (tInodeCache*) &gVFS_InodeCache;
+       tCachedInode    *ent, *next;
+       
+       cache = Inode_int_GetFSCache(Handle);
+       if(!cache)      return;
+       
+       // Search Cache
+       ent = cache->FirstNode;
+       while( ent )
+       {
+               ent->Node.ReferenceCount = 1;
+               next = ent->Next;
+               
+               if(ent->Node.Close)
+                       ent->Node.Close( &ent->Node );
+               free(ent);
+               
+               ent = next;
+       }
+       
+       // Free Cache
+       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
new file mode 100644 (file)
index 0000000..f025e0d
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * AcessMicro VFS
+ * - Open, Close and ChDir
+ */
+#include <common.h>
+#include "vfs.h"
+#include "vfs_int.h"
+#include "vfs_ext.h"
+
+#define DEBUG  0
+
+#if DEBUG
+#else
+# undef ENTER
+# undef LOG
+# undef LEAVE
+# define ENTER(...)
+# define LOG(...)
+# define LEAVE(...)
+#endif
+
+// === CONSTANTS ===
+#define        OPEN_MOUNT_ROOT 1
+#define MAX_KERNEL_FILES       128
+
+// === IMPORTS ===
+extern tVFS_Node       gVFS_MemRoot;
+extern tVFS_Mount      *gRootMount;
+
+// === GLOBALS ===
+tVFS_Handle    *gaUserHandles = (void*)MM_PPD_VFS;
+tVFS_Handle    *gaKernelHandles = (void*)MM_KERNEL_VFS;
+
+// === CODE ===
+/**
+ * \fn char *VFS_GetAbsPath(char *Path)
+ * \brief Create an absolute path from a relative one
+ */
+char *VFS_GetAbsPath(char *Path)
+{
+       char    *ret;
+        int    pathLen = strlen(Path);
+        int    read, write;
+        int    pos, slashNum=0, baseLen;
+       Uint    slashOffsets[256];
+       char    *cwd = CFGPTR(CFG_VFS_CWD);
+        int    cwdLen;
+       
+       ENTER("sPath", Path);
+       
+       // Memory File
+       if(Path[0] == '$') {
+               ret = malloc(strlen(Path)+1);
+               strcpy(ret, Path);
+               LEAVE('p', ret);
+               return ret;
+       }
+       
+       // Check if the path is already absolute
+       if(Path[0] == '/') {
+               ret = malloc(pathLen + 1);
+               strcpy(ret, Path);
+               baseLen = 1;
+       } else {
+               cwdLen = strlen(cwd);
+               // Prepend the current directory
+               ret = malloc(cwdLen+pathLen+1);
+               strcpy(ret, cwd);
+               strcpy(&ret[cwdLen], Path);
+       
+               // Pre-fill the slash positions
+               pos = 0;
+               while( (pos = strpos( &ret[pos+1], '/' )) != -1 )
+                       slashOffsets[slashNum++] = pos;
+                       
+               baseLen = cwdLen;
+       }
+       
+       // Remove . and ..
+       read = write = baseLen; // Cwd has already been parsed
+       for(; read < baseLen+pathLen; read = pos+1)
+       {
+               pos = strpos( &ret[read], '/' );
+               // If we are in the last section, force a break at the end of the itteration
+               if(pos == -1)   pos = baseLen+pathLen;
+               else    pos += read;    // Else, Adjust to absolute
+               
+               // Check Length
+               if(pos - read <= 2)
+               {
+                       // Current Dir "."
+                       if(strncmp(&ret[read], ".", pos-read) == 0)     continue;
+                       // Parent ".."
+                       if(strncmp(&ret[read], "..", pos-read) == 0)
+                       {
+                               // If there is no higher, silently ignore
+                               if(!slashNum)   continue;
+                               // Reverse write pointer
+                               write = slashOffsets[ slashNum-- ];
+                               continue;
+                       }
+               }
+               
+               
+               // Only copy if the positions differ
+               if(read != write) {
+                       memcpy( &ret[write], &ret[read], pos-read+1 );
+               }
+               write = pos+1;
+               if(slashNum < 256)
+                       slashOffsets[ slashNum++ ] = pos;
+               else {
+                       LOG("Path '%s' has too many elements", Path);
+                       free(ret);
+                       LEAVE('n');
+                       return NULL;
+               }
+       }
+       
+       // `ret` should now be the absolute path
+       LEAVE('s', ret);
+       return ret;
+}
+
+/**
+ * \fn char *VFS_ParsePath(char *Path, char **TruePath)
+ * \brief Parses a path, resolving sysmlinks and applying permissions
+ */
+tVFS_Node *VFS_ParsePath(char *Path, char **TruePath)
+{
+       tVFS_Mount      *mnt;
+       tVFS_Mount      *longestMount = gRootMount;     // Root is first
+        int    cmp, retLength = 0;
+        int    ofs, nextSlash;
+       tVFS_Node       *curNode, *tmpNode;
+       char    *tmp;
+       
+       ENTER("sPath pTruePath", Path, TruePath);
+       
+       // Memory File
+       if(Path[0] == '$') {
+               if(TruePath) {
+                       *TruePath = malloc(strlen(Path)+1);
+                       strcpy(*TruePath, Path);
+               }
+               curNode = gVFS_MemRoot.FindDir(&gVFS_MemRoot, Path);
+               LEAVE('p', curNode);
+               return curNode;
+       }
+       // For root we always fast return
+       
+       if(Path[0] == '/' && Path[1] == '\0') {
+               if(TruePath) {
+                       *TruePath = malloc( gRootMount->MountPointLen+1 );
+                       strcpy(*TruePath, gRootMount->MountPoint);
+               }
+               LEAVE('p', gRootMount->RootNode);
+               return gRootMount->RootNode;
+       }
+       
+       // Check if there is anything mounted
+       if(!gMounts)    return NULL;
+       
+       // Find Mountpoint
+       for(mnt = gMounts;
+               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);
+                       }
+                       LEAVE('p', mnt->RootNode);
+                       return mnt->RootNode;
+               }
+               #endif
+               // Not a match, continue
+               if(cmp != '/')  continue;
+               longestMount = mnt;
+       }
+       
+       // Sanity Check
+       /*if(!longestMount) {
+               Log("VFS_GetTruePath - ERROR: No Root Node\n");
+               return NULL;
+       }*/
+       
+       // Save to shorter variable
+       mnt = longestMount;
+       
+       LOG("mnt = {MountPoint:\"%s\"}", mnt->MountPoint);
+       
+       // Initialise String
+       if(TruePath)
+       {
+               *TruePath = malloc( mnt->MountPointLen+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; Path[nextSlash]='/',ofs = nextSlash + 1)
+       {
+               nextSlash += ofs;
+               Path[nextSlash] = '\0';
+       
+               // Check for empty string
+               if( Path[ofs] == '\0' ) continue;
+       
+               // Check permissions on root of filesystem
+               if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
+                       curNode->Close( curNode );
+                       if(TruePath)    free(*TruePath);
+                       LEAVE('n');
+                       return NULL;
+               }
+               
+               // Check if the node has a FindDir method
+               if(!curNode->FindDir) {
+                       if(curNode->Close)      curNode->Close(curNode);
+                       if(TruePath)    free(*TruePath);
+                       Path[nextSlash] = '/';
+                       LEAVE('n');
+                       return NULL;
+               }
+               LOG("FindDir(%p, '%s')", curNode, &Path[ofs]);
+               // Get Child Node
+               tmpNode = curNode->FindDir(curNode, &Path[ofs]);
+               LOG("tmpNode = %p", tmpNode);
+               if(curNode->Close)
+                       curNode->Close(curNode);
+               curNode = tmpNode;
+               
+               // Error Check
+               if(!curNode) {
+                       LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
+                       if(TruePath)
+                               free(*TruePath);
+                       Path[nextSlash] = '/';
+                       LEAVE('n');
+                       return NULL;
+               }
+               
+               // Handle Symbolic Links
+               if(curNode->Flags & VFS_FFLAG_SYMLINK) {
+                       if(TruePath)
+                               free(*TruePath);
+                       tmp = malloc( curNode->Size + 1 );
+                       curNode->Read( curNode, 0, curNode->Size, tmp );
+                       tmp[ curNode->Size ] = '\0';
+                       
+                       // Parse Symlink Path
+                       curNode = VFS_ParsePath(tmp, TruePath);
+                       free(tmp);      // Free temp string
+                       
+                       // Error Check
+                       if(!curNode) {
+                               LEAVE('n');
+                               return NULL;
+                       }
+                       
+                       // Set Path Variable
+                       if(TruePath) {
+                               *TruePath = tmp;
+                               retLength = strlen(tmp);
+                       }
+                       
+                       continue;
+               }
+               
+               // Handle Non-Directories
+               if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) )
+               {
+                       Warning("VFS_ParsePath - File in directory context");
+                       if(TruePath)    free(*TruePath);
+                       LEAVE('n');
+                       return NULL;
+               }
+               
+               // Check if path needs extending
+               if(!TruePath)   continue;
+               
+               // Increase buffer space
+               tmp = realloc( *TruePath, retLength + strlen(&Path[ofs]) + 1 + 1 );
+               // Check if allocation succeeded
+               if(!tmp) {
+                       Warning("VFS_ParsePath -  Unable to reallocate true path buffer");
+                       free(*TruePath);
+                       if(curNode->Close)      curNode->Close(curNode);
+                       LEAVE('n');
+                       return NULL;
+               }
+               *TruePath = tmp;
+               // Append to path
+               (*TruePath)[retLength] = '/';
+               strcpy(*TruePath+retLength+1, &Path[ofs]);
+               // - Extend Path
+               retLength += strlen(&Path[ofs])+1;
+       }
+       
+       // Get last node
+       LOG("VFS_ParsePath: FindDir(%p, '%s')", curNode, &Path[ofs]);
+       tmpNode = curNode->FindDir(curNode, &Path[ofs]);
+       LOG("tmpNode = %p", tmpNode);
+       if(curNode->Close)      curNode->Close(curNode);
+       // Check if file was found
+       if(!tmpNode) {
+               LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
+               if(TruePath)    free(*TruePath);
+               if(curNode->Close)      curNode->Close(curNode);
+               LEAVE('n');
+               return NULL;
+       }
+       
+       if(TruePath)
+       {
+               // Increase buffer space
+               tmp = realloc(*TruePath, retLength + strlen(&Path[ofs]) + 1 + 1);
+               // Check if allocation succeeded
+               if(!tmp) {
+                       Warning("VFS_ParsePath -  Unable to reallocate true path buffer");
+                       free(*TruePath);
+                       if(tmpNode->Close)      tmpNode->Close(curNode);
+                       LEAVE('n');
+                       return NULL;
+               }
+               *TruePath = tmp;
+               // Append to path
+               (*TruePath)[retLength] = '/';
+               strcpy(*TruePath + retLength + 1, &Path[ofs]);
+               // - Extend Path
+               //retLength += strlen(tmpNode->Name) + 1;
+       }
+       
+       LEAVE('p', tmpNode);
+       return tmpNode;
+}
+
+/**
+ * \fn int VFS_Open(char *Path, Uint Mode)
+ * \brief Open a file
+ */
+int VFS_Open(char *Path, Uint Mode)
+{
+       tVFS_Node       *node;
+       char    *absPath;
+        int    i;
+       
+       ENTER("sPath xMode", Path, Mode);
+       
+       // Get absolute path
+       absPath = VFS_GetAbsPath(Path);
+       LOG("absPath = \"%s\"", absPath);
+       // Parse path and get mount point
+       node = VFS_ParsePath(absPath, NULL);
+       // Free generated path
+       free(absPath);
+       
+       if(!node) {
+               LOG("Cannot find node");
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       // Check for symlinks
+       if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
+       {
+               if( !node->Read ) {
+                       LOG("No read method on symlink");
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               absPath = malloc(node->Size+1); // Allocate Buffer
+               node->Read( node, 0, node->Size, absPath );     // Read Path
+               
+               absPath[ node->Size ] = '\0';   // End String
+               if(node->Close) node->Close( node );    // Close old node
+               node = VFS_ParsePath(absPath, NULL);    // Get new node
+               free( absPath );        // Free allocated path
+       }
+       
+       if(!node) {
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       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) ) {
+               node->Close( node );
+               LEAVE('i', -1);
+               return -1;
+       }
+       
+       // Check for a user open
+       if(Mode & VFS_OPENFLAG_USER)
+       {
+               // Allocate Buffer
+               if( MM_GetPhysAddr( (Uint)gaUserHandles ) == 0 )
+               {
+                       Uint    addr, size;
+                       size = CFGINT(CFG_VFS_MAXFILES) * sizeof(tVFS_Handle);
+                       for(addr = 0; addr < size; addr += 0x1000)
+                               MM_Allocate( (Uint)gaUserHandles + addr );
+                       memset( gaUserHandles, 0, size );
+               }
+               // Get a handle
+               for(i=0;i<CFGINT(CFG_VFS_MAXFILES);i++)
+               {
+                       if(gaUserHandles[i].Node)       continue;
+                       gaUserHandles[i].Node = node;
+                       gaUserHandles[i].Position = 0;
+                       gaUserHandles[i].Mode = Mode;
+                       LEAVE('i', i);
+                       return i;
+               }
+       }
+       else
+       {
+               // Allocate space if not already
+               if( MM_GetPhysAddr( (Uint)gaKernelHandles ) == 0 )
+               {
+                       Uint    addr, size;
+                       size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
+                       for(addr = 0; addr < size; addr += 0x1000)
+                               MM_Allocate( (Uint)gaKernelHandles + addr );
+                       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;
+                       LEAVE('x', i|VFS_KERNEL_FLAG);
+                       return i|VFS_KERNEL_FLAG;
+               }
+       }
+       
+       LEAVE('i', -1);
+       return -1;
+}
+
+/**
+ * \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) {
+               Warning("Invalid file handle passed to VFS_Close, 0x%x\n", FD);
+               return;
+       }
+       
+       if(h->Node->Close)
+               h->Node->Close( h->Node );
+       
+       h->Node = NULL;
+}
+
+/**
+ * \fn tVFS_Handle *VFS_GetHandle(int FD)
+ * \brief Gets a pointer to the handle information structure
+ */
+tVFS_Handle *VFS_GetHandle(int FD)
+{
+       if(FD < 0)      return NULL;
+       
+       if(FD & VFS_KERNEL_FLAG) {
+               FD &= (VFS_KERNEL_FLAG - 1);
+               if(FD >= MAX_KERNEL_FILES)      return NULL;
+               return &gaKernelHandles[ FD ];
+       } else {
+               if(FD >= CFGINT(CFG_VFS_MAXFILES))      return NULL;
+               return &gaUserHandles[ FD ];
+       }
+}

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