SAVED_CC_ := $(CC)
SAVED_LD_ := $(LD)
-include $(ACESSDIR)/BuildConf/x86_64/Makefile.cfg
+include $(ACESSDIR)/BuildConf/$(HOST_ARCH)/Makefile.cfg
OBJDUMP := objdump -S
-CC := $(SAVED_CC_)
-LD := $(SAVED_LD_)
+CC_SUFFIX =
+
+ifeq ($(HOST_ARCH),x86)
+CC_SUFFIX := -m32
+LD_SUFFIX := -melf_i386
+endif
+
+CC := $(SAVED_CC_) $(CC_SUFFIX)
+LD := $(SAVED_LD_) $(LD_SUFFIX)
MODULES += Display/BochsGA
MODULES += Input/PS2KbMouse
MODULES += x86/ISADMA x86/VGAText
-MODULES += USB/Core USB/UHCI
+#MODULES += USB/Core USB/UHCI
#MODULES += Interfaces/UDI
--- /dev/null
+#!/bin/sh
+
+# NOTE: This is rather specific to my setup :)
+
+REL_DOT=`grep 'ACESS_VERSION =' Makefile.Version.cfg | sed -r 's/.*([0-9]+\.[0-9]+).*/\1/'`
+REL=`echo $REL_DOT | sed -r 's/\.//g'`
+
+_RELDIR=/serenade/http/www/Downloads/Acess2/
+
+./MakeReleaseSet x86 smp
+./MakeReleaseSet x86_64
+./MakeReleaseSet armv7 tegra2
+
+for arch in x86 x86_64 armv7; do
+ cp Releases/Acess2_latest_${arch}-bin.tar.gz ${_RELDIR}Acess2_${REL}_${arch}-bin.tar.gz
+ cp Releases/Acess2_latest_${arch}.img.gz ${_RELDIR}Acess2_${REL}_${arch}.img.gz
+done
+
+git archive --format=tar --prefix=Acess2/ HEAD | gzip > ${_RELDIR}Acess2_git.tar.gz
+git tag rel${REL_DOT}
+
+cd ${_RELDIR}
+cp Acess2_git.tar.gz Acess2_${REL}.tar.gz
+rm Acess2.img.gz; ln -s Acess2_${REL}_x86.img.gz Acess2.img.gz
+rm Acess2.tar.gz; ln -s Acess2_${REL}.tar.gz Acess2.tar.gz
OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
OBJ += messages.o modules.o syscalls.o system.o
-OBJ += threads.o mutex.o semaphore.o workqueue.o
-OBJ += drv/vterm.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
+OBJ += drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
OBJ += binary.o bin/elf.o bin/pe.o
OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o
all: $(BIN)
clean:
-# $(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt $(OBJ) $(DEPFILES)
- @$(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt -r $(OBJDIR) $(OBJ) $(DEPFILES) $(BUILDINFO_SRC)
+ @$(RM) $(BIN) ../Acess2.$(ARCH).gz $(BIN).dsm ../Map.$(ARCH).txt LineCounts.$(ARCH).txt
+ @$(RM) -r $(OBJDIR) $(OBJ) $(DEPFILES) $(BUILDINFO_SRC)
install: $(BIN)
- cp $(BIN) $(BIN)_
- $(STRIP) $(BIN)_
- gzip -c $(BIN)_ > $(GZBIN)
- $(RM) $(BIN)_
+ @cp $(BIN) $(BIN)_
+ @$(STRIP) $(BIN)_
+ @gzip -c $(BIN)_ > $(GZBIN)
+ @$(RM) $(BIN)_
$(xCP) $(GZBIN) $(DISTROOT)
apidoc:
doxygen Doxyfile.api
-$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
+$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile ../BuildConf/$(ARCH)/Makefile.cfg ../BuildConf/$(ARCH)/$(PLATFORM).mk
@echo --- LD -o $(BIN)
@$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
@$(DISASM) -S $(BIN) > $(BIN).dsm
{
if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
{
- Debug("%p => %8s - 0x%7x %i %x",
+ Debug("%p => %8s - 0x%7x %i %x %s",
Start, "ZERO", Len,
- Info->Domain, Info->AP
+ Info->Domain, Info->AP,
+ Info->bGlobal ? "G" : "nG"
);
}
else
{
- Debug("%p => %8x - 0x%7x %i %x",
+ Debug("%p => %8x - 0x%7x %i %x %s",
Start, Info->PhysAddr-Len, Len,
- Info->Domain, Info->AP
+ Info->Domain, Info->AP,
+ Info->bGlobal ? "G" : "nG"
);
}
}
tMM_PageInfo pi, pi_old;
int i = 0, inRange=0;
- pi_old.Size = 0;
- pi_old.AP = 0;
- pi_old.PhysAddr = 0;
+ memset(&pi_old, 0, sizeof(pi_old));
Debug("Page Table Dump (%p to %p):", Start, End);
range_start = Start;
|| pi.Size != pi_old.Size
|| pi.Domain != pi_old.Domain
|| pi.AP != pi_old.AP
+ || pi.bGlobal != pi_old.bGlobal
|| pi_old.PhysAddr != pi.PhysAddr )
{
if(inRange) {
// === IMPORTS ===
extern tThread gThreadZero;
+extern tProcess gProcessZero;
extern void SwitchTask(Uint32 NewSP, Uint32 *OldSP, Uint32 NewIP, Uint32 *OldIP, Uint32 MemPtr);
extern void KernelThreadHeader(void); // Actually takes args on stack
extern void Proc_int_DropToUser(Uint32 IP, Uint32 SP) NORETURN __attribute__((long_call));
// === CODE ===
void ArchThreads_Init(void)
{
- gThreadZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
+ gProcessZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
}
void Proc_IdleThread(void *unused)
return gpCurrentThread;
}
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
{
Uint32 *usr_sp;
int i;
- char **envp;
+ const char **envp;
tVAddr delta;
// Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
}
-void Proc_ClearThread(tThread *Thread)
+void Proc_ClearProcess(tProcess *Process)
{
Log_Warning("Proc", "TODO: Nuke address space etc");
}
+void Proc_ClearThread(tThread *Thread)
+{
+}
+
tTID Proc_Clone(Uint Flags)
{
tThread *new;
new->SavedState.SP = sp;
new->SavedState.UserSP = Proc_int_SwapUserSP(0);
new->SavedState.UserIP = Proc_GetCurThread()->SavedState.UserIP;
- new->MemState.Base = mem;
+ new->Process->MemState.Base = mem;
Threads_AddActive(new);
return new->TID;
}
-tTID Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
{
tThread *new;
Uint32 sp;
Log("Switching to %p (%i %s) IP=%p SP=%p TTBR0=%p UsrSP=%p",
next, next->TID, next->ThreadName,
- next->SavedState.IP, next->SavedState.SP, next->MemState.Base,
+ next->SavedState.IP, next->SavedState.SP, next->Process->MemState.Base,
next->SavedState.UserSP
);
SwitchTask(
next->SavedState.SP, &cur->SavedState.SP,
next->SavedState.IP, &cur->SavedState.IP,
- next->MemState.Base
+ next->Process->MemState.Base
);
}
push eax ; Line up with interrupt number
mov eax, dr1 ; CPU Number
push eax
- mov eax, [esp-4] ; Load EAX back
+ mov eax, [esp+4] ; Load EAX back
jmp SchedulerBase
; Spurious Interrupt
[global Isr0xEF]
popa
add esp, 8 ; Error Code and ID
iret
+
+; vim: ft=nasm ts=8
}
// Check if it's a user mode fault
- if( Regs->eip < KERNEL_BASE || (Regs->cs & 3) == 3 ) {
+ if( (Regs->cs & 3) == 3 ) {
Log_Warning("Arch", "User Fault - %s, Code: 0x%x",
csaERROR_NAMES[Regs->int_num], Regs->err_code);
Log_Warning("Arch", "at CS:EIP %04x:%08x",
Debug_KernelPanic();
- LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x",
+ LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x\n",
GetCPUNum(),
Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code,
Regs->eip);
{
case 6: // #UD
Warning(" Offending bytes: %02x %02x %02x %02x",
- *(Uint8*)Regs->eip+0, *(Uint8*)Regs->eip+1,
- *(Uint8*)Regs->eip+2, *(Uint8*)Regs->eip+3);
+ *(Uint8*)(Regs->eip+0), *(Uint8*)(Regs->eip+1),
+ *(Uint8*)(Regs->eip+2), *(Uint8*)(Regs->eip+3));
break;
}
void Error_Backtrace(Uint eip, Uint ebp)
{
int i = 0;
- Uint delta = 0;
- char *str = NULL;
+// Uint delta = 0;
+// char *str = NULL;
//if(eip < 0xC0000000 && eip > 0x1000)
//{
// LogF("Backtrace: User - 0x%x\n", eip);
// return;
//}
-
+
+ #if 0
if(eip > 0xE0000000)
{
LogF("Backtrace: Data Area - 0x%x\n", eip);
LogF("Backtrace: Kernel Module - 0x%x\n", eip);
return;
}
-
+ #endif
+
//str = Debug_GetSymbol(eip, &delta);
- if(str == NULL)
+// if(str == NULL)
LogF("Backtrace: 0x%x", eip);
- else
- LogF("Backtrace: %s+0x%x", str, delta);
+// else
+// LogF("Backtrace: %s+0x%x", str, delta);
if(!MM_GetPhysAddr(ebp))
{
LogF("\nBacktrace: Invalid EBP, stopping\n");
{
if( ebp >= MM_KERNEL_STACKS_END ) break;
//str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
- if(str == NULL)
+// if(str == NULL)
LogF(" >> 0x%x", *(Uint*)(ebp+4));
- else
- LogF(" >> %s+0x%x", str, delta);
+// else
+// LogF(" >> %s+0x%x", str, delta);
ebp = *(Uint*)ebp;
i++;
}
/*
* Acess2
* - x86 Architecture
- * arch/i386/include/arch.h
+ * arch/x86/include/arch.h
*/
#ifndef _ARCH_H_
#define _ARCH_H_
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * x86 Arch - Internal Definitions
+ * - arch/x86/include/arch_int.h
+ */
+#ifndef _ARCH_INT_H_
+#define _ARCH_INT_H_
+
+/**
+ * \brief Spinlock primative atomic set-if-zero loop
+ */
+extern void __AtomicTestSetLoop(Uint *Ptr, Uint Value);
+
+/**
+ * \brief Clear and free an address space
+ */
+extern void MM_ClearSpace(Uint32 CR3);
+
+#endif
+
// === FUNCTIONS ===
extern void MM_FinishVirtualInit(void);
extern void MM_SetCR3(Uint CR3);
-extern tPAddr MM_Clone(void);
+extern tPAddr MM_Clone(int bCloneUser);
extern tVAddr MM_NewKStack(void);
extern tVAddr MM_NewWorkerStack(Uint *InitialStack, size_t StackSize);
*/
#include <acess.h>
#include <threads_int.h>
+#include <arch_int.h>
+#include <hal_proc.h> // GetCPUNum
#define TRACE_LOCKS 0
// === IMPRORTS ===
#if TRACE_LOCKS
extern struct sShortSpinlock glDebug_Lock;
-extern struct sShortSpinlock glThreadListLock;
+extern tMutex glPhysAlloc;
+#define TRACE_LOCK_COND (Lock != &glDebug_Lock && Lock != &glThreadListLock && Lock != &glPhysAlloc.Protector)
+//#define TRACE_LOCK_COND (Lock != &glDebug_Lock && Lock != &glPhysAlloc.Protector)
#endif
-extern int GetCPUNum(void);
// === PROTOTYPES ==
Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
return Lock->Lock == GetCPUNum() + 1;
}
+void __AtomicTestSetLoop(Uint *Ptr, Uint Value)
+{
+ __ASM__(
+ "1:\n\t"
+ "xor %%eax, %%eax;\n\t"
+ "lock cmpxchgl %0, (%1);\n\t"
+ "jnz 1b;\n\t"
+ :: "r"(Value), "r"(Ptr)
+ : "eax" // EAX clobbered
+ );
+}
/**
* \brief Acquire a Short Spinlock
* \param Lock Lock pointer
*/
void SHORTLOCK(struct sShortSpinlock *Lock)
{
- int v = 1;
int IF;
int cpu = GetCPUNum() + 1;
IF &= 0x200; // AND out all but the interrupt flag
#if TRACE_LOCKS
- if( Lock != &glDebug_Lock && Lock != &glThreadListLock )
+ if( TRACE_LOCK_COND )
{
//Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
- Debug("%p obtaining %p (Called by %p)", __builtin_return_address(0), Lock, __builtin_return_address(1));
+ Debug("%i %p obtaining %p (Called by %p)", cpu-1, __builtin_return_address(0), Lock, __builtin_return_address(1));
}
#endif
__ASM__("cli");
// Wait for another CPU to release
- __ASM__(
- "1: lock cmpxchgl %2, (%3)\n\t"
- "jnz 1b"
- : "=a"(v)
- : "a"(0), "r"(cpu), "r"(&Lock->Lock)
- );
-
+ __AtomicTestSetLoop( (Uint*)&Lock->Lock, cpu );
Lock->IF = IF;
#if TRACE_LOCKS
- if( Lock != &glDebug_Lock && Lock != &glThreadListLock )
+ if( TRACE_LOCK_COND )
{
//Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
- //Debug("Lock %p locked by %p\t%p", Lock, __builtin_return_address(0), __builtin_return_address(1));
- Debug("got it");
+ Debug("%i %p locked by %p\t%p", cpu-1, Lock, __builtin_return_address(0), __builtin_return_address(1));
+// Debug("got it");
}
#endif
}
void SHORTREL(struct sShortSpinlock *Lock)
{
#if TRACE_LOCKS
- if( Lock != &glDebug_Lock && Lock != &glThreadListLock )
+ if( TRACE_LOCK_COND )
{
//Log_Log("LOCK", "%p released by %p", Lock, __builtin_return_address(0));
Debug("Lock %p released by %p\t%p", Lock, __builtin_return_address(0), __builtin_return_address(1));
int first, last;
for( i = numAddrClasses; i -- > 1; )
{
- first = 1 << (addrClasses[i-1] - 12);
- last = (1 << (addrClasses[i] - 12)) - 1;
+ first = 1UL << (addrClasses[i-1] - 12);
+ last = (1UL << (addrClasses[i] - 12)) - 1;
// Range is above the last free page
if( first > giLastPossibleFree )
continue;
#include <mm_phys.h>
#include <proc.h>
#include <hal_proc.h>
+#include <arch_int.h>
#define TAB 22
#define INVLPG(addr) __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
+#define GET_TEMP_MAPPING(cr3) do { \
+ __ASM__("cli"); \
+ __AtomicTestSetLoop( (Uint *)gpTmpCR3, cr3 | 3 ); \
+} while(0)
+#define REL_TEMP_MAPPING() do { \
+ *gpTmpCR3 = 0; \
+ __ASM__("sti"); \
+} while(0)
+
typedef Uint32 tTabEnt;
// === IMPORTS ===
for( i = ((tVAddr)&_UsertextEnd-(tVAddr)&_UsertextBase+0xFFF)/4096; i--; ) {
MM_SetFlags( (tVAddr)&_UsertextBase + i*4096, 0, MM_PFLAG_KERNEL );
}
+
+ *gpTmpCR3 = 0;
}
/**
INVLPG( Addr & ~0xFFF );
return;
}
-
- __asm__ __volatile__ ("pushf; andw $0xFEFF, 0(%esp); popf");
+
+ // Disable instruction tracing
+ __ASM__("pushf; andw $0xFEFF, 0(%esp); popf");
Proc_GetCurThread()->bInstrTrace = 0;
// If it was a user, tell the thread handler
(ErrorCode&16?" (Instruction Fetch)":"")
);
Log_Warning("MMVirt", "Instruction %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr);
- __asm__ __volatile__ ("sti"); // Restart IRQs
+ __ASM__("sti"); // Restart IRQs
#if 1
Error_Backtrace(Regs->eip, Regs->ebp);
#endif
{
tPAddr paddr;
//ENTER("xVAddr", VAddr);
- //__asm__ __volatile__ ("xchg %bx,%bx");
+ //__ASM__("xchg %bx,%bx");
// Check if the directory is mapped
if( gaPageDir[ VAddr >> 22 ] == 0 )
{
*/
void MM_SetCR3(Uint CR3)
{
- __asm__ __volatile__ ("mov %0, %%cr3"::"r"(CR3));
+ __ASM__("mov %0, %%cr3"::"r"(CR3));
}
/**
//ENTER("xVAddr xPAddr", VAddr, PAddr);
// Sanity check
if( PAddr & 0xFFF || VAddr & 0xFFF ) {
- Warning("MM_Map - Physical or Virtual Addresses are not aligned");
+ Log_Warning("MM_Virt", "MM_Map - Physical or Virtual Addresses are not aligned");
//LEAVE('i', 0);
return 0;
}
INVLPG( gaPageDir );
}
+/**
+ * \brief Deallocate an address space
+ */
+void MM_ClearSpace(Uint32 CR3)
+{
+ int i, j;
+
+ if(CR3 == (*gpPageCR3 & ~0xFFF)) {
+ Log_Error("MMVirt", "Can't clear current address space");
+ return ;
+ }
+
+ if( MM_GetRefCount(CR3) > 1 ) {
+ MM_DerefPhys(CR3);
+ Log_Log("MMVirt", "CR3 %P is still referenced, not cleaning (but dereferenced)", CR3);
+ return ;
+ }
+
+ Log_Debug("MMVirt", "Clearing out address space 0x%x from 0x%x", CR3, *gpPageCR3);
+
+ GET_TEMP_MAPPING(CR3);
+ INVLPG( gaTmpDir );
+
+ for( i = 0; i < 1024; i ++ )
+ {
+ Uint32 *table = &gaTmpTable[i*1024];
+ if( !(gaTmpDir[i] & PF_PRESENT) )
+ continue ;
+
+ INVLPG( table );
+
+ if( i < 768 || (i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) )
+ {
+ for( j = 0; j < 1024; j ++ )
+ {
+ if( !(table[j] & 1) )
+ continue;
+ MM_DerefPhys( table[j] & ~0xFFF );
+ }
+ }
+
+ if( i != (PAGE_TABLE_ADDR >> 22) )
+ {
+ MM_DerefPhys( gaTmpDir[i] & ~0xFFF );
+ }
+ }
+
+
+ MM_DerefPhys( CR3 );
+
+ REL_TEMP_MAPPING();
+}
+
/**
* \fn tPAddr MM_Clone(void)
* \brief Clone the current address space
*/
-tPAddr MM_Clone(void)
+tPAddr MM_Clone(int bNoUserCopy)
{
Uint i, j;
- tVAddr ret;
+ tPAddr ret;
Uint page = 0;
tVAddr kStackBase = Proc_GetCurThread()->KernelStack - MM_KERNEL_STACK_SIZE;
void *tmp;
- Mutex_Acquire( &glTempFractal );
-
// Create Directory Table
- *gpTmpCR3 = MM_AllocPhys() | 3;
- if( *gpTmpCR3 == 3 ) {
- *gpTmpCR3 = 0;
+ ret = MM_AllocPhys();
+ if( ret == 0 ) {
return 0;
}
+
+ // Map
+ GET_TEMP_MAPPING( ret );
INVLPG( gaTmpDir );
- //LOG("Allocated Directory (%x)", *gpTmpCR3);
memsetd( gaTmpDir, 0, 1024 );
- if( Threads_GetPID() != 0 )
+ if( Threads_GetPID() != 0 && !bNoUserCopy )
{
// Copy Tables
for( i = 0; i < 768; i ++)
gaTmpDir[ PAGE_TABLE_ADDR >> 22 ] = *gpTmpCR3;
continue;
}
+ if( i == (TMP_TABLE_ADDR >> 22) ) {
+ gaTmpDir[ TMP_TABLE_ADDR >> 22 ] = 0;
+ continue ;
+ }
if( gaPageDir[i] == 0 ) {
gaTmpDir[i] = 0;
}
}
- ret = *gpTmpCR3 & ~0xFFF;
- Mutex_Release( &glTempFractal );
+ REL_TEMP_MAPPING();
//LEAVE('x', ret);
return ret;
base = WORKER_STACKS + base * WORKER_STACK_SIZE;
//Log(" MM_NewWorkerStack: base = 0x%x", base);
- // Acquire the lock for the temp fractal mappings
- Mutex_Acquire(&glTempFractal);
-
// Set the temp fractals to TID0's address space
- *gpTmpCR3 = ((Uint)gaInitPageDir - KERNEL_BASE) | 3;
- //Log(" MM_NewWorkerStack: *gpTmpCR3 = 0x%x", *gpTmpCR3);
+ GET_TEMP_MAPPING( ((Uint)gaInitPageDir - KERNEL_BASE) );
INVLPG( gaTmpDir );
-
// Check if the directory is mapped (we are assuming that the stacks
// will fit neatly in a directory)
//Log(" MM_NewWorkerStack: gaTmpDir[ 0x%x ] = 0x%x", base>>22, gaTmpDir[ base >> 22 ]);
page = MM_AllocPhys();
gaTmpTable[ (base + addr) >> 12 ] = page | 3;
}
- *gpTmpCR3 = 0;
- // Release the temp mapping lock
- Mutex_Release(&glTempFractal);
+
+ // Release temporary fractal
+ REL_TEMP_MAPPING();
// NOTE: Max of 1 page
// `page` is the last allocated page from the previious for loop
; Save RSP
mov eax, [esp+0x20+4]
mov [eax], esp
+ push DWORD [esp+0x20+12]
call MM_Clone
+ add esp, 4
; Save CR3
mov esi, [esp+0x20+8]
mov [esi], eax
jmp ecx
.restore:
-
popa
xor eax, eax
ret
.parent:
ret
-; void Proc_ReturnToUser(void *Method, Uint Parameter)
+; void Proc_ReturnToUser(void *Method, Uint Parameter, tVAddr KernelStack)
; Calls a user fault handler
;
[global Proc_ReturnToUser]
; [EBP+12]: parameter
; [EBP+16]: kernel stack top
- ;call Proc_GetCurThread
-
- ; EAX is the current thread
- ;mov ebx, eax
- ;mov eax, [ebx+12*4] ; Get Kernel Stack
- mov eax, [ebp+16] ; Get Kernel Stack
+ ; Get kernel stack
+ mov eax, [ebp+16]
sub eax, KSTACK_USERSTATE_SIZE
;
[global GetCPUNum]
GetCPUNum: ; TODO: Store in debug registers
-; xor eax, eax
-; str ax
-; sub ax, 0x30
-; shr ax, 3 ; ax /= 8
mov eax, dr1
ret
# include <mp.h>
#endif
#include <hal_proc.h>
+#include <arch_int.h>
// === FLAGS ===
#define DEBUG_TRACE_SWITCH 0
extern Uint GetEIP(void); // start.asm
extern Uint GetEIP_Sched(void); // proc.asm
extern void NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...); // Actually takes cdecl args
-extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3);
+extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
extern int giNumCPUs;
extern int giNextTID;
extern tThread gThreadZero;
+extern tProcess gProcessZero;
extern void Isr8(void); // Double Fault
extern void Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
extern char scheduler_return[]; // Return address in SchedulerBase
gaCPUs[0].Current = &gThreadZero;
gThreadZero.CurCPU = 0;
- gThreadZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
+ gProcessZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
// Create Per-Process Data Block
if( !MM_Allocate(MM_PPD_CFG) )
__asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
}
+void Proc_ClearProcess(tProcess *Process)
+{
+ MM_ClearSpace(Process->MemState.CR3);
+}
+
void Proc_ClearThread(tThread *Thread)
{
- Log_Warning("Proc", "TODO: Nuke address space etc");
if(Thread->SavedState.SSE) {
free(Thread->SavedState.SSE);
Thread->SavedState.SSE = NULL;
}
}
-int Proc_NewKThread(void (*Fcn)(void*), void *Data)
+tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
{
Uint esp;
tThread *newThread, *cur;
newThread = Threads_CloneTCB(0);
if(!newThread) return -1;
- // Set CR3
- newThread->MemState.CR3 = cur->MemState.CR3;
-
// Create new KStack
newThread->KernelStack = MM_NewKStack();
// Check for errors
* \fn int Proc_Clone(Uint *Err, Uint Flags)
* \brief Clone the current process
*/
-int Proc_Clone(Uint Flags)
+tPID Proc_Clone(Uint Flags)
{
tThread *newThread;
tThread *cur = Proc_GetCurThread();
newThread->KernelStack = cur->KernelStack;
// Clone state
- eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->MemState.CR3);
+ eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
if( eip == 0 ) {
- // ACK the interrupt
return 0;
}
newThread->SavedState.EIP = eip;
newThread->SavedState.bSSEModified = 0;
// Check for errors
- if( newThread->MemState.CR3 == 0 ) {
+ if( newThread->Process->MemState.CR3 == 0 ) {
Log_Error("Proc", "Proc_Clone: MM_Clone failed");
Threads_Delete(newThread);
return -1;
return base + USER_STACK_SZ;
}
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
{
Uint *stack;
int i;
- char **envp = NULL;
+ const char **envp = NULL;
Uint16 ss, cs;
// Copy data to the user stack and free original buffer
stack = (void*)Proc_MakeUserStack();
- stack -= DataSize/sizeof(*stack);
+ stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
memcpy( stack, ArgV, DataSize );
free(ArgV);
if( DataSize )
{
Uint delta = (Uint)stack - (Uint)ArgV;
- ArgV = (char**)stack;
+ ArgV = (const char**)stack;
for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
envp = &ArgV[i+1];
for( i = 0; envp[i]; i++ ) envp[i] += delta;
LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
GetCPUNum(),
nextthread, nextthread->TID, nextthread->ThreadName,
- nextthread->MemState.CR3,
+ nextthread->Process->MemState.CR3,
nextthread->SavedState.EIP,
nextthread->SavedState.ESP
);
+ LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
}
#endif
SwitchTasks(
nextthread->SavedState.ESP, &curthread->SavedState.ESP,
nextthread->SavedState.EIP, &curthread->SavedState.EIP,
- nextthread->MemState.CR3
+ nextthread->Process->MemState.CR3
);
}
else
SwitchTasks(
nextthread->SavedState.ESP, 0,
nextthread->SavedState.EIP, 0,
- nextthread->MemState.CR3
+ nextthread->Process->MemState.CR3
);
}
*/
void Proc_Scheduler(int CPU)
{
+#if 0
tThread *thread;
// If the spinlock is set, let it complete
regs->eflags &= ~0x100; // Clear TF
}
-#if 0
// TODO: Ack timer?
#if USE_MP
if( GetCPUNum() )
&& Threads_GetPID() == gVM8086_WorkerPID)
{
if( gpVM8086_State == (void*)-1 ) {
-// Log_Log("VM8086", "Worker thread ready and waiting");
+ Log_Log("VM8086", "Worker thread ready and waiting");
gpVM8086_State = NULL;
Mutex_Release( &glVM8086_Process ); // Release lock obtained in VM8086_Install
}
#include <proc.h>
#include <hal_proc.h>
+// === DEBUG OPTIONS ===
+#define TRACE_COW 0
+
// === CONSTANTS ===
#define PHYS_BITS 52 // TODO: Move out
#define VIRT_BITS 48
{
*Ent &= ~PF_COW;
*Ent |= PF_PRESENT|PF_WRITE;
+ #if TRACE_COW
Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
+ #endif
}
else
{
memcpy( tmp, NextLevel, 0x1000 );
MM_FreeTemp( (tVAddr)tmp );
+ #if TRACE_COW
Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
+ #endif
MM_DerefPhys( curpage );
*Ent &= PF_USER;
LogF("%13s", "zero" );
else
LogF("%13llx", PAGETABLE(RangeStart>>12) & PADDR_MASK );
- LogF(" : 0x%6llx (%c%c%c%c)\r\n",
+ LogF(" : 0x%6llx (%c%c%c%c%c%c)\r\n",
Length,
+ (Expected & PF_GLOBAL ? 'G' : '-'),
+ (Expected & PF_NX ? '-' : 'x'),
(Expected & PF_PAGED ? 'p' : '-'),
(Expected & PF_COW ? 'C' : '-'),
(Expected & PF_USER ? 'U' : '-'),
*/
void MM_DumpTables(tVAddr Start, tVAddr End)
{
- const tPAddr CHANGEABLE_BITS = ~(PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED) & 0xFFF;
+ const tPAddr FIXED_BITS = PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED|PF_NX|PF_GLOBAL;
+ const tPAddr CHANGEABLE_BITS = ~FIXED_BITS & 0xFFF;
const tPAddr MASK = ~CHANGEABLE_BITS; // Physical address and access bits
tVAddr rangeStart = 0;
tPAddr expected = CHANGEABLE_BITS; // CHANGEABLE_BITS is used because it's not a vaild value
tVAddr curPos;
Uint page;
-
+ tPAddr expected_pml4 = PF_WRITE|PF_USER;
+ tPAddr expected_pdp = PF_WRITE|PF_USER;
+ tPAddr expected_pd = PF_WRITE|PF_USER;
+
Log("Table Entries: (%p to %p)", Start, End);
End &= (1L << 48) - 1;
// End of a range
if(!(PAGEMAPLVL4(page>>27) & PF_PRESENT)
+ || (PAGEMAPLVL4(page>>27) & FIXED_BITS) != expected_pml4
|| !(PAGEDIRPTR(page>>18) & PF_PRESENT)
+ || (PAGEDIRPTR(page>>18) & FIXED_BITS) != expected_pdp
|| !(PAGEDIR(page>>9) & PF_PRESENT)
+ || (PAGEDIR(page>>9) & FIXED_BITS) != expected_pd
|| !(PAGETABLE(page) & PF_PRESENT)
- || (PAGETABLE(page) & MASK) != expected)
+ || (PAGETABLE(page) & MASK) != expected)
{
if(expected != CHANGEABLE_BITS)
{
+ // Merge
+ expected &= expected_pml4 | ~(PF_WRITE|PF_USER);
+ expected &= expected_pdp | ~(PF_WRITE|PF_USER);
+ expected &= expected_pd | ~(PF_WRITE|PF_USER);
+ expected |= expected_pml4 & PF_NX;
+ expected |= expected_pdp & PF_NX;
+ expected |= expected_pd & PF_NX;
+ Log("expected (pml4 = %x, pdp = %x, pd = %x)",
+ expected_pml4, expected_pdp, expected_pd);
+ // Dump
MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
expected = CHANGEABLE_BITS;
}
if( !(PAGETABLE(page) & PF_PRESENT) ) continue;
expected = (PAGETABLE(page) & MASK);
+ expected_pml4 = (PAGEMAPLVL4(page>>27) & FIXED_BITS);
+ expected_pdp = (PAGEDIRPTR (page>>18) & FIXED_BITS);
+ expected_pd = (PAGEDIR (page>> 9) & FIXED_BITS);
rangeStart = curPos;
}
if(gMM_ZeroPage && (expected & PADDR_MASK) == gMM_ZeroPage )
}
if(expected != CHANGEABLE_BITS) {
+ // Merge
+
+ // Dump
MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
expected = 0;
}
*ent |= PF_USER;
INVLPG( &pmlevels[i+1][ (Addr>>size)*512 ] );
memset( &pmlevels[i+1][ (Addr>>size)*512 ], 0, 0x1000 );
- LOG("Init PML%i ent 0x%x %p with %P", 4 - i,
- Addr>>size, (Addr>>size) << size, tmp);
+ LOG("Init PML%i ent 0x%x %p with %P (*ent = %P)", 4 - i,
+ Addr>>size, (Addr>>size) << size, tmp, *ent);
}
// Catch large pages
else if( *ent & PF_LARGE )
if( Flags & MM_PFLAG_COW ) {
*ent &= ~PF_WRITE;
*ent |= PF_COW;
+ INVLPG_ALL();
}
else {
*ent &= ~PF_COW;
INVLPG_ALL();
// #3 Set Copy-On-Write to all user pages
- for( i = 0; i < 256; i ++)
+ if( Threads_GetPID() != 0 )
{
- if( PAGEMAPLVL4(i) & PF_WRITE ) {
- PAGEMAPLVL4(i) |= PF_COW;
- PAGEMAPLVL4(i) &= ~PF_WRITE;
+ for( i = 0; i < 256; i ++)
+ {
+ if( PAGEMAPLVL4(i) & PF_WRITE ) {
+ PAGEMAPLVL4(i) |= PF_COW;
+ PAGEMAPLVL4(i) &= ~PF_WRITE;
+ }
+
+ TMPMAPLVL4(i) = PAGEMAPLVL4(i);
+// Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i));
+ if( !(TMPMAPLVL4(i) & PF_PRESENT) ) continue ;
+
+ MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
+ }
+ }
+ else
+ {
+ for( i = 0; i < 256; i ++ )
+ {
+ TMPMAPLVL4(i) = 0;
}
-
- TMPMAPLVL4(i) = PAGEMAPLVL4(i);
-// Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i));
- if( !(TMPMAPLVL4(i) & PF_PRESENT) ) continue ;
-
- MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
}
// #4 Map in kernel pages
tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize)
{
tVAddr ret;
+ tPAddr phys;
int i;
// #1 Set temp fractal to PID0
Mutex_Acquire(&glMM_TempFractalLock);
TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3;
+ INVLPG_ALL();
// #2 Scan for a free stack addresss < 2^47
for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE)
}
// #3 Map all save the last page in the range
- // - This acts as as guard page, and doesn't cost us anything.
+ // - This acts as as guard page
+ MM_GetPageEntryPtr(ret, 1, 1, 0, NULL); // Make sure tree is allocated
for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ )
{
- tPAddr phys = MM_AllocPhys();
+ phys = MM_AllocPhys();
if(!phys) {
// TODO: Clean up
Log_Error("MM", "MM_NewWorkerStack - Unable to allocate page");
return 0;
}
MM_MapEx(ret + i*0x1000, phys, 1, 0);
+ MM_SetFlags(ret + i*0x1000, MM_PFLAG_KERNEL|MM_PFLAG_RO, MM_PFLAG_KERNEL);
}
+ // Copy data
if( StackSize > 0x1000 ) {
Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize);
}
else {
- tPAddr *ptr, paddr;
- tVAddr tmp_addr;
- MM_GetPageEntryPtr(ret + i*0x1000, 1, 0, 0, &ptr);
- paddr = *ptr & ~0xFFF;
- tmp_addr = MM_MapTemp(paddr);
- memcpy( (void*)(tmp_addr + (0x1000 - StackSize)), StackData, StackSize );
+ tVAddr tmp_addr, dest;
+ tmp_addr = MM_MapTemp(phys);
+ dest = tmp_addr + (0x1000 - StackSize);
+ memcpy( (void*)dest, StackData, StackSize );
+ Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i);
+ Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret);
MM_FreeTemp(tmp_addr);
}
-
+
+ TMPCR3() = 0;
Mutex_Release(&glMM_TempFractalLock);
return ret + i*0x1000;
[global NewTaskHeader]
NewTaskHeader:
- mov rax, [rsp]
- mov dr0, rax
-
- sti
- mov al, 0x20
- mov dx, 0x20
- out dx, al
+ ; [rsp+0x00]: Thread
+ ; [rsp+0x08]: Function
+ ; [rsp+0x10]: Argument
- mov rdi, [rsp+0x18]
- dec QWORD [rsp+0x10]
- jz .call
- mov rsi, [rsp+0x20]
- dec QWORD [rsp+0x10]
- jz .call
- mov rdx, [rsp+0x28]
- dec QWORD [rsp+0x10]
- jz .call
- mov rcx, [rsp+0x30]
- dec QWORD [rsp+0x10]
- jz .call
-.call:
+ mov rdi, [rsp+0x10]
mov rax, [rsp+0x8]
-; xchg bx, bx
+ add rsp, 0x10 ; Reclaim stack space (thread/fcn)
+ xchg bx, bx
call rax
; Quit thread with RAX as the return code
mov cr3, r8
; Make sure the stack is valid before jumping
+ invlpg [rdi-0x1000]
invlpg [rdi]
invlpg [rdi+0x1000]
extern int giTotalTickets;
extern int giNumActiveThreads;
extern tThread gThreadZero;
+extern tProcess gProcessZero;
extern void Threads_Dump(void);
extern void Proc_ReturnToUser(tVAddr Handler, tVAddr KStackTop, int Argument);
extern void Time_UpdateTimestamp(void);
gaCPUs[0].Current = &gThreadZero;
- gThreadZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
+ gProcessZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
gThreadZero.CurCPU = 0;
gThreadZero.KernelStack = 0xFFFFA00000000000 + KERNEL_STACK_SIZE;
// BSP still should run the current task
gaCPUs[0].Current = &gThreadZero;
+ __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
// Start interrupts and wait for APs to come up
Log("Waiting for APs to come up\n");
tThread *Proc_GetCurThread(void)
{
#if USE_MP
- return gaCPUs[ GetCPUNum() ].Current;
+ tThread *ret;
+ __asm__ __volatile__ ("mov %%db0, %0" : "=r"(thread));
+ return ret; // gaCPUs[ GetCPUNum() ].Current;
#else
return gaCPUs[ 0 ].Current;
#endif
}
+void Proc_ClearProcess(tProcess *Process)
+{
+ Log_Warning("Proc", "TODO: Nuke address space etc");
+}
+
/*
*
*/
void Proc_ClearThread(tThread *Thread)
{
- Log_Warning("Proc", "TODO: Nuke address space etc");
}
/**
* \brief Create a new kernel thread
*/
-int Proc_NewKThread(void (*Fcn)(void*), void *Data)
+tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
{
Uint rsp;
tThread *newThread, *cur;
newThread = Threads_CloneTCB(0);
if(!newThread) return -1;
- // Set CR3
- newThread->MemState.CR3 = cur->MemState.CR3;
-
// Create new KStack
newThread->KernelStack = MM_NewKStack();
// Check for errors
rsp = newThread->KernelStack;
*(Uint*)(rsp-=8) = (Uint)Data; // Data (shadowed)
- *(Uint*)(rsp-=8) = 1; // Number of params
*(Uint*)(rsp-=8) = (Uint)Fcn; // Function to call
*(Uint*)(rsp-=8) = (Uint)newThread; // Thread ID
* \fn int Proc_Clone(Uint Flags)
* \brief Clone the current process
*/
-int Proc_Clone(Uint Flags)
+tTID Proc_Clone(Uint Flags)
{
tThread *newThread, *cur = Proc_GetCurThread();
Uint rip;
if(!newThread) return -1;
// Save core machine state
- rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->MemState.CR3);
+ rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->Process->MemState.CR3);
if(rip == 0) return 0; // Child
newThread->KernelStack = cur->KernelStack;
newThread->SavedState.RIP = rip;
int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
{
tThread *new, *cur;
- Uint stack_contents[4];
+ Uint stack_contents[3];
cur = Proc_GetCurThread();
// Create new thread
- new = malloc( sizeof(tThread) );
+ new = Threads_CloneThreadZero();
if(!new) {
Warning("Proc_SpawnWorker - Out of heap space!\n");
return -1;
}
- memcpy(new, &gThreadZero, sizeof(tThread));
- // Set Thread ID
- new->TID = giNextTID++;
// Create the stack contents
- stack_contents[3] = (Uint)Data;
- stack_contents[2] = 1;
+ stack_contents[2] = (Uint)Data;
stack_contents[1] = (Uint)Fcn;
stack_contents[0] = (Uint)new;
// Create a new worker stack (in PID0's address space)
- // The stack is relocated by this code
+ // - The stack is built by this code using stack_contents
new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
new->SavedState.RSP = new->KernelStack - sizeof(stack_contents);
if(i != -1) return 0;
// Allocate Stack - Allocate incrementally to clean up MM_Dump output
+ // - Most of the user stack is the zero page
for( i = 0; i < (USER_STACK_SZ-USER_STACK_PREALLOC)/0x1000; i++ )
{
MM_AllocateZero( base + (i<<12) );
}
+ // - but the top USER_STACK_PREALLOC pages are actually allocated
for( ; i < USER_STACK_SZ/0x1000; i++ )
{
tPAddr alloc = MM_Allocate( base + (i<<12) );
return base + USER_STACK_SZ;
}
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
{
Uint *stack;
int i;
- char **envp = NULL;
+ const char **envp = NULL;
Uint16 ss, cs;
if(DataSize)
{
Uint delta = (Uint)stack - (Uint)ArgV;
- ArgV = (char**)stack;
+ ArgV = (const char**)stack;
for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
envp = &ArgV[i+1];
for( i = 0; envp[i]; i++ ) envp[i] += delta;
#if DEBUG_TRACE_SWITCH
LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n",
- nextthread->MemState.CR3,
+ nextthread->Process->MemState.CR3,
nextthread->SavedState.RIP,
nextthread->SavedState.RSP,
nextthread->TID,
gTSSs[cpu].RSP0 = nextthread->KernelStack-4;
__asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread));
- // Save FPU/MMX/XMM/SSE state
- if( curthread->SavedState.SSE )
+ if( curthread )
+ {
+ // Save FPU/MMX/XMM/SSE state
+ if( curthread->SavedState.SSE )
+ {
+ Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
+ curthread->SavedState.bSSEModified = 0;
+ Proc_DisableSSE();
+ }
+ SwitchTasks(
+ nextthread->SavedState.RSP, &curthread->SavedState.RSP,
+ nextthread->SavedState.RIP, &curthread->SavedState.RIP,
+ nextthread->Process->MemState.CR3
+ );
+ }
+ else
{
- Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
- curthread->SavedState.bSSEModified = 0;
- Proc_DisableSSE();
+ Uint tmp;
+ SwitchTasks(
+ nextthread->SavedState.RSP, &tmp,
+ nextthread->SavedState.RIP, &tmp,
+ nextthread->Process->MemState.CR3
+ );
}
-
- SwitchTasks(
- nextthread->SavedState.RSP, &curthread->SavedState.RSP,
- nextthread->SavedState.RIP, &curthread->SavedState.RIP,
- nextthread->MemState.CR3
- );
return ;
}
void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
{
#if 0
- {
tThread *thread;
// If the spinlock is set, let it complete
// ACK Timer here?
Proc_Reschedule();
- }
#endif
}
[global GetCPUNum]
GetCPUNum:
- xor rax, rax
- str ax
- sub ax, 0x38 ; TSS Base
- shr ax, 4 ; One 16-byte TSS per CPU
+ mov rax, dr1
ret
KSTACK_USERSTATE_SIZE equ (5+2+16+2)*8 ; IRET, ErrorNum, ErrorCode, GPRs, FS&GS
#include <binary.h>
#include <mm_virt.h>
#include <hal_proc.h>
+#include <vfs_threads.h>
// === CONSTANTS ===
#define BIN_LOWEST MM_USER_MIN // 1MiB
extern tBinaryType gELF_Info;
// === PROTOTYPES ===
- int Proc_Execve(const char *File, const char **ArgV, const char **EnvP);
+ int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
LOG("stackPath = '%s'", stackPath);
- if(Proc_Clone(CLONE_VM) == 0)
+ if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
{
// CHILD
const char *args[2] = {stackPath, NULL};
LOG("stackPath = '%s'", stackPath);
- Proc_Execve(stackPath, args, &args[1]);
+ Proc_Execve(stackPath, args, &args[1], 0);
for(;;);
}
LEAVE('i', 0);
return 0;
}
+/**
+ * \todo Document
+ */
+int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
+{
+ int size, argc=0, envc=0;
+ int i;
+ char *strbuf;
+ const char **arrays;
+
+ // Calculate size
+ size = 0;
+ if( ArgV && *ArgV )
+ {
+ const char **argv = *ArgV;
+ for( argc = 0; argv[argc]; argc ++ )
+ size += strlen( argv[argc] ) + 1;
+ }
+ if( EnvP && *EnvP )
+ {
+ const char **envp = *EnvP;
+ for( envc = 0; envp[envc]; envc ++ )
+ size += strlen( envp[envc] ) + 1;
+ }
+ size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); // Word align
+ size += (argc+1+envc+1)*sizeof(void*); // Arrays
+ if( Path )
+ {
+ size += strlen( *Path ) + 1;
+ }
+
+ if( DestBuffer )
+ {
+ arrays = DestBuffer;
+ strbuf = (void*)&arrays[argc+1+envc+1];
+
+ // Fill ArgV
+ if( ArgV && *ArgV )
+ {
+ const char **argv = *ArgV;
+ for( i = 0; argv[i]; i ++ )
+ {
+ arrays[i] = strbuf;
+ strcpy(strbuf, argv[i]);
+ strbuf += strlen( argv[i] ) + 1;
+ }
+ *ArgV = arrays;
+ arrays += i;
+ }
+ *arrays++ = NULL;
+ // Fill EnvP
+ if( EnvP && *EnvP )
+ {
+ const char **envp = *EnvP;
+ for( i = 0; envp[i]; i ++ )
+ {
+ arrays[i] = strbuf;
+ strcpy(strbuf, envp[i]);
+ strbuf += strlen( envp[i] ) + 1;
+ }
+ *EnvP = arrays;
+ arrays += i;
+ }
+ *arrays++ = NULL;
+ // Fill path
+ if( Path )
+ {
+ strcpy(strbuf, *Path);
+ *Path = strbuf;
+ }
+ }
+
+ return size;
+}
+
+/**
+ * \brief Create a new process with the specified set of file descriptors
+ */
+int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
+{
+ void *handles;
+ void *cachebuf;
+ int size;
+ tPID ret;
+
+ // --- Save File, ArgV and EnvP
+ size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
+ cachebuf = malloc( size );
+ Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
+
+ // Cache the VFS handles
+ handles = VFS_SaveHandles(nFD, FDs);
+
+ // Create new process
+ ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
+ if( ret == 0 )
+ {
+ VFS_RestoreHandles(nFD, handles);
+ VFS_FreeSavedHandles(nFD, handles);
+ // Frees cachebuf
+ Proc_Execve(Binary, ArgV, EnvP, size);
+ for(;;);
+ }
+ if( ret < 0 )
+ {
+ VFS_FreeSavedHandles(nFD, handles);
+ }
+
+ return ret;
+}
+
/**
* \brief Replace the current user image with another
* \param File File to load as the next image
* \param EnvP User's environment
* \note Called Proc_ for historical reasons
*/
-int Proc_Execve(const char *File, const char **ArgV, const char **EnvP)
+int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
{
- int argc, envc, i;
- int argenvBytes;
- char **argenvBuf, *strBuf;
- char **argvSaved, **envpSaved;
- char *savedFile;
+ void *cachebuf;
tVAddr entry;
Uint base; // Uint because Proc_StartUser wants it
+ int argc;
ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
- // --- Save File, ArgV and EnvP (also get argc)
-
- // Count Arguments, Environment Variables and total string sizes
- argenvBytes = 0;
- for( argc = 0; ArgV && ArgV[argc]; argc++ )
- argenvBytes += strlen(ArgV[argc])+1;
- for( envc = 0; EnvP && EnvP[envc]; envc++ )
- argenvBytes += strlen(EnvP[envc])+1;
- LOG("argc = %i, envc = %i", envc);
- argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
- argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
-
- // Allocate
- argenvBuf = malloc(argenvBytes);
- if(argenvBuf == NULL) {
- Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
- LEAVE('i', 0);
- return 0;
- }
- strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
-
- // Populate
- argvSaved = argenvBuf;
- for( i = 0; i < argc; i++ )
- {
- argvSaved[i] = strBuf;
- strcpy(argvSaved[i], ArgV[i]);
- LOG("argv[%i] = '%s'", i, strBuf);
- strBuf += strlen(ArgV[i])+1;
- }
- argvSaved[i] = NULL;
- envpSaved = &argvSaved[i+1];
- for( i = 0; i < envc; i++ )
+ // --- Save File, ArgV and EnvP
+ if( DataSize == 0 )
{
- envpSaved[i] = strBuf;
- LOG("envp[%i] = '%s'", i, strBuf);
- strcpy(envpSaved[i], EnvP[i]);
- strBuf += strlen(EnvP[i])+1;
+ DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
+ cachebuf = malloc( DataSize );
+ Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
}
- envpSaved[i] = NULL;
-
- savedFile = malloc(strlen(File)+1);
- strcpy(savedFile, File);
+
+ // --- Get argc
+ for( argc = 0; ArgV && ArgV[argc]; argc ++ );
// --- Set Process Name
Threads_SetName(File);
// --- Clear User Address space
- MM_ClearUser();
+ // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
+ // PPD area would be a better idea.
+ {
+ int nfd = *Threads_GetMaxFD();
+ void *handles;
+ handles = VFS_SaveHandles(nfd, NULL);
+ VFS_CloseAllUserHandles();
+ MM_ClearUser();
+ VFS_RestoreHandles(nfd, handles);
+ VFS_FreeSavedHandles(nfd, handles);
+ }
// --- Load new binary
- base = Binary_Load(savedFile, &entry);
- free(savedFile);
+ base = Binary_Load(File, &entry);
if(base == 0)
{
- free(argvSaved);
- Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
+ Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
LEAVE('-');
Threads_Exit(0, -10);
for(;;);
}
LOG("entry = 0x%x, base = 0x%x", entry, base);
-
-// MM_DumpTables(0, KERNEL_BASE);
-
LEAVE('-');
// --- And... Jump to it
- Proc_StartUser(entry, base, argc, argvSaved, argenvBytes);
+ Proc_StartUser(entry, base, argc, ArgV, DataSize);
for(;;); // Tell GCC that we never return
}
/* AcessOS
* FIFO Pipe Driver
*/
+#define DEBUG 0
#include <acess.h>
#include <modules.h>
#include <fs_devfs.h>
char *FIFO_ReadDir(tVFS_Node *Node, int Id);
tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+void FIFO_Reference(tVFS_Node *Node);
void FIFO_Close(tVFS_Node *Node);
int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
tPipe *FIFO_Int_NewPipe(int Size, const char *Name);
// === GLOBALS ===
MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
+tVFS_NodeType gFIFO_DirNodeType = {
+ .TypeName = "FIFO Dir Node",
+ .ReadDir = FIFO_ReadDir,
+ .FindDir = FIFO_FindDir,
+ .MkNod = FIFO_MkNod,
+ .Relink = FIFO_Relink,
+ .IOCtl = FIFO_IOCtl
+};
+tVFS_NodeType gFIFO_PipeNodeType = {
+ .TypeName = "FIFO Pipe Node",
+ .Read = FIFO_Read,
+ .Write = FIFO_Write,
+ .Close = FIFO_Close,
+ .Reference = FIFO_Reference
+};
tDevFS_Driver gFIFO_DriverInfo = {
NULL, "fifo",
{
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRW,
.Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = FIFO_ReadDir,
- .FindDir = FIFO_FindDir,
- .MkNod = FIFO_MkNod,
- .Relink = FIFO_Relink,
- .IOCtl = FIFO_IOCtl
+ .Type = &gFIFO_DirNodeType
}
};
tVFS_Node gFIFO_AnonNode = {
return 0;
}
+void FIFO_Reference(tVFS_Node *Node)
+{
+ if(!Node->ImplPtr) return ;
+
+ Node->ReferenceCount ++;
+}
+
/**
* \fn void FIFO_Close(tVFS_Node *Node)
* \brief Close a FIFO end
pipe = Node->ImplPtr;
if(strcmp(pipe->Name, "anon") == 0) {
+ Log_Debug("FIFO", "Pipe %p closed", Node->ImplPtr);
free(Node->ImplPtr);
return ;
}
tPipe *pipe = Node->ImplPtr;
Uint len;
Uint remaining = Length;
-
+
if(!pipe) return 0;
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
while(remaining)
{
// Wait for buffer to fill
if(pipe->Flags & PF_BLOCKING)
{
- #if 0
- len = Semaphore_Wait( &pipe->Semaphore, remaining );
- #else
- VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
- // Read buffer
- // TODO: Rethink this, it might not work on buffer overflow
- if(pipe->WritePos - pipe->ReadPos < remaining)
- len = pipe->WritePos - pipe->ReadPos;
- else
- len = remaining;
- #endif
+ if( pipe->ReadPos == pipe->WritePos )
+ VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "FIFO_Read");
+
}
else
{
if(pipe->ReadPos == pipe->WritePos)
+ {
+ VFS_MarkAvaliable(Node, 0);
+ LEAVE('i', 0);
return 0;
- // Read buffer
- if(pipe->WritePos - pipe->ReadPos < remaining)
- len = pipe->WritePos - pipe->ReadPos;
- else
- len = remaining;
+ }
}
-
+
+ len = remaining;
+ if( pipe->ReadPos < pipe->WritePos )
+ {
+ int avail_bytes = pipe->WritePos - pipe->ReadPos;
+ if( avail_bytes < remaining ) len = avail_bytes;
+ }
+ else
+ {
+ int avail_bytes = pipe->WritePos + pipe->BufSize - pipe->ReadPos;
+ if( avail_bytes < remaining ) len = avail_bytes;
+ }
+
+ LOG("len = %i, remaining = %i", len, remaining);
+
// Check if read overflows buffer
if(len > pipe->BufSize - pipe->ReadPos)
{
remaining -= len;
// Increment Buffer address
Buffer = (Uint8*)Buffer + len;
+
+ // TODO: Option to read differently
+ LEAVE('i', len);
+ return len;
}
+ LEAVE('i', Length);
return Length;
}
* \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
* \brief Write to a fifo pipe
*/
-Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tPipe *pipe = Node->ImplPtr;
Uint len;
Uint remaining = Length;
if(!pipe) return 0;
+
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
while(remaining)
{
// Wait for buffer to empty
if(pipe->Flags & PF_BLOCKING) {
- #if 0
- len = Semaphore_Signal( &pipe->Semaphore, remaining );
- #else
- VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
- if(pipe->ReadPos - pipe->WritePos < remaining)
- len = pipe->ReadPos - pipe->WritePos;
+ if( pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize )
+ VFS_SelectNode(Node, VFS_SELECT_WRITE, NULL, "FIFO_Write");
+
+ len = remaining;
+ if( pipe->ReadPos > pipe->WritePos )
+ {
+ int rem_space = pipe->ReadPos - pipe->WritePos;
+ if(rem_space < remaining) len = rem_space;
+ }
else
- len = remaining;
- #endif
+ {
+ int rem_space = pipe->ReadPos + pipe->BufSize - pipe->WritePos;
+ if(rem_space < remaining) len = rem_space;
+ }
}
else
{
if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
+ {
+ LEAVE('i', 0);
return 0;
+ }
// Write buffer
if(pipe->ReadPos - pipe->WritePos < remaining)
len = pipe->ReadPos - pipe->WritePos;
Buffer = (Uint8*)Buffer + len;
}
+ LEAVE('i', Length);
return Length;
}
int namelen = strlen(Name) + 1;
int allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
- ret = malloc(allocsize);
+ ret = calloc(1, allocsize);
if(!ret) return NULL;
// Clear Return
- memset(ret, 0, allocsize);
ret->Flags = PF_BLOCKING;
// Allocate Buffer
//Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
// Set Node
+ ret->Node.ReferenceCount = 1;
ret->Node.Size = 0;
ret->Node.ImplPtr = ret;
ret->Node.UID = Threads_GetUID();
ret->Node.CTime
= ret->Node.MTime
= ret->Node.ATime = now();
- ret->Node.Read = FIFO_Read;
- ret->Node.Write = FIFO_Write;
- ret->Node.Close = FIFO_Close;
+ ret->Node.Type = &gFIFO_PipeNodeType;
return ret;
}
int giPCI_InodeHandle = -1;\r
int giPCI_DeviceCount = 0;\r
tPCIDevice *gPCI_Devices = NULL;\r
+tVFS_NodeType gPCI_RootNodeType = {\r
+ .TypeName = "PCI Root Node",\r
+ .ReadDir = PCI_int_ReadDirRoot,\r
+ .FindDir = PCI_int_FindDirRoot\r
+};\r
+tVFS_NodeType gPCI_DevNodeType = {\r
+ .TypeName = "PCI Dev Node",\r
+ .Read = PCI_int_ReadDevice\r
+};\r
tDevFS_Driver gPCI_DriverStruct = {\r
NULL, "pci",\r
{\r
.Size = -1,\r
.NumACLs = 1,\r
.ACLs = &gVFS_ACL_EveryoneRX,\r
- .ReadDir = PCI_int_ReadDirRoot,\r
- .FindDir = PCI_int_FindDirRoot\r
+ .Type = &gPCI_RootNodeType\r
}\r
};\r
Uint32 *gaPCI_PortBitmap = NULL;\r
info->Node.NumACLs = 1;\r
info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
\r
- info->Node.Read = PCI_int_ReadDevice;\r
+ info->Node.Type = &gPCI_RootNodeType;\r
\r
return 1;\r
}\r
extern tSysFS_Ent gSysFS_Version; // Defined Later
extern tSysFS_Ent gSysFS_Root; // Defined Later
MODULE_DEFINE(0, VERSION, SysFS, SysFS_Install, NULL, NULL);
+tVFS_NodeType gSysFS_FileNodeType = {
+ .TypeName = "SysFS File",
+ .Read = SysFS_Comm_ReadFile
+ };
+tVFS_NodeType gSysFS_DirNodeType = {
+ .TypeName = "SysFS Dir",
+ .ReadDir = SysFS_Comm_ReadDir,
+ .FindDir = SysFS_Comm_FindDir
+ };
tSysFS_Ent gSysFS_Version_Kernel = {
NULL, NULL, // Nexts
&gSysFS_Version, // Parent
.Size = 0,
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRO,
- .Read = SysFS_Comm_ReadFile
+ .Type = &gSysFS_FileNodeType
},
"Kernel"
};
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = SysFS_Comm_ReadDir,
- .FindDir = SysFS_Comm_FindDir
+ .Type = &gSysFS_DirNodeType
},
"Version"
};
.Flags = VFS_FFLAG_DIRECTORY,
.ImplPtr = &gSysFS_Version,
.Size = sizeof(gSysFS_Root)/sizeof(tSysFS_Ent),
- .ReadDir = SysFS_Comm_ReadDir,
- .FindDir = SysFS_Comm_FindDir,
- .IOCtl = NULL
+ .Type = &gSysFS_DirNodeType
}
};
int giSysFS_NextFileID = 2;
child->Node.NumACLs = 1;
child->Node.ACLs = &gVFS_ACL_EveryoneRX;
child->Node.Flags = VFS_FFLAG_DIRECTORY;
- child->Node.ReadDir = SysFS_Comm_ReadDir;
- child->Node.FindDir = SysFS_Comm_FindDir;
+ child->Node.Type = &gSysFS_DirNodeType;
if( !prev ) {
if(ent)
ent->Node.ImplPtr = child;
child->Node.Size = Length;
child->Node.NumACLs = 1;
child->Node.ACLs = &gVFS_ACL_EveryoneRO;
- child->Node.Read = SysFS_Comm_ReadFile;
- child->Node.Close = SysFS_Comm_CloseFile;
+ child->Node.Type = &gSysFS_FileNodeType;
// Add to parent's child list
if(ent) {
* Acess2 Virtual Terminal Driver
*/
#define DEBUG 0
-#include <acess.h>
+#include "vterm.h"
#include <fs_devfs.h>
#include <modules.h>
-#include <api_drv_video.h>
#include <api_drv_keyboard.h>
-#include <api_drv_terminal.h>
+#include <api_drv_video.h>
#include <errno.h>
#include <semaphore.h>
#define VERSION ((0<<8)|(50))
#define NUM_VTS 8
-#define MAX_INPUT_CHARS32 64
-#define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4)
//#define DEFAULT_OUTPUT "BochsGA"
#define DEFAULT_OUTPUT "Vesa"
#define FALLBACK_OUTPUT "x86_VGAText"
#define DEFAULT_HEIGHT 480
#define DEFAULT_SCROLLBACK 2 // 2 Screens of text + current screen
//#define DEFAULT_SCROLLBACK 0
-#define DEFAULT_COLOUR (VT_COL_BLACK|(0xAAA<<16))
-
-#define VT_FLAG_HIDECSR 0x01
-#define VT_FLAG_ALTBUF 0x02 //!< Alternate screen buffer
-#define VT_FLAG_RAWIN 0x04 //!< Don't handle ^Z/^C/^V
-#define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer
-#define VT_FLAG_SHOWCSR 0x20 //!< Always show the text cursor
-
-enum eVT_InModes {
- VT_INMODE_TEXT8, // UTF-8 Text Mode (VT100/xterm Emulation)
- VT_INMODE_TEXT32, // UTF-32 Text Mode (Acess Native)
- NUM_VT_INMODES
-};
// === TYPES ===
-typedef struct {
- int Mode; //!< Current Mode (see ::eTplTerminal_Modes)
- int Flags; //!< Flags (see VT_FLAG_*)
-
- short NewWidth; //!< Un-applied dimensions (Width)
- short NewHeight; //!< Un-applied dimensions (Height)
- short Width; //!< Virtual Width
- short Height; //!< Virtual Height
- short TextWidth; //!< Text Virtual Width
- short TextHeight; //!< Text Virtual Height
-
- Uint32 CurColour; //!< Current Text Colour
-
- int ViewPos; //!< View Buffer Offset (Text Only)
- int WritePos; //!< Write Buffer Offset (Text Only)
- tVT_Char *Text;
-
- tVT_Char *AltBuf; //!< Alternate Screen Buffer
- int AltWritePos; //!< Alternate write position
- short ScrollTop; //!< Top of scrolling region (smallest)
- short ScrollHeight; //!< Length of scrolling region
-
- int VideoCursorX;
- int VideoCursorY;
-
- tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it
- tTID ReadingThread; //!< Owner of the lock
- int InputRead; //!< Input buffer read position
- int InputWrite; //!< Input buffer write position
- char InputBuffer[MAX_INPUT_CHARS8];
-// tSemaphore InputSemaphore;
-
- Uint32 *Buffer;
-
- // TODO: Do I need to keep this about?
- // When should it be deallocated? on move to text mode, or some other time
- // Call set again, it's freed, and if NULL it doesn't get reallocated.
- tVideo_IOCtl_Bitmap *VideoCursor;
-
- char Name[2]; //!< Name of the terminal
- tVFS_Node Node;
-} tVTerm;
// === IMPORTS ===
extern void Debug_SetKTerminal(const char *File);
// === PROTOTYPES ===
int VT_Install(char **Arguments);
-void VT_InitOutput(void);
-void VT_InitInput(void);
char *VT_ReadDir(tVFS_Node *Node, int Pos);
tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name);
int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data);
-void VT_SetResolution(int Width, int Height);
-void VT_SetMode(int Mode);
-void VT_SetTerminal(int ID);
-void VT_KBCallBack(Uint32 Codepoint);
-void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count);
-void VT_int_ClearLine(tVTerm *Term, int Num);
-void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args);
- int VT_int_ParseEscape(tVTerm *Term, char *Buffer);
-void VT_int_PutChar(tVTerm *Term, Uint32 Ch);
-void VT_int_ScrollText(tVTerm *Term, int Count);
-void VT_int_ScrollFramebuffer( tVTerm *Term, int Count );
-void VT_int_UpdateCursor( tVTerm *Term, int bShow );
-void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
-void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight);
-void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
// === CONSTANTS ===
-const Uint16 caVT100Colours[] = {
- // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
- // Same again, but bright
- VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
- VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
- };
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, NULL);
+tVFS_NodeType gVT_RootNodeType = {
+ .TypeName = "VTerm Root",
+ .ReadDir = VT_ReadDir,
+ .FindDir = VT_FindDir,
+ .IOCtl = VT_Root_IOCtl
+ };
+tVFS_NodeType gVT_TermNodeType = {
+ .TypeName = "VTerm",
+ .Read = VT_Read,
+ .Write = VT_Write,
+ .IOCtl = VT_Terminal_IOCtl
+ };
tDevFS_Driver gVT_DrvInfo = {
NULL, "VTerm",
{
.Size = NUM_VTS,
.Inode = -1,
.NumACLs = 0,
- .ReadDir = VT_ReadDir,
- .FindDir = VT_FindDir,
- .IOCtl = VT_Root_IOCtl
+ .Type = &gVT_RootNodeType
}
};
// --- Terminals ---
char *gsVT_InputDevice = NULL;
int giVT_OutputDevHandle = -2;
int giVT_InputDevHandle = -2;
-// --- Key States --- (Used for VT Switching/Magic Combos)
- int gbVT_CtrlDown = 0;
- int gbVT_AltDown = 0;
- int gbVT_SysrqDown = 0;
// === CODE ===
/**
gVT_Terminals[i].Node.Inode = i;
gVT_Terminals[i].Node.ImplPtr = &gVT_Terminals[i];
gVT_Terminals[i].Node.NumACLs = 0; // Only root can open virtual terminals
-
- gVT_Terminals[i].Node.Read = VT_Read;
- gVT_Terminals[i].Node.Write = VT_Write;
- gVT_Terminals[i].Node.IOCtl = VT_Terminal_IOCtl;
+
+ gVT_Terminals[i].Node.Type = &gVT_TermNodeType;
// Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
}
return MODULE_ERR_OK;
}
-/**
- * \fn void VT_InitOutput()
- * \brief Initialise Video Output
- */
-void VT_InitOutput()
-{
- giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
- if(giVT_OutputDevHandle == -1) {
- Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
- return ;
- }
- VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
- VT_SetTerminal( 0 );
- VT_SetMode( VIDEO_BUFFMT_TEXT );
-}
-
-/**
- * \fn void VT_InitInput()
- * \brief Initialises the input
- */
-void VT_InitInput()
-{
- giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
- if(giVT_InputDevHandle == -1) {
- Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice);
- return ;
- }
- VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
-}
-
/**
* \brief Set the video resolution
* \param Width New screen width
}
}
-/**
- * \brief Set video output buffer mode
- */
-void VT_SetMode(int Mode)
-{
- VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode );
-}
-
/**
* \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
* \brief Read from the VTerm Directory
}
/**
- * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
* \brief Write to a virtual terminal
*/
-Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tVTerm *term = &gVT_Terminals[ Node->Inode ];
int size;
// Update the screen
VT_int_UpdateScreen(gpVT_CurTerm, 1);
}
-
-/**
- * \fn void VT_KBCallBack(Uint32 Codepoint)
- * \brief Called on keyboard interrupt
- * \param Codepoint Pseudo-UTF32 character
- *
- * Handles a key press and sends the key code to the user's buffer.
- * If the code creates a kernel-magic sequence, it is not passed to the
- * user and is handled in-kernel.
- */
-void VT_KBCallBack(Uint32 Codepoint)
-{
- tVTerm *term = gpVT_CurTerm;
-
- // Catch VT binds
- switch( Codepoint & KEY_ACTION_MASK )
- {
- case KEY_ACTION_RELEASE:
- switch(Codepoint & KEY_CODEPOINT_MASK)
- {
- case KEY_LALT: gbVT_AltDown &= ~1; break;
- case KEY_RALT: gbVT_AltDown &= ~2; break;
- case KEY_LCTRL: gbVT_CtrlDown &= ~1; break;
- case KEY_RCTRL: gbVT_CtrlDown &= ~2; break;
- }
- break;
-
- case KEY_ACTION_PRESS:
- switch(Codepoint & KEY_CODEPOINT_MASK)
- {
- case KEY_LALT: gbVT_AltDown |= 1; break;
- case KEY_RALT: gbVT_AltDown |= 2; break;
- case KEY_LCTRL: gbVT_CtrlDown |= 1; break;
- case KEY_RCTRL: gbVT_CtrlDown |= 2; break;
- }
-
- if(!gbVT_AltDown || !gbVT_CtrlDown)
- break;
- switch(Codepoint & KEY_CODEPOINT_MASK)
- {
- case KEY_F1: VT_SetTerminal(0); return;
- case KEY_F2: VT_SetTerminal(1); return;
- case KEY_F3: VT_SetTerminal(2); return;
- case KEY_F4: VT_SetTerminal(3); return;
- case KEY_F5: VT_SetTerminal(4); return;
- case KEY_F6: VT_SetTerminal(5); return;
- case KEY_F7: VT_SetTerminal(6); return;
- case KEY_F8: VT_SetTerminal(7); return;
- case KEY_F9: VT_SetTerminal(8); return;
- case KEY_F10: VT_SetTerminal(9); return;
- case KEY_F11: VT_SetTerminal(10); return;
- case KEY_F12: VT_SetTerminal(11); return;
- }
-
- // Scrolling is only valid in text mode
- if(gpVT_CurTerm->Mode != TERM_MODE_TEXT)
- break;
-
- switch(Codepoint & KEY_CODEPOINT_MASK)
- {
- // Scrolling
- case KEY_PGUP:
- if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
- return ;
- gpVT_CurTerm->ViewPos = MAX(
- 0,
- gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width
- );
- return;
- case KEY_PGDOWN:
- if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
- return ;
- gpVT_CurTerm->ViewPos = MIN(
- gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width,
- gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback
- );
- return;
- }
- break;
- }
-
- // Encode key
- if(term->Mode == TERM_MODE_TEXT)
- {
- Uint8 buf[6] = {0};
- int len = 0;
-
- // Ignore anything that isn't a press or refire
- if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
- && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
- )
- {
- return ;
- }
-
- Codepoint &= KEY_CODEPOINT_MASK;
-
- // Ignore Modifer Keys
- if(Codepoint > KEY_MODIFIERS) return;
-
- // Get UTF-8/ANSI Encoding
- switch(Codepoint)
- {
- // 0: No translation, don't send to user
- case 0: break;
- case KEY_LEFT:
- buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
- len = 3;
- break;
- case KEY_RIGHT:
- buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
- len = 3;
- break;
- case KEY_UP:
- buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
- len = 3;
- break;
- case KEY_DOWN:
- buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
- len = 3;
- break;
-
- case KEY_PGUP:
- buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
- len = 4;
- break;
- case KEY_PGDOWN:
- buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
- len = 4;
- break;
-
- // Attempt to encode in UTF-8
- default:
- len = WriteUTF8( buf, Codepoint );
- if(len == 0) {
- Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
- }
- break;
- }
-
- if(len == 0) {
- // Unprintable / Don't Pass
- return;
- }
-
-#if 0
- // Handle meta characters
- if( !(term->Flags & VT_FLAG_RAWIN) )
- {
- switch(buf[0])
- {
- case '\3': // ^C
-
- break;
- }
- }
-#endif
-
- // Write
- if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
- memcpy( &term->InputBuffer[term->InputWrite], buf, len );
- else {
- memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
- memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
- }
- // Roll the buffer over
- term->InputWrite += len;
- term->InputWrite %= MAX_INPUT_CHARS8;
- if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
- term->InputRead = term->InputWrite + 1;
- term->InputRead %= MAX_INPUT_CHARS8;
- }
- }
- else
- {
- // Encode the raw key event
- Uint32 *raw_in = (void*)term->InputBuffer;
-
- #if 0
- // Drop new keys
- if( term->InputWrite == term->InputRead )
- return ;
- #endif
-
- raw_in[ term->InputWrite ] = Codepoint;
- term->InputWrite ++;
- if(term->InputWrite >= MAX_INPUT_CHARS32)
- term->InputWrite -= MAX_INPUT_CHARS32;
-
- #if 1
- // TODO: Should old or new be dropped?
- if(term->InputRead == term->InputWrite) {
- term->InputRead ++;
- if( term->InputRead >= MAX_INPUT_CHARS32 )
- term->InputRead -= MAX_INPUT_CHARS32;
- }
- #endif
- }
-
- VFS_MarkAvaliable(&term->Node, 1);
-}
-
-/**
- * \brief Clears a line in a virtual terminal
- * \param Term Terminal to modify
- * \param Num Line number to clear
- */
-void VT_int_ClearLine(tVTerm *Term, int Num)
-{
- int i;
- tVT_Char *cell;
-
- if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ;
-
- cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
- cell = &cell[ Num*Term->TextWidth ];
-
- for( i = Term->TextWidth; i--; )
- {
- cell[ i ].Ch = 0;
- cell[ i ].Colour = Term->CurColour;
- }
-}
-
-/**
- * \brief Handle a standard large escape code
- *
- * Handles any escape code of the form \x1B[n,...A where n is an integer
- * and A is any letter.
- */
-void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
-{
- int tmp = 1;
- switch(CmdChar)
- {
- // Left
- case 'D':
- tmp = -1;
- // Right
- case 'C':
- if(argc == 1) tmp *= args[0];
- if( Term->Flags & VT_FLAG_ALTBUF )
- {
- if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
- Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
- Term->AltWritePos += Term->TextWidth - 1;
- }
- else
- Term->AltWritePos += tmp;
- }
- else
- {
- if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
- Term->WritePos -= Term->WritePos % Term->TextWidth;
- Term->WritePos += Term->TextWidth - 1;
- }
- else
- Term->WritePos += tmp;
- }
- break;
-
- // Erase
- case 'J':
- switch(args[0])
- {
- case 0: // Erase below
- break;
- case 1: // Erase above
- break;
- case 2: // Erase all
- if( Term->Flags & VT_FLAG_ALTBUF )
- {
- int i = Term->TextHeight;
- while( i-- ) VT_int_ClearLine(Term, i);
- Term->AltWritePos = 0;
- VT_int_UpdateScreen(Term, 1);
- }
- else
- {
- int i = Term->TextHeight * (giVT_Scrollback + 1);
- while( i-- ) VT_int_ClearLine(Term, i);
- Term->WritePos = 0;
- Term->ViewPos = 0;
- VT_int_UpdateScreen(Term, 1);
- }
- break;
- }
- break;
-
- // Erase in line
- case 'K':
- switch(args[0])
- {
- case 0: // Erase to right
- if( Term->Flags & VT_FLAG_ALTBUF )
- {
- int i, max;
- max = Term->Width - Term->AltWritePos % Term->Width;
- for( i = 0; i < max; i ++ )
- Term->AltBuf[Term->AltWritePos+i].Ch = 0;
- }
- else
- {
- int i, max;
- max = Term->Width - Term->WritePos % Term->Width;
- for( i = 0; i < max; i ++ )
- Term->Text[Term->WritePos+i].Ch = 0;
- }
- VT_int_UpdateScreen(Term, 0);
- break;
- case 1: // Erase to left
- if( Term->Flags & VT_FLAG_ALTBUF )
- {
- int i = Term->AltWritePos % Term->Width;
- while( i -- )
- Term->AltBuf[Term->AltWritePos++].Ch = 0;
- }
- else
- {
- int i = Term->WritePos % Term->Width;
- while( i -- )
- Term->Text[Term->WritePos++].Ch = 0;
- }
- VT_int_UpdateScreen(Term, 0);
- break;
- case 2: // Erase all
- if( Term->Flags & VT_FLAG_ALTBUF )
- {
- VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
- }
- else
- {
- VT_int_ClearLine(Term, Term->WritePos / Term->Width);
- }
- VT_int_UpdateScreen(Term, 0);
- break;
- }
- break;
-
- // Set cursor position
- case 'H':
- if( Term->Flags & VT_FLAG_ALTBUF )
- Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
- else
- Term->WritePos = args[0] + args[1]*Term->TextWidth;
- //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
- break;
-
- // Scroll up `n` lines
- case 'S':
- tmp = -1;
- // Scroll down `n` lines
- case 'T':
- if(argc == 1) tmp *= args[0];
- if( Term->Flags & VT_FLAG_ALTBUF )
- VT_int_ScrollText(Term, tmp);
- else
- {
- if(Term->ViewPos/Term->TextWidth + tmp < 0)
- break;
- if(Term->ViewPos/Term->TextWidth + tmp > Term->TextHeight * (giVT_Scrollback + 1))
- break;
-
- Term->ViewPos += Term->TextWidth*tmp;
- }
- break;
-
- // Set Font flags
- case 'm':
- for( ; argc--; )
- {
- int colour_idx;
- // Flags
- if( 0 <= args[argc] && args[argc] <= 8)
- {
- switch(args[argc])
- {
- case 0: Term->CurColour = DEFAULT_COLOUR; break; // Reset
- case 1: Term->CurColour |= 0x80000000; break; // Bright
- case 2: Term->CurColour &= ~0x80000000; break; // Dim
- }
- }
- // Foreground Colour
- else if(30 <= args[argc] && args[argc] <= 37) {
- // Get colour index, accounting for bright bit
- colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
- Term->CurColour &= 0x8000FFFF;
- Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
- }
- // Background Colour
- else if(40 <= args[argc] && args[argc] <= 47) {
- // Get colour index, accounting for bright bit
- colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
- Term->CurColour &= 0xFFFF8000;
- Term->CurColour |= caVT100Colours[ colour_idx ];
- }
- else {
- Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
- }
- }
- break;
-
- // Set scrolling region
- case 'r':
- if( argc != 2 ) break;
- Term->ScrollTop = args[0];
- Term->ScrollHeight = args[1] - args[0];
- break;
-
- default:
- Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
- break;
- }
-}
-
-/**
- * \fn int VT_int_ParseEscape(tVTerm *Term, 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[6] = {0,0,0,0};
- int bQuestionMark = 0;
-
- switch(Buffer[0])
- {
- //Large Code
- case '[':
- // Get Arguments
- c = Buffer[j++];
- if(c == '?') {
- bQuestionMark = 1;
- c = Buffer[j++];
- }
- if( '0' <= c && c <= '9' )
- {
- do {
- if(c == ';') c = Buffer[j++];
- while('0' <= c && c <= '9') {
- args[argc] *= 10;
- args[argc] += c-'0';
- c = Buffer[j++];
- }
- argc ++;
- } while(c == ';');
- }
-
- // Get Command
- if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
- {
- if( bQuestionMark )
- {
- switch(c)
- {
- // DEC Private Mode Set
- case 'h':
- if(argc != 1) break;
- switch(args[0])
- {
- case 25:
- Term->Flags &= ~VT_FLAG_HIDECSR;
- break;
- case 1047:
- VT_int_ToggleAltBuffer(Term, 1);
- break;
- }
- break;
- case 'l':
- if(argc != 1) break;
- switch(args[0])
- {
- case 25:
- Term->Flags |= VT_FLAG_HIDECSR;
- break;
- case 1047:
- VT_int_ToggleAltBuffer(Term, 0);
- break;
- }
- break;
- default:
- Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
- break;
- }
- }
- else
- {
- VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
- }
- }
- break;
-
- default:
- Log_Notice("VTerm", "TODO: Handle short escape codes");
- break;
- }
-
- //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
- return j;
-}
-
-/**
- * \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;
-
- // Iterate
- for( i = 0; i < Count; i++ )
- {
- // Handle escape sequences
- if( Buffer[i] == 0x1B )
- {
- i ++;
- i += VT_int_ParseEscape(Term, (char*)&Buffer[i]) - 1;
- continue;
- }
-
- // Fast check for non UTF-8
- if( Buffer[i] < 128 ) // Plain ASCII
- VT_int_PutChar(Term, Buffer[i]);
- else { // UTF-8
- i += ReadUTF8(&Buffer[i], &val) - 1;
- VT_int_PutChar(Term, val);
- }
- }
- // Update Screen
- VT_int_UpdateScreen( Term, 0 );
-}
-
-/**
- * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
- * \brief Write a single character to a VTerm
- */
-void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
-{
- int i;
- tVT_Char *buffer;
- int write_pos;
-
- if(Term->Flags & VT_FLAG_ALTBUF) {
- buffer = Term->AltBuf;
- write_pos = Term->AltWritePos;
- }
- else {
- buffer = Term->Text;
- write_pos = Term->WritePos;
- }
-
- switch(Ch)
- {
- case '\0': return; // Ignore NULL byte
- case '\n':
- VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
- write_pos += Term->TextWidth;
- case '\r':
- write_pos -= write_pos % Term->TextWidth;
- break;
-
- case '\t': { int tmp = write_pos / Term->TextWidth;
- write_pos %= Term->TextWidth;
- do {
- buffer[ write_pos ].Ch = '\0';
- buffer[ write_pos ].Colour = Term->CurColour;
- write_pos ++;
- } while(write_pos & 7);
- write_pos += tmp * Term->TextWidth;
- break; }
-
- case '\b':
- // Backspace is invalid at Offset 0
- if(write_pos == 0) break;
-
- write_pos --;
- // Singe Character
- if(buffer[ write_pos ].Ch != '\0') {
- buffer[ write_pos ].Ch = 0;
- buffer[ write_pos ].Colour = Term->CurColour;
- break;
- }
- // Tab
- i = 7; // Limit it to 8
- do {
- buffer[ write_pos ].Ch = 0;
- buffer[ write_pos ].Colour = Term->CurColour;
- write_pos --;
- } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
- if(buffer[ write_pos ].Ch != '\0')
- write_pos ++;
- break;
-
- default:
- buffer[ write_pos ].Ch = Ch;
- buffer[ write_pos ].Colour = Term->CurColour;
- // Update the line before wrapping
- if( (write_pos + 1) % Term->TextWidth == 0 )
- VT_int_UpdateScreen( Term, 0 );
- write_pos ++;
- break;
- }
-
- if(Term->Flags & VT_FLAG_ALTBUF)
- {
- Term->AltBuf = buffer;
- Term->AltWritePos = write_pos;
-
- if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
- {
- Term->AltWritePos -= Term->TextWidth;
- VT_int_ScrollText(Term, 1);
- }
-
- }
- else
- {
- Term->Text = buffer;
- Term->WritePos = write_pos;
- // Move Screen
- // - Check if we need to scroll the entire scrollback buffer
- if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
- {
- int base;
-
- // Update previous line
- Term->WritePos -= Term->TextWidth;
- VT_int_UpdateScreen( Term, 0 );
-
- // Update view position
- base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
- if(Term->ViewPos < base)
- Term->ViewPos += Term->Width;
- if(Term->ViewPos > base)
- Term->ViewPos = base;
-
- VT_int_ScrollText(Term, 1);
- }
- // Ok, so we only need to scroll the screen
- else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
- {
- // Update the last line
- Term->WritePos -= Term->TextWidth;
- VT_int_UpdateScreen( Term, 0 );
- Term->WritePos += Term->TextWidth;
-
- VT_int_ScrollText(Term, 1);
-
- Term->ViewPos += Term->TextWidth;
- }
- }
-
- //LEAVE('-');
-}
-
-void VT_int_ScrollText(tVTerm *Term, int Count)
-{
- tVT_Char *buf;
- int height, init_write_pos;
- int len, i;
- int scroll_top, scroll_height;
-
- // Get buffer pointer and attributes
- if( Term->Flags & VT_FLAG_ALTBUF )
- {
- buf = Term->AltBuf;
- height = Term->TextHeight;
- init_write_pos = Term->AltWritePos;
- scroll_top = Term->ScrollTop;
- scroll_height = Term->ScrollHeight;
- }
- else
- {
- buf = Term->Text;
- height = Term->TextHeight*(giVT_Scrollback+1);
- init_write_pos = Term->WritePos;
- scroll_top = 0;
- scroll_height = height;
- }
-
- // Scroll text downwards
- if( Count > 0 )
- {
- int base;
-
- // Set up
- if(Count > scroll_height) Count = scroll_height;
- base = Term->TextWidth*(scroll_top + scroll_height - Count);
- len = Term->TextWidth*(scroll_height - Count);
-
- // Scroll terminal cache
- memmove(
- &buf[Term->TextWidth*scroll_top],
- &buf[Term->TextWidth*(scroll_top+Count)],
- len*sizeof(tVT_Char)
- );
- // Clear last rows
- for( i = 0; i < Term->TextWidth*Count; i ++ )
- {
- buf[ base + i ].Ch = 0;
- buf[ base + i ].Colour = Term->CurColour;
- }
-
- // Update Screen
- VT_int_ScrollFramebuffer( Term, Count );
- if( Term->Flags & VT_FLAG_ALTBUF )
- Term->AltWritePos = base;
- else
- Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
- for( i = 0; i < Count; i ++ )
- {
- VT_int_UpdateScreen( Term, 0 );
- if( Term->Flags & VT_FLAG_ALTBUF )
- Term->AltWritePos += Term->TextWidth;
- else
- Term->WritePos += Term->TextWidth;
- }
- }
- else
- {
- Count = -Count;
- if(Count > scroll_height) Count = scroll_height;
-
- len = Term->TextWidth*(scroll_height - Count);
-
- // Scroll terminal cache
- memmove(
- &buf[Term->TextWidth*(scroll_top+Count)],
- &buf[Term->TextWidth*scroll_top],
- len*sizeof(tVT_Char)
- );
- // Clear preceding rows
- for( i = 0; i < Term->TextWidth*Count; i ++ )
- {
- buf[ i ].Ch = 0;
- buf[ i ].Colour = Term->CurColour;
- }
-
- VT_int_ScrollFramebuffer( Term, -Count );
- if( Term->Flags & VT_FLAG_ALTBUF )
- Term->AltWritePos = Term->TextWidth*scroll_top;
- else
- Term->WritePos = Term->ViewPos;
- for( i = 0; i < Count; i ++ )
- {
- VT_int_UpdateScreen( Term, 0 );
- if( Term->Flags & VT_FLAG_ALTBUF )
- Term->AltWritePos += Term->TextWidth;
- else
- Term->WritePos += Term->TextWidth;
- }
- }
-
- if( Term->Flags & VT_FLAG_ALTBUF )
- Term->AltWritePos = init_write_pos;
- else
- Term->WritePos = init_write_pos;
-}
-
-/**
- * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
- * \note Scrolls the framebuffer down by \a Count text lines
- */
-void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
-{
- int tmp;
- struct {
- Uint8 Op;
- Uint16 DstX, DstY;
- Uint16 SrcX, SrcY;
- Uint16 W, H;
- } PACKED buf;
-
- // Only update if this is the current terminal
- if( Term != gpVT_CurTerm ) return;
-
- if( Count > Term->ScrollHeight ) Count = Term->ScrollHeight;
- if( Count < -Term->ScrollHeight ) Count = -Term->ScrollHeight;
-
- // Switch to 2D Command Stream
- tmp = VIDEO_BUFFMT_2DSTREAM;
- VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
-
- // BLIT to 0,0 from 0,giVT_CharHeight
- buf.Op = VIDEO_2DOP_BLIT;
- buf.SrcX = 0; buf.DstX = 0;
- // TODO: Don't assume character dimensions
- buf.W = Term->TextWidth * giVT_CharWidth;
- if( Count > 0 )
- {
- buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
- buf.DstY = Term->ScrollTop * giVT_CharHeight;
- }
- else // Scroll up, move text down
- {
- Count = -Count;
- buf.SrcY = Term->ScrollTop * giVT_CharHeight;
- buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
- }
- buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
- VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
-
- // Restore old mode (this function is only called during text mode)
- tmp = VIDEO_BUFFMT_TEXT;
- VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
-}
-
-void VT_int_UpdateCursor( tVTerm *Term, int bShow )
-{
- tVideo_IOCtl_Pos csr_pos;
-
- if( Term != gpVT_CurTerm ) return ;
-
- if( !bShow )
- {
- csr_pos.x = -1;
- csr_pos.y = -1;
- }
- else if( Term->Mode == TERM_MODE_TEXT )
- {
- int offset;
-
-// if( !(Term->Flags & VT_FLAG_SHOWCSR)
-// && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads)
-// )
- if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR )
- {
- csr_pos.x = -1;
- csr_pos.y = -1;
- }
- else
- {
- if(Term->Flags & VT_FLAG_ALTBUF)
- offset = Term->AltWritePos;
- else
- offset = Term->WritePos - Term->ViewPos;
-
- csr_pos.x = offset % Term->TextWidth;
- csr_pos.y = offset / Term->TextWidth;
- if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight )
- csr_pos.y = -1, csr_pos.x = -1;
- }
- }
- else
- {
- csr_pos.x = Term->VideoCursorX;
- csr_pos.y = Term->VideoCursorY;
- }
- VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
-}
-
-/**
- * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
- * \brief Updates the video framebuffer
- */
-void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
-{
- tVT_Char *buffer;
- int view_pos, write_pos;
- // Only update if this is the current terminal
- if( Term != gpVT_CurTerm ) return;
-
- switch( Term->Mode )
- {
- case TERM_MODE_TEXT:
- view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos;
- write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
- buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
- // Re copy the entire screen?
- if(UpdateAll) {
- VFS_WriteAt(
- giVT_OutputDevHandle,
- 0,
- Term->TextWidth*Term->TextHeight*sizeof(tVT_Char),
- &buffer[view_pos]
- );
- }
- // Only copy the current line
- else {
- int ofs = write_pos - write_pos % Term->TextWidth;
- VFS_WriteAt(
- giVT_OutputDevHandle,
- (ofs - view_pos)*sizeof(tVT_Char),
- Term->TextWidth*sizeof(tVT_Char),
- &buffer[ofs]
- );
- }
- break;
- case TERM_MODE_FB:
- break;
- }
-
- VT_int_UpdateCursor(Term, 1);
-}
-
-/**
- * \brief Update the screen mode
- * \param Term Terminal to update
- * \param NewMode New mode to set
- * \param NewWidth New framebuffer width
- * \param NewHeight New framebuffer height
- */
-void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
-{
- int oldW = Term->Width;
- int oldTW = Term->TextWidth;
- int oldH = Term->Height;
- int oldTH = Term->TextHeight;
- tVT_Char *oldTBuf = Term->Text;
- Uint32 *oldFB = Term->Buffer;
- int w, h, i;
-
- // TODO: Increase RealWidth/RealHeight when this happens
- if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth;
- if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
-
- Term->Mode = NewMode;
-
- // Fast exit if no resolution change
- if(NewWidth == Term->Width && NewHeight == Term->Height)
- return ;
-
- // Calculate new dimensions
- Term->Width = NewWidth;
- Term->Height = NewHeight;
- Term->TextWidth = NewWidth / giVT_CharWidth;
- Term->TextHeight = NewHeight / giVT_CharHeight;
- Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
-
- // Allocate new buffers
- // - Text
- Term->Text = calloc(
- Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
- sizeof(tVT_Char)
- );
- if(oldTBuf) {
- // Copy old buffer
- w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
- h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
- h *= giVT_Scrollback + 1;
- for( i = 0; i < h; i ++ )
- {
- memcpy(
- &Term->Text[i*Term->TextWidth],
- &oldTBuf[i*oldTW],
- w*sizeof(tVT_Char)
- );
- }
- free(oldTBuf);
- }
-
- // - Alternate Text
- Term->AltBuf = realloc(
- Term->AltBuf,
- Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
- );
-
- // - Framebuffer
- if(oldFB) {
- Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
- // Copy old buffer
- w = (oldW > Term->Width) ? Term->Width : oldW;
- h = (oldH > Term->Height) ? Term->Height : oldH;
- for( i = 0; i < h; i ++ )
- {
- memcpy(
- &Term->Buffer[i*Term->Width],
- &oldFB[i*oldW],
- w*sizeof(Uint32)
- );
- }
- free(oldFB);
- }
-
- // Debug
- switch(NewMode)
- {
- case TERM_MODE_TEXT:
- Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
- Term, Term->TextWidth, Term->TextHeight);
- break;
- case TERM_MODE_FB:
- Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
- Term, Term->Width, Term->Height);
- break;
- //case TERM_MODE_2DACCEL:
- //case TERM_MODE_3DACCEL:
- // return;
- }
-}
-
-
-void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
-{
- if(Enabled)
- Term->Flags |= VT_FLAG_ALTBUF;
- else
- Term->Flags &= ~VT_FLAG_ALTBUF;
- VT_int_UpdateScreen(Term, 1);
-}
-
-// ---
-// Font Render
-// ---
-#define MONOSPACE_FONT 10816
-
-#if MONOSPACE_FONT == 10808 // 8x8
-# include "vterm_font_8x8.h"
-#elif MONOSPACE_FONT == 10816 // 8x16
-# include "vterm_font_8x16.h"
-#endif
-
-// === PROTOTYPES ===
-Uint8 *VT_Font_GetChar(Uint32 Codepoint);
-
-// === GLOBALS ===
-int giVT_CharWidth = FONT_WIDTH;
-int giVT_CharHeight = FONT_HEIGHT;
-
-// === CODE ===
-/**
- * \brief Render a font character
- */
-void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC)
-{
- Uint8 *font;
- int x, y;
-
- // 8-bpp and below
- if( Depth <= 8 )
- {
- Uint8 *buf = Buffer;
-
- font = VT_Font_GetChar(Codepoint);
-
- for(y = 0; y < FONT_HEIGHT; y ++)
- {
- for(x = 0; x < FONT_WIDTH; x ++)
- {
- if(*font & (1 << (FONT_WIDTH-x-1)))
- buf[x] = FGC;
- else
- buf[x] = BGC;
- }
- buf = (void*)( (tVAddr)buf + Pitch );
- font ++;
- }
- }
- // 16-bpp and below
- else if( Depth <= 16 )
- {
- Uint16 *buf = Buffer;
-
- font = VT_Font_GetChar(Codepoint);
-
- for(y = 0; y < FONT_HEIGHT; y ++)
- {
- for(x = 0; x < FONT_WIDTH; x ++)
- {
- if(*font & (1 << (FONT_WIDTH-x-1)))
- buf[x] = FGC;
- else
- buf[x] = BGC;
- }
- buf = (void*)( (tVAddr)buf + Pitch );
- font ++;
- }
- }
- // 24-bpp colour
- // - Special handling to not overwrite the next pixel
- //TODO: Endian issues here
- else if( Depth == 24 )
- {
- Uint8 *buf = Buffer;
- Uint8 bg_r = (BGC >> 16) & 0xFF;
- Uint8 bg_g = (BGC >> 8) & 0xFF;
- Uint8 bg_b = (BGC >> 0) & 0xFF;
- Uint8 fg_r = (FGC >> 16) & 0xFF;
- Uint8 fg_g = (FGC >> 8) & 0xFF;
- Uint8 fg_b = (FGC >> 0) & 0xFF;
-
- font = VT_Font_GetChar(Codepoint);
-
- for(y = 0; y < FONT_HEIGHT; y ++)
- {
- for(x = 0; x < FONT_WIDTH; x ++)
- {
- Uint8 r, g, b;
-
- if(*font & (1 << (FONT_WIDTH-x-1))) {
- r = fg_r; g = fg_g; b = fg_b;
- }
- else {
- r = bg_r; g = bg_g; b = bg_b;
- }
- buf[x*3+0] = b;
- buf[x*3+1] = g;
- buf[x*3+2] = r;
- }
- buf = (void*)( (tVAddr)buf + Pitch );
- font ++;
- }
- }
- // 32-bpp colour (nice and easy)
- else if( Depth == 32 )
- {
- Uint32 *buf = Buffer;
-
- font = VT_Font_GetChar(Codepoint);
-
- for(y = 0; y < FONT_HEIGHT; y ++)
- {
- for(x = 0; x < FONT_WIDTH; x ++)
- {
- if(*font & (1 << (FONT_WIDTH-x-1)))
- buf[x] = FGC;
- else
- buf[x] = BGC;
- }
- buf = (Uint32*)( (tVAddr)buf + Pitch );
- font ++;
- }
- }
-}
-
-/**
- * \fn Uint32 VT_Colour12to24(Uint16 Col12)
- * \brief Converts a 12-bit colour into 24 bits
- */
-Uint32 VT_Colour12to24(Uint16 Col12)
-{
- Uint32 ret;
- int tmp;
- tmp = Col12 & 0xF;
- ret = (tmp << 0) | (tmp << 4);
- tmp = (Col12 & 0xF0) >> 4;
- ret |= (tmp << 8) | (tmp << 12);
- tmp = (Col12 & 0xF00) >> 8;
- ret |= (tmp << 16) | (tmp << 20);
- return ret;
-}
-/**
- * \brief Converts a 12-bit colour into 15 bits
- */
-Uint16 VT_Colour12to15(Uint16 Col12)
-{
- Uint32 ret;
- int tmp;
- tmp = Col12 & 0xF;
- ret = (tmp << 1) | (tmp & 1);
- tmp = (Col12 & 0xF0) >> 4;
- ret |= ( (tmp << 1) | (tmp & 1) ) << 5;
- tmp = (Col12 & 0xF00) >> 8;
- ret |= ( (tmp << 1) | (tmp & 1) ) << 10;
- return ret;
-}
-
-/**
- * \brief Converts a 12-bit colour into any other depth
- * \param Col12 12-bit source colour
- * \param Depth Desired bit deptj
- * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5)
- */
-Uint32 VT_Colour12toN(Uint16 Col12, int Depth)
-{
- Uint32 ret;
- Uint32 r, g, b;
- int rSize, gSize, bSize;
-
- // Fast returns
- if( Depth == 24 ) return VT_Colour12to24(Col12);
- if( Depth == 15 ) return VT_Colour12to15(Col12);
- // - 32 is a special case, it's usually 24-bit colour with an unused byte
- if( Depth == 32 ) return VT_Colour12to24(Col12);
-
- // Bounds checks
- if( Depth < 8 ) return 0;
- if( Depth > 32 ) return 0;
-
- r = Col12 & 0xF;
- g = (Col12 & 0xF0) >> 4;
- b = (Col12 & 0xF00) >> 8;
-
- rSize = gSize = bSize = Depth / 3;
- if( rSize + gSize + bSize < Depth ) // Depth % 3 == 1
- gSize ++;
- if( rSize + gSize + bSize < Depth ) // Depth % 3 == 2
- bSize ++;
-
- // Expand
- r <<= rSize - 4; g <<= gSize - 4; b <<= bSize - 4;
- // Fill with the lowest bit
- if( Col12 & 0x001 ) r |= (1 << (rSize - 4)) - 1;
- if( Col12 & 0x010 ) r |= (1 << (gSize - 4)) - 1;
- if( Col12 & 0x100 ) r |= (1 << (bSize - 4)) - 1;
-
- // Create output
- ret = r;
- ret |= g << rSize;
- ret |= b << (rSize + gSize);
-
- return ret;
-}
-
-/**
- * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)
- * \brief Gets an index into the font array given a Unicode Codepoint
- * \note See http://en.wikipedia.org/wiki/CP437
- */
-Uint8 *VT_Font_GetChar(Uint32 Codepoint)
-{
- int index = 0;
- if(Codepoint < 128)
- return &VTermFont[Codepoint*FONT_HEIGHT];
- switch(Codepoint)
- {
- case 0xC7: index = 128; break; // Ç
- case 0xFC: index = 129; break; // ü
- case 0xE9: index = 130; break; // é
- case 0xE2: index = 131; break; // â
- case 0xE4: index = 132; break; // ä
- case 0xE0: index = 133; break; // Ã
- case 0xE5: index = 134; break; // å
- case 0xE7: index = 135; break; // ç
- case 0xEA: index = 136; break; // ê
- case 0xEB: index = 137; break; // ë
- case 0xE8: index = 138; break; // è
- case 0xEF: index = 139; break; // ï
- case 0xEE: index = 140; break; // î
- case 0xEC: index = 141; break; // ì
- case 0xC4: index = 142; break; // Ä
- case 0xC5: index = 143; break; // Ã…
- }
-
- return &VTermFont[index*FONT_HEIGHT];
-}
-
-EXPORTAS(&giVT_CharWidth, giVT_CharWidth);
-EXPORTAS(&giVT_CharHeight, giVT_CharHeight);
-EXPORT(VT_Font_Render);
-EXPORT(VT_Colour12to24);
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm.h
+ * - Virtual Terminal - Common
+ */
+#ifndef _VTERM_H_
+#define _VTERM_H_
+
+#include <acess.h>
+#include <api_drv_video.h> // tVT_Char
+#include <api_drv_terminal.h>
+#include <vfs.h>
+
+// === CONSTANTS ===
+#define MAX_INPUT_CHARS32 64
+#define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4)
+#define DEFAULT_COLOUR (VT_COL_BLACK|(0xAAA<<16))
+
+/**
+ * \{
+ */
+#define VT_FLAG_HIDECSR 0x01 //!< Hide the cursor
+#define VT_FLAG_ALTBUF 0x02 //!< Alternate screen buffer
+#define VT_FLAG_RAWIN 0x04 //!< Don't handle ^Z/^C/^V
+#define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer
+#define VT_FLAG_SHOWCSR 0x20 //!< Always show the text cursor
+/**
+ * \}
+ */
+
+enum eVT_InModes {
+ VT_INMODE_TEXT8, // UTF-8 Text Mode (VT100/xterm Emulation)
+ VT_INMODE_TEXT32, // UTF-32 Text Mode (Acess Native)
+ NUM_VT_INMODES
+};
+
+
+// === TYPES ==
+typedef struct sVTerm tVTerm;
+
+// === STRUCTURES ===
+struct sVTerm
+{
+ int Mode; //!< Current Mode (see ::eTplTerminal_Modes)
+ int Flags; //!< Flags (see VT_FLAG_*)
+
+ short NewWidth; //!< Un-applied dimensions (Width)
+ short NewHeight; //!< Un-applied dimensions (Height)
+ short Width; //!< Virtual Width
+ short Height; //!< Virtual Height
+ short TextWidth; //!< Text Virtual Width
+ short TextHeight; //!< Text Virtual Height
+
+ Uint32 CurColour; //!< Current Text Colour
+
+ int ViewPos; //!< View Buffer Offset (Text Only)
+ int WritePos; //!< Write Buffer Offset (Text Only)
+ tVT_Char *Text;
+
+ tVT_Char *AltBuf; //!< Alternate Screen Buffer
+ int AltWritePos; //!< Alternate write position
+ short ScrollTop; //!< Top of scrolling region (smallest)
+ short ScrollHeight; //!< Length of scrolling region
+
+ int VideoCursorX;
+ int VideoCursorY;
+
+ tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it
+ tTID ReadingThread; //!< Owner of the lock
+ int InputRead; //!< Input buffer read position
+ int InputWrite; //!< Input buffer write position
+ char InputBuffer[MAX_INPUT_CHARS8];
+// tSemaphore InputSemaphore;
+
+ Uint32 *Buffer;
+
+ // TODO: Do I need to keep this about?
+ // When should it be deallocated? on move to text mode, or some other time
+ // Call set again, it's freed, and if NULL it doesn't get reallocated.
+ tVideo_IOCtl_Bitmap *VideoCursor;
+
+ char Name[2]; //!< Name of the terminal
+ tVFS_Node Node;
+};
+
+// === GOBALS ===
+extern tVTerm *gpVT_CurTerm;
+extern int giVT_Scrollback;
+extern short giVT_RealWidth; //!< Screen Width
+extern short giVT_RealHeight; //!< Screen Width
+extern char *gsVT_OutputDevice;
+extern char *gsVT_InputDevice;
+extern int giVT_OutputDevHandle;
+extern int giVT_InputDevHandle;
+
+// === FUNCTIONS ===
+extern void VT_SetResolution(int Width, int Height);
+extern void VT_SetTerminal(int ID);
+// --- Output ---
+extern void VT_InitOutput(void);
+extern void VT_SetMode(int Mode);
+extern void VT_int_ScrollFramebuffer( tVTerm *Term, int Count );
+extern void VT_int_UpdateCursor( tVTerm *Term, int bShow );
+extern void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll );
+// --- Input ---
+extern void VT_InitInput(void);
+extern void VT_KBCallBack(Uint32 Codepoint);
+// --- VT100 Emulation ---
+extern void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args);
+extern int VT_int_ParseEscape(tVTerm *Term, const char *Buffer);
+// --- Terminal Buffer ---
+extern void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count);
+extern void VT_int_PutChar(tVTerm *Term, Uint32 Ch);
+extern void VT_int_ScrollText(tVTerm *Term, int Count);
+extern void VT_int_ClearLine(tVTerm *Term, int Num);
+extern void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight);
+extern void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_font.c
+ * - Virtual Terminal - Font rendering code
+ */
+#include "vterm.h"
+#include <api_drv_terminal.h>
+
+// ---
+// Font Render
+// ---
+#define MONOSPACE_FONT 10816
+
+#if MONOSPACE_FONT == 10808 // 8x8
+# include "vterm_font_8x8.h"
+#elif MONOSPACE_FONT == 10816 // 8x16
+# include "vterm_font_8x16.h"
+#endif
+
+// === PROTOTYPES ===
+Uint8 *VT_Font_GetChar(Uint32 Codepoint);
+
+// === GLOBALS ===
+int giVT_CharWidth = FONT_WIDTH;
+int giVT_CharHeight = FONT_HEIGHT;
+
+// === CODE ===
+/**
+ * \brief Render a font character
+ */
+void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC)
+{
+ Uint8 *font;
+ int x, y;
+
+ // 8-bpp and below
+ if( Depth <= 8 )
+ {
+ Uint8 *buf = Buffer;
+
+ font = VT_Font_GetChar(Codepoint);
+
+ for(y = 0; y < FONT_HEIGHT; y ++)
+ {
+ for(x = 0; x < FONT_WIDTH; x ++)
+ {
+ if(*font & (1 << (FONT_WIDTH-x-1)))
+ buf[x] = FGC;
+ else
+ buf[x] = BGC;
+ }
+ buf = (void*)( (tVAddr)buf + Pitch );
+ font ++;
+ }
+ }
+ // 16-bpp and below
+ else if( Depth <= 16 )
+ {
+ Uint16 *buf = Buffer;
+
+ font = VT_Font_GetChar(Codepoint);
+
+ for(y = 0; y < FONT_HEIGHT; y ++)
+ {
+ for(x = 0; x < FONT_WIDTH; x ++)
+ {
+ if(*font & (1 << (FONT_WIDTH-x-1)))
+ buf[x] = FGC;
+ else
+ buf[x] = BGC;
+ }
+ buf = (void*)( (tVAddr)buf + Pitch );
+ font ++;
+ }
+ }
+ // 24-bpp colour
+ // - Special handling to not overwrite the next pixel
+ //TODO: Endian issues here
+ else if( Depth == 24 )
+ {
+ Uint8 *buf = Buffer;
+ Uint8 bg_r = (BGC >> 16) & 0xFF;
+ Uint8 bg_g = (BGC >> 8) & 0xFF;
+ Uint8 bg_b = (BGC >> 0) & 0xFF;
+ Uint8 fg_r = (FGC >> 16) & 0xFF;
+ Uint8 fg_g = (FGC >> 8) & 0xFF;
+ Uint8 fg_b = (FGC >> 0) & 0xFF;
+
+ font = VT_Font_GetChar(Codepoint);
+
+ for(y = 0; y < FONT_HEIGHT; y ++)
+ {
+ for(x = 0; x < FONT_WIDTH; x ++)
+ {
+ Uint8 r, g, b;
+
+ if(*font & (1 << (FONT_WIDTH-x-1))) {
+ r = fg_r; g = fg_g; b = fg_b;
+ }
+ else {
+ r = bg_r; g = bg_g; b = bg_b;
+ }
+ buf[x*3+0] = b;
+ buf[x*3+1] = g;
+ buf[x*3+2] = r;
+ }
+ buf = (void*)( (tVAddr)buf + Pitch );
+ font ++;
+ }
+ }
+ // 32-bpp colour (nice and easy)
+ else if( Depth == 32 )
+ {
+ Uint32 *buf = Buffer;
+
+ font = VT_Font_GetChar(Codepoint);
+
+ for(y = 0; y < FONT_HEIGHT; y ++)
+ {
+ for(x = 0; x < FONT_WIDTH; x ++)
+ {
+ if(*font & (1 << (FONT_WIDTH-x-1)))
+ buf[x] = FGC;
+ else
+ buf[x] = BGC;
+ }
+ buf = (Uint32*)( (tVAddr)buf + Pitch );
+ font ++;
+ }
+ }
+}
+
+/**
+ * \fn Uint32 VT_Colour12to24(Uint16 Col12)
+ * \brief Converts a 12-bit colour into 24 bits
+ */
+Uint32 VT_Colour12to24(Uint16 Col12)
+{
+ Uint32 ret;
+ int tmp;
+ tmp = Col12 & 0xF;
+ ret = (tmp << 0) | (tmp << 4);
+ tmp = (Col12 & 0xF0) >> 4;
+ ret |= (tmp << 8) | (tmp << 12);
+ tmp = (Col12 & 0xF00) >> 8;
+ ret |= (tmp << 16) | (tmp << 20);
+ return ret;
+}
+/**
+ * \brief Converts a 12-bit colour into 15 bits
+ */
+Uint16 VT_Colour12to15(Uint16 Col12)
+{
+ Uint32 ret;
+ int tmp;
+ tmp = Col12 & 0xF;
+ ret = (tmp << 1) | (tmp & 1);
+ tmp = (Col12 & 0xF0) >> 4;
+ ret |= ( (tmp << 1) | (tmp & 1) ) << 5;
+ tmp = (Col12 & 0xF00) >> 8;
+ ret |= ( (tmp << 1) | (tmp & 1) ) << 10;
+ return ret;
+}
+
+/**
+ * \brief Converts a 12-bit colour into any other depth
+ * \param Col12 12-bit source colour
+ * \param Depth Desired bit deptj
+ * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5)
+ */
+Uint32 VT_Colour12toN(Uint16 Col12, int Depth)
+{
+ Uint32 ret;
+ Uint32 r, g, b;
+ int rSize, gSize, bSize;
+
+ // Fast returns
+ if( Depth == 24 ) return VT_Colour12to24(Col12);
+ if( Depth == 15 ) return VT_Colour12to15(Col12);
+ // - 32 is a special case, it's usually 24-bit colour with an unused byte
+ if( Depth == 32 ) return VT_Colour12to24(Col12);
+
+ // Bounds checks
+ if( Depth < 8 ) return 0;
+ if( Depth > 32 ) return 0;
+
+ r = Col12 & 0xF;
+ g = (Col12 & 0xF0) >> 4;
+ b = (Col12 & 0xF00) >> 8;
+
+ rSize = gSize = bSize = Depth / 3;
+ if( rSize + gSize + bSize < Depth ) // Depth % 3 == 1
+ gSize ++;
+ if( rSize + gSize + bSize < Depth ) // Depth % 3 == 2
+ bSize ++;
+
+ // Expand
+ r <<= rSize - 4; g <<= gSize - 4; b <<= bSize - 4;
+ // Fill with the lowest bit
+ if( Col12 & 0x001 ) r |= (1 << (rSize - 4)) - 1;
+ if( Col12 & 0x010 ) r |= (1 << (gSize - 4)) - 1;
+ if( Col12 & 0x100 ) r |= (1 << (bSize - 4)) - 1;
+
+ // Create output
+ ret = r;
+ ret |= g << rSize;
+ ret |= b << (rSize + gSize);
+
+ return ret;
+}
+
+/**
+ * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint)
+ * \brief Gets an index into the font array given a Unicode Codepoint
+ * \note See http://en.wikipedia.org/wiki/CP437
+ */
+Uint8 *VT_Font_GetChar(Uint32 Codepoint)
+{
+ int index = 0;
+ if(Codepoint < 128)
+ return &VTermFont[Codepoint*FONT_HEIGHT];
+ switch(Codepoint)
+ {
+ case 0xC7: index = 128; break; // Ç
+ case 0xFC: index = 129; break; // ü
+ case 0xE9: index = 130; break; // é
+ case 0xE2: index = 131; break; // â
+ case 0xE4: index = 132; break; // ä
+ case 0xE0: index = 133; break; // Ã
+ case 0xE5: index = 134; break; // å
+ case 0xE7: index = 135; break; // ç
+ case 0xEA: index = 136; break; // ê
+ case 0xEB: index = 137; break; // ë
+ case 0xE8: index = 138; break; // è
+ case 0xEF: index = 139; break; // ï
+ case 0xEE: index = 140; break; // î
+ case 0xEC: index = 141; break; // ì
+ case 0xC4: index = 142; break; // Ä
+ case 0xC5: index = 143; break; // Ã…
+ }
+
+ return &VTermFont[index*FONT_HEIGHT];
+}
+
+EXPORTAS(&giVT_CharWidth, giVT_CharWidth);
+EXPORTAS(&giVT_CharHeight, giVT_CharHeight);
+EXPORT(VT_Font_Render);
+EXPORT(VT_Colour12to24);
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_input.c
+ * - Virtual Terminal - Input code
+ */
+#include "vterm.h"
+#include <api_drv_keyboard.h>
+
+// === GLOBALS ===
+// --- Key States --- (Used for VT Switching/Magic Combos)
+ int gbVT_CtrlDown = 0;
+ int gbVT_AltDown = 0;
+ int gbVT_SysrqDown = 0;
+
+// === CODE ===
+/**
+ * \fn void VT_InitInput()
+ * \brief Initialises the input
+ */
+void VT_InitInput()
+{
+ giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ);
+ if(giVT_InputDevHandle == -1) {
+ Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice);
+ return ;
+ }
+ VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
+}
+
+/**
+ * \fn void VT_KBCallBack(Uint32 Codepoint)
+ * \brief Called on keyboard interrupt
+ * \param Codepoint Pseudo-UTF32 character
+ *
+ * Handles a key press and sends the key code to the user's buffer.
+ * If the code creates a kernel-magic sequence, it is not passed to the
+ * user and is handled in-kernel.
+ */
+void VT_KBCallBack(Uint32 Codepoint)
+{
+ tVTerm *term = gpVT_CurTerm;
+
+ // Catch VT binds
+ switch( Codepoint & KEY_ACTION_MASK )
+ {
+ case KEY_ACTION_RELEASE:
+ switch(Codepoint & KEY_CODEPOINT_MASK)
+ {
+ case KEY_LALT: gbVT_AltDown &= ~1; break;
+ case KEY_RALT: gbVT_AltDown &= ~2; break;
+ case KEY_LCTRL: gbVT_CtrlDown &= ~1; break;
+ case KEY_RCTRL: gbVT_CtrlDown &= ~2; break;
+ }
+ break;
+
+ case KEY_ACTION_PRESS:
+ switch(Codepoint & KEY_CODEPOINT_MASK)
+ {
+ case KEY_LALT: gbVT_AltDown |= 1; break;
+ case KEY_RALT: gbVT_AltDown |= 2; break;
+ case KEY_LCTRL: gbVT_CtrlDown |= 1; break;
+ case KEY_RCTRL: gbVT_CtrlDown |= 2; break;
+ }
+
+ if(!gbVT_AltDown || !gbVT_CtrlDown)
+ break;
+ switch(Codepoint & KEY_CODEPOINT_MASK)
+ {
+ case KEY_F1: VT_SetTerminal(0); return;
+ case KEY_F2: VT_SetTerminal(1); return;
+ case KEY_F3: VT_SetTerminal(2); return;
+ case KEY_F4: VT_SetTerminal(3); return;
+ case KEY_F5: VT_SetTerminal(4); return;
+ case KEY_F6: VT_SetTerminal(5); return;
+ case KEY_F7: VT_SetTerminal(6); return;
+ case KEY_F8: VT_SetTerminal(7); return;
+ case KEY_F9: VT_SetTerminal(8); return;
+ case KEY_F10: VT_SetTerminal(9); return;
+ case KEY_F11: VT_SetTerminal(10); return;
+ case KEY_F12: VT_SetTerminal(11); return;
+ }
+
+ // Scrolling is only valid in text mode
+ if(gpVT_CurTerm->Mode != TERM_MODE_TEXT)
+ break;
+
+ switch(Codepoint & KEY_CODEPOINT_MASK)
+ {
+ // Scrolling
+ case KEY_PGUP:
+ if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
+ return ;
+ gpVT_CurTerm->ViewPos = MAX(
+ 0,
+ gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width
+ );
+ return;
+ case KEY_PGDOWN:
+ if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
+ return ;
+ gpVT_CurTerm->ViewPos = MIN(
+ gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width,
+ gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback
+ );
+ return;
+ }
+ break;
+ }
+
+ // Encode key
+ if(term->Mode == TERM_MODE_TEXT)
+ {
+ Uint8 buf[6] = {0};
+ int len = 0;
+
+ // Ignore anything that isn't a press or refire
+ if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS
+ && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE
+ )
+ {
+ return ;
+ }
+
+ Codepoint &= KEY_CODEPOINT_MASK;
+
+ // Ignore Modifer Keys
+ if(Codepoint > KEY_MODIFIERS) return;
+
+ // Get UTF-8/ANSI Encoding
+ switch(Codepoint)
+ {
+ // 0: No translation, don't send to user
+ case 0: break;
+ case KEY_LEFT:
+ buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D';
+ len = 3;
+ break;
+ case KEY_RIGHT:
+ buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C';
+ len = 3;
+ break;
+ case KEY_UP:
+ buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A';
+ len = 3;
+ break;
+ case KEY_DOWN:
+ buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B';
+ len = 3;
+ break;
+
+ case KEY_PGUP:
+ buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~';
+ len = 4;
+ break;
+ case KEY_PGDOWN:
+ buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~';
+ len = 4;
+ break;
+
+ // Attempt to encode in UTF-8
+ default:
+ len = WriteUTF8( buf, Codepoint );
+ if(len == 0) {
+ Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint);
+ }
+ break;
+ }
+
+ if(len == 0) {
+ // Unprintable / Don't Pass
+ return;
+ }
+
+#if 0
+ // Handle meta characters
+ if( !(term->Flags & VT_FLAG_RAWIN) )
+ {
+ switch(buf[0])
+ {
+ case '\3': // ^C
+
+ break;
+ }
+ }
+#endif
+
+ // Write
+ if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
+ memcpy( &term->InputBuffer[term->InputWrite], buf, len );
+ else {
+ memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
+ memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
+ }
+ // Roll the buffer over
+ term->InputWrite += len;
+ term->InputWrite %= MAX_INPUT_CHARS8;
+ if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) {
+ term->InputRead = term->InputWrite + 1;
+ term->InputRead %= MAX_INPUT_CHARS8;
+ }
+ }
+ else
+ {
+ // Encode the raw key event
+ Uint32 *raw_in = (void*)term->InputBuffer;
+
+ #if 0
+ // Drop new keys
+ if( term->InputWrite == term->InputRead )
+ return ;
+ #endif
+
+ raw_in[ term->InputWrite ] = Codepoint;
+ term->InputWrite ++;
+ if(term->InputWrite >= MAX_INPUT_CHARS32)
+ term->InputWrite -= MAX_INPUT_CHARS32;
+
+ #if 1
+ // TODO: Should old or new be dropped?
+ if(term->InputRead == term->InputWrite) {
+ term->InputRead ++;
+ if( term->InputRead >= MAX_INPUT_CHARS32 )
+ term->InputRead -= MAX_INPUT_CHARS32;
+ }
+ #endif
+ }
+
+ VFS_MarkAvaliable(&term->Node, 1);
+}
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_input.c
+ * - Virtual Terminal - Input code
+ */
+#include "vterm.h"
+#include <api_drv_video.h>
+
+// === CODE ===
+/**
+ * \fn void VT_InitOutput()
+ * \brief Initialise Video Output
+ */
+void VT_InitOutput()
+{
+ giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE);
+ if(giVT_OutputDevHandle == -1) {
+ Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice);
+ return ;
+ }
+ VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
+ VT_SetTerminal( 0 );
+ VT_SetMode( VIDEO_BUFFMT_TEXT );
+}
+
+/**
+ * \brief Set video output buffer mode
+ */
+void VT_SetMode(int Mode)
+{
+ VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode );
+}
+
+/**
+ * \fn void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
+ * \note Scrolls the framebuffer down by \a Count text lines
+ */
+void VT_int_ScrollFramebuffer( tVTerm *Term, int Count )
+{
+ int tmp;
+ struct {
+ Uint8 Op;
+ Uint16 DstX, DstY;
+ Uint16 SrcX, SrcY;
+ Uint16 W, H;
+ } PACKED buf;
+
+ // Only update if this is the current terminal
+ if( Term != gpVT_CurTerm ) return;
+
+ if( Count > Term->ScrollHeight ) Count = Term->ScrollHeight;
+ if( Count < -Term->ScrollHeight ) Count = -Term->ScrollHeight;
+
+ // Switch to 2D Command Stream
+ tmp = VIDEO_BUFFMT_2DSTREAM;
+ VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
+
+ // BLIT to 0,0 from 0,giVT_CharHeight
+ buf.Op = VIDEO_2DOP_BLIT;
+ buf.SrcX = 0; buf.DstX = 0;
+ // TODO: Don't assume character dimensions
+ buf.W = Term->TextWidth * giVT_CharWidth;
+ if( Count > 0 )
+ {
+ buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
+ buf.DstY = Term->ScrollTop * giVT_CharHeight;
+ }
+ else // Scroll up, move text down
+ {
+ Count = -Count;
+ buf.SrcY = Term->ScrollTop * giVT_CharHeight;
+ buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
+ }
+ buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
+ VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
+
+ // Restore old mode (this function is only called during text mode)
+ tmp = VIDEO_BUFFMT_TEXT;
+ VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp);
+}
+
+void VT_int_UpdateCursor( tVTerm *Term, int bShow )
+{
+ tVideo_IOCtl_Pos csr_pos;
+
+ if( Term != gpVT_CurTerm ) return ;
+
+ if( !bShow )
+ {
+ csr_pos.x = -1;
+ csr_pos.y = -1;
+ }
+ else if( Term->Mode == TERM_MODE_TEXT )
+ {
+ int offset;
+
+// if( !(Term->Flags & VT_FLAG_SHOWCSR)
+// && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads)
+// )
+ if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR )
+ {
+ csr_pos.x = -1;
+ csr_pos.y = -1;
+ }
+ else
+ {
+ if(Term->Flags & VT_FLAG_ALTBUF)
+ offset = Term->AltWritePos;
+ else
+ offset = Term->WritePos - Term->ViewPos;
+
+ csr_pos.x = offset % Term->TextWidth;
+ csr_pos.y = offset / Term->TextWidth;
+ if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight )
+ csr_pos.y = -1, csr_pos.x = -1;
+ }
+ }
+ else
+ {
+ csr_pos.x = Term->VideoCursorX;
+ csr_pos.y = Term->VideoCursorY;
+ }
+ VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos);
+}
+
+/**
+ * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+ * \brief Updates the video framebuffer
+ */
+void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll )
+{
+ tVT_Char *buffer;
+ int view_pos, write_pos;
+ // Only update if this is the current terminal
+ if( Term != gpVT_CurTerm ) return;
+
+ switch( Term->Mode )
+ {
+ case TERM_MODE_TEXT:
+ view_pos = (Term->Flags & VT_FLAG_ALTBUF) ? 0 : Term->ViewPos;
+ write_pos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
+ buffer = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
+ // Re copy the entire screen?
+ if(UpdateAll) {
+ VFS_WriteAt(
+ giVT_OutputDevHandle,
+ 0,
+ Term->TextWidth*Term->TextHeight*sizeof(tVT_Char),
+ &buffer[view_pos]
+ );
+ }
+ // Only copy the current line
+ else {
+ int ofs = write_pos - write_pos % Term->TextWidth;
+ VFS_WriteAt(
+ giVT_OutputDevHandle,
+ (ofs - view_pos)*sizeof(tVT_Char),
+ Term->TextWidth*sizeof(tVT_Char),
+ &buffer[ofs]
+ );
+ }
+ break;
+ case TERM_MODE_FB:
+ break;
+ }
+
+ VT_int_UpdateCursor(Term, 1);
+}
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_termbuf.c
+ * - Virtual Terminal - Terminal buffer manipulation
+ */
+#include "vterm.h"
+
+// === CODE ===
+
+/**
+ * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
+ * \brief Print a string to the Virtual Terminal
+ */
+void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
+{
+ Uint32 val;
+ int i;
+
+ // Iterate
+ for( i = 0; i < Count; i++ )
+ {
+ // Handle escape sequences
+ if( Buffer[i] == 0x1B )
+ {
+ i ++;
+ i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
+ continue;
+ }
+
+ // Fast check for non UTF-8
+ if( Buffer[i] < 128 ) // Plain ASCII
+ VT_int_PutChar(Term, Buffer[i]);
+ else { // UTF-8
+ i += ReadUTF8(&Buffer[i], &val) - 1;
+ VT_int_PutChar(Term, val);
+ }
+ }
+ // Update Screen
+ VT_int_UpdateScreen( Term, 0 );
+}
+
+/**
+ * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
+ * \brief Write a single character to a VTerm
+ */
+void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
+{
+ int i;
+ tVT_Char *buffer;
+ int write_pos;
+
+ if(Term->Flags & VT_FLAG_ALTBUF) {
+ buffer = Term->AltBuf;
+ write_pos = Term->AltWritePos;
+ }
+ else {
+ buffer = Term->Text;
+ write_pos = Term->WritePos;
+ }
+
+ switch(Ch)
+ {
+ case '\0': return; // Ignore NULL byte
+ case '\n':
+ VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
+ write_pos += Term->TextWidth;
+ case '\r':
+ write_pos -= write_pos % Term->TextWidth;
+ break;
+
+ case '\t': { int tmp = write_pos / Term->TextWidth;
+ write_pos %= Term->TextWidth;
+ do {
+ buffer[ write_pos ].Ch = '\0';
+ buffer[ write_pos ].Colour = Term->CurColour;
+ write_pos ++;
+ } while(write_pos & 7);
+ write_pos += tmp * Term->TextWidth;
+ break; }
+
+ case '\b':
+ // Backspace is invalid at Offset 0
+ if(write_pos == 0) break;
+
+ write_pos --;
+ // Singe Character
+ if(buffer[ write_pos ].Ch != '\0') {
+ buffer[ write_pos ].Ch = 0;
+ buffer[ write_pos ].Colour = Term->CurColour;
+ break;
+ }
+ // Tab
+ i = 7; // Limit it to 8
+ do {
+ buffer[ write_pos ].Ch = 0;
+ buffer[ write_pos ].Colour = Term->CurColour;
+ write_pos --;
+ } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
+ if(buffer[ write_pos ].Ch != '\0')
+ write_pos ++;
+ break;
+
+ default:
+ buffer[ write_pos ].Ch = Ch;
+ buffer[ write_pos ].Colour = Term->CurColour;
+ // Update the line before wrapping
+ if( (write_pos + 1) % Term->TextWidth == 0 )
+ VT_int_UpdateScreen( Term, 0 );
+ write_pos ++;
+ break;
+ }
+
+ if(Term->Flags & VT_FLAG_ALTBUF)
+ {
+ Term->AltBuf = buffer;
+ Term->AltWritePos = write_pos;
+
+ if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
+ {
+ Term->AltWritePos -= Term->TextWidth;
+ VT_int_ScrollText(Term, 1);
+ }
+
+ }
+ else
+ {
+ Term->Text = buffer;
+ Term->WritePos = write_pos;
+ // Move Screen
+ // - Check if we need to scroll the entire scrollback buffer
+ if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
+ {
+ int base;
+
+ // Update previous line
+ Term->WritePos -= Term->TextWidth;
+ VT_int_UpdateScreen( Term, 0 );
+
+ // Update view position
+ base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
+ if(Term->ViewPos < base)
+ Term->ViewPos += Term->Width;
+ if(Term->ViewPos > base)
+ Term->ViewPos = base;
+
+ VT_int_ScrollText(Term, 1);
+ }
+ // Ok, so we only need to scroll the screen
+ else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
+ {
+ // Update the last line
+ Term->WritePos -= Term->TextWidth;
+ VT_int_UpdateScreen( Term, 0 );
+ Term->WritePos += Term->TextWidth;
+
+ VT_int_ScrollText(Term, 1);
+
+ Term->ViewPos += Term->TextWidth;
+ }
+ }
+
+ //LEAVE('-');
+}
+
+void VT_int_ScrollText(tVTerm *Term, int Count)
+{
+ tVT_Char *buf;
+ int height, init_write_pos;
+ int len, i;
+ int scroll_top, scroll_height;
+
+ // Get buffer pointer and attributes
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ buf = Term->AltBuf;
+ height = Term->TextHeight;
+ init_write_pos = Term->AltWritePos;
+ scroll_top = Term->ScrollTop;
+ scroll_height = Term->ScrollHeight;
+ }
+ else
+ {
+ buf = Term->Text;
+ height = Term->TextHeight*(giVT_Scrollback+1);
+ init_write_pos = Term->WritePos;
+ scroll_top = 0;
+ scroll_height = height;
+ }
+
+ // Scroll text downwards
+ if( Count > 0 )
+ {
+ int base;
+
+ // Set up
+ if(Count > scroll_height) Count = scroll_height;
+ base = Term->TextWidth*(scroll_top + scroll_height - Count);
+ len = Term->TextWidth*(scroll_height - Count);
+
+ // Scroll terminal cache
+ memmove(
+ &buf[Term->TextWidth*scroll_top],
+ &buf[Term->TextWidth*(scroll_top+Count)],
+ len*sizeof(tVT_Char)
+ );
+ // Clear last rows
+ for( i = 0; i < Term->TextWidth*Count; i ++ )
+ {
+ buf[ base + i ].Ch = 0;
+ buf[ base + i ].Colour = Term->CurColour;
+ }
+
+ // Update Screen
+ VT_int_ScrollFramebuffer( Term, Count );
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos = base;
+ else
+ Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
+ for( i = 0; i < Count; i ++ )
+ {
+ VT_int_UpdateScreen( Term, 0 );
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos += Term->TextWidth;
+ else
+ Term->WritePos += Term->TextWidth;
+ }
+ }
+ else
+ {
+ Count = -Count;
+ if(Count > scroll_height) Count = scroll_height;
+
+ len = Term->TextWidth*(scroll_height - Count);
+
+ // Scroll terminal cache
+ memmove(
+ &buf[Term->TextWidth*(scroll_top+Count)],
+ &buf[Term->TextWidth*scroll_top],
+ len*sizeof(tVT_Char)
+ );
+ // Clear preceding rows
+ for( i = 0; i < Term->TextWidth*Count; i ++ )
+ {
+ buf[ i ].Ch = 0;
+ buf[ i ].Colour = Term->CurColour;
+ }
+
+ VT_int_ScrollFramebuffer( Term, -Count );
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos = Term->TextWidth*scroll_top;
+ else
+ Term->WritePos = Term->ViewPos;
+ for( i = 0; i < Count; i ++ )
+ {
+ VT_int_UpdateScreen( Term, 0 );
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos += Term->TextWidth;
+ else
+ Term->WritePos += Term->TextWidth;
+ }
+ }
+
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos = init_write_pos;
+ else
+ Term->WritePos = init_write_pos;
+}
+
+/**
+ * \brief Clears a line in a virtual terminal
+ * \param Term Terminal to modify
+ * \param Num Line number to clear
+ */
+void VT_int_ClearLine(tVTerm *Term, int Num)
+{
+ int i;
+ tVT_Char *cell;
+
+ if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ;
+
+ cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
+ cell = &cell[ Num*Term->TextWidth ];
+
+ for( i = Term->TextWidth; i--; )
+ {
+ cell[ i ].Ch = 0;
+ cell[ i ].Colour = Term->CurColour;
+ }
+}
+
+/**
+ * \brief Update the screen mode
+ * \param Term Terminal to update
+ * \param NewMode New mode to set
+ * \param NewWidth New framebuffer width
+ * \param NewHeight New framebuffer height
+ */
+void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
+{
+ int oldW = Term->Width;
+ int oldTW = Term->TextWidth;
+ int oldH = Term->Height;
+ int oldTH = Term->TextHeight;
+ tVT_Char *oldTBuf = Term->Text;
+ Uint32 *oldFB = Term->Buffer;
+ int w, h, i;
+
+ // TODO: Increase RealWidth/RealHeight when this happens
+ if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth;
+ if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
+
+ Term->Mode = NewMode;
+
+ // Fast exit if no resolution change
+ if(NewWidth == Term->Width && NewHeight == Term->Height)
+ return ;
+
+ // Calculate new dimensions
+ Term->Width = NewWidth;
+ Term->Height = NewHeight;
+ Term->TextWidth = NewWidth / giVT_CharWidth;
+ Term->TextHeight = NewHeight / giVT_CharHeight;
+ Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
+
+ // Allocate new buffers
+ // - Text
+ Term->Text = calloc(
+ Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
+ sizeof(tVT_Char)
+ );
+ if(oldTBuf) {
+ // Copy old buffer
+ w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
+ h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
+ h *= giVT_Scrollback + 1;
+ for( i = 0; i < h; i ++ )
+ {
+ memcpy(
+ &Term->Text[i*Term->TextWidth],
+ &oldTBuf[i*oldTW],
+ w*sizeof(tVT_Char)
+ );
+ }
+ free(oldTBuf);
+ }
+
+ // - Alternate Text
+ Term->AltBuf = realloc(
+ Term->AltBuf,
+ Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
+ );
+
+ // - Framebuffer
+ if(oldFB) {
+ Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
+ // Copy old buffer
+ w = (oldW > Term->Width) ? Term->Width : oldW;
+ h = (oldH > Term->Height) ? Term->Height : oldH;
+ for( i = 0; i < h; i ++ )
+ {
+ memcpy(
+ &Term->Buffer[i*Term->Width],
+ &oldFB[i*oldW],
+ w*sizeof(Uint32)
+ );
+ }
+ free(oldFB);
+ }
+
+ // Debug
+ switch(NewMode)
+ {
+ case TERM_MODE_TEXT:
+ Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
+ Term, Term->TextWidth, Term->TextHeight);
+ break;
+ case TERM_MODE_FB:
+ Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
+ Term, Term->Width, Term->Height);
+ break;
+ //case TERM_MODE_2DACCEL:
+ //case TERM_MODE_3DACCEL:
+ // return;
+ }
+}
+
+
+void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
+{
+ if(Enabled)
+ Term->Flags |= VT_FLAG_ALTBUF;
+ else
+ Term->Flags &= ~VT_FLAG_ALTBUF;
+ VT_int_UpdateScreen(Term, 1);
+}
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vterm_vt100.c
+ * - Virtual Terminal - VT100 (Kinda) Emulation
+ */
+#include "vterm.h"
+
+// === CONSTANTS ===
+const Uint16 caVT100Colours[] = {
+ // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
+ // Same again, but bright
+ VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
+ VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
+ };
+
+// === CODE ===
+/**
+ * \brief Handle a standard large escape code
+ *
+ * Handles any escape code of the form \x1B[n,...A where n is an integer
+ * and A is any letter.
+ */
+void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
+{
+ int tmp = 1;
+ switch(CmdChar)
+ {
+ // Left
+ case 'D':
+ tmp = -1;
+ // Right
+ case 'C':
+ if(argc == 1) tmp *= args[0];
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
+ Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
+ Term->AltWritePos += Term->TextWidth - 1;
+ }
+ else
+ Term->AltWritePos += tmp;
+ }
+ else
+ {
+ if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
+ Term->WritePos -= Term->WritePos % Term->TextWidth;
+ Term->WritePos += Term->TextWidth - 1;
+ }
+ else
+ Term->WritePos += tmp;
+ }
+ break;
+
+ // Erase
+ case 'J':
+ switch(args[0])
+ {
+ case 0: // Erase below
+ break;
+ case 1: // Erase above
+ break;
+ case 2: // Erase all
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ int i = Term->TextHeight;
+ while( i-- ) VT_int_ClearLine(Term, i);
+ Term->AltWritePos = 0;
+ VT_int_UpdateScreen(Term, 1);
+ }
+ else
+ {
+ int i = Term->TextHeight * (giVT_Scrollback + 1);
+ while( i-- ) VT_int_ClearLine(Term, i);
+ Term->WritePos = 0;
+ Term->ViewPos = 0;
+ VT_int_UpdateScreen(Term, 1);
+ }
+ break;
+ }
+ break;
+
+ // Erase in line
+ case 'K':
+ switch(args[0])
+ {
+ case 0: // Erase to right
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ int i, max;
+ max = Term->Width - Term->AltWritePos % Term->Width;
+ for( i = 0; i < max; i ++ )
+ Term->AltBuf[Term->AltWritePos+i].Ch = 0;
+ }
+ else
+ {
+ int i, max;
+ max = Term->Width - Term->WritePos % Term->Width;
+ for( i = 0; i < max; i ++ )
+ Term->Text[Term->WritePos+i].Ch = 0;
+ }
+ VT_int_UpdateScreen(Term, 0);
+ break;
+ case 1: // Erase to left
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ int i = Term->AltWritePos % Term->Width;
+ while( i -- )
+ Term->AltBuf[Term->AltWritePos++].Ch = 0;
+ }
+ else
+ {
+ int i = Term->WritePos % Term->Width;
+ while( i -- )
+ Term->Text[Term->WritePos++].Ch = 0;
+ }
+ VT_int_UpdateScreen(Term, 0);
+ break;
+ case 2: // Erase all
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
+ }
+ else
+ {
+ VT_int_ClearLine(Term, Term->WritePos / Term->Width);
+ }
+ VT_int_UpdateScreen(Term, 0);
+ break;
+ }
+ break;
+
+ // Set cursor position
+ case 'H':
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
+ else
+ Term->WritePos = args[0] + args[1]*Term->TextWidth;
+ //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
+ break;
+
+ // Scroll up `n` lines
+ case 'S':
+ tmp = -1;
+ // Scroll down `n` lines
+ case 'T':
+ if(argc == 1) tmp *= args[0];
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ VT_int_ScrollText(Term, tmp);
+ else
+ {
+ if(Term->ViewPos/Term->TextWidth + tmp < 0)
+ break;
+ if(Term->ViewPos/Term->TextWidth + tmp > Term->TextHeight * (giVT_Scrollback + 1))
+ break;
+
+ Term->ViewPos += Term->TextWidth*tmp;
+ }
+ break;
+
+ // Set Font flags
+ case 'm':
+ for( ; argc--; )
+ {
+ int colour_idx;
+ // Flags
+ if( 0 <= args[argc] && args[argc] <= 8)
+ {
+ switch(args[argc])
+ {
+ case 0: Term->CurColour = DEFAULT_COLOUR; break; // Reset
+ case 1: Term->CurColour |= 0x80000000; break; // Bright
+ case 2: Term->CurColour &= ~0x80000000; break; // Dim
+ }
+ }
+ // Foreground Colour
+ else if(30 <= args[argc] && args[argc] <= 37) {
+ // Get colour index, accounting for bright bit
+ colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
+ Term->CurColour &= 0x8000FFFF;
+ Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
+ }
+ // Background Colour
+ else if(40 <= args[argc] && args[argc] <= 47) {
+ // Get colour index, accounting for bright bit
+ colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
+ Term->CurColour &= 0xFFFF8000;
+ Term->CurColour |= caVT100Colours[ colour_idx ];
+ }
+ else {
+ Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
+ }
+ }
+ break;
+
+ // Set scrolling region
+ case 'r':
+ if( argc != 2 ) break;
+ Term->ScrollTop = args[0];
+ Term->ScrollHeight = args[1] - args[0];
+ break;
+
+ default:
+ Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
+ break;
+ }
+}
+
+/**
+ * \fn int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
+ * \brief Parses a VT100 Escape code
+ */
+int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
+{
+ char c;
+ int argc = 0, j = 1;
+ int args[6] = {0,0,0,0};
+ int bQuestionMark = 0;
+
+ switch(Buffer[0])
+ {
+ //Large Code
+ case '[':
+ // Get Arguments
+ c = Buffer[j++];
+ if(c == '?') {
+ bQuestionMark = 1;
+ c = Buffer[j++];
+ }
+ if( '0' <= c && c <= '9' )
+ {
+ do {
+ if(c == ';') c = Buffer[j++];
+ while('0' <= c && c <= '9') {
+ args[argc] *= 10;
+ args[argc] += c-'0';
+ c = Buffer[j++];
+ }
+ argc ++;
+ } while(c == ';');
+ }
+
+ // Get Command
+ if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+ {
+ if( bQuestionMark )
+ {
+ switch(c)
+ {
+ // DEC Private Mode Set
+ case 'h':
+ if(argc != 1) break;
+ switch(args[0])
+ {
+ case 25:
+ Term->Flags &= ~VT_FLAG_HIDECSR;
+ break;
+ case 1047:
+ VT_int_ToggleAltBuffer(Term, 1);
+ break;
+ }
+ break;
+ case 'l':
+ if(argc != 1) break;
+ switch(args[0])
+ {
+ case 25:
+ Term->Flags |= VT_FLAG_HIDECSR;
+ break;
+ case 1047:
+ VT_int_ToggleAltBuffer(Term, 0);
+ break;
+ }
+ break;
+ default:
+ Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
+ break;
+ }
+ }
+ else
+ {
+ VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
+ }
+ }
+ break;
+
+ default:
+ Log_Notice("VTerm", "TODO: Handle short escape codes");
+ break;
+ }
+
+ //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
+ return j;
+}
// === CODE ===
// --- Video Driver Helpers ---
-int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
+int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
{
- void *stream = Buffer;
+ const Uint8 *stream = Buffer;
int rem = Length;
int op;
while( rem )
{
rem --;
- op = *(Uint8*)stream;
- stream = (void*)((tVAddr)stream + 1);
+ op = *stream;
+ stream ++;
if(op > NUM_VIDEO_2DOPS) {
Log_Warning("DrvUtil",
case VIDEO_2DOP_NOP: break;
case VIDEO_2DOP_FILL:
- if(rem < 12) return Length-rem;
+ if(rem < 10) return Length-rem;
if(!Handlers->Fill) {
Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
Handlers->Fill(
Ent,
- ((Uint16*)stream)[0], ((Uint16*)stream)[1],
- ((Uint16*)stream)[2], ((Uint16*)stream)[3],
- ((Uint32*)stream)[2]
+ ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
+ ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
+ ((const Uint32*)stream)[4]
);
- rem -= 12;
- stream = (void*)((tVAddr)stream + 12);
+ rem -= 10;
+ stream += 10;
break;
case VIDEO_2DOP_BLIT:
Handlers->Blit(
Ent,
- ((Uint16*)stream)[0], ((Uint16*)stream)[1],
- ((Uint16*)stream)[2], ((Uint16*)stream)[3],
- ((Uint16*)stream)[4], ((Uint16*)stream)[5]
+ ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
+ ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
+ ((const Uint16*)stream)[4], ((const Uint16*)stream)[5]
);
rem -= 12;
- stream = (void*)((tVAddr)stream + 12);
+ stream += 12;
break;
}
return 0;
}
-int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Buffer)
+int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
{
Uint8 *dest;
- Uint32 *src = Buffer;
+ const Uint32 *src = Buffer;
int csr_x, csr_y;
int x, y;
int bytes_per_px = (FBInfo->Depth + 7) / 8;
{
case VIDEO_BUFFMT_TEXT:
{
- tVT_Char *chars = Buffer;
+ const tVT_Char *chars = Buffer;
int widthInChars = FBInfo->Width/giVT_CharWidth;
int heightInChars = FBInfo->Height/giVT_CharHeight;
int i;
// --- Disk Driver Helpers ---
Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
- tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
+ tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
{
Uint8 tmp[BlockSize]; // C99
Uint64 block = Start / BlockSize;
return Length;
}
-Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,
- tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,
+Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
+ tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
Uint64 BlockSize, Uint Argument)
{
Uint8 tmp[BlockSize]; // C99
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * events.c
+ * - Thread level event handling
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <threads_int.h>
+#include <events.h>
+
+// === CODE ===
+void Threads_PostEvent(tThread *Thread, Uint32 EventMask)
+{
+ // Sanity checking
+ if( !Thread ) return ;
+ if( EventMask == 0 ) return ;
+ // TODO: Check that only one bit is set?
+
+ ENTER("pThread xEventMask", Thread, EventMask);
+
+ SHORTLOCK( &Thread->IsLocked );
+
+ Thread->EventState |= EventMask;
+ LOG("Thread->EventState = 0x%x", Thread->EventState);
+
+ // Currently sleeping on an event?
+ if( Thread->Status == THREAD_STAT_EVENTSLEEP )
+ {
+ // Waiting on this event?
+ if( (Uint32)Thread->RetStatus & EventMask )
+ {
+ // Wake up
+ LOG("Waking thread %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
+ Threads_AddActive(Thread);
+ }
+ }
+
+ SHORTREL( &Thread->IsLocked );
+ LEAVE('-');
+}
+
+/**
+ * \brief Wait for an event to occur
+ */
+Uint32 Threads_WaitEvents(Uint32 EventMask)
+{
+ Uint32 rv;
+ tThread *us = Proc_GetCurThread();
+
+ ENTER("xEventMask", EventMask);
+
+ // Early return check
+ if( EventMask == 0 )
+ {
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ LOG("us = %p(%i %s)", us, us->TID, us->ThreadName);
+
+ // Check if a wait is needed
+ SHORTLOCK( &us->IsLocked );
+ while( !(us->EventState & EventMask) )
+ {
+ LOG("Locked and preparing for wait");
+ // Wait
+ us->RetStatus = EventMask; // HACK: Store EventMask in RetStatus
+ SHORTLOCK( &glThreadListLock );
+ us = Threads_RemActive();
+ us->Status = THREAD_STAT_EVENTSLEEP;
+ // Note stored anywhere because we're woken using other means
+ SHORTREL( &glThreadListLock );
+ SHORTREL( &us->IsLocked );
+ while(us->Status == THREAD_STAT_EVENTSLEEP) Threads_Yield();
+ // Woken when lock is acquired
+ SHORTLOCK( &us->IsLocked );
+ }
+
+ // Get return value and clear changed event bits
+ rv = us->EventState & EventMask;
+ us->EventState &= ~EventMask;
+
+ SHORTREL( &us->IsLocked );
+
+ LEAVE('x', rv);
+ return rv;
+}
+
// Bounds Check
if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
- Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
+// Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
return NULL;
}
#include "errno.h"
// --- Types ---
-typedef int tPID; //!< Process ID type
-typedef int tTID; //!< Thread ID Type
-typedef Uint tUID; //!< User ID Type
-typedef Uint tGID; //!< Group ID Type
+typedef Uint32 tPID; //!< Process ID type
+typedef Uint32 tTID; //!< Thread ID Type
+typedef Uint32 tUID; //!< User ID Type
+typedef Uint32 tGID; //!< Group ID Type
typedef Sint64 tTimestamp; //!< Timestamp (miliseconds since 00:00 1 Jan 1970)
typedef Sint64 tTime; //!< Same again
typedef struct sShortSpinlock tShortSpinlock; //!< Opaque (kinda) spinlock
* \}
*/
-/**
- * \name Per-Thread Configuration Settings
- * \{
- */
-enum eConfigTypes {
- CFGT_NULL,
- CFGT_INT,
- CFGT_HEAPSTR,
- CFGT_PTR
-};
-enum eConfigs {
- CFG_VFS_CWD,
- CFG_VFS_MAXFILES,
- CFG_VFS_CHROOT,
- CFG_ERRNO,
- NUM_CFG_ENTRIES
-};
-#define CFGINT(id) (*Threads_GetCfgPtr(id))
-#define CFGPTR(id) (*(void**)Threads_GetCfgPtr(id))
-
-#define errno (CFGINT(CFG_ERRNO))
-/**
- * \}
- */
+//! \brief Error number
+#define errno (*Threads_GetErrno())
// === CONSTANTS ===
// --- Memory Flags --
*/
//! Clone the entire process
#define CLONE_VM 0x10
+//! Don't copy user pages
+#define CLONE_NOUSER 0x20
/**
* \}
*/
// --- IO ---
#if NO_IO_BUS
-#define inb(a) (Log_Panic("Arch", "ARMv7 does not support in*/out* (%s:%i)", __FILE__, __LINE__),0)
+#define inb(a) (Log_Panic("Arch", STR(ARCHDIR)" does not support in*/out* (%s:%i)", __FILE__, __LINE__),0)
#define inw(a) inb(a)
#define ind(a) inb(a)
#define inq(a) inb(a)
extern int strpos8(const char *str, Uint32 search);
extern void itoa(char *buf, Uint64 num, int base, int minLength, char pad);
extern int atoi(const char *string);
+extern int ParseInt(const char *string, int *Val);
extern int ReadUTF8(const Uint8 *str, Uint32 *Val);
extern int WriteUTF8(Uint8 *str, Uint32 Val);
extern int ModUtil_SetIdent(char *Dest, const char *Value);
extern int ModUtil_LookupString(const char **Array, const char *Needle);
extern Uint8 ByteSum(const void *Ptr, int Size);
+extern int Hex(char *Dest, size_t Size, const Uint8 *SourceData);
extern int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
/**
* \}
// --- Heap ---
#include <heap.h>
+/**
+ * \brief Magic heap allocation function
+ */
+extern void *alloca(size_t Size);
// --- Modules ---
/**
*/
extern int Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
extern int Proc_Spawn(const char *Path);
+extern int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
+extern int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
extern void Threads_Exit(int TID, int Status);
extern void Threads_Yield(void);
extern void Threads_Sleep(void);
extern tUID Threads_GetUID(void);
extern tGID Threads_GetGID(void);
extern int SpawnTask(tThreadFunction Function, void *Arg);
-extern Uint *Threads_GetCfgPtr(int Id);
+extern int *Threads_GetErrno(void);
extern int Threads_SetName(const char *NewName);
/**
* \}
* \param Buffer Destination for read blocks\r
* \param Argument Argument provided in ::DrvUtil_ReadBlock and ::DrvUtil_WriteBlock\r
*/\r
-typedef Uint (*tDrvUtil_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
+typedef Uint (*tDrvUtil_Read_Callback)(Uint64 Address, Uint Count, void *Buffer, Uint Argument);\r
+typedef Uint (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *Buffer, Uint Argument);\r
\r
/**\r
* \brief Reads a range from a block device using aligned reads\r
* \return Number of bytes read\r
*/\r
extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
- tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
+ tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, Uint Argument);\r
/**\r
* \brief Writes a range to a block device using aligned writes\r
* \param Start Base byte offset\r
* \param Argument An argument to pass to \a ReadBlocks and \a WriteBlocks\r
* \return Number of bytes written\r
*/\r
-extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
- tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,\r
+extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
+ tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
Uint64 BlockSize, Uint Argument);\r
\r
/**\r
* \param SizeofHandlers Size of \a tDrvUtil_Video_2DHandlers according\r
* to the driver. Used as version control and error avoidence.\r
*/\r
-extern int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,\r
+extern int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,\r
tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);\r
\r
/**\r
* Handles all write modes in software, using the VT font calls for rendering.\r
* \note Calls the cursor clear and redraw if the cursor area is touched\r
*/\r
-extern int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);\r
+extern int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Src);\r
\r
/**\r
* \name Software cursor rendering\r
EREADONLY, // Read only
ENOTIMPL, // Not implemented
ENOENT, // No entry?
+ EEXIST, // Already exists
ENFILE, // Too many open files
ENOTDIR, // Not a directory
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * events.h
+ * - Thread Events
+ */
+#ifndef _EVENTS_H_
+#define _EVENTS_H_
+
+#include <threads.h>
+
+#define THREAD_EVENT_VFS 0x00000001
+#define THREAD_EVENT_IPCMSG 0x00000002
+#define THREAD_EVENT_SIGNAL 0x00000004
+
+// === FUNCTIONS ===
+extern void Threads_PostEvent(tThread *Thread, Uint32 EventMask);
+extern Uint32 Threads_WaitEvents(Uint32 EventMask);
+
+#endif
+
* \brief Called just before a thread is freed
*/
extern void Proc_ClearThread(tThread *Thread);
+/**
+ * \brief Called just before a process is freed
+ */
+extern void Proc_ClearProcess(tProcess *Process);
/**
* \brief Get the ID of this CPU
* \return Zero based CPU ID
* \param DataSize Size of the \a ArgV buffer in bytes
* \note This function should free \a ArgV
*/
-extern void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize) NORETURN;
+extern void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize) NORETURN;
/**
* \brief Call the fault handler for a thread
* \param Thread Thread that is at fault :)
#define SYS_SETFAULTHANDLER 3 // Set signal Handler
#define SYS_YIELD 4 // Yield remainder of timestamp
#define SYS_SLEEP 5 // Sleep until messaged or signaled
-#define SYS_WAIT 6 // Wait for a time or a message
+#define SYS_WAITEVENT 6 // Wait for an event
#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_SETNAME 8 // Sets the name of the current thread
+#define SYS_GETNAME 9 // Gets the name of a thread
#define SYS_GETTID 10 // Get current thread ID
#define SYS_GETPID 11 // Get current thread group ID
#define SYS_SETPRI 12 // Set process priority
"SYS_SETFAULTHANDLER",
"SYS_YIELD",
"SYS_SLEEP",
- "SYS_WAIT",
+ "SYS_WAITEVENT",
"SYS_WAITTID",
"SYS_SETNAME",
"SYS_GETNAME",
%define SYS_SETFAULTHANDLER 3 ;Set signal Handler
%define SYS_YIELD 4 ;Yield remainder of timestamp
%define SYS_SLEEP 5 ;Sleep until messaged or signaled
-%define SYS_WAIT 6 ;Wait for a time or a message
+%define SYS_WAITEVENT 6 ;Wait for an event
%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_SETNAME 8 ;Sets the name of the current thread
+%define SYS_GETNAME 9 ;Gets the name of a thread
%define SYS_GETTID 10 ;Get current thread ID
%define SYS_GETPID 11 ;Get current thread group ID
%define SYS_SETPRI 12 ;Set process priority
/*
+ * Acess2 Kernel
*/
#ifndef _THREADS_H_
#define _THREADS_H_
#include <arch.h>
#include <signal.h>
-#include <proc.h>
+//#include <proc.h>
enum eFaultNumbers
{
#define GETMSG_IGNORE ((void*)-1)
+typedef struct sThread tThread;
+
// === FUNCTIONS ===
extern void Threads_SetFaultHandler(Uint Handler);
-extern int Threads_SetUID(Uint *Errno, tUID ID);
-extern int Threads_SetGID(Uint *Errno, tUID ID);
-extern int Threads_WaitTID(int TID, int *Status);
+extern int Threads_SetUID(tUID ID);
+extern int Threads_SetGID(tUID ID);
+extern tTID Threads_WaitTID(int TID, int *Status);
+
+
+extern int *Threads_GetMaxFD(void);
+extern char **Threads_GetCWD(void);
+extern char **Threads_GetChroot(void);
-extern int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data);
-extern int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer);
+extern int Proc_SendMessage(Uint Dest, int Length, void *Data);
+extern int Proc_GetMessage(Uint *Source, void *Buffer);
#endif
#include <threads.h>
#include <proc.h>
+
+typedef struct sProcess tProcess;
+
/**
* \brief IPC Message
*/
Uint8 Data[]; //!< Message data
} tMsg;
+/**
+ * \brief Process state
+ */
+struct sProcess
+{
+ tPID PID;
+ int nThreads;
+
+ tUID UID; //!< User ID
+ tGID GID; //!< User and Group
+ tMemoryState MemState;
+
+ int MaxFD;
+ char *CurrentWorkingDir;
+ char *RootDir;
+};
+
/**
* \brief Core threading structure
*
*/
-typedef struct sThread
+struct sThread
{
// --- threads.c's
/**
void *WaitPointer; //!< What (Mutex/Thread/other) is the thread waiting on
int RetStatus; //!< Return Status
- Uint TID; //!< Thread ID
- Uint TGID; //!< Thread Group (Process)
+ tTID TID; //!< Thread ID
+ struct sProcess *Process; //!< Thread Group / Process
struct sThread *Parent; //!< Parent Thread
- Uint UID, GID; //!< User and Group
char *ThreadName; //!< Name of thread
// --- arch/proc.c's responsibility
//! Kernel Stack Base
tVAddr KernelStack;
- //! Memory Manager State
- tMemoryState MemState;
-
//! State on task switch
tTaskState SavedState;
int Quantum, Remaining; //!< Quantum Size and remaining timesteps
int Priority; //!< Priority - 0: Realtime, higher means less time
- Uint Config[NUM_CFG_ENTRIES]; //!< Per-process configuration
+ int _errno;
volatile int CurCPU;
- int bInstrTrace;
-} tThread;
+ bool bInstrTrace;
+
+ // --- event.c
+ Uint32 EventState;
+};
enum {
THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
THREAD_STAT_SEMAPHORESLEEP, // Semaphore Sleep
THREAD_STAT_QUEUESLEEP, // Queue
+ THREAD_STAT_EVENTSLEEP, // Event sleep
THREAD_STAT_WAITING, // ??? (Waiting for a thread)
THREAD_STAT_PREINIT, // Being created
THREAD_STAT_ZOMBIE, // Died/Killed, but parent not informed
"THREAD_STAT_MUTEXSLEEP",
"THREAD_STAT_SEMAPHORESLEEP",
"THREAD_STAT_QUEUESLEEP",
+ "THREAD_STAT_EVENTSLEEP",
"THREAD_STAT_WAITING",
"THREAD_STAT_PREINIT",
"THREAD_STAT_ZOMBIE",
*/
typedef struct sVFS_SelectList tVFS_SelectList;
+typedef struct sVFS_NodeType tVFS_NodeType;
+
/**
* \name tVFS_Node Flags
* \brief Flag values for tVFS_Node.Flags
* \}
*/
+ /**
+ * \brief Functions associated with the node
+ */
+ tVFS_NodeType *Type;
+} tVFS_Node;
+
+/**
+ * \brief Functions for a specific node type
+ */
+struct sVFS_NodeType
+{
+ /**
+ * \brief Debug name for the type
+ */
+ const char *TypeName;
+
/**
* \name Common Functions
* \brief Functions that are used no matter the value of .Flags
* \param Buffer Source of written data
* \return Number of bytes read
*/
- Uint64 (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ Uint64 (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
/**
* \brief Map a region of a file into memory
* \param Node Pointer to this node (directory)
* \param Child Node to create a new link to
* \param NewName Name for the new link
- * \return Zeron on success, non-zero on error (see errno.h)
+ * \retur Zeron on success, non-zero on error (see errno.h)
*/
int (*Link)(struct sVFS_Node *Node, struct sVFS_Node *Child, const char *NewName);
/**
* \}
*/
-} tVFS_Node;
+};
/**
* \brief VFS Driver (Filesystem) Definition
#define VFS_OPENFLAG_WRITE 0x04
//! Do not resolve the final symbolic link
#define VFS_OPENFLAG_NOLINK 0x40
+//! Create the file if it doesn't exist
+#define VFS_OPENFLAG_CREATE 0x80
//! Open as a user
-#define VFS_OPENFLAG_USER 0x80
+#define VFS_OPENFLAG_USER 0x8000
/**
* \}
*/
/**
* \brief Open a file
* \param Path Absolute or relative path to the file
- * \param Mode Flags defining how to open the file
+ * \param Flags Flags defining how to open the file
* \return VFS Handle (an integer) or -1 if an error occured
+ * \note Calls VFS_OpenEx(Path, Flags, 0)
*/
-extern int VFS_Open(const char *Path, Uint Mode);
+extern int VFS_Open(const char *Path, Uint Flags);
+/**
+ * \brief Open a file
+ * \param Path Absolute or relative path to the file
+ * \param Flags Flags defining how to open the file
+ * \param Mode Mode for newly created file (POSIX compatability)
+ * \return VFS Handle (an integer) or -1 if an error occured
+ */
+extern int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode);
/**
* \brief Opens a file via an open directory
* \note The file to open must be a direct child of the parent
* \param WriteHandles Handles to wait to write to
* \param ErrHandles Handle to wait for errors on
* \param Timeout Timeout for select() (if null, there is no timeout), if zero select() is non blocking
+ * \param ExtraEvents Extra event set to wait on
* \param IsKernel Use kernel handles as opposed to user handles
* \return Number of handles that actioned
*/
-extern int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, BOOL IsKernel);
+extern int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
/**
* \brief Map a file into memory
extern int VFS_CheckACL(tVFS_Node *Node, Uint Permissions);
// --- mount.c ---
extern tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID);
+// --- dir.c ---
+extern int VFS_MkNod(const char *Path, Uint Flags);
+
+
+// --- VFS Helpers ---
+static inline void _CloseNode(tVFS_Node *Node)
+{
+ if(Node && Node->Type && Node->Type->Close)
+ Node->Type->Close( Node );
+}
+
#endif
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/vfs_threads.h
+ * - Handle maintainance functions for the VFS used by threading code
+ */
+#ifndef _VFS_THREADS_H_
+#define _VFS_THREADS_H_
+
+// === FUNCTIONS ===
+extern void VFS_ReferenceUserHandles(void);
+extern void VFS_CloseAllUserHandles(void);
+
+extern void *VFS_SaveHandles(int NumFDs, int *FDs);
+extern void VFS_RestoreHandles(int NumFDs, void *Handles);
+extern void VFS_FreeSavedHandles(int NumFDs, void *Handles);
+
+#endif
int WriteUTF8(Uint8 *str, Uint32 Val);
int DivUp(int num, int dem);
Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
+#endif
+void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+#if 0
int rand(void);
int CheckString(char *String);
int ModUtil_LookupString(char **Array, char *Needle);
int ModUtil_SetIdent(char *Dest, char *Value);
+ int Hex(char *Dest, size_t Size, const Uint8 *SourceData);
int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
#endif
* \brief Convert a string into an integer
*/
int atoi(const char *string)
+{
+ int ret = 0;
+ ParseInt(string, &ret);
+ return ret;
+}
+int ParseInt(const char *string, int *Val)
{
int ret = 0;
int bNeg = 0;
+ const char *orig_string = string;
//Log("atoi: (string='%s')", string);
ret *= 10;
ret += *string - '0';
}
+ // Error check
+ if( ret == 0 ) return 0;
}
if(bNeg) ret = -ret;
//Log("atoi: RETURN %i", ret);
- return ret;
+ if(Val) *Val = ret;
+
+ return string - orig_string;
}
static const char cUCDIGITS[] = "0123456789ABCDEF";
* \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 timestamp(int sec, int min, int hrs, int day, int month, int year)
{
+ int is_leap;
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;
+
+ if( !(0 <= sec && sec < 60) ) return 0;
+ if( !(0 <= min && min < 60) ) return 0;
+ if( !(0 <= hrs && hrs < 24) ) return 0;
+ if( !(0 <= day && day < 31) ) return 0;
+ if( !(0 <= month && month < 12) ) return 0;
+
+ stamp = DAYS_BEFORE[month] + day;
+
+ // Every 4 years
+ // - every 100 years
+ // + every 400 years
+ is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
+ ASSERT(is_leap == 0 || is_leap == 1);
+
+ if( is_leap && month > 1 ) // Leap year and after feb
+ stamp += 1;
+
+ // Get seconds before the first of specified year
+ year -= 2000; // Base off Y2K
+ // base year days + total leap year days
+ stamp += year*365 + (year/400) - (year/100) + (year/4);
- stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24; // Four Year Segments
- stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
+ stamp *= 3600*24;
stamp += UNIX_TO_2K;
+ stamp += sec;
+ stamp += min*60;
+ stamp += hrs*3600;
return stamp * 1000;
}
+void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms)
+{
+ int is_leap = 0, i;
+
+ auto Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R);
+
+ Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R)
+ {
+ int sign = (N < 0) != (D < 0);
+ if(N < 0) N = -N;
+ if(D < 0) D = -D;
+ if(sign)
+ return -DivMod64U(N, D, (Uint64*)R);
+ else
+ return DivMod64U(N, D, (Uint64*)R);
+ }
+
+ // Get time
+ // TODO: Leap-seconds?
+ {
+ Sint64 rem;
+ TS = DivMod64( TS, 1000, &rem );
+ *ms = rem;
+ TS = DivMod64( TS, 60, &rem );
+ *sec = rem;
+ TS = DivMod64( TS, 60, &rem );
+ *mins = rem;
+ TS = DivMod64( TS, 24, &rem );
+ *hrs = rem;
+ }
+
+ // Adjust to Y2K
+ TS -= UNIX_TO_2K/(3600*24);
+
+ // Year (400 yr blocks) - (400/4-3) leap years
+ *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS );
+ if( TS < 366 ) // First year in 400 is a leap
+ is_leap = 1;
+ else
+ {
+ // 100 yr blocks - 100/4-1 leap years
+ *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS );
+ if( TS < 366 ) // First year in 100 isn't a leap
+ is_leap = 0;
+ else
+ {
+ *year += 4 * DivMod64( TS, 365*4 + 1, &TS );
+ if( TS < 366 ) // First year in 4 is a leap
+ is_leap = 1;
+ else
+ {
+ *year += DivMod64( TS, 356, &TS );
+ }
+ }
+ }
+ *year += 2000;
+
+ ASSERT(TS >= 0);
+
+ *day = 0;
+ // Month (if after the first of march, which is 29 Feb in a leap year)
+ if( is_leap && TS > DAYS_BEFORE[2] ) {
+ TS -= 1; // Shifts 29 Feb to 28 Feb
+ *day = 1;
+ }
+ // Get what month it is
+ for( i = 0; i < 12; i ++ ) {
+ if( TS < DAYS_BEFORE[i] )
+ break;
+ }
+ *month = i - 1;
+ // Get day
+ TS -= DAYS_BEFORE[i-1];
+ *day += TS; // Plus offset from leap handling above
+}
+
/**
* \fn int rand()
* \brief Pseudo random number generator
return 1;
}
+int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
+{
+ int i;
+ for( i = 0; i < Size; i ++ )
+ {
+ sprintf(Dest + i*2, "%02x", SourceData[i]);
+ }
+ return i*2;
+}
+
/**
* \brief Convert a string of hexadecimal digits into a byte stream
*/
#include <threads.h>
#include <threads_int.h>
#include <errno.h>
+#include <events.h>
// === CODE ===
/**
- * \fn int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
+ * \fn int Proc_SendMessage(Uint Dest, int Length, void *Data)
* \brief Send an IPC message
- * \param Err Pointer to the errno variable
* \param Dest Destination Thread
* \param Length Length of the message
* \param Data Message data
*/
-int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
+int Proc_SendMessage(Uint Dest, int Length, void *Data)
{
tThread *thread;
tMsg *msg;
ENTER("pErr iDest iLength pData", Err, Dest, Length, Data);
if(Length <= 0 || !Data) {
- *Err = -EINVAL;
+ errno = -EINVAL;
LEAVE_RET('i', -1);
}
+ // TODO: Check message length against global/per-thread maximums
+ // TODO: Restrict queue length
+
// Get thread
thread = Threads_GetThread( Dest );
}
SHORTREL(&thread->IsLocked);
-
+
+ // Wake the thread
LOG("Waking %p (%i %s)", thread, thread->TID, thread->ThreadName);
- Threads_Wake( thread );
+ Threads_PostEvent( thread, THREAD_EVENT_IPCMSG );
LEAVE_RET('i', 0);
}
/**
- * \fn int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
+ * \fn int Proc_GetMessage(Uint *Source, void *Buffer)
* \brief Gets a message
- * \param Err Pointer to \a errno
* \param Source Where to put the source TID
* \param Buffer Buffer to place the message data (set to NULL to just get message length)
+ * \return Message length
*/
-int Proc_GetMessage(Uint *Err, Uint *Source, void *Buffer)
+int Proc_GetMessage(Uint *Source, void *Buffer)
{
int ret;
void *tmp;
if( !CheckMem( Buffer, cur->Messages->Length ) )
{
LOG("Invalid buffer");
- *Err = -EINVAL;
+ errno = -EINVAL;
SHORTREL( &cur->IsLocked );
LEAVE('i', -1);
return -1;
Log_Warning("Module", "Unable to load, reason: Miscelanious");
break;
case MODULE_ERR_NOTNEEDED:
- Log_Warning("Module", "Unable to load, reason: Module not needed");
+ Log_Debug("Module", "Unable to load, reason: Module not needed");
break;
case MODULE_ERR_MALLOC:
Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
// Get protector
SHORTLOCK( &Mutex->Protector );
- //Log("Mutex_Acquire: (%p)", Mutex);
+// Log("Mutex_Acquire: (%p)", Mutex);
// Check if the lock is already held
if( Mutex->Owner ) {
Mutex->Owner = Mutex->Waiting; // Set owner
Mutex->Waiting = Mutex->Waiting->Next; // Next!
// Reset ->LastWaiting to NULL if we have just removed the last waiting thread
- // 2010-10-02 21:50 - Comemerating the death of the longest single
- // blocker in the Acess2 history. REMEMBER TO
- // FUCKING MAINTAIN YOUR FUCKING LISTS DIPWIT
if( Mutex->LastWaiting == Mutex->Owner )
Mutex->LastWaiting = NULL;
// Wake new owner
- SHORTLOCK( &glThreadListLock );
if( Mutex->Owner->Status != THREAD_STAT_ACTIVE )
Threads_AddActive(Mutex->Owner);
- SHORTREL( &glThreadListLock );
}
else {
Mutex->Owner = NULL;
#include <hal_proc.h>
#include <errno.h>
#include <threads.h>
+#include <events.h>
#define CHECK_NUM_NULLOK(v,size) \
if((v)&&!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
if(!(v)||!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
#define CHECK_STR_NONULL(v) \
if(!(v)||!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
+#define CHECK_STR_ARRAY(arr) do {\
+ int i;\
+ char **tmp = (char**)arr; \
+ CHECK_NUM_NONULL( tmp, sizeof(char**) ); \
+ for(i=0;tmp[i];i++) { \
+ CHECK_STR_NONULL( tmp[i] ); \
+ CHECK_NUM_NONULL( &tmp[i+1], sizeof(char*) ); \
+ }\
+ if(tmp[i]) break;\
+} while(0)
// === IMPORTS ===
-extern int Proc_Execve(char *File, char **ArgV, char **EnvP);
extern Uint Binary_Load(const char *file, Uint *entryPoint);
// === PROTOTYPES ===
err = -ENOSYS;
ret = -1;
break;
-
+
+ // -- Wait fr an event
+ case SYS_WAITEVENT:
+ // Message mask
+ ret = Threads_WaitEvents(Regs->Arg1);
+ break;
+
// -- Wait for a thread
case SYS_WAITTID:
// Sanity Check (Status can be NULL)
case SYS_GETGID: ret = Threads_GetGID(); break;
// -- Set User/Group IDs
- case SYS_SETUID: ret = Threads_SetUID(&err, Regs->Arg1); break;
- case SYS_SETGID: ret = Threads_SetGID(&err, Regs->Arg1); break;
+ case SYS_SETUID: ret = Threads_SetUID(Regs->Arg1); break;
+ case SYS_SETGID: ret = Threads_SetGID(Regs->Arg1); break;
// -- Send Message
case SYS_SENDMSG:
CHECK_NUM_NONULL( (void*)Regs->Arg3, Regs->Arg2 );
// Destination, Size, *Data
- ret = Proc_SendMessage(&err, Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
+ ret = Proc_SendMessage(Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
break;
// -- Check for messages
case SYS_GETMSG:
err = -EINVAL; ret = -1; break;
}
// *Source, *Data
- ret = Proc_GetMessage(&err, (Uint*)Regs->Arg1, (void*)Regs->Arg2);
+ ret = Proc_GetMessage((Uint*)Regs->Arg1, (void*)Regs->Arg2);
break;
// -- Get the current timestamp
// ---
// Binary Control
// ---
+ // -- Create a new process
+ case SYS_SPAWN:
+ CHECK_STR_NONULL((const char*)Regs->Arg1);
+ CHECK_STR_ARRAY((const char**)Regs->Arg2);
+ CHECK_STR_ARRAY((const char**)Regs->Arg3);
+ CHECK_NUM_NONULL((void*)Regs->Arg5, Regs->Arg4*sizeof(int));
+ ret = Proc_SysSpawn(
+ (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
+ Regs->Arg4, (int*)Regs->Arg5
+ );
+ break;
// -- Replace the current process with another
case SYS_EXECVE:
CHECK_STR_NONULL((char*)Regs->Arg1);
- // Check the argument arrays
- {
- int i;
- char **tmp = (char**)Regs->Arg2;
- // Check ArgV (traverse array checking all string pointers)
- CHECK_NUM_NONULL( tmp, sizeof(char**) );
- //Log("tmp = %p", tmp);
- for(i=0;tmp[i];i++) {
- CHECK_NUM_NONULL( &tmp[i], sizeof(char*) );
- CHECK_STR_NONULL( tmp[i] );
- }
- if(ret == -1) break;
- // Check EnvP also
- // - EnvP can be NULL
- if( Regs->Arg3 )
- {
- tmp = (char**)Regs->Arg3;
- CHECK_NUM_NONULL(tmp, sizeof(char**));
- for(i=0;tmp[i];i++) {
- CHECK_NUM_NONULL( &tmp[i], sizeof(char*) );
- CHECK_STR_NONULL( tmp[i] );
- }
- if(ret == -1) break;
- }
- }
+ CHECK_STR_ARRAY( (char**)Regs->Arg2 );
+ if( Regs->Arg3 )
+ CHECK_STR_ARRAY( (char**)Regs->Arg3 );
LEAVE('s', "Assuming 0");
- // Path, **Argv, **Envp
- ret = Proc_Execve( (char*)Regs->Arg1, (char**)Regs->Arg2, (char**)Regs->Arg3 );
+ // Path, **Argv, **Envp, DataSize (=0 to tell it to create a copy)
+ ret = Proc_Execve(
+ (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
+ 0
+ );
break;
// -- Load a binary into the current process
case SYS_LOADBIN:
- if( !Syscall_ValidString( (char*) Regs->Arg1)
- || !Syscall_Valid(sizeof(Uint), (Uint*)Regs->Arg2) ) {
- err = -EINVAL;
- ret = 0;
- break;
- }
+ CHECK_STR_NONULL( (char*)Regs->Arg1 );
+ CHECK_NUM_NONULL( (Uint*)Regs->Arg2, sizeof(Uint) );
// Path, *Entrypoint
ret = Binary_Load((char*)Regs->Arg1, (Uint*)Regs->Arg2);
break;
// Open a file that is a entry in an open directory
case SYS_OPENCHILD:
CHECK_STR_NONULL( (char*)Regs->Arg2 );
- ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3);
+ ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3 | VFS_OPENFLAG_USER);
break;
// Change Directory
(fd_set *)Regs->Arg3, // Write
(fd_set *)Regs->Arg4, // Errors
(tTime *)Regs->Arg5, // Timeout
+ (Uint32)Regs->Arg6, // Extra wakeup events
0 // User handles
);
break;
SYS_SETFAULTHANDLER 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_WAITEVENT Wait for an event
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_SETNAME Sets the name of the current thread
+SYS_GETNAME Gets the name of a thread
SYS_GETTID Get current thread ID
SYS_GETPID Get current thread group ID
SYS_SETPRI Set process priority
#include <errno.h>
#include <hal_proc.h>
#include <semaphore.h>
+#include <vfs_threads.h> // VFS Handle maintainence
// Configuration
#define DEBUG_TRACE_TICKETS 0 // Trace ticket counts
#define DEFAULT_QUANTUM 5
#define DEFAULT_PRIORITY 5
#define MIN_PRIORITY 10
-const enum eConfigTypes cCONFIG_TYPES[NUM_CFG_ENTRIES] = {
- CFGT_HEAPSTR, // e.g. CFG_VFS_CWD
- CFGT_INT, // e.g. CFG_VFS_MAXFILES
- CFGT_NULL
-};
// === IMPORTS ===
+// === TYPE ===
+typedef struct
+{
+ tThread *Head;
+ tThread *Tail;
+} tThreadList;
+
// === PROTOTYPES ===
void Threads_Init(void);
#if 0
void Threads_Delete(tThread *Thread);
int Threads_SetName(const char *NewName);
#endif
-char *Threads_GetName(int ID);
+char *Threads_GetName(tTID ID);
#if 0
void Threads_SetPriority(tThread *Thread, int Pri);
tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
int Threads_WaitTID(int TID, int *status);
tThread *Threads_GetThread(Uint TID);
#endif
-tThread *Threads_int_DelFromQueue(tThread **List, tThread *Thread);
+tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread);
+void Threads_int_AddToList(tThreadList *List, tThread *Thread);
#if 0
void Threads_Exit(int TID, int Status);
void Threads_Kill(tThread *Thread, int Status);
// === GLOBALS ===
// -- Core Thread --
+struct sProcess gProcessZero = {
+ };
// Only used for the core kernel
tThread gThreadZero = {
.Status = THREAD_STAT_ACTIVE, // Status
volatile Uint giNextTID = 1; // Next TID to allocate
// --- Thread Lists ---
tThread *gAllThreads = NULL; // All allocated threads
-tThread *gSleepingThreads = NULL; // Sleeping Threads
+tThreadList gSleepingThreads; // Sleeping Threads
int giNumCPUs = 1; // Number of CPUs
BOOL gaThreads_NoTaskSwitch[MAX_CPUS]; // Disables task switches for each core (Pseudo-IF)
// --- Scheduler Types ---
#if SCHEDULER_TYPE == SCHED_LOTTERY
const int caiTICKET_COUNTS[MIN_PRIORITY+1] = {100,81,64,49,36,25,16,9,4,1,0};
volatile int giFreeTickets = 0; // Number of tickets held by non-scheduled threads
-tThread *gActiveThreads = NULL; // Currently Running Threads
+tThreadList gActiveThreads; // Currently Running Threads
#elif SCHEDULER_TYPE == SCHED_RR_SIM
-tThread *gActiveThreads = NULL; // Currently Running Threads
+tThreadList gActiveThreads; // Currently Running Threads
#elif SCHEDULER_TYPE == SCHED_RR_PRI
-tThread *gaActiveThreads[MIN_PRIORITY+1]; // Active threads for each priority level
+tThreadList gaActiveThreads[MIN_PRIORITY+1]; // Active threads for each priority level
#else
# error "Unkown scheduler type"
#endif
Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
// Create Initial Task
- #if SCHEDULER_TYPE == SCHED_RR_PRI
- gaActiveThreads[gThreadZero.Priority] = &gThreadZero;
- #else
- gActiveThreads = &gThreadZero;
- #endif
+// #if SCHEDULER_TYPE == SCHED_RR_PRI
+// gaActiveThreads[gThreadZero.Priority].Head = &gThreadZero;
+// gaActiveThreads[gThreadZero.Priority].Tail = &gThreadZero;
+// #else
+// gActiveThreads.Head = &gThreadZero;
+// gActiveThreads.Tail = &gThreadZero;
+// #endif
gAllThreads = &gThreadZero;
giNumActiveThreads = 1;
+ gThreadZero.Process = &gProcessZero;
Proc_Start();
}
{
// Set to dead
Thread->Status = THREAD_STAT_BURIED;
+
+ // Clear out process state
+ Proc_ClearThread(Thread);
+
+ Thread->Process->nThreads --;
+ if( Thread->Process->nThreads == 0 )
+ {
+ tProcess *proc = Thread->Process;
+ // VFS Cleanup
+ VFS_CloseAllUserHandles();
+ // Architecture cleanup
+ Proc_ClearProcess( proc );
+ // VFS Configuration strings
+ if( proc->CurrentWorkingDir)
+ free( proc->CurrentWorkingDir );
+ if( proc->RootDir )
+ free( proc->RootDir );
+ // Process descriptor
+ free( proc );
+ }
// Free name
if( IsHeap(Thread->ThreadName) )
cur->ThreadName = NULL;
- if( IsHeap(oldname) ) free( oldname );
-
+ if( IsHeap(oldname) ) free( oldname );
cur->ThreadName = strdup(NewName);
+
+ Log_Debug("Threads", "Thread renamed to '%s'", NewName);
+
return 0;
}
if( Pri == Thread->Priority ) return;
#if SCHEDULER_TYPE == SCHED_RR_PRI
- SHORTLOCK( &glThreadListLock );
- // Remove from old priority
- Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
- // And add to new
- Thread->Next = gaActiveThreads[Pri];
- gaActiveThreads[Pri] = Thread;
- Thread->Priority = Pri;
- SHORTREL( &glThreadListLock );
+ if( Thread != Proc_GetCurThread() )
+ {
+ SHORTLOCK( &glThreadListLock );
+ // Remove from old priority
+ Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
+ // And add to new
+ Threads_int_AddToList( &gaActiveThreads[Pri], Thread );
+ Thread->Priority = Pri;
+ SHORTREL( &glThreadListLock );
+ }
+ else
+ Thread->Priority = Pri;
#else
// If this isn't the current thread, we need to lock
if( Thread != Proc_GetCurThread() )
tThread *Threads_CloneTCB(Uint Flags)
{
tThread *cur, *new;
- int i;
cur = Proc_GetCurThread();
// Allocate and duplicate
new->ThreadName = strdup(cur->ThreadName);
// Set Thread Group ID (PID)
- if(Flags & CLONE_VM)
- new->TGID = new->TID;
- else
- new->TGID = cur->TGID;
+ if(Flags & CLONE_VM) {
+ tProcess *newproc, *oldproc;
+ oldproc = cur->Process;
+ new->Process = malloc( sizeof(struct sProcess) );
+ newproc = new->Process;
+ newproc->PID = new->TID;
+ newproc->UID = oldproc->UID;
+ newproc->GID = oldproc->GID;
+ newproc->MaxFD = oldproc->MaxFD;
+ if( oldproc->CurrentWorkingDir )
+ newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir );
+ else
+ newproc->CurrentWorkingDir = NULL;
+ if( oldproc->RootDir )
+ newproc->RootDir = strdup( oldproc->RootDir );
+ else
+ newproc->RootDir = NULL;
+ newproc->nThreads = 1;
+ // Reference all handles in the VFS
+ VFS_ReferenceUserHandles();
+ }
+ else {
+ new->Process->nThreads ++;
+ }
// Messages are not inherited
new->Messages = NULL;
// Set State
new->Remaining = new->Quantum = cur->Quantum;
new->Priority = cur->Priority;
+ new->_errno = 0;
// Set Signal Handlers
new->CurFaultNum = 0;
new->FaultHandler = cur->FaultHandler;
- for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
- {
- switch(cCONFIG_TYPES[i])
- {
- default:
- new->Config[i] = cur->Config[i];
- break;
- case CFGT_HEAPSTR:
- if(cur->Config[i])
- new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
- else
- new->Config[i] = 0;
- break;
- }
- }
-
// Maintain a global list of threads
SHORTLOCK( &glThreadListLock );
new->GlobalPrev = NULL; // Protect against bugs
tThread *Threads_CloneThreadZero(void)
{
tThread *new;
- int i;
// Allocate and duplicate
new = malloc(sizeof(tThread));
return NULL;
}
memcpy(new, &gThreadZero, sizeof(tThread));
+
+ new->Process->nThreads ++;
new->CurCPU = -1;
new->Next = NULL;
new->CurFaultNum = 0;
new->FaultHandler = 0;
- for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
- {
- new->Config[i] = 0;
- }
-
// Maintain a global list of threads
SHORTLOCK( &glThreadListLock );
new->GlobalPrev = NULL; // Protect against bugs
return new;
}
-/**
- * \brief Get a configuration pointer from the Per-Thread data area
- * \param ID Config slot ID
- * \return Pointer at ID
- */
-Uint *Threads_GetCfgPtr(int ID)
-{
- if(ID < 0 || ID >= NUM_CFG_ENTRIES) {
- Warning("Threads_GetCfgPtr: Index %i is out of bounds", ID);
- return NULL;
- }
-
- return &Proc_GetCurThread()->Config[ID];
-}
-
/**
* \brief Wait for a task to change state
* \param TID Thread ID to wait on (-1: Any child thread, 0: Any Child/Sibling, <-1: -PID)
// Specific Thread
if(TID > 0) {
tThread *t = Threads_GetThread(TID);
- int initStatus = t->Status;
tTID ret;
// Wait for the thread to die!
- if(initStatus != THREAD_STAT_ZOMBIE) {
- // TODO: Handle child also being suspended if wanted
- while(t->Status != THREAD_STAT_ZOMBIE) {
- Threads_Sleep();
- Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
- Threads_GetTID(), t->TID, t->Status);
- }
+ // TODO: Handle child also being suspended if wanted
+ while(t->Status != THREAD_STAT_ZOMBIE) {
+ Threads_Sleep();
+ Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
+ Threads_GetTID(), t->TID, t->Status);
}
// Set return status
- Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
- Threads_GetTID(), t->TID, t->Status);
ret = t->TID;
switch(t->Status)
{
* \param Thread Thread to find
* \return \a Thread
*/
-tThread *Threads_int_DelFromQueue(tThread **List, tThread *Thread)
+tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread)
{
tThread *ret, *prev = NULL;
- for(ret = *List;
+ for(ret = List->Head;
ret && ret != Thread;
prev = ret, ret = ret->Next
);
}
if( !prev ) {
- *List = Thread->Next;
+ List->Head = Thread->Next;
//LogF("%p(%s) removed from head of %p\n", Thread, Thread->ThreadName, List);
}
else {
prev->Next = Thread->Next;
//LogF("%p(%s) removed from %p (prev=%p)\n", Thread, Thread->ThreadName, List, prev);
}
+ if( Thread->Next == NULL )
+ List->Tail = prev;
return Thread;
}
+void Threads_int_AddToList(tThreadList *List, tThread *Thread)
+{
+ if( List->Head )
+ List->Tail->Next = Thread;
+ else
+ List->Head = Thread;
+ List->Tail = Thread;
+ Thread->Next = NULL;
+}
+
/**
* \brief Exit the current process (or another?)
* \param TID Thread ID to kill
// Currently active thread
case THREAD_STAT_ACTIVE:
- #if SCHEDULER_TYPE == SCHED_RR_PRI
- if( Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
- #else
- if( Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
- #endif
+ if( Thread != Proc_GetCurThread() )
{
- // Ensure that we are not rescheduled
- Thread->Remaining = 0; // Clear Remaining Quantum
- Thread->Quantum = 0; // Clear Quantum to indicate dead thread
-
- // Update bookkeeping
- giNumActiveThreads --;
+ #if SCHEDULER_TYPE == SCHED_RR_PRI
+ tThreadList *list = &gaActiveThreads[Thread->Priority];
+ #else
+ tThreadList *list = &gActiveThreads;
+ #endif
+ if( Threads_int_DelFromQueue( list, Thread ) )
+ {
+ }
+ else
+ {
+ Log_Warning("Threads",
+ "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
+ Thread, Thread->TID, Thread->ThreadName
+ );
+ }
#if SCHEDULER_TYPE == SCHED_LOTTERY
- if( Thread != Proc_GetCurThread() )
- giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
+ giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
#endif
}
- else
- {
- Log_Warning("Threads",
- "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
- Thread, Thread->TID, Thread->ThreadName
- );
- }
+ // Ensure that we are not rescheduled
+ Thread->Remaining = 0; // Clear Remaining Quantum
+ Thread->Quantum = 0; // Clear Quantum to indicate dead thread
+
+ // Update bookkeeping
+ giNumActiveThreads --;
break;
// Kill it while it sleeps!
case THREAD_STAT_SLEEPING:
Thread->RetStatus = Status;
SHORTREL( &Thread->IsLocked );
- // Clear out process state
- Proc_ClearThread(Thread);
Thread->Status = THREAD_STAT_ZOMBIE;
SHORTREL( &glThreadListLock );
cur->Status = THREAD_STAT_SLEEPING;
// Add to Sleeping List (at the top)
- cur->Next = gSleepingThreads;
- gSleepingThreads = cur;
-
+ Threads_int_AddToList( &gSleepingThreads, cur );
#if DEBUG_TRACE_STATE
Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
// Thread->CurCPU = -1;
// Add to active list
{
- tThread *tmp, *prev = NULL;
#if SCHEDULER_TYPE == SCHED_RR_PRI
- for( tmp = gaActiveThreads[Thread->Priority]; tmp; prev = tmp, tmp = tmp->Next );
- if(prev)
- prev->Next = Thread;
- else
- gaActiveThreads[Thread->Priority] = Thread;
+ tThreadList *list = &gaActiveThreads[Thread->Priority];
#else
- for( tmp = gActiveThreads; tmp; prev = tmp, tmp = tmp->Next );
- if(prev)
- prev->Next = Thread;
- else
- gActiveThreads = Thread;
+ tThreadList *list = &gActiveThreads;
#endif
- Thread->Next = NULL;
+ Threads_int_AddToList( list, Thread );
}
// Update bookkeeping
*/
tThread *Threads_RemActive(void)
{
+ #if 0
tThread *ret = Proc_GetCurThread();
if( !IS_LOCKED(&glThreadListLock) ) {
if( !Threads_int_DelFromQueue(&gActiveThreads, ret) )
#endif
{
- SHORTREL( &glThreadListLock );
Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue",
ret, ret->TID, ret->ThreadName
);
#endif
return ret;
+ #else
+ return Proc_GetCurThread();
+ #endif
}
/**
// --- Process Structure Access Functions ---
tPID Threads_GetPID(void)
{
- return Proc_GetCurThread()->TGID;
+ return Proc_GetCurThread()->Process->PID;
}
tTID Threads_GetTID(void)
{
}
tUID Threads_GetUID(void)
{
- return Proc_GetCurThread()->UID;
+ return Proc_GetCurThread()->Process->UID;
}
tGID Threads_GetGID(void)
{
- return Proc_GetCurThread()->GID;
+ return Proc_GetCurThread()->Process->GID;
}
-int Threads_SetUID(Uint *Errno, tUID ID)
+int Threads_SetUID(tUID ID)
{
tThread *t = Proc_GetCurThread();
- if( t->UID != 0 ) {
- *Errno = -EACCES;
+ if( t->Process->UID != 0 ) {
+ errno = -EACCES;
return -1;
}
- Log_Debug("Threads", "TID %i's UID set to %i", t->TID, ID);
- t->UID = ID;
+ Log_Debug("Threads", "PID %i's UID set to %i", t->Process->PID, ID);
+ t->Process->UID = ID;
return 0;
}
-int Threads_SetGID(Uint *Errno, tGID ID)
+int Threads_SetGID(tGID ID)
{
tThread *t = Proc_GetCurThread();
- if( t->UID != 0 ) {
- *Errno = -EACCES;
+ if( t->Process->UID != 0 ) {
+ errno = -EACCES;
return -1;
}
- Log_Debug("Threads", "TID %i's GID set to %i", t->TID, ID);
- t->GID = ID;
+ Log_Debug("Threads", "PID %i's GID set to %i", t->Process->PID, ID);
+ t->Process->GID = ID;
return 0;
}
+// --- Per-thread storage ---
+int *Threads_GetErrno(void)
+{
+ return &Proc_GetCurThread()->_errno;
+}
+
+// --- Configuration ---
+int *Threads_GetMaxFD(void)
+{
+ return &Proc_GetCurThread()->Process->MaxFD;
+}
+char **Threads_GetChroot(void)
+{
+ return &Proc_GetCurThread()->Process->RootDir;
+}
+char **Threads_GetCWD(void)
+{
+ return &Proc_GetCurThread()->Process->CurrentWorkingDir;
+}
+// ---
+
/**
* \fn void Threads_Dump(void)
*/
void Threads_DumpActive(void)
{
tThread *thread;
+ tThreadList *list;
#if SCHEDULER_TYPE == SCHED_RR_PRI
int i;
#endif
#if SCHEDULER_TYPE == SCHED_RR_PRI
for( i = 0; i < MIN_PRIORITY+1; i++ )
{
- for(thread=gaActiveThreads[i];thread;thread=thread->Next)
+ list = &gaActiveThreads[i];
#else
- for(thread=gActiveThreads;thread;thread=thread->Next)
+ list = &gActiveThreads;
#endif
+ for(thread=list->Head;thread;thread=thread->Next)
{
Log(" %p %i (%i) - %s (CPU %i)",
- thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+ thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
if(thread->Status != THREAD_STAT_ACTIVE)
- Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE);
+ Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)",
+ thread->Status, THREAD_STAT_ACTIVE);
Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum);
Log(" KStack 0x%x", thread->KernelStack);
if( thread->bInstrTrace )
for(thread=gAllThreads;thread;thread=thread->GlobalNext)
{
Log(" %p %i (%i) - %s (CPU %i)",
- thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+ thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
Log(" State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
switch(thread->Status)
{
#endif
return NULL;
}
-
+
+ #if 0
#if SCHEDULER_TYPE != SCHED_RR_PRI
// Special case: 1 thread
if(giNumActiveThreads == 1) {
- if( gActiveThreads->CurCPU == -1 )
- gActiveThreads->CurCPU = CPU;
+ if( gActiveThreads.Head->CurCPU == -1 )
+ gActiveThreads.Head->CurCPU = CPU;
SHORTREL( &glThreadListLock );
- if( gActiveThreads->CurCPU == CPU )
- return gActiveThreads;
+ if( gActiveThreads.Head->CurCPU == CPU )
+ return gActiveThreads.Head;
return NULL; // CPU has nothing to do
}
#endif
-
+ #endif
+
// Allow the old thread to be scheduled again
if( Last ) {
if( Last->Status == THREAD_STAT_ACTIVE ) {
+ tThreadList *list;
#if SCHEDULER_TYPE == SCHED_LOTTERY
giFreeTickets += caiTICKET_COUNTS[ Last->Priority ];
# if DEBUG_TRACE_TICKETS
caiTICKET_COUNTS[ Last->Priority ]);
# endif
#endif
+
+ #if SCHEDULER_TYPE == SCHED_RR_PRI
+ list = &gaActiveThreads[ Last->Priority ];
+ #else
+ list = &gActiveThreads;
+ #endif
+ // Add to end of list
+ Threads_int_AddToList( list, Last );
}
#if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
else
int ticket, number;
# if 1
number = 0;
- for(thread = gActiveThreads; thread; thread = thread->Next) {
- if(thread->CurCPU >= 0) continue;
+ for(thread = gActiveThreads.Head; thread; thread = thread->Next)
+ {
if(thread->Status != THREAD_STAT_ACTIVE)
Panic("Bookkeeping fail - %p %i(%s) is on the active queue with a status of %i",
thread, thread->TID, thread->ThreadName, thread->Status);
ticket = number = rand() % giFreeTickets;
// Find the next thread
- for(thread=gActiveThreads;thread;thread=thread->Next)
+ for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
{
- if(thread->CurCPU >= 0) continue;
if( caiTICKET_COUNTS[ thread->Priority ] > number) break;
number -= caiTICKET_COUNTS[ thread->Priority ];
}
Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
giFreeTickets, number);
}
-
+
+ // Remove
+ if(prev)
+ prev->Next = thread->Next;
+ else
+ gActiveThreads.Head = thread->Next;
+ if(!thread->Next)
+ gActiveThreads.Tail = prev;
+
giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ];
# if DEBUG_TRACE_TICKETS
LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n",
#elif SCHEDULER_TYPE == SCHED_RR_PRI
{
int i;
+ thread = NULL;
for( i = 0; i < MIN_PRIORITY + 1; i ++ )
{
- for(thread = gaActiveThreads[i]; thread; thread = thread->Next)
- {
- if( thread->CurCPU == -1 ) break;
- }
- // If we fall onto the same queue again, special handling is
- // needed
- if( Last && Last->Status == THREAD_STAT_ACTIVE && i == Last->Priority ) {
- tThread *savedThread = thread;
-
- // Find the next unscheduled thread in the list
- for( thread = Last->Next; thread; thread = thread->Next )
- {
- if( thread->CurCPU == -1 ) break;
- }
- // If we don't find anything after, just use the one
- // found above.
- if( !thread ) thread = savedThread;
- }
- // Found a thread? Schedule it!
- if( thread ) break;
+ if( !gaActiveThreads[i].Head )
+ continue ;
+
+ thread = gaActiveThreads[i].Head;
+
+ // Remove from head
+ gaActiveThreads[i].Head = thread->Next;
+ if(!thread->Next)
+ gaActiveThreads[i].Tail = NULL;
+ thread->Next = NULL;
+ break;
}
// Anything to do?
}
}
#elif SCHEDULER_TYPE == SCHED_RR_SIM
- {
- // Find the next unscheduled thread in the list
- for( thread = Last->Next; thread; thread = thread->Next )
- {
- if( thread->CurCPU == -1 ) break;
- }
- // If we don't find anything after, search from the beginning
- if( !thread )
- {
- for(thread = gActiveThreads; thread; thread = thread->Next)
- {
- if( thread->CurCPU == -1 ) break;
- }
- }
+ {
+ // Get the next thread off the list
+ thread = gActiveThreads.Head;
+ gActiveThreads.Head = thread->Next;
+ if(!thread->Next)
+ gaActiveThreads.Tail = NULL;
+ thread->Next = NULL;
// Anything to do?
if( !thread ) {
// Permissions Check
if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
- if(parent->Close) parent->Close( parent );
+ _CloseNode(parent);
free(absPath);
LEAVE('i', -1);
return -1;
LOG("parent = %p", parent);
- if(parent->MkNod == NULL) {
+ if(!parent->Type || !parent->Type->MkNod) {
Warning("VFS_MkNod - Directory has no MkNod method");
LEAVE('i', -1);
return -1;
}
// Create node
- ret = parent->MkNod(parent, name, Flags);
+ ret = parent->Type->MkNod(parent, name, Flags);
// Free allocated string
free(absPath);
// Free Parent
- if(parent->Close) parent->Close( parent );
+ _CloseNode(parent);
// Error Check
if(ret == 0) {
{
char *realLink;
int fp;
- char *_link;
ENTER("sName sLink", Name, Link);
// Get absolue path name
- _link = VFS_GetAbsPath( Link );
- if(!_link) {
+ realLink = VFS_GetAbsPath( Link );
+ if(!realLink) {
Log_Warning("VFS", "Path '%s' is badly formed", Link);
LEAVE('i', -1);
return -1;
}
- LOG("_link = '%s'", _link);
-
- #if 1
- {
- tVFS_Node *destNode = VFS_ParsePath( _link, &realLink, NULL );
- #if 0
- // Get true path and node
- free(_link);
- _link = NULL;
- #else
- realLink = _link;
- #endif
-
- // Check if destination exists
- if(!destNode) {
- Log_Warning("VFS", "File '%s' does not exist, symlink not created", Link);
- return -1;
- }
-
- // Derefence the destination
- if(destNode->Close) destNode->Close(destNode);
- }
- #else
- realLink = _link;
- #endif
LOG("realLink = '%s'", realLink);
// Make node
if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
Log_Warning("VFS", "Unable to create link node '%s'", Name);
+ free(realLink);
LEAVE('i', -2);
return -2; // Make link node
}
//ENTER("ph pDest", h, Dest);
- if(!h || h->Node->ReadDir == NULL) {
+ if(!h || !h->Node->Type || !h->Node->Type->ReadDir) {
//LEAVE('i', 0);
return 0;
}
}
do {
- tmp = h->Node->ReadDir(h->Node, h->Position);
+ tmp = h->Node->Type->ReadDir(h->Node, h->Position);
if((Uint)tmp < (Uint)VFS_MAXSKIP)
h->Position += (Uint)tmp;
else
tVFS_Driver gDevFS_Info = {
"devfs", 0, DevFS_InitDevice, NULL, NULL
};
+tVFS_NodeType gDevFS_DirType = {
+ .TypeName = "DevFS-Dir",
+ .ReadDir = DevFS_ReadDir,
+ .FindDir = DevFS_FindDir
+ };
tVFS_Node gDevFS_RootNode = {
.Size = 0,
.Flags = VFS_FFLAG_DIRECTORY,
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
- .ReadDir = DevFS_ReadDir,
- .FindDir = DevFS_FindDir
+ .Type = &gDevFS_DirType
};
tDevFS_Driver *gDevFS_Drivers = NULL;
int giDevFS_NextID = 1;
tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name);
char *Root_ReadDir(tVFS_Node *Node, int Pos);
Uint64 Root_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
tRamFS_File *Root_int_AllocFile(void);
// === GLOBALS ===
{{1,0}, {0,VFS_PERM_ALL^VFS_PERM_EXECUTE}}, // Group (Root)
{{0,-1}, {0,VFS_PERM_READ}} // World (Nobody)
};
+tVFS_NodeType gRootFS_DirType = {
+ .TypeName = "RootFS-Dir",
+ .ReadDir = Root_ReadDir,
+ .FindDir = Root_FindDir,
+ .MkNod = Root_MkNod
+};
+tVFS_NodeType gRootFS_FileType = {
+ .TypeName = "RootFS-File",
+ .Read = Root_Read,
+ .Write = Root_Write,
+};
// === CODE ===
/**
= root->Node.ATime = now();
root->Node.NumACLs = 3;
root->Node.ACLs = RootFS_DirACLs;
-
- //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;
+
+ root->Node.Type = &gRootFS_DirType;
return &root->Node;
}
if(Flags & VFS_FFLAG_DIRECTORY)
{
child->Node.ACLs = RootFS_DirACLs;
- child->Node.ReadDir = Root_ReadDir;
- child->Node.FindDir = Root_FindDir;
- child->Node.MkNod = Root_MkNod;
+ child->Node.Type = &gRootFS_DirType;
} else {
if(Flags & VFS_FFLAG_SYMLINK)
child->Node.ACLs = RootFS_DirACLs;
else
child->Node.ACLs = RootFS_FileACLs;
- child->Node.Read = Root_Read;
- child->Node.Write = Root_Write;
+ child->Node.Type = &gRootFS_FileType;
}
prev->Next = child;
* \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)
+Uint64 Root_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tRamFS_File *file = Node->ImplPtr;
#include "vfs.h"
#include "vfs_int.h"
#include "vfs_ext.h"
+#include <threads.h> // GetMaxFD
+#include <vfs_threads.h> // Handle maintainance
// === CONSTANTS ===
#define MAX_KERNEL_FILES 128
if(FD >= MAX_KERNEL_FILES) return NULL;
h = &gaKernelHandles[ FD ];
} else {
- if(FD >= CFGINT(CFG_VFS_MAXFILES)) return NULL;
+ if(FD >= *Threads_GetMaxFD()) return NULL;
h = &gaUserHandles[ FD ];
}
// Check for a user open
if(bIsUser)
{
+ int max_handles = *Threads_GetMaxFD();
// Allocate Buffer
- if( MM_GetPhysAddr( (Uint)gaUserHandles ) == 0 )
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
{
Uint addr, size;
- size = CFGINT(CFG_VFS_MAXFILES) * sizeof(tVFS_Handle);
+ size = max_handles * sizeof(tVFS_Handle);
for(addr = 0; addr < size; addr += 0x1000)
{
- if( !MM_Allocate( (Uint)gaUserHandles + addr ) )
+ if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
{
Warning("OOM - VFS_AllocHandle");
Threads_Exit(0, 0xFF); // Terminate user
memset( gaUserHandles, 0, size );
}
// Get a handle
- for(i=0;i<CFGINT(CFG_VFS_MAXFILES);i++)
+ for( i = 0; i < max_handles; i ++ )
{
if(gaUserHandles[i].Node) continue;
gaUserHandles[i].Node = Node;
else
{
// Allocate space if not already
- if( MM_GetPhysAddr( (Uint)gaKernelHandles ) == 0 )
+ if( MM_GetPhysAddr( (tVAddr)gaKernelHandles ) == 0 )
{
Uint addr, size;
size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
for(addr = 0; addr < size; addr += 0x1000)
{
- if( !MM_Allocate( (Uint)gaKernelHandles + addr ) )
+ if( !MM_Allocate( (tVAddr)gaKernelHandles + addr ) )
{
Panic("OOM - VFS_AllocHandle");
Threads_Exit(0, 0xFF); // Terminate application (get some space back)
return -1;
}
+
+void VFS_ReferenceUserHandles(void)
+{
+ int i;
+ int max_handles = *Threads_GetMaxFD();
+
+ // Check if this process has any handles
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ return ;
+
+ for( i = 0; i < max_handles; i ++ )
+ {
+ tVFS_Handle *h;
+ h = &gaUserHandles[i];
+ if( !h->Node )
+ continue ;
+ if( h->Node->Type && h->Node->Type->Reference )
+ h->Node->Type->Reference( h->Node );
+ }
+}
+
+void VFS_CloseAllUserHandles(void)
+{
+ int i;
+ int max_handles = *Threads_GetMaxFD();
+
+ // Check if this process has any handles
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ return ;
+
+ for( i = 0; i < max_handles; i ++ )
+ {
+ tVFS_Handle *h;
+ h = &gaUserHandles[i];
+ if( !h->Node )
+ continue ;
+ if( h->Node->Type && h->Node->Type->Close )
+ h->Node->Type->Close( h->Node );
+ }
+}
+
+/**
+ * \brief Take a backup of a set of file descriptors
+ */
+void *VFS_SaveHandles(int NumFDs, int *FDs)
+{
+ tVFS_Handle *ret;
+ int i;
+ int max_handles = *Threads_GetMaxFD();
+
+ // Check if this process has any handles
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ return NULL;
+
+ // Allocate
+ ret = malloc( NumFDs * sizeof(tVFS_Handle) );
+ if( !ret )
+ return NULL;
+
+ if( NumFDs > max_handles )
+ NumFDs = max_handles;
+
+ // Take copies of the handles
+ for( i = 0; i < NumFDs; i ++ )
+ {
+ tVFS_Handle *h;
+ if( FDs == NULL )
+ h = &gaUserHandles[i];
+ else {
+ h = VFS_GetHandle(FDs[i] & (VFS_KERNEL_FLAG - 1));
+ if(!h) {
+ Log_Warning("VFS", "VFS_SaveHandles - Invalid FD %i",
+ FDs[i] & (VFS_KERNEL_FLAG - 1) );
+ free(ret);
+ return NULL;
+ }
+ }
+ memcpy( &ret[i], h, sizeof(tVFS_Handle) );
+
+ // Reference node
+ if( !h->Node )
+ continue ;
+ if( h->Node->Type && h->Node->Type->Reference )
+ h->Node->Type->Reference( h->Node );
+ }
+
+ return ret;
+}
+
+void VFS_RestoreHandles(int NumFDs, void *Handles)
+{
+ tVFS_Handle *handles = Handles;
+ int i;
+
+ // NULL = nothing to do
+ if( !Handles )
+ return ;
+
+ // Check if there is already a set of handles
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
+ return ;
+
+
+ // Allocate user handle area
+ {
+ Uint addr, size;
+ int max_handles = *Threads_GetMaxFD();
+ size = max_handles * sizeof(tVFS_Handle);
+ for(addr = 0; addr < size; addr += 0x1000)
+ {
+ if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
+ {
+ Warning("OOM - VFS_AllocHandle");
+ Threads_Exit(0, 0xFF); // Terminate user
+ }
+ }
+ memset( gaUserHandles, 0, size );
+ }
+
+ // Restore handles
+ memcpy( gaUserHandles, handles, NumFDs * sizeof(tVFS_Handle) );
+ // Reference when copied
+ for( i = 0; i < NumFDs; i ++ )
+ {
+ tVFS_Handle *h = &handles[i];
+
+ if( !h->Node )
+ continue ;
+ if( h->Node->Type && h->Node->Type->Reference )
+ h->Node->Type->Reference( h->Node );
+ }
+}
+
+void VFS_FreeSavedHandles(int NumFDs, void *Handles)
+{
+ tVFS_Handle *handles = Handles;
+ int i;
+
+ // NULL = nothing to do
+ if( !Handles )
+ return ;
+
+ // Dereference all saved nodes
+ for( i = 0; i < NumFDs; i ++ )
+ {
+ tVFS_Handle *h = &handles[i];
+
+ if( !h->Node )
+ continue ;
+ if( h->Node->Type && h->Node->Type->Close )
+ h->Node->Type->Close( h->Node );
+ }
+ free( Handles );
+}
if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
LEAVE_RET('i', -1);
- if(!h->Node->Read) LEAVE_RET('i', 0);
+ if(!h->Node->Type || !h->Node->Type->Read) LEAVE_RET('i', 0);
- ret = h->Node->Read(h->Node, h->Position, Length, Buffer);
+ ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
if(ret == -1) LEAVE_RET('i', -1);
h->Position += ret;
if( !(h->Mode & VFS_OPENFLAG_READ) ) return -1;
if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1;
- if(!h->Node->Read) {
+ if( !h->Node->Type || !h->Node->Type->Read) {
Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
return 0;
}
- ret = h->Node->Read(h->Node, Offset, Length, Buffer);
+ ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
if(ret == -1) return -1;
return ret;
}
if( !(h->Mode & VFS_OPENFLAG_WRITE) ) return -1;
if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1;
- if(!h->Node->Write) return 0;
+ if( !h->Node->Type || !h->Node->Type->Write ) return 0;
- // TODO: This is a hack, I need to change VFS_Node to have "const void*"
- ret = h->Node->Write(h->Node, h->Position, Length, (void*)Buffer);
+ ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
if(ret == -1) return -1;
+
h->Position += ret;
return ret;
}
if( !(h->Mode & VFS_OPENFLAG_WRITE) ) return -1;
if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1;
- if(!h->Node->Write) return 0;
- // TODO: This is a hack, I need to change VFS_Node to have "const void*"
- ret = h->Node->Write(h->Node, Offset, Length, (void*)Buffer);
+ if(!h->Node->Type || !h->Node->Type->Write) return 0;
+ ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
+
if(ret == -1) return -1;
return ret;
}
h = VFS_GetHandle(FD);
if(!h) return -1;
- if(!h->Node->IOCtl) return -1;
- return h->Node->IOCtl(h->Node, ID, Buffer);
+ if(!h->Node->Type || !h->Node->Type->IOCtl) return -1;
+ return h->Node->Type->IOCtl(h->Node, ID, Buffer);
}
/**
*/
#include <acess.h>
#include <fs_sysfs.h>
-#include "vfs.h"
-#include "vfs_int.h"
-#include "vfs_ext.h"
+#include <threads.h>
+#include <vfs.h>
+#include <vfs_int.h>
+#include <vfs_ext.h>
// === IMPORTS ===
extern tVFS_Driver gRootFS_Info;
VFS_Mount("dev", "/Devices", "devfs", "");
Log_Debug("VFS", "Setting max files");
- CFGINT(CFG_VFS_MAXFILES) = 32;
+ *Threads_GetMaxFD() = 32;
return 0;
}
//Log(" VFS_GetTruePath: node=%p, ret='%s'", node, ret);
if(!node) return NULL;
- if(node->Close) node->Close(node);
+ if(node->Type->Close) node->Type->Close(node);
return ret;
}
#include <vfs.h>
// === PROTOTYPES ===
-tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path);
+tVFS_Node *VFS_MemFile_Create(const char *Path);
void VFS_MemFile_Close(tVFS_Node *Node);
Uint64 VFS_MemFile_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
// === GLOBALS ===
-tVFS_Node gVFS_MemRoot = {
- .Flags = VFS_FFLAG_DIRECTORY,
- .NumACLs = 0,
- .FindDir = VFS_MemFile_Create
+tVFS_NodeType gVFS_MemFileType = {
+ .Close = VFS_MemFile_Close,
+ .Read = VFS_MemFile_Read,
+ .Write = VFS_MemFile_Write
};
// === CODE ===
/**
- * \fn tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path)
- * \note Treated as finddir by VFS_ParsePath
+ * \fn tVFS_Node *VFS_MemFile_Create(const char *Path)
*/
-tVFS_Node *VFS_MemFile_Create(tVFS_Node *Unused, const char *Path)
+tVFS_Node *VFS_MemFile_Create(const char *Path)
{
Uint base, size;
const char *str = Path;
ret->ACLs = &gVFS_ACL_EveryoneRWX;
// Functions
- ret->Close = VFS_MemFile_Close;
- ret->Read = VFS_MemFile_Read;
- ret->Write = VFS_MemFile_Write;
+ ret->Type = &gVFS_MemFileType;
return ret;
}
* \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)
+Uint64 VFS_MemFile_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
// Check for use of free'd file
if(Node->ImplPtr == NULL) return 0;
{
if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
{
- if( h->Node->MMap )
- h->Node->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+ tVFS_NodeType *nt = h->Node->Type;
+ if( !nt )
+ {
+ // TODO: error
+ }
+ else if( nt->MMap )
+ nt->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
else
{
int read_len;
return NULL;
}
// TODO: Clip read length
- read_len = h->Node->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+ read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
// if( read_len != PAGE_SIZE ) {
// memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
// }
ent->Node.ReferenceCount = 1;
next = ent->Next;
- if(ent->Node.Close)
- ent->Node.Close( &ent->Node );
+ if(ent->Node.Type && ent->Node.Type->Close)
+ ent->Node.Type->Close( &ent->Node );
free(ent);
ent = next;
#include "vfs.h"
#include "vfs_int.h"
#include "vfs_ext.h"
+#include <threads.h>
// === CONSTANTS ===
#define OPEN_MOUNT_ROOT 1
#define MAX_PATH_LEN 255
// === IMPORTS ===
-extern tVFS_Node gVFS_MemRoot;
extern tVFS_Mount *gVFS_RootMount;
extern int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode);
+extern tVFS_Node *VFS_MemFile_Create(const char *Path);
// === PROTOTYPES ===
int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode );
char *tmpStr;
int iPos = 0;
int iPos2 = 0;
- const char *chroot = CFGPTR(CFG_VFS_CHROOT);
+ const char *chroot = *Threads_GetChroot();
int chrootLen;
- const char *cwd = CFGPTR(CFG_VFS_CWD);
+ const char *cwd = *Threads_GetCWD();
int cwdLen;
ENTER("sPath", Path);
ENTER("sPath pTruePath", Path, TruePath);
- // Memory File
- if(Path[0] == '$') {
+ // HACK: Memory File
+ if(Threads_GetUID() == 0 && Path[0] == '$') {
if(TruePath) {
*TruePath = malloc(strlen(Path)+1);
strcpy(*TruePath, Path);
}
- curNode = gVFS_MemRoot.FindDir(&gVFS_MemRoot, Path);
+ curNode = VFS_MemFile_Create(Path);
if(MountPoint) {
*MountPoint = NULL;
}
// Check permissions on root of filesystem
if( !VFS_CheckACL(curNode, VFS_PERM_EXECUTE) ) {
- if(curNode->Close) curNode->Close( curNode );
- if(TruePath) {
- free(*TruePath);
- *TruePath = NULL;
- }
//Log("Permissions fail on '%s'", Path);
- LEAVE('n');
- return NULL;
+ goto _error;
}
// Check if the node has a FindDir method
- if( !curNode->FindDir )
+ if( !curNode->Type->FindDir )
{
- if(curNode->Close) curNode->Close(curNode);
- if(TruePath) {
- free(*TruePath);
- *TruePath = NULL;
- }
//Log("FindDir fail on '%s'", Path);
- LEAVE('n');
- return NULL;
+ goto _error;
}
- LOG("FindDir{=%p}(%p, '%s')", curNode->FindDir, curNode, pathEle);
+ LOG("FindDir{=%p}(%p, '%s')", curNode->Type->FindDir, curNode, pathEle);
// Get Child Node
- tmpNode = curNode->FindDir(curNode, pathEle);
+ tmpNode = curNode->Type->FindDir(curNode, pathEle);
LOG("tmpNode = %p", tmpNode);
- if(curNode->Close) {
- //LOG2("curNode->Close = %p", curNode->Close);
- curNode->Close(curNode);
- }
+ _CloseNode( curNode );
curNode = tmpNode;
// Error Check
if(!curNode) {
LOG("Node '%s' not found in dir '%s'", pathEle, Path);
- if(TruePath) {
- free(*TruePath);
- *TruePath = NULL;
- }
- //Log("Child fail on '%s' ('%s)", Path, pathEle);
- LEAVE('n');
- return NULL;
+ goto _error;
}
// Handle Symbolic Links
free(*TruePath);
*TruePath = NULL;
}
- if(!curNode->Read) {
+ if(!curNode->Type || !curNode->Type->Read) {
Log_Warning("VFS", "VFS_ParsePath - Read of symlink node %p'%s' is NULL",
curNode, Path);
- if(curNode->Close) curNode->Close(curNode);
- // No need to free *TruePath, it should already be NULL
- LEAVE('n');
- return NULL;
+ goto _error;
}
if(iNestedLinks > MAX_NESTED_LINKS) {
- if(curNode->Close) curNode->Close(curNode);
- LEAVE('n');
- return NULL;
+ Log_Notice("VFS", "VFS_ParsePath - Nested link limit exceeded");
+ goto _error;
}
// Parse Symlink Path
{
int remlen = strlen(Path) - (ofs + nextSlash);
if( curNode->Size + remlen > MAX_PATH_LEN ) {
- if(curNode->Close) curNode->Close(curNode);
Log_Warning("VFS", "VFS_ParsePath - Symlinked path too long");
- LEAVE('n');
- return NULL;
+ goto _error;
}
- curNode->Read( curNode, 0, curNode->Size, path_buffer );
+ curNode->Type->Read( curNode, 0, curNode->Size, path_buffer );
path_buffer[ curNode->Size ] = '\0';
LOG("path_buffer = '%s'", path_buffer);
strcat(path_buffer, Path + ofs+nextSlash);
if( !(curNode->Flags & VFS_FFLAG_DIRECTORY) )
{
Log_Warning("VFS", "VFS_ParsePath - Path segment is not a directory");
- if(TruePath) free(*TruePath);
- LEAVE('n');
- return NULL;
+ goto _error;
}
// Check if path needs extending
// Check if allocation succeeded
if(!tmp) {
Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer");
- free(*TruePath);
- *TruePath = NULL;
- if(curNode->Close) curNode->Close(curNode);
- LEAVE('n');
- return NULL;
+ goto _error;
}
*TruePath = tmp;
// Append to path
// - Extend Path
retLength += nextSlash + 1;
}
-
- if( !curNode->FindDir ) {
- if(curNode->Close) curNode->Close(curNode);
- if(TruePath) {
- free(*TruePath);
- *TruePath = NULL;
- }
+
+ // Check final finddir call
+ if( !curNode->Type || !curNode->Type->FindDir ) {
Log_Warning("VFS", "VFS_ParsePath - FindDir doesn't exist for element of '%s'", Path);
- LEAVE('n');
- return NULL;
+ goto _error;
}
// Get last node
LOG("FindDir(%p, '%s')", curNode, &Path[ofs]);
- tmpNode = curNode->FindDir(curNode, &Path[ofs]);
+ tmpNode = curNode->Type->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);
- //Log("Child fail '%s' ('%s')", Path, &Path[ofs]);
- if(TruePath) free(*TruePath);
- if(curNode->Close) curNode->Close(curNode);
- LEAVE('n');
- return NULL;
+ goto _error;
}
+ _CloseNode( curNode );
if(TruePath)
{
// Check if allocation succeeded
if(!tmp) {
Log_Warning("VFS", "VFS_ParsePath - Unable to reallocate true path buffer");
- free(*TruePath);
- if(tmpNode->Close) tmpNode->Close(curNode);
- LEAVE('n');
- return NULL;
+ goto _error;
}
*TruePath = tmp;
// Append to path
LEAVE('p', tmpNode);
return tmpNode;
+
+_error:
+ _CloseNode( curNode );
+
+ if(TruePath && *TruePath) {
+ free(*TruePath);
+ *TruePath = NULL;
+ }
+ LEAVE('n');
+ return NULL;
}
/**
// Permissions Check
if( !VFS_CheckACL(Node, i) ) {
- if(Node->Close) Node->Close( Node );
+ _CloseNode( Node );
Log_Log("VFS", "VFS_int_CreateHandle: Permissions Failed");
errno = EACCES;
LEAVE_RET('i', -1);
* \fn int VFS_Open(const char *Path, Uint Mode)
* \brief Open a file
*/
-int VFS_Open(const char *Path, Uint Mode)
+int VFS_Open(const char *Path, Uint Flags)
+{
+ return VFS_OpenEx(Path, Flags, 0);
+}
+
+int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
{
tVFS_Node *node;
tVFS_Mount *mnt;
char *absPath;
- ENTER("sPath xMode", Path, Mode);
+ ENTER("sPath xFlags oMode", Path, Flags);
// Get absolute path
absPath = VFS_GetAbsPath(Path);
LEAVE_RET('i', -1);
}
LOG("absPath = \"%s\"", absPath);
+
// Parse path and get mount point
node = VFS_ParsePath(absPath, NULL, &mnt);
+
+ // Create file if requested and it doesn't exist
+ if( !node && (Flags & VFS_OPENFLAG_CREATE) )
+ {
+ // TODO: Translate `Mode` into ACL and node flags
+ // Get parent, create node
+ VFS_MkNod(absPath, 0);
+ node = VFS_ParsePath(absPath, NULL, &mnt);
+ }
+
// Free generated path
free(absPath);
- if(!node) {
+ // Check for error
+ if(!node)
+ {
LOG("Cannot find node");
errno = ENOENT;
LEAVE_RET('i', -1);
}
// Check for symlinks
- if( !(Mode & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
+ if( !(Flags & VFS_OPENFLAG_NOLINK) && (node->Flags & VFS_FFLAG_SYMLINK) )
{
char tmppath[node->Size+1];
if( node->Size > MAX_PATH_LEN ) {
Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size);
LEAVE_RET('i', -1);
}
- if( !node->Read ) {
+ if( !node->Type || !node->Type->Read ) {
Log_Warning("VFS", "VFS_Open - No read method on symlink");
LEAVE_RET('i', -1);
}
// Read symlink's path
- node->Read( node, 0, node->Size, tmppath );
+ node->Type->Read( node, 0, node->Size, tmppath );
tmppath[ node->Size ] = '\0';
- if(node->Close) node->Close( node );
+ _CloseNode( node );
// Open the target
node = VFS_ParsePath(tmppath, NULL, &mnt);
if(!node) {
}
}
- LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Mode));
+ LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Flags));
}
// Check for directory
if( !(h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
- Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory", FD);
+ Log_Warning("VFS", "VFS_OpenChild - Passed handle is not a directory");
+ errno = ENOTDIR;
+ LEAVE_RET('i', -1);
+ }
+
+ // Sanity check
+ if( !h->Node->Type || !h->Node->Type->FindDir ) {
+ Log_Error("VFS", "VFS_OpenChild - Node does not have a type/is missing FindDir");
errno = ENOTDIR;
LEAVE_RET('i', -1);
}
// Find Child
- node = h->Node->FindDir(h->Node, Name);
+ node = h->Node->Type->FindDir(h->Node, Name);
if(!node) {
errno = ENOENT;
LEAVE_RET('i', -1);
}
#endif
- if(h->Node->Close)
- h->Node->Close( h->Node );
+ _CloseNode(h->Node);
h->Node = NULL;
}
// Close file
VFS_Close(fd);
- // Free old working directory
- if( CFGPTR(CFG_VFS_CWD) )
- free( CFGPTR(CFG_VFS_CWD) );
- // Set new
- CFGPTR(CFG_VFS_CWD) = buf;
+ {
+ char **cwdptr = Threads_GetCWD();
+ // Free old working directory
+ if( *cwdptr ) free( *cwdptr );
+ // Set new
+ *cwdptr = buf;
+ }
Log("Updated CWD to '%s'", buf);
// Close file
VFS_Close(fd);
-
- // Free old working directory
- if( CFGPTR(CFG_VFS_CHROOT) )
- free( CFGPTR(CFG_VFS_CHROOT) );
- // Set new
- CFGPTR(CFG_VFS_CHROOT) = buf;
+
+ // Update
+ {
+ char **chroot_ptr = Threads_GetChroot();
+ if( *chroot_ptr ) free( *chroot_ptr );
+ *chroot_ptr = buf;
+ }
LOG("Updated Root to '%s'", buf);
*
* select.c
* - Implements the select() system call (and supporting code)
+ *
+ * TODO: Implment timeouts (via an alarm event?)
+ * TODO: Remove malloc for read/write queues
*/
#define DEBUG 0
#include <acess.h>
#include "vfs_int.h"
#include "vfs_ext.h"
#include <semaphore.h>
+#include <threads.h>
+#include <events.h>
// === CONSTANTS ===
#define NUM_THREADS_PER_ALLOC 4
+// === IMPORTS ===
+extern tThread *Proc_GetCurThread(void);
+
// === TYPES ===
-typedef struct sVFS_SelectThread tVFS_SelectThread;
typedef struct sVFS_SelectListEnt tVFS_SelectListEnt;
// === STRUCTURES ===
struct sVFS_SelectListEnt
{
tVFS_SelectListEnt *Next;
- tVFS_SelectThread *Threads[NUM_THREADS_PER_ALLOC];
+ tThread *Threads[NUM_THREADS_PER_ALLOC];
};
+// NOTE: Typedef is in vfs.h
struct sVFS_SelectList
{
tMutex Lock;
tVFS_SelectListEnt FirstEnt;
};
-struct sVFS_SelectThread
-{
- //! \brief Semaphore to atomically put the listener to sleep
- tSemaphore SleepHandle; // TODO: Allow timeouts (by setting an alarm?)
-};
-
// === PROTOTYPES ===
// int VFS_SelectNode(tVFS_Node *Node, enum eVFS_SelectTypes Type, tTime *Timeout);
-// int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, BOOL IsKernel);
+// int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel);
// int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull);
// int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable);
// int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState);
int VFS_int_Select_GetType(int Type, tVFS_Node *Node, tVFS_SelectList ***List, int **Flag, int *WantedFlag, int *MaxAllowed);
- int VFS_int_Select_Register(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
- int VFS_int_Select_Deregister(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
- int VFS_int_Select_AddThread(tVFS_SelectList *List, tVFS_SelectThread *Thread, int MaxAllowed);
-void VFS_int_Select_RemThread(tVFS_SelectList *List, tVFS_SelectThread *Thread);
+ int VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
+ int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel);
+ int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed);
+void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread);
void VFS_int_Select_SignalAll(tVFS_SelectList *List);
// === GLOBALS ===
// === FUNCTIONS ===
int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *Name)
{
- tVFS_SelectThread *thread_info;
+ tThread *thisthread = Proc_GetCurThread();
int ret, type;
- ENTER("pNode iTypeFlags pTimeout", Node, TypeFlags, Timeout);
-
- thread_info = malloc(sizeof(tVFS_SelectThread));
- if(!thread_info) LEAVE_RET('i', -1);
-
- Semaphore_Init(&thread_info->SleepHandle, 0, 0, "VFS_SelectNode()", Name);
+ ENTER("pNode iTypeFlags pTimeout sName", Node, TypeFlags, Timeout, Name);
// Initialise
for( type = 0; type < 3; type ++ )
int *flag, wanted, maxAllowed;
if( !(TypeFlags & (1 << type)) ) continue;
if( VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed) ) {
- free(thread_info);
LEAVE('i', -1);
return -1;
}
// Alloc if needed
if( !*list ) *list = calloc(1, sizeof(tVFS_SelectList));
- VFS_int_Select_AddThread(*list, thread_info, maxAllowed);
+ VFS_int_Select_AddThread(*list, thisthread, maxAllowed);
if( *flag == wanted )
{
- VFS_int_Select_RemThread(*list, thread_info);
- free(thread_info);
+ VFS_int_Select_RemThread(*list, thisthread);
LEAVE('i', 1);
return 1;
}
{
LOG("Semaphore_Wait()");
// TODO: Actual timeout
- Semaphore_Wait(&thread_info->SleepHandle, 1);
+ Threads_WaitEvents( THREAD_EVENT_VFS );
}
// Get return value
if( !(TypeFlags & (1 << type)) ) continue;
VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed);
LOG("VFS_int_Select_RemThread()");
- VFS_int_Select_RemThread(*list, thread_info);
+ VFS_int_Select_RemThread(*list, thisthread);
ret = ret || *flag == wanted;
}
- free(thread_info);
-
LEAVE('i', ret);
return ret;
}
-int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, BOOL IsKernel)
+int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set *ErrHandles, tTime *Timeout, Uint32 ExtraEvents, BOOL IsKernel)
{
- tVFS_SelectThread *thread_info;
+ tThread *thisthread = Proc_GetCurThread();
int ret;
- thread_info = malloc(sizeof(tVFS_SelectThread));
- if(!thread_info) return -1;
-
ENTER("iMaxHandle pReadHandles pWriteHandles pErrHandles pTimeout bIsKernel",
MaxHandle, ReadHandles, WriteHandles, ErrHandles, Timeout, IsKernel);
- Semaphore_Init(&thread_info->SleepHandle, 0, 0, "VFS_Select()", "");
-
- // Notes: The idea is to make sure we only enter wait (on the semaphore)
+ // Notes: The idea is to make sure we only enter wait (Threads_WaitEvents)
// if we are going to be woken up (either by an event at a later time,
// or by an event that happened while or before we were registering).
// Hence, register must happen _before_ we check the state flag
// or the semaphore is incremeneted (or both, but never none)
// Register with nodes
- ret = VFS_int_Select_Register(thread_info, MaxHandle, ReadHandles, 0, IsKernel);
- ret += VFS_int_Select_Register(thread_info, MaxHandle, WriteHandles, 1, IsKernel);
- ret += VFS_int_Select_Register(thread_info, MaxHandle, ErrHandles, 2, IsKernel);
+ ret = VFS_int_Select_Register(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+ ret += VFS_int_Select_Register(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+ ret += VFS_int_Select_Register(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
LOG("Register ret = %i", ret);
// If there were events waiting, de-register and return
if( ret > 0 )
{
- ret = VFS_int_Select_Deregister(thread_info, MaxHandle, ReadHandles, 0, IsKernel);
- ret += VFS_int_Select_Deregister(thread_info, MaxHandle, WriteHandles, 1, IsKernel);
- ret += VFS_int_Select_Deregister(thread_info, MaxHandle, ErrHandles, 2, IsKernel);
- free(thread_info);
+ ret = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+ ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+ ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
LEAVE('i', ret);
return ret;
}
// Wait (only if there is no timeout, or it is greater than zero
if( !Timeout || *Timeout > 0 )
{
- ret = Semaphore_Wait(&thread_info->SleepHandle, 1);
- // TODO: Do something with ret?
+ // TODO: Timeout
+ // TODO: Allow extra events to be waited upon
+ Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
}
// Fill output (modify *Handles)
// - Also, de-register
- ret = VFS_int_Select_Deregister(thread_info, MaxHandle, ReadHandles, 0, IsKernel);
- ret += VFS_int_Select_Deregister(thread_info, MaxHandle, WriteHandles, 1, IsKernel);
- ret += VFS_int_Select_Deregister(thread_info, MaxHandle, ErrHandles, 2, IsKernel);
- free(thread_info);
+ ret = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
+ ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
+ ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
LEAVE('i', ret);
return ret;
}
// Mark a node as having a full buffer
int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
{
- ENTER("pNode bIsDataAvaliable", Node, IsBufferFull);
+ ENTER("pNode bIsBufferFull", Node, IsBufferFull);
Node->BufferFull = !!IsBufferFull;
if( !Node->BufferFull )
VFS_int_Select_SignalAll(Node->WriteThreads);
// Mark a node as errored
int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState)
{
- ENTER("pNode bIsDataAvaliable", Node, IsErrorState);
+ ENTER("pNode bIsErrorState", Node, IsErrorState);
Node->ErrorOccurred = !!IsErrorState;
if( Node->ErrorOccurred )
VFS_int_Select_SignalAll(Node->ErrorThreads);
/**
* \return Number of files with an action
*/
-int VFS_int_Select_Register(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
+int VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
{
int i, numFlagged = 0;
tVFS_SelectList **list;
/**
* \return Number of files with an action
*/
-int VFS_int_Select_Deregister(tVFS_SelectThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
+int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, int Type, BOOL IsKernel)
{
int i, numFlagged = 0;
tVFS_SelectList **list;
/**
* \return Boolean failure
*/
-int VFS_int_Select_AddThread(tVFS_SelectList *List, tVFS_SelectThread *Thread, int MaxAllowed)
+int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllowed)
{
int i, count = 0;
tVFS_SelectListEnt *block, *prev;
return 0;
}
-void VFS_int_Select_RemThread(tVFS_SelectList *List, tVFS_SelectThread *Thread)
+void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
{
int i;
tVFS_SelectListEnt *block, *prev = NULL;
if( block->Threads[i] )
{
LOG("block(%p)->Threads[%i] = %p", block, i, block->Threads[i]);
- Semaphore_Signal( &block->Threads[i]->SleepHandle, 1 );
+ Threads_PostEvent( block->Threads[i], THREAD_EVENT_VFS );
}
}
else
ARCH=x86
fi
+
+if [ $# -ge 2 ]; then
+ PLATFORM=$2
+else
+ PLATFORM=default
+fi
+
mkdir -p Releases/
BUILD_DIST=y ARCH=$ARCH make clean all-install
+while [ $# -ge 2 ]; do
+ BUILD_DIST=y ARCH=$ARCH PLATFORM=$2 make
+ shift
+done
tar --transform="s|Dist/($ARCH/)*|Acess/|x" -zcf Releases/Acess2_latest_${ARCH}_bin.tar.gz Dist/$ARCH Dist/Acess2.$ARCH.gz
mdeltree b:/Acess2 2>&1 >/dev/null || true
mcopy -s Dist/$ARCH/ b:/Acess2
USRLIBS += libimage_sif.so
USRAPPS := init login CLIShell cat ls mount
-USRAPPS += bomb
+USRAPPS += bomb dhcpclient
USRAPPS += ifconfig ping telnet irc
USRAPPS += axwin3
-ACESS_VERSION = 0.14
+ACESS_VERSION = 0.15
-ifeq ($(BUILD_DIST),y)
- ACESS_VERSION := $(ACESS_VERSION)-rel
+ifneq ($(BUILD_DIST),y)
+ ACESS_VERSION := $(ACESS_VERSION)-pr
endif
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
+Uint64 BGA_Write(tVFS_Node *Node, Uint64 off, Uint64 len, const void *buffer);\r
int BGA_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
\r
// === GLOBALS ===\r
MODULE_DEFINE(0, VERSION, BochsGA, BGA_Install, NULL, "PCI", NULL);\r
-tDevFS_Driver gBGA_DriverStruct = {\r
- NULL, "BochsGA",\r
- {\r
+tVFS_NodeType gBGA_NodeType = {\r
.Read = BGA_Read,\r
.Write = BGA_Write,\r
.IOCtl = BGA_IOCtl\r
- }\r
-};\r
+ };\r
+tDevFS_Driver gBGA_DriverStruct = {\r
+ NULL, "BochsGA",\r
+ {.Type = &gBGA_NodeType}\r
+ };\r
int giBGA_CurrentMode = -1;\r
tVideo_IOCtl_Pos gBGA_CursorPos = {-1,-1};\r
Uint *gBGA_Framebuffer;\r
/**\r
* \brief Write to the framebuffer\r
*/\r
-Uint64 BGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 BGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
{\r
if( giBGA_CurrentMode == -1 ) BGA_int_UpdateMode(0);\r
return DrvUtil_Video_WriteLFB(&gBGA_DrvUtil_BufInfo, Offset, Length, Buffer);\r
// Internal\r
// Filesystem\r
Uint64 PL110_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 PL110_Write(tVFS_Node *node, Uint64 off, Uint64 len, const void *buffer);\r
int PL110_IOCtl(tVFS_Node *node, int id, void *data);\r
// -- Internals\r
int PL110_int_SetResolution(int W, int H);\r
\r
// === GLOBALS ===\r
MODULE_DEFINE(0, VERSION, PL110, PL110_Install, NULL, NULL);\r
-tDevFS_Driver gPL110_DriverStruct = {\r
- NULL, "PL110",\r
- {\r
+tVFS_NodeType gPL110_DevNodeType = {\r
.Read = PL110_Read,\r
.Write = PL110_Write,\r
.IOCtl = PL110_IOCtl\r
- }\r
+ };\r
+tDevFS_Driver gPL110_DriverStruct = {\r
+ NULL, "PL110",\r
+ {.Type = &gPL110_DevNodeType}\r
};\r
// -- Options\r
tPAddr gPL110_PhysBase = PL110_BASE;\r
/**\r
* \brief Write to the framebuffer\r
*/\r
-Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 PL110_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
{\r
gPL110_DrvUtil_BufInfo.BufferFormat = giPL110_BufferMode;\r
return DrvUtil_Video_WriteLFB(&gPL110_DrvUtil_BufInfo, Offset, Length, Buffer);\r
// === PROTOTYPES ===\r
int Vesa_Install(char **Arguments);\r
Uint64 Vesa_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
-Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);\r
int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
int Vesa_Int_SetMode(int Mode);\r
int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
\r
// === GLOBALS ===\r
MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
-tDevFS_Driver gVesa_DriverStruct = {\r
- NULL, "Vesa",\r
- {\r
+tVFS_NodeType gVesa_NodeType = {\r
.Read = Vesa_Read,\r
.Write = Vesa_Write,\r
.IOCtl = Vesa_IOCtl\r
- }\r
-};\r
+ };\r
+tDevFS_Driver gVesa_DriverStruct = {\r
+ NULL, "Vesa",\r
+ {.Type = &gVesa_NodeType}\r
+ };\r
tMutex glVesa_Lock;\r
tVM8086 *gpVesa_BiosState;\r
int giVesaDriverId = -1;\r
/**\r
* \brief Write to the framebuffer\r
*/\r
-Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)\r
{\r
if( gVesa_Modes[giVesaCurrentMode].framebuffer == 0 ) {\r
Log_Warning("VESA", "Vesa_Write - Non-LFB Modes not yet supported.");\r
// --- Helpers ---
tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
+// === GLOBALS ===
+tVFS_NodeType gExt2_DirType = {
+ .TypeName = "ext2-dir",
+ .ReadDir = Ext2_ReadDir,
+ .FindDir = Ext2_FindDir,
+ .MkNod = Ext2_MkNod,
+ .Relink = Ext2_Relink,
+ .Link = Ext2_Link,
+ .Close = Ext2_CloseFile
+ };
+tVFS_NodeType gExt2_FileType = {
+ .TypeName = "ext2-file",
+ .Read = Ext2_Read,
+ .Write = Ext2_Write,
+ .Close = Ext2_CloseFile
+ };
+
// === CODE ===
/**
* \brief Reads a directory entry
retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
// Set Function Pointers
- retNode.Read = Ext2_Read;
- retNode.Write = Ext2_Write;
- retNode.Close = Ext2_CloseFile;
+ retNode.Type = &gExt2_FileType;
switch(inode.i_mode & EXT2_S_IFMT)
{
break;
// Directory
case EXT2_S_IFDIR:
- retNode.ReadDir = Ext2_ReadDir;
- retNode.FindDir = Ext2_FindDir;
- retNode.MkNod = Ext2_MkNod;
- retNode.Relink = Ext2_Relink;
- retNode.Link = Ext2_Link;
+ retNode.Type = &gExt2_DirType;
retNode.Flags = VFS_FFLAG_DIRECTORY;
retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );
break;
#include "ext2_common.h"\r
#include <modules.h>\r
\r
+// === IMPORTS ===\r
+extern tVFS_NodeType gExt2_DirType;\r
+\r
// === PROTOTYPES ===\r
int Ext2_Install(char **Arguments);\r
// Interface Functions\r
disk->RootNode.ImplPtr = disk; // Save disk pointer\r
disk->RootNode.Size = -1; // Fill in later (on readdir)\r
disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
- \r
- disk->RootNode.ReadDir = Ext2_ReadDir;\r
- disk->RootNode.FindDir = Ext2_FindDir;\r
- //disk->RootNode.Relink = Ext2_Relink;\r
+\r
+ disk->RootNode.Type = &gExt2_DirType;\r
\r
// Complete root node\r
disk->RootNode.UID = inode.i_uid;\r
// --- Read ---
extern Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
// --- Write ---
-extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, const void *buffer);
#endif
#include "ext2_common.h"
// === PROTOYPES ===
-Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
* \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
* \brief Write to a file
*/
-Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tExt2_Disk *disk = Node->ImplPtr;
tExt2_Inode inode;
tFAT_VolInfo gFAT_Disks[8];\r
int giFAT_PartCount = 0;\r
tVFS_Driver gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
+tVFS_NodeType gFAT_DirType = {\r
+ .TypeName = "FAT-Dir",\r
+ .ReadDir = FAT_ReadDir,\r
+ .FindDir = FAT_FindDir,\r
+ #if SUPPORT_WRITE\r
+ .MkNod = FAT_Mknod,\r
+ .Relink = FAT_Relink,\r
+ #endif\r
+ .Close = FAT_CloseFile\r
+ };\r
+tVFS_NodeType gFAT_FileType = {\r
+ .TypeName = "FAT-File",\r
+ .Read = FAT_Read,\r
+ #if SUPPORT_WRITE\r
+ .Write = FAT_Write,\r
+ #endif\r
+ .Close = FAT_CloseFile\r
+ };\r
\r
// === CODE ===\r
/**\r
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
- #if SUPPORT_WRITE\r
- node->Relink = FAT_Relink;\r
- node->MkNod = FAT_Mknod;\r
- #else\r
- node->Relink = NULL;\r
- node->MkNod = NULL;\r
- #endif\r
- //node->Close = FAT_Unmount;\r
+\r
+ node->Type = &gFAT_DirType; \r
\r
giFAT_PartCount ++;\r
return node;\r
// Set pointers\r
if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
//Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
- node.ReadDir = FAT_ReadDir;\r
- node.FindDir = FAT_FindDir;\r
- #if SUPPORT_WRITE\r
- node.MkNod = FAT_Mknod;\r
- node.Relink = FAT_Relink;\r
- #endif\r
+ node.Type = &gFAT_DirType; \r
node.Size = -1;\r
}\r
else {\r
- node.Read = FAT_Read;\r
- #if SUPPORT_WRITE\r
- node.Write = FAT_Write;\r
- #endif\r
+ node.Type = &gFAT_FileType;\r
}\r
- node.Close = FAT_CloseFile;\r
\r
ret = Inode_CacheNode(disk->inodeHandle, &node);\r
LEAVE('p', ret);\r
.Size = $size,
.Inode = {$inode},
.ImplPtr = {$prefix}_{$i}_entries,
- .ReadDir = InitRD_ReadDir,
- .FindDir = InitRD_FindDir
+ .Type = &gInitRD_DirType
};
EOF;
.Size = $size,
.Inode = {$inode},
.ImplPtr = $_sym,
- .Read = InitRD_ReadFile
+ .Type = &gInitRD_FileType
};
EOF;
.Flags = VFS_FFLAG_DIRECTORY,
.Size = $nRootFiles,
.ImplPtr = gInitRD_Root_Files,
- .ReadDir = InitRD_ReadDir,
- .FindDir = InitRD_FindDir
+ .Type = &gInitRD_DirType
};
EOF;
extern char *InitRD_ReadDir(tVFS_Node *Node, int ID);
extern tVFS_Node *InitRD_FindDir(tVFS_Node *Node, const char *Name);
+// === Globals ===
+tVFS_NodeType gInitRD_DirType;
+tVFS_NodeType gInitRD_FileType;
+
#endif
tVFS_Driver gInitRD_FSInfo = {
"initrd", 0, InitRD_InitDevice, InitRD_Unmount, InitRD_GetNodeFromINode
};
+tVFS_NodeType gInitRD_DirType = {
+ .ReadDir = InitRD_ReadFile,
+ .FindDir = InitRD_FindDir
+ };
+tVFS_NodeType gInitRD_FileType = {
+ .Read = InitRD_ReadFile
+ };
/**
* \brief Register initrd with the kernel
// === GLOBALS ===
MODULE_DEFINE(0, 0x0A /*v0.1*/, FS_NTFS, NTFS_Install, NULL);
tVFS_Driver gNTFS_FSInfo = {"ntfs", 0, NTFS_InitDevice, NTFS_Unmount, NULL};
+tVFS_NodeType gNTFS_DirType = {
+ .TypeName = "NTFS-File",
+ .ReadDir = NTFS_ReadDir,
+ .FindDir = NTFS_FindDir,
+ .Close = NULL
+ };
tNTFS_Disk gNTFS_Disks;
disk->RootNode.NumACLs = 1;
disk->RootNode.ACLs = &gVFS_ACL_EveryoneRX;
- disk->RootNode.ReadDir = NTFS_ReadDir;
- disk->RootNode.FindDir = NTFS_FindDir;
- disk->RootNode.MkNod = NULL;
- disk->RootNode.Link = NULL;
- disk->RootNode.Relink = NULL;
- disk->RootNode.Close = NULL;
+ disk->RootNode.Type = &gNTFS_DirType;
+
NTFS_DumpEntry(disk, 5);
ENTER("pInterface xAddress", Interface, Address);
+ // Check for broadcast
+ if( Address.L == -1 )
+ {
+ LOG("Broadcast");
+ LEAVE('-');
+ return cMAC_BROADCAST;
+ }
+
// Check routing tables if not on this subnet
if( IPStack_CompareAddress(4, &Address, Interface->Address, Interface->SubnetBits) == 0 )
{
if( route && ((tIPv4*)route->NextHop)->L != 0 )
{
// Recursion: see /Recursion/
+ LOG("Recursing with %s", IPStack_PrintAddress(4, route->NextHop));
+ LEAVE('-');
return ARP_Resolve4(Interface, *(tIPv4*)route->NextHop);
}
+ // No route, fall though
+ }
+ else
+ {
+ Uint32 netmask;
+ // Check for broadcast
+ netmask = IPv4_Netmask(Interface->SubnetBits);
+ if( (Address.L & ~netmask) == (0xFFFFFFFF & ~netmask) )
+ {
+ LOG("Local Broadcast");
+ LEAVE('-');
+ return cMAC_BROADCAST;
+ }
}
// Check ARP Cache
int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
// === GLOBALS ===
+tVFS_NodeType gIP_InterfaceNodeType = {
+ .ReadDir = IPStack_Iface_ReadDir,
+ .FindDir = IPStack_Iface_FindDir,
+ .IOCtl = IPStack_Iface_IOCtl
+};
//! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
tInterface gIP_LoopInterface = {
.Node = {
.Size = -1,
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
- .ReadDir = IPStack_Iface_ReadDir,
- .FindDir = IPStack_Iface_FindDir,
- .IOCtl = IPStack_Iface_IOCtl
+ .Type = &gIP_InterfaceNodeType
},
.Adapter = NULL,
.Type = 0
// Routing Subdir
if( Pos == 0 ) {
+ LEAVE('s', "routes");
return strdup("routes");
}
// Pseudo Interfaces
if( Pos == 1 ) {
+ LEAVE('s', "lo");
return strdup("lo");
}
Pos -= 2;
// Routing subdir
if( strcmp(Name, "routes") == 0 ) {
+ LEAVE('p', &gIP_RouteNode);
return &gIP_RouteNode;
}
// Loopback
if( strcmp(Name, "lo") == 0 ) {
+ LEAVE('p', &gIP_LoopInterface.Node);
return &gIP_LoopInterface.Node;
}
case 4:
if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1);
if( !CheckString( Data ) ) LEAVE_RET('i', -1);
+ LOG("New interface for '%s'", Data);
{
char name[4] = "";
tInterface *iface = IPStack_AddInterface(Data, name);
iface->Node.Size = -1;
iface->Node.NumACLs = 1;
iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
- iface->Node.ReadDir = IPStack_Iface_ReadDir;
- iface->Node.FindDir = IPStack_Iface_FindDir;
- iface->Node.IOCtl = IPStack_Iface_IOCtl;
- iface->Node.MkNod = NULL;
- iface->Node.Link = NULL;
- iface->Node.Relink = NULL;
- iface->Node.Close = NULL;
+ iface->Node.Type = &gIP_InterfaceNodeType;
// Set Defaults
iface->TimeoutDelay = DEFAULT_TIMEOUT;
// Set type
iface->Type = *(int*)Data;
+ LOG("Interface type set to %i", iface->Type);
size = IPStack_GetAddressSize(iface->Type);
// Check it's actually valid
if( iface->Type != 0 && size == 0 ) {
size = IPStack_GetAddressSize(iface->Type);
if( !CheckMem( Data, size ) ) LEAVE_RET('i', -1);
// TODO: Protect against trashing
+ LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
memcpy( iface->Address, Data, size );
- LEAVE('i', 1);
- return 1;
+ LEAVE_RET('i', 1);
/*
* getset_subnet
// Is the mask sane?
if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
LEAVE_RET('i', -1);
-
+ LOG("Set subnet bits to %i", *(int*)Data);
// Ok, set it
iface->SubnetBits = *(int*)Data;
}
- LEAVE('i', iface->SubnetBits);
- return iface->SubnetBits;
+ LEAVE_RET('i', iface->SubnetBits);
/*
* get_device
if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
LEAVE_RET('i', -1);
strcpy( Data, iface->Adapter->Device );
- return iface->Adapter->DeviceLen;
+ LEAVE_RET('i', iface->Adapter->DeviceLen);
/*
* ping
case 4:
if( !CheckMem( Data, sizeof(tIPv4) ) ) LEAVE_RET('i', -1);
tmp = IPv4_Ping(iface, *(tIPv4*)Data);
- LEAVE('i', tmp);
- return tmp;
+ LEAVE_RET('i', tmp);
case 6:
LEAVE_RET('i', 1);
* Acess2 IP Stack
* - IPv4 Protcol Handling
*/
+#define DEBUG 1
#include "ipstack.h"
#include "link.h"
#include "ipv4.h"
*/
int IPv4_SendPacket(tInterface *Iface, tIPv4 Address, int Protocol, int ID, int Length, const void *Data)
{
- tMacAddr to = ARP_Resolve4(Iface, Address);
+ tMacAddr to;
int bufSize = sizeof(tIPv4Header) + Length;
char buf[bufSize];
tIPv4Header *hdr = (void*)buf;
int ret;
+ to = ARP_Resolve4(Iface, Address);
if( MAC_EQU(to, cMAC_ZERO) ) {
// No route to host
Log_Notice("IPv4", "No route to host %i.%i.%i.%i",
// TODO: Handle packet fragmentation
+ Log_Debug("IPv4", " From %i.%i.%i.%i to %i.%i.%i.%i",
+ hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3],
+ hdr->Destination.B[0], hdr->Destination.B[1], hdr->Destination.B[2], hdr->Destination.B[3]
+ );
+
// Get Data and Data Length
dataLength = ntohs(hdr->TotalLength) - sizeof(tIPv4Header);
data = &hdr->Options[0];
Log_Debug("IPv4", "Route the packet");
// Drop the packet if the TTL is zero
if( hdr->TTL == 0 ) {
- Log_Warning("IPv4", "TODO: Sent ICMP-Timeout when TTL exceeded");
+ Log_Warning("IPv4", "TODO: Send ICMP-Timeout when TTL exceeded");
return ;
}
hdr->TTL --;
rt = IPStack_FindRoute(4, NULL, &hdr->Destination); // Get the route (gets the interface)
+ if( !rt || !rt->Interface )
+ return ;
to = ARP_Resolve4(rt->Interface, hdr->Destination); // Resolve address
if( MAC_EQU(to, cMAC_ZERO) )
return ;
tInterface *iface = NULL;
Uint32 netmask;
Uint32 addr, this;
-
+
+ ENTER("pAdapter xAddress bBroadcast", Adapter, Address, Broadcast);
+
addr = ntohl( Address.L );
+ LOG("addr = 0x%x", addr);
for( iface = gIP_Interfaces; iface; iface = iface->Next)
{
if( iface->Adapter != Adapter ) continue;
if( iface->Type != 4 ) continue;
- if( IP4_EQU(Address, *(tIPv4*)iface->Address) )
+ if( IP4_EQU(Address, *(tIPv4*)iface->Address) ) {
+ LOG("Exact match");
+ LEAVE('p', iface);
return iface;
+ }
if( !Broadcast ) continue;
- this = ntohl( ((tIPv4*)iface->Address)->L );
-
// Check for broadcast
+ this = ntohl( ((tIPv4*)iface->Address)->L );
netmask = IPv4_Netmask(iface->SubnetBits);
-
- if( (addr & netmask) == (this & netmask)
- && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
+ LOG("iface addr = 0x%x, netmask = 0x%x (bits = %i)", this, netmask, iface->SubnetBits);
+
+ if( (addr & netmask) == (this & netmask) && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
+ {
+ LOG("Broadcast match");
+ LEAVE('p', iface);
return iface;
+ }
}
+ LEAVE('n');
return NULL;
}
Uint32 IPv4_Netmask(int FixedBits)
{
Uint32 ret = 0xFFFFFFFF;
- ret >>= (32-FixedBits);
- ret <<= (32-FixedBits);
+ if( FixedBits == 0 )
+ return 0;
+ if( FixedBits < 32 )
+ {
+ ret >>= (32-FixedBits);
+ ret <<= (32-FixedBits);
+ }
// Returns a native endian netmask
return ret;
}
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
+tVFS_NodeType gIP_RootNodeType = {
+ .ReadDir = IPStack_Root_ReadDir,
+ .FindDir = IPStack_Root_FindDir,
+ .IOCtl = IPStack_Root_IOCtl
+};
tDevFS_Driver gIP_DriverInfo = {
NULL, "ip",
{
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = IPStack_Root_ReadDir,
- .FindDir = IPStack_Root_FindDir,
- .IOCtl = IPStack_Root_IOCtl
+ .Type = &gIP_RootNodeType
}
};
static char ret[8*4+7+1];
const Uint16 *addr = Address;
sprintf(ret, "%x:%x:%x:%x:%x:%x:%x:%x",
- addr[0], addr[1], addr[2], addr[3],
- addr[4], addr[5], addr[6], addr[7]
+ ntohs(addr[0]), ntohs(addr[1]), ntohs(addr[2]), ntohs(addr[3]),
+ ntohs(addr[4]), ntohs(addr[5]), ntohs(addr[6]), ntohs(addr[7])
);
return ret;
}
// - Routes directory
char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
+ int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
+ int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
// - Route Management
-tRoute *IPStack_Route_Create(const char *InterfaceName);
+tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric);
tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
tRoute *IPStack_FindRoute(int AddressType, tInterface *Interface, void *Address);
// - Individual Routes
int giIP_NextRouteId = 1;
tRoute *gIP_Routes;
tRoute *gIP_RoutesEnd;
+tVFS_NodeType gIP_RouteNodeType = {
+ .IOCtl = IPStack_Route_IOCtl
+};
+tVFS_NodeType gIP_RouteDirNodeType = {
+ .ReadDir = IPStack_RouteDir_ReadDir,
+ .FindDir = IPStack_RouteDir_FindDir,
+ .MkNod = IPStack_RouteDir_MkNod,
+ .Relink = IPStack_RouteDir_Relink,
+ .IOCtl = IPStack_RouteDir_IOCtl
+};
tVFS_Node gIP_RouteNode = {
.Flags = VFS_FFLAG_DIRECTORY,
.Size = -1,
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
- .ReadDir = IPStack_RouteDir_ReadDir,
- .FindDir = IPStack_RouteDir_FindDir,
- .IOCtl = IPStack_RouteDir_IOCtl
+ .Type = &gIP_RouteDirNodeType
};
// === CODE ===
tRoute *rt;
for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
-
- if( !rt ) {
- return NULL;
- }
+ if( !rt ) return NULL;
{
- int len = sprintf(NULL, "%i", (int)rt->Node.Inode);
+ int addrlen = IPStack_GetAddressSize(rt->AddressType);
+ int len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
char buf[len+1];
- sprintf(buf, "%i", (int)rt->Node.Inode);
+ int ofs;
+ ofs = sprintf(buf, "%i:", rt->AddressType);
+ ofs += Hex(buf+ofs, addrlen, rt->Network);
+ sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
return strdup(buf);
}
}
*/
tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
{
- int num = atoi(Name);
- tRoute *rt;
-
- // Zero is invalid, sorry :)
- if( !num ) return NULL;
-
// Interpret the name as <type>:<addr>, returning the interface for
// needed to access that address.
- // E.g. '4:0A02000A' - 10.2.0.10
+ // E.g. '@4:0A02000A' - 10.2.0.10
// Hm... It could do with a way to have a better address type representation
- if( Name[1] == ':' ) // TODO: Allow variable length type codes
+ if( Name[0] == '@' )
{
- int addrSize = IPStack_GetAddressSize(num);
- Uint8 addrData[addrSize];
+ tRoute *rt;
+ int ofs = 1;
+ int type;
- // Errof if the size is invalid
- if( strlen(Name) != 2 + addrSize*2 )
+ ofs += ParseInt(Name+ofs, &type);
+ int addrSize = IPStack_GetAddressSize(type);
+ Uint8 addrData[addrSize];
+
+ // Separator
+ if( Name[ofs] != ':' ) return NULL;
+ ofs ++;
+
+ // Error if the size is invalid
+ if( strlen(Name+ofs) != addrSize*2 )
return NULL;
// Parse the address
// - Error if the address data is not fully hex
- if( UnHex(addrData, addrSize, Name + 2) != addrSize )
+ if( UnHex(addrData, addrSize, Name + ofs) != addrSize )
return NULL;
// Find the route
- rt = IPStack_FindRoute(num, NULL, addrData);
+ rt = IPStack_FindRoute(type, NULL, addrData);
if(!rt) return NULL;
+
+ if( rt->Interface )
+ {
+ // Return the interface node
+ // - Sure it's hijacking it from inteface.c's area, but it's
+ // simpler this way
+ return &rt->Interface->Node;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else if( Name[0] == '#' )
+ {
+ int num, ofs = 1;
- // Return the interface node
- // - Sure it's hijacking it from inteface.c's area, but it's
- // simpler this way
- return &rt->Interface->Node;
+ ofs = ParseInt(Name+ofs, &num);
+ if( ofs == 1 ) return NULL;
+ if( Name[ofs] != '\0' ) return NULL;
+ if( num < 0) return NULL;
+
+ for( tRoute *rt = gIP_Routes; rt; rt = rt->Next )
+ {
+ if( rt->Node.Inode > num ) return NULL;
+ if( rt->Node.Inode == num ) return &rt->Node;
+ }
+ return NULL;
}
+ else
+ {
+ int type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
+ if( type <= 0 ) return NULL;
+
+ int addrSize = IPStack_GetAddressSize(type);
+ Uint8 addrData[addrSize];
+ int subnet_bits, metric;
+
+ _Route_ParseRouteName(Name, addrData, &subnet_bits, &metric);
+
+ tRoute *rt = _Route_FindExactRoute(type, addrData, subnet_bits, metric);
+ if(rt) return &rt->Node;
+ return NULL;
+ }
+}
+
+/**
+ * \brief Create a new route node
+ */
+int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+ if( Flags ) return -EINVAL;
+ if( Threads_GetUID() != 0 ) return -EACCES;
+
+ int type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
+ if( type <= 0 ) return -EINVAL;
+
+ int size = IPStack_GetAddressSize(type);
+ Uint8 addrdata[size];
+ int subnet, metric;
+
+ _Route_ParseRouteName(Name, addrdata, &subnet, &metric);
+
+ // Check for duplicates
+ if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
+ return -EEXIST;
+
+ IPStack_Route_Create(type, addrdata, subnet, metric);
+
+ return 0;
+}
+
+/**
+ * \brief Rename / Delete a route
+ */
+int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+{
+ tRoute *rt;
- // The list is inherently sorted, so we can do a quick search
- for(rt = gIP_Routes; rt && rt->Node.Inode < num; rt = rt->Next);
+ if( Threads_GetUID() != 0 ) return -EACCES;
+
+ // Get the original route entry
+ {
+ int type = _Route_ParseRouteName(OldName, NULL, NULL, NULL);
+ if(type <= 0) return -EINVAL;
+ Uint8 addr[IPStack_GetAddressSize(type)];
+ int subnet, metric;
+ _Route_ParseRouteName(OldName, addr, &subnet, &metric);
+
+ rt = _Route_FindExactRoute(type, addr, subnet, metric);
+ }
+
+ if( NewName == NULL )
+ {
+ // Delete the route
+ tRoute *prev = NULL;
+ for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
+
+ if(prev)
+ prev->Next = rt->Next;
+ else
+ gIP_Routes = rt->Next;
+ free(rt);
+ }
+ else
+ {
+ // Change the route
+ int type = _Route_ParseRouteName(NewName, NULL, NULL, NULL);
+ if(type <= 0) return -EINVAL;
+ Uint8 addr[IPStack_GetAddressSize(type)];
+ int subnet, metric;
+ _Route_ParseRouteName(NewName, addr, &subnet, &metric);
+
+ return -ENOTIMPL;
+ }
+ return 0;
+}
+
+tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric)
+{
+ for(tRoute *rt = gIP_Routes; rt; rt = rt->Next)
+ {
+ if( rt->AddressType != Type ) continue;
+ if( rt->Metric != Metric ) continue;
+ if( rt->SubnetBits != Subnet ) continue;
+ if( IPStack_CompareAddress(Type, rt->Network, Network, -1) == 0 )
+ continue ;
+ return rt;
+ }
+ return NULL;
+}
+
+int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric)
+{
+ int type, addrlen;
+ int ofs = 0, ilen;
- // Fast fail end of list / larger number
- if( !rt || rt->Node.Inode > num )
- return NULL;
+ ENTER("sName pAddr pSubnetBits pMetric", Name, Addr, SubnetBits, Metric);
+
+ ilen = ParseInt(Name, &type);
+ if(ilen == 0) {
+ LOG("Type failed to parse");
+ LEAVE_RET('i', -1);
+ }
+ ofs += ilen;
+
+ if(Name[ofs] != ':') LEAVE_RET('i', -1);
+ ofs ++;
+
+ addrlen = IPStack_GetAddressSize(type);
+ if( Addr )
+ {
+ if( UnHex(Addr, addrlen, Name + ofs) != addrlen )
+ return -1;
+ }
+ ofs += addrlen*2;
+
+ if(Name[ofs] != ':') LEAVE_RET('i', -1);
+ ofs ++;
+
+ ilen = ParseInt(Name+ofs, SubnetBits);
+ if(ilen == 0) {
+ LOG("Subnet failed to parse");
+ LEAVE_RET('i', -1);
+ }
+ ofs += ilen;
- return &rt->Node;
+ if(Name[ofs] != ':') LEAVE_RET('i', -1);
+ ofs ++;
+
+ ilen = ParseInt(Name+ofs, Metric);
+ if(ilen == 0) {
+ LOG("Metric failed to parse");
+ LEAVE_RET('i', -1);
+ }
+ ofs += ilen;
+
+ if(Name[ofs] != '\0') LEAVE_RET('i', -1);
+
+ LEAVE('i', type);
+ return type;
}
/**
*/
static const char *casIOCtls_RouteDir[] = {
DRV_IOCTLNAMES,
- "add_route", // Add a route - char *InterfaceName
"locate_route", // Find the best route for an address - struct {int Type, char Address[]} *
NULL
};
*/
int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data)
{
- int tmp;
tRoute *rt;
ENTER("pNode iID pData", Node, ID, Data);
switch(ID)
// --- Standard IOCtls (0-3) ---
BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_RouteDir)
- case 4: // Add Route
- if( !CheckString(Data) ) LEAVE_RET('i', -1);
- rt = IPStack_Route_Create(Data);
- if( !rt )
- tmp = -1;
- else
- tmp = rt->Node.Inode;
- LEAVE('i', tmp);
- return tmp;
-
- case 5: // Locate Route
+ case 4: // Locate Route
{
struct {
int Type;
* \brief Create a new route entry
* \param InterfaceName Name of the interface using this route
*/
-tRoute *IPStack_Route_Create(const char *InterfaceName)
+tRoute *IPStack_Route_Create(int AddrType, void *Network, int SubnetBits, int Metric)
{
tRoute *rt;
- tInterface *iface;
int size;
- // Get interface
- // Note: Oh man! This is such a hack
- {
- tVFS_Node *node = IPStack_Root_FindDir(NULL, InterfaceName);
- if( !node ) {
- Log_Debug("IPStack", "IPStack_Route_Create - Unknown interface '%s'\n", InterfaceName);
- return NULL;
- }
- iface = node->ImplPtr;
- if(node->Close) node->Close(node);
- }
-
// Get the size of the specified address type
- size = IPStack_GetAddressSize(iface->Type);
+ size = IPStack_GetAddressSize(AddrType);
if( size == 0 ) {
return NULL;
}
rt->Node.Size = 0;
rt->Node.NumACLs = 1,
rt->Node.ACLs = &gVFS_ACL_EveryoneRO;
- rt->Node.IOCtl = IPStack_Route_IOCtl;
+ rt->Node.Type = &gIP_RouteNodeType;
// Set up state
- rt->AddressType = iface->Type;
+ rt->AddressType = AddrType;
rt->Network = (void *)( (tVAddr)rt + sizeof(tRoute) );
- rt->SubnetBits = 0;
+ rt->SubnetBits = SubnetBits;
rt->NextHop = (void *)( (tVAddr)rt + sizeof(tRoute) + size );
- rt->Interface = iface;
- rt->Metric = DEFAUTL_METRIC;
- memset(rt->Network, 0, size);
+ rt->Interface = NULL;
+ rt->Metric = Metric;
+ memcpy(rt->Network, Network, size);
memset(rt->NextHop, 0, size);
+ // Clear non-fixed bits
+ {
+ Uint8 *data = rt->Network;
+ int i;
+ i = SubnetBits / 8;
+ if( SubnetBits % 8 ) {
+ data[i] &= ~((1 << (8 - SubnetBits % 8)) - 1);
+ i ++;
+ }
+ memset(data + i, 0, size - i);
+ }
+
+
// Add to list
if( gIP_RoutesEnd ) {
gIP_RoutesEnd->Next = rt;
gIP_Routes = gIP_RoutesEnd = rt;
}
- Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
+// Log_Log("IPStack", "Route entry for '%s' created", InterfaceName);
return rt;
}
*/
tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric)
{
- tRoute *rt = IPStack_Route_Create(Interface);
+ tInterface *iface;
+ tRoute *rt;
int addrSize;
+ {
+ tVFS_Node *tmp;
+ tmp = IPStack_Root_FindDir(NULL, Interface);
+ if(!tmp) return NULL;
+ iface = tmp->ImplPtr;
+ if(tmp->Type->Close) tmp->Type->Close(tmp);
+ }
+
+ rt = IPStack_Route_Create(iface->Type, Network, SubnetBits, Metric);
if( !rt ) return NULL;
- addrSize = IPStack_GetAddressSize(rt->Interface->Type);
+ addrSize = IPStack_GetAddressSize(iface->Type);
+ rt->Interface = iface;
- memcpy(rt->Network, Network, addrSize);
if( NextHop )
memcpy(rt->NextHop, NextHop, addrSize);
- rt->SubnetBits = SubnetBits;
- if( Metric )
- rt->Metric = Metric;
return rt;
}
*/
static const char *casIOCtls_Route[] = {
DRV_IOCTLNAMES,
- "get_type", // Get address type - (void), returns integer type
- "get_network", // Get network - (void *Data), returns boolean success
- "set_network", // Set network - (void *Data), returns boolean success
"get_nexthop", // Get next hop - (void *Data), returns boolean success
"set_nexthop", // Set next hop - (void *Data), returns boolean success
- "getset_subnetbits", // Get/Set subnet bits - (int *Bits), returns current value
- "getset_metric", // Get/Set metric - (int *Metric), returns current value
"get_interface", // Get interface name - (char *Name), returns name length, NULL OK
+ "set_interface", // Set interface - (const char *Name)
NULL
};
*/
int IPStack_Route_IOCtl(tVFS_Node *Node, int ID, void *Data)
{
- int *iData = Data;
tRoute *rt = Node->ImplPtr;
int addrSize = IPStack_GetAddressSize(rt->AddressType);
// --- Standard IOCtls (0-3) ---
BASE_IOCTLS(DRV_TYPE_MISC, STR(IDENT), VERSION, casIOCtls_Route)
- // Get address type
- case 4:
- return rt->AddressType;
-
- // Get Network
- case 5:
- if( !CheckMem(Data, addrSize) ) return -1;
- memcpy(Data, rt->Network, addrSize);
- return 1;
- // Set Network
- case 6:
- if( !CheckMem(Data, addrSize) ) return -1;
- memcpy(rt->Network, Data, addrSize);
- return 1;
-
// Get Next Hop
- case 7:
+ case 4:
if( !CheckMem(Data, addrSize) ) return -1;
memcpy(Data, rt->NextHop, addrSize);
return 1;
// Set Next Hop
- case 8:
+ case 5:
+ if( Threads_GetUID() != 0 ) return -1;
if( !CheckMem(Data, addrSize) ) return -1;
memcpy(rt->NextHop, Data, addrSize);
return 1;
-
- // Get/Set Subnet Bits
- case 9:
- if( Data ) {
- if( !CheckMem(Data, sizeof(int)) ) return -1;
- if( *iData < 0 || *iData > addrSize*8 )
+
+ // Get interface name
+ case 6:
+ if( !rt->Interface ) {
+ if(Data && !CheckMem(Data, 1) )
return -1;
- rt->SubnetBits = *iData;
+ if(Data)
+ *(char*)Data = 0;
+ return 0;
}
- return rt->SubnetBits;
-
- // Get/Set Metric
- case 10:
- if( Data ) {
- if( !CheckMem(Data, sizeof(int)) ) return -1;
- if( *iData < 0 ) return -1;
- rt->Metric = *iData;
- }
- return rt->Metric;
-
- // Get interface name
- case 11:
if( Data ) {
if( !CheckMem(Data, strlen(rt->Interface->Name) + 1) )
return -1;
strcpy(Data, rt->Interface->Name);
}
return strlen(rt->Interface->Name);
+ // Set interface name
+ case 7:
+ if( Threads_GetUID() != 0 )
+ return -1;
+ if( !CheckString(Data) )
+ return -1;
+ else
+ {
+ tInterface *iface;
+ tVFS_Node *tmp;
+ tmp = IPStack_Root_FindDir(NULL, Data);
+ if(!tmp)
+ return -1;
+ iface = tmp->ImplPtr;
+ if(tmp->Type->Close) tmp->Type->Close(tmp);
+
+ if( iface->Type != rt->AddressType )
+ return -1;
+
+ // TODO: Other checks?
+ rt->Interface = iface;
+ }
+ return 0;
+
default:
return -1;
}
// --- Client
tVFS_Node *TCP_Client_Init(tInterface *Interface);
Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
void TCP_Client_Close(tVFS_Node *Node);
// --- Helpers
// === TEMPLATES ===
tSocketFile gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
tSocketFile gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
+tVFS_NodeType gTCP_ServerNodeType = {
+ .TypeName = "TCP Server",
+ .ReadDir = TCP_Server_ReadDir,
+ .FindDir = TCP_Server_FindDir,
+ .IOCtl = TCP_Server_IOCtl,
+ .Close = TCP_Server_Close
+ };
+tVFS_NodeType gTCP_ClientNodeType = {
+ .TypeName = "TCP Client/Connection",
+ .Read = TCP_Client_Read,
+ .Write = TCP_Client_Write,
+ .IOCtl = TCP_Client_IOCtl,
+ .Close = TCP_Client_Close
+ };
// === GLOBALS ===
int giTCP_NumHalfopen = 0;
tTCPConnection *conn;
Log_Log("TCP", "TCP_GetPacket: <Local>:%i from [%s]:%i, Flags= %s%s%s%s%s%s%s%s",
- ntohs(hdr->SourcePort),
- IPStack_PrintAddress(Interface->Type, Address),
ntohs(hdr->DestPort),
+ IPStack_PrintAddress(Interface->Type, Address),
+ ntohs(hdr->SourcePort),
(hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "",
(hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "",
(hdr->Flags & TCP_FLAG_URG) ? "URG " : "",
if(conn->RemotePort != ntohs(hdr->SourcePort)) continue;
// Check Source IP
- if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) != 0 )
+ Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)",
+ IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP));
+ Log_Debug("TCP", " == Address(%s)",
+ IPStack_PrintAddress(conn->Interface->Type, Address));
+ if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
continue ;
Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn);
conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
conn->Node.ImplPtr = conn;
conn->Node.ImplInt = srv->NextID ++;
- conn->Node.Read = TCP_Client_Read;
- conn->Node.Write = TCP_Client_Write;
- //conn->Node.Close = TCP_SrvConn_Close;
+ conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end?
// Hmm... Theoretically, this lock will never have to wait,
// as the interface is locked to the watching thread, and this
srv->ConnectionsTail = conn;
if(!srv->NewConnections)
srv->NewConnections = conn;
+ VFS_MarkAvaliable( &srv->Node, 1 );
SHORTREL(&srv->lConnections);
// Send the SYN ACK
// Get Next outbound port
ret = giTCP_NextOutPort++;
- while( gaTCP_PortBitmap[ret/32] & (1 << (ret%32)) )
+ while( gaTCP_PortBitmap[ret/32] & (1UL << (ret%32)) )
{
ret ++;
giTCP_NextOutPort++;
{
tTCPListener *srv;
- srv = malloc( sizeof(tTCPListener) );
+ srv = calloc( 1, sizeof(tTCPListener) );
if( srv == NULL ) {
Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
srv->Node.ImplPtr = srv;
srv->Node.NumACLs = 1;
srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
- srv->Node.ReadDir = TCP_Server_ReadDir;
- srv->Node.FindDir = TCP_Server_FindDir;
- srv->Node.IOCtl = TCP_Server_IOCtl;
- srv->Node.Close = TCP_Server_Close;
+ srv->Node.Type = &gTCP_ServerNodeType;
SHORTLOCK(&glTCP_Listeners);
srv->Next = gTCP_Listeners;
if( srv->NewConnections != NULL ) break;
SHORTREL( &srv->lConnections );
Threads_Yield(); // TODO: Sleep until poked
- continue;
}
// normal list)
conn = srv->NewConnections;
srv->NewConnections = conn->Next;
+
+ if( srv->NewConnections == NULL )
+ VFS_MarkAvaliable( Node, 0 );
SHORTREL( &srv->lConnections );
int id = atoi(Name);
ENTER("pNode sName", Node, Name);
-
- // Sanity Check
- itoa(tmp, id, 16, 8, '0');
- if(strcmp(tmp, Name) != 0) {
- LOG("'%s' != '%s' (%08x)", Name, tmp, id);
- LEAVE('n');
- return NULL;
+
+ // Check for a non-empty name
+ if( Name[0] )
+ {
+ // Sanity Check
+ itoa(tmp, id, 16, 8, '0');
+ if(strcmp(tmp, Name) != 0) {
+ LOG("'%s' != '%s' (%08x)", Name, tmp, id);
+ LEAVE('n');
+ return NULL;
+ }
+
+ Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
+ Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
+ Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
+
+ // Search
+ SHORTLOCK( &srv->lConnections );
+ for(conn = srv->Connections;
+ conn;
+ conn = conn->Next)
+ {
+ LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
+ if(conn->Node.ImplInt == id) break;
+ }
+ SHORTREL( &srv->lConnections );
+
+ // If not found, ret NULL
+ if(!conn) {
+ LOG("Connection %i not found", id);
+ LEAVE('n');
+ return NULL;
+ }
}
-
- Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
- Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
- Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
-
- // Search
- SHORTLOCK( &srv->lConnections );
- for(conn = srv->Connections;
- conn;
- conn = conn->Next)
+ // Empty Name - Check for a new connection and if it's there, open it
+ else
{
- LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
- if(conn->Node.ImplInt == id) break;
- }
- SHORTREL( &srv->lConnections );
-
- // If not found, ret NULL
- if(!conn) {
- LOG("Connection %i not found", id);
- LEAVE('n');
- return NULL;
+ SHORTLOCK( &srv->lConnections );
+ conn = srv->NewConnections;
+ if( conn != NULL )
+ srv->NewConnections = conn->Next;
+ VFS_MarkAvaliable( Node, srv->NewConnections != NULL );
+ SHORTREL( &srv->lConnections );
+ if( !conn ) {
+ LOG("No new connections");
+ LEAVE('n');
+ return NULL;
+ }
}
-
+
// Return node
LEAVE('p', &conn->Node);
return &conn->Node;
conn->Node.ImplPtr = conn;
conn->Node.NumACLs = 1;
conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
- conn->Node.Read = TCP_Client_Read;
- conn->Node.Write = TCP_Client_Write;
- conn->Node.IOCtl = TCP_Client_IOCtl;
- conn->Node.Close = TCP_Client_Close;
+ conn->Node.Type = &gTCP_ClientNodeType;
conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
#if 0
/**
* \brief Send a data packet on a connection
*/
-void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, void *Data)
+void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const void *Data)
{
char buf[sizeof(tTCPHeader)+Length];
tTCPHeader *packet = (void*)buf;
/**
* \brief Send some bytes on a connection
*/
-Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tTCPConnection *conn = Node->ImplPtr;
size_t rem = Length;
void UDP_Initialise();
void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
-void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, void *Address, Uint16 Port, void *Data, size_t Length);
+void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length);
// --- Client Channels
tVFS_Node *UDP_Channel_Init(tInterface *Interface);
Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
void UDP_Channel_Close(tVFS_Node *Node);
// --- Helpers
void UDP_int_FreePort(Uint16 Port);
// === GLOBALS ===
+tVFS_NodeType gUDP_NodeType = {
+ .Read = UDP_Channel_Read,
+ .Write = UDP_Channel_Write,
+ .IOCtl = UDP_Channel_IOCtl,
+ .Close = UDP_Channel_Close
+};
tMutex glUDP_Channels;
tUDPChannel *gpUDP_Channels;
pack->Next = NULL;
memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type));
pack->Remote.Port = ntohs(hdr->SourcePort);
+ pack->Remote.AddrType = Interface->Type;
pack->Length = len;
memcpy(pack->Data, hdr->Data, len);
* \param Data Packet data
* \param Length Length in bytes of packet data
*/
-void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, void *Address, Uint16 Port, void *Data, size_t Length)
+void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length)
{
tUDPHeader *hdr;
new->Node.ImplPtr = new;
new->Node.NumACLs = 1;
new->Node.ACLs = &gVFS_ACL_EveryoneRW;
- new->Node.Read = UDP_Channel_Read;
- new->Node.Write = UDP_Channel_Write;
- new->Node.IOCtl = UDP_Channel_IOCtl;
- new->Node.Close = UDP_Channel_Close;
+ new->Node.Type = &gUDP_NodeType;
Mutex_Acquire(&glUDP_Channels);
new->Next = gpUDP_Channels;
tUDPChannel *chan = Node->ImplPtr;
tUDPPacket *pack;
tUDPEndpoint *ep;
- int ofs;
+ int ofs, addrlen;
if(chan->LocalPort == 0) {
Log_Notice("UDP", "Channel %p sent with no local port", chan);
}
// Check that the header fits
+ addrlen = IPStack_GetAddressSize(pack->Remote.AddrType);
ep = Buffer;
- ofs = 4 + IPStack_GetAddressSize(pack->Remote.AddrType);
+ ofs = 4 + addrlen;
if(Length < ofs) {
free(pack);
Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs);
// Fill header
ep->Port = pack->Remote.Port;
ep->AddrType = pack->Remote.AddrType;
- memcpy(&ep->Addr, &pack->Remote.Addr, IPStack_GetAddressSize(pack->Remote.AddrType));
+ memcpy(&ep->Addr, &pack->Remote.Addr, addrlen);
// Copy packet data
if(Length > ofs + pack->Length) Length = ofs + pack->Length;
/**
* \brief Write to the channel file (send a packet)
*/
-Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tUDPChannel *chan = Node->ImplPtr;
- tUDPEndpoint *ep;
- void *data;
+ const tUDPEndpoint *ep;
+ const void *data;
int ofs;
if(chan->LocalPort == 0) return 0;
ep = Buffer;
ofs = 2 + 2 + IPStack_GetAddressSize( ep->AddrType );
- data = (char*)Buffer + ofs;
+ data = (const char *)Buffer + ofs;
UDP_SendPacketTo(chan, ep->AddrType, &ep->Addr, ep->Port, data, (size_t)Length - ofs);
int KB_IOCtl(tVFS_Node *Node, int Id, void *Data);
// === GLOBALS ===
+tVFS_NodeType gKB_NodeType = {
+ .IOCtl = KB_IOCtl
+};
tDevFS_Driver gKB_DevInfo = {
NULL, "PS2Keyboard",
- {
- .NumACLs = 0,
- .Size = 0,
- .IOCtl = KB_IOCtl
- }
+ { .Type = &gKB_NodeType }
};
tKeybardCallback gKB_Callback = NULL;
Uint32 **gpKB_Map = gpKBDUS;
int giMouse_Cycle = 0; // IRQ Position\r
Uint8 gaMouse_Bytes[4] = {0,0,0,0};\r
// - Driver definition\r
+tVFS_NodeType gMouse_NodeType = {\r
+ .Read = PS2Mouse_Read,\r
+ .IOCtl = PS2Mouse_IOCtl\r
+};\r
tDevFS_Driver gMouse_DriverStruct = {\r
NULL, "PS2Mouse",\r
{\r
.NumACLs = 1, .ACLs = &gVFS_ACL_EveryoneRX,\r
- .Read = PS2Mouse_Read, .IOCtl = PS2Mouse_IOCtl\r
+ .Type = &gMouse_NodeType\r
}\r
};\r
\r
char *Ne2k_ReadDir(tVFS_Node *Node, int Pos);
tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name);
int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data);
-Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
int Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer);
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, Ne2k, Ne2k_Install, NULL, NULL);
+tVFS_NodeType gNe2K_RootNodeType = {
+ .ReadDir = Ne2k_ReadDir,
+ .FindDir = Ne2k_FindDir,
+ .IOCtl = Ne2k_IOCtl
+ };
+tVFS_NodeType gNe2K_DevNodeType = {
+ .Write = Ne2k_Write,
+ .Read = Ne2k_Read,
+ .IOCtl = Ne2k_IOCtl
+ };
tDevFS_Driver gNe2k_DriverInfo = {
NULL, "ne2k",
{
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = Ne2k_ReadDir,
- .FindDir = Ne2k_FindDir,
- .IOCtl = Ne2k_IOCtl
+ .Type = &gNe2K_RootNodeType
}
};
Uint16 gNe2k_BaseAddress;
gpNe2k_Cards[ k ].Node.ImplPtr = &gpNe2k_Cards[ k ];
gpNe2k_Cards[ k ].Node.NumACLs = 0; // Root Only
gpNe2k_Cards[ k ].Node.CTime = now();
- gpNe2k_Cards[ k ].Node.Write = Ne2k_Write;
- gpNe2k_Cards[ k ].Node.Read = Ne2k_Read;
- gpNe2k_Cards[ k ].Node.IOCtl = Ne2k_IOCtl;
+ gpNe2k_Cards[ k ].Node.Type = &gNe2K_DevNodeType;
// Initialise packet semaphore
// - Start at zero, no max
}
/**
- * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
* \brief Send a packet from the network card
*/
-Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
tCard *Card = (tCard*)Node->ImplPtr;
- Uint16 *buf = Buffer;
+ const Uint16 *buf = Buffer;
int rem = Length;
int page;
tVFS_Node *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
int RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
int RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
void RTL8139_IRQHandler(int Num, void *Ptr);
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
+tVFS_NodeType gRTL8139_RootNodeType = {
+ .ReadDir = RTL8139_ReadDir,
+ .FindDir = RTL8139_FindDir,
+ .IOCtl = RTL8139_IOCtl
+ };
+tVFS_NodeType gRTL8139_DevNodeType = {
+ .Write = RTL8139_Write,
+ .Read = RTL8139_Read,
+ .IOCtl = RTL8139_IOCtl
+ };
tDevFS_Driver gRTL8139_DriverInfo = {
NULL, "RTL8139",
{
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = RTL8139_ReadDir,
- .FindDir = RTL8139_FindDir,
- .IOCtl = RTL8139_RootIOCtl
+ .Type = &gRTL8139_RootNodeType
}
};
int giRTL8139_CardCount;
card->Node.ImplPtr = card;
card->Node.NumACLs = 0;
card->Node.CTime = now();
- card->Node.Write = RTL8139_Write;
- card->Node.Read = RTL8139_Read;
- card->Node.IOCtl = RTL8139_IOCtl;
+ card->Node.Type = &gRTL8139_DevNodeType;
Log_Log("RTL8139", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
i, card->IOBase, card->IRQ,
return Length;
}
-Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
int td;
Uint32 status;
char *ATA_ReadDir(tVFS_Node *Node, int Pos);
tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name);
Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
// Read/Write Interface/Quantiser
Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk);
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
+tVFS_NodeType gATA_RootNodeType = {
+ .TypeName = "ATA Root Node",
+ .ReadDir = ATA_ReadDir,
+ .FindDir = ATA_FindDir
+ };
+tVFS_NodeType gATA_DiskNodeType = {
+ .TypeName = "ATA Volume",
+ .Read = ATA_ReadFS,
+ .Write = ATA_WriteFS,
+ .IOCtl = ATA_IOCtl
+ };
tDevFS_Driver gATA_DriverInfo = {
NULL, "ata",
{
.Size = -1,
.Flags = VFS_FFLAG_DIRECTORY,
.ACLs = &gVFS_ACL_EveryoneRX,
- .ReadDir = ATA_ReadDir,
- .FindDir = ATA_FindDir
+ .Type = &gATA_RootNodeType
}
};
tATA_Disk gATA_Disks[MAX_ATA_DISKS];
node->Inode = (Disk << 8) | 0xFF;
node->ImplPtr = gATA_Disks[ Disk ].Name;
- node->ATime = node->MTime
- = node->CTime = now();
+ node->ATime = node->MTime = node->CTime = now();
- node->Read = ATA_ReadFS;
- node->Write = ATA_WriteFS;
- node->IOCtl = ATA_IOCtl;
+ node->Type = &gATA_DiskNodeType;
// --- Scan Partitions ---
LOG("Reading MBR");
Part->Node.Inode = (Disk << 8) | Num;
Part->Node.ImplPtr = Part->Name;
- Part->Node.Read = ATA_ReadFS;
- Part->Node.Write = ATA_WriteFS;
- Part->Node.IOCtl = ATA_IOCtl;
+ Part->Node.Type = &gATA_DiskNodeType;
Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
LEAVE('-');
}
/**
- * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
*/
-Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
int disk = Node->Inode >> 8;
int part = Node->Inode & 0xFF;
}
/**
- * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
*/
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
{
int ret;
Uint offset;
MODULE_DEFINE(0, FDD_VERSION, Storage_FDDv2, FDD_Install, NULL, "x86_ISADMA", NULL);
tDrive gaFDD_Disks[MAX_DISKS];
tVFS_Node gaFDD_DiskNodes[MAX_DISKS];
+tVFS_NodeType gFDD_RootNodeType = {
+ .TypeName = "FDD Root Node",
+ .ReadDir = FDD_ReadDir,
+ .FindDir = FDD_FindDir,
+ .IOCtl = FDD_IOCtl
+ };
+tVFS_NodeType gFDD_DevNodeType = {
+ .TypeName = "FDD Device",
+ .Read = FDD_ReadFS,
+ .Write = NULL // FDD_WriteFS?
+ };
tDevFS_Driver gFDD_DriverInfo = {
NULL, "fdd",
{
.NumACLs = 1,
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = FDD_ReadDir,
- .FindDir = FDD_FindDir,
- .IOCtl = FDD_IOCtl
+ .Type = &gFDD_RootNodeType
}
};
gaFDD_DiskNodes[i].Inode = i;
gaFDD_DiskNodes[i].Flags = 0;
gaFDD_DiskNodes[i].NumACLs = 0;
- gaFDD_DiskNodes[i].Read = FDD_ReadFS;
- gaFDD_DiskNodes[i].Write = NULL;//FDD_WriteFS;
+ gaFDD_DiskNodes[i].Type = &gFDD_DevNodeType;
gaFDD_DiskNodes[i].Size = 1440*1024; // TODO: Non 1.44 disks
}
{
// TODO: Fix this to work with a non-contiguous pool
static tPAddr td_pool_base;
+ const int pool_size = NUM_TDs;
+ int offset;
if(!td_pool_base) td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
- return gaUHCI_TDPool + (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
+ offset = (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
+ if( offset < 0 || offset >= pool_size )
+ {
+ Log_Error("UHCI", "TD PAddr %P not from pool", PAddr);
+ return NULL;
+ }
+ return gaUHCI_TDPool + offset;
}
void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD)
{
link = Host->FrameList[frame];
Host->FrameList[frame] = 1;
- while( !(link & 1) )
+ while( link && !(link & 1) )
{
tUHCI_TD *td = UHCI_int_GetTDFromPhys(link);
int byte_count = (td->Control&0x7FF)+1;
if(td->_info.bCopyData)
{
void *ptr = (void*)MM_MapTemp(td->BufferPointer);
+ Log_Debug("UHCI", "td->_info.DataPtr = %p", td->_info.DataPtr);
memcpy(td->_info.DataPtr, ptr, byte_count);
MM_FreeTemp((tVAddr)ptr);
}
// === PROTOTYPES ===
int VGA_Install(char **Arguments);
-Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
int VGA_IOCtl(tVFS_Node *Node, int Id, void *Data);
Uint8 VGA_int_GetColourNibble(Uint16 col);
-Uint16 VGA_int_GetWord(tVT_Char *Char);
+Uint16 VGA_int_GetWord(const tVT_Char *Char);
void VGA_int_SetCursor(Sint16 x, Sint16 y);
// --- 2D Acceleration Functions --
void VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
// === GLOBALS ===
MODULE_DEFINE(0, 0x000A, x86_VGAText, VGA_Install, NULL, NULL);
+tVFS_NodeType gVGA_NodeType = {
+ //.Read = VGA_Read,
+ .Write = VGA_Write,
+ .IOCtl = VGA_IOCtl
+ };
tDevFS_Driver gVGA_DevInfo = {
NULL, "x86_VGAText",
{
.NumACLs = 0,
.Size = VGA_WIDTH*VGA_HEIGHT*sizeof(tVT_Char),
- //.Read = VGA_Read,
- .Write = VGA_Write,
- .IOCtl = VGA_IOCtl
+ .Type = &gVGA_NodeType
}
};
Uint16 *gVGA_Framebuffer = (void*)( KERNEL_BASE|0xB8000 );
}
/**
- * \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)
+Uint64 VGA_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
{
if( giVGA_BufferFormat == VIDEO_BUFFMT_TEXT )
{
int num = Length / sizeof(tVT_Char);
int ofs = Offset / sizeof(tVT_Char);
int i = 0;
- tVT_Char *chars = Buffer;
+ const tVT_Char *chars = Buffer;
Uint16 word;
//ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
* \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 VGA_int_GetWord(const tVT_Char *Char)
{
Uint16 ret;
Uint16 col;
--- /dev/null
+Per-thread event system
+
+enum eEvents
+{
+ EVENT_VFS,
+ EVENT_IPCMESSAGE,
+ ...
+};
+
+Uint32 tThread.ActiveEvents
+tSemaphore tThread.EventSemaphore
+
+
+Threads_PostEvent(tThread *, int EventID);
+Threads_WaitEvents(Uint32 Mask);
+- Clears events watched when wait is over
--- /dev/null
+Network only?
+- "/Devices/ip/routes/4:0A000200:24"
+Network and Metric?
+- "/Devices/ip/routes/4:0A000200:24:10"
+
+Would it need the interface?
+- "/Devices/ip/routes/0:4:0A000200:24:10"
+
+
+Current model
+- num = "/Devices/ip/routes"->CreateRoute("interface")
+- "/Devices/ip/routes/{num}"->SetNetwork()
+- "/Devices/ip/routes/{num}"->SetSubnetBits()
+- "/Devices/ip/routes/{num}"->SetMetric()
+- "/Devices/ip/routes/{num}"->SetNextHop()
+
+New Model
+- "/Devices/ip/routes/{type}:{network}:{subnet}:{metric}"->SetNextHop()
+- "/Devices/ip/routes/{type}:{network}:{subnet}:{metric}"->SetInterface()?
shift
QEMU_PARAMS=$QEMU_PARAMS" "$1
;;
+ -fwd)
+ _NETTYPE=$_NETTYPE",hostfwd=tcp::10023-10.0.2.10:23"
+ ;;
-tuntap)
_NETTYPE="tap"
esac
@$(xMKDIR) $(DISTROOT)/Apps/AxWin ; true
@$(xMKDIR) $(DISTROOT)/Apps/3.0 ; true
@$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
- @$(foreach FILE,$(FILES), $(SUBMAKE) $FILE;) true
+ @$(foreach FILE,$(FILES), $(xCP) $(FILE:-%=%) $(DISTROOT)/Apps/AxWin/3.0/$(FILE:-%=%) &&) true
clean:
@$(foreach DIR,$(DIRS), $(SUBMAKE) -C $(DIR) $@ &&) true
void Decorator_Redraw(tWindow *Window)
{
- int bActive;
+ int bActive = 0;
int text_width, text_height;
// TODO: This could possibly be expensive, but is there a better way?
IPC_FillSelect(&nfds, &fds);
nfds ++;
- if( select(nfds, &fds, NULL, NULL, NULL) == -1 ) {
+ if( _SysSelect(nfds, &fds, NULL, NULL, NULL, THREAD_EVENT_IPCMSG) == -1 ) {
_SysDebug("ERROR: select() returned -1");
return -1;
}
tElement *ret, *next, *ele;
next = &Info->RootElement;
- while(next)
+ do
{
ret = next;
next = NULL;
if(Y >= ele->CachedY + ele->CachedH) continue;
next = ele;
}
- }
+ } while(next);
return ret;
}
// === CODE ===
tWindow *WM_int_GetWindowAtPos(int X, int Y)
{
- tWindow *win, *next_win, *ret;
+ tWindow *win, *next_win, *ret = NULL;
next_win = gpWM_RootWindow;
prev = next, next = next->Next
);
- if( next->Codepoint == Codepoint )
+ if( next && next->Codepoint == Codepoint )
return next;
}
prev && prev->Codepoint > Codepoint;
next = prev, prev = prev->Prev
);
- if( prev->Codepoint == Codepoint )
+ if( prev && prev->Codepoint == Codepoint )
return prev;
}
}
{
case CONNTYPE_SENDMESSAGE:
// TODO: Less hack, I need a version of select for GetMessage etc
- if(SysGetMessage(NULL, NULL) == 0) sleep();
+ if(SysGetMessage(NULL, NULL) == 0) _SysWaitEvent(THREAD_EVENT_IPCMSG);
while(SysGetMessage(NULL, NULL))
{
pid_t tid;
--- /dev/null
+# Project: DHCP Client
+
+-include ../Makefile.cfg
+
+LDFLAGS += -lnet
+
+OBJ = main.o
+BIN = dhcpc
+DIR = SBin
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ */
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <net.h>
+
+#define FILENAME_MAX 255
+// --- Translation functions ---
+static inline uint32_t htonl(uint32_t v)
+{
+ return (((v >> 24) & 0xFF) << 0)
+ | (((v >> 16) & 0xFF) << 8)
+ | (((v >> 8) & 0xFF) << 16)
+ | (((v >> 0) & 0xFF) << 24);
+}
+static inline uint16_t htons(uint16_t v)
+{
+ return (((v >> 8) & 0xFF) << 0)
+ | (((v >> 0) & 0xFF) << 8);
+}
+#define htonb(v) v
+#define ntohl(v) htonl(v)
+#define ntohs(v) htons(v)
+
+// === CONSTANTS ===
+enum eStates
+{
+ STATE_PREINIT,
+ STATE_DISCOVER_SENT,
+ STATE_REQUEST_SENT,
+ STATE_COMPLETE
+};
+
+// === STRUCTURES ===
+#define DHCP_MAGIC 0x63825363
+struct sDHCP_Message
+{
+ uint8_t op;
+ uint8_t htype; // 1 = Ethernet
+ uint8_t hlen; // 6 bytes for MAC
+ uint8_t hops; // Hop counting
+ uint32_t xid;
+ uint16_t secs;
+ uint16_t flags;
+ uint32_t ciaddr;
+ uint32_t yiaddr;
+ uint32_t siaddr;
+ uint32_t giaddr;
+ uint8_t chaddr[16];
+ uint8_t sname[64];
+ uint8_t file[128];
+ uint32_t dhcp_magic; // 0x63 0x82 0x53 0x63
+ uint8_t options[];
+};
+
+typedef struct sInterface
+{
+ struct sInterface *Next;
+ char *Adapter;
+ int State;
+ int Num;
+ int SocketFD;
+ int IfaceFD;
+} tInterface;
+
+// === PROTOTYPES ===
+int main(int argc, char *argv[]);
+void Scan_Dir(tInterface **IfaceList, const char *Directory);
+int Start_Interface(tInterface *Iface);
+void Send_DHCPDISCOVER(tInterface *Iface);
+void Send_DHCPREQUEST(tInterface *Iface, void *OfferBuffer, int TypeOffset);
+int Handle_Packet(tInterface *Iface);
+void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router);
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ tInterface *ifaces = NULL, *i;
+
+ // TODO: Scan /Devices and search for network adapters
+ if( argc > 2 ) {
+ fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
+ return -1;
+ }
+
+ if( argc == 2 ) {
+ ifaces = malloc(sizeof(tInterface));
+ ifaces->Next = NULL;
+ ifaces->Adapter = argv[1];
+ }
+ else {
+ Scan_Dir( &ifaces, "/Devices" );
+ }
+
+ for( i = ifaces; i; i = i->Next )
+ {
+ i->State = STATE_PREINIT;
+ if( Start_Interface(i) < 0 ) {
+ return -1;
+ }
+
+ // Send request
+ Send_DHCPDISCOVER(i);
+ }
+
+ while( ifaces )
+ {
+ int maxfd;
+ fd_set fds;
+
+ maxfd = 0;
+ FD_ZERO(&fds);
+ for( i = ifaces; i; i = i->Next )
+ {
+ FD_SET(i->SocketFD, &fds);
+ if(maxfd < i->SocketFD) maxfd = i->SocketFD;
+ }
+ if( select(maxfd+1, &fds, NULL, NULL, NULL) < 0 )
+ {
+ // TODO: Check error result
+ return -1;
+ }
+
+ _SysDebug("select returned");
+ tInterface *p;
+ for( p = (void*)&ifaces, i = ifaces; i; p=i,i = i->Next )
+ {
+ if( FD_ISSET(i->SocketFD, &fds) )
+ {
+ if( Handle_Packet( i ) )
+ {
+ close(i->SocketFD);
+ close(i->IfaceFD);
+ p->Next = i->Next;
+ free(i);
+ i = p;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void Scan_Dir(tInterface **IfaceList, const char *Directory)
+{
+ int dp = open(Directory, OPENFLAG_READ);
+ char filename[FILENAME_MAX];
+
+ while( readdir(dp, filename) )
+ {
+ int pathlen = strlen(Directory) + 1 + strlen(filename) + 1;
+ char path[pathlen];
+ int fd;
+ t_sysFInfo info;
+
+ sprintf(path, "%s/%s", Directory, filename);
+ fd = open(path, 0);
+
+ if( ioctl(fd, 0, NULL) != 9 )
+ continue ;
+
+ finfo(fd, &info, 0);
+
+ if( info.flags & FILEFLAG_DIRECTORY )
+ {
+ Scan_Dir(IfaceList, path);
+ }
+ else
+ {
+ tInterface *new = malloc(sizeof(tInterface) + pathlen);
+ new->Adapter = (void*)(new + 1);
+ strcpy(new->Adapter, path);
+ new->Next = *IfaceList;
+ *IfaceList = new;
+ }
+ }
+ close(dp);
+}
+
+// RETURN: Client FD
+int Start_Interface(tInterface *Iface)
+{
+ int fd, tmp;
+ char path[] = "/Devices/ip/XXXXX/udpc";
+ char addr[4] = {0,0,0,0};
+
+ // TODO: Check that the adapter is not in use
+
+ // Initialise an interface, with a dummy IP address (zero)
+ fd = open("/Devices/ip", 0);
+ if( fd == -1 ) {
+ fprintf(stderr, "ERROR: Unable to open '/Devices/ip'\n");
+ return -1;
+ }
+ Iface->Num = ioctl(fd, 4, (void*)Iface->Adapter); // Create interface
+ if( Iface->Num == -1 ) {
+ fprintf(stderr, "ERROR: Unable to create new interface\n");
+ return -1;
+ }
+ close(fd);
+
+ // Open new interface
+ snprintf(path, sizeof(path), "/Devices/ip/%i", Iface->Num);
+ Iface->IfaceFD = fd = open(path, 0);
+ if( fd == -1 ) {
+ fprintf(stderr, "ERROR: Unable to open '%s'\n", path);
+ return -1;
+ }
+ tmp = 4; ioctl(fd, 4, &tmp); // Set to IPv4
+ ioctl(fd, 6, addr); // Set address to 0.0.0.0
+ tmp = 0; ioctl(fd, 7, &tmp); // Set subnet mask to 0
+
+ // Open UDP Client
+ snprintf(path, sizeof(path), "/Devices/ip/%i/udp", Iface->Num);
+ Iface->SocketFD = fd = open(path, O_RDWR);
+ if( fd == -1 ) {
+ fprintf(stderr, "ERROR: Unable to open '%s'\n", path);
+ return -1;
+ }
+ tmp = 68; ioctl(fd, 4, &tmp); // Local port
+ tmp = 67; ioctl(fd, 5, &tmp); // Remote port
+ tmp = 0; ioctl(fd, 7, &tmp); // Remote addr mask - we don't care where the reply comes from
+ addr[0] = addr[1] = addr[2] = addr[3] = 255; // 255.255.255.255
+ ioctl(fd, 8, addr); // Remote address
+
+ return fd;
+}
+
+void Send_DHCPDISCOVER(tInterface *Iface)
+{
+ uint32_t transaction_id;
+ struct sDHCP_Message *msg;
+ char data[8 + sizeof(struct sDHCP_Message) + 3 + 1];
+ msg = (void*)data + 8;
+
+ transaction_id = rand();
+
+ msg->op = htonb(1); // BOOTREQUEST
+ msg->htype = htonb(1); // 10mb Ethernet
+ msg->hlen = htonb(6); // 6 byte MAC
+ msg->hops = htonb(0); // Hop count so far
+ msg->xid = htonl(transaction_id); // Transaction ID
+ msg->secs = htons(0); // secs - No time has elapsed
+ msg->flags = htons(0); // flags - TODO: Check if broadcast bit need be set
+ msg->ciaddr = htonl(0); // ciaddr - Zero, as we don't have one yet
+ msg->yiaddr = htonl(0); // yiaddr - Zero?
+ msg->siaddr = htonl(0); // siaddr - Zero? maybe -1
+ msg->giaddr = htonl(0); // giaddr - Zero?
+ // Request MAC address from network adapter
+ {
+ int fd = open(Iface->Adapter, 0);
+ // TODO: Check if open() failed
+ ioctl(fd, 4, msg->chaddr);
+ // TODO: Check if ioctl() failed
+ close(fd);
+ }
+ memset(msg->sname, 0, sizeof(msg->sname)); // Nuke the rest
+ memset(msg->file, 0, sizeof(msg->file)); // Nuke the rest
+ msg->dhcp_magic = htonl(DHCP_MAGIC);
+
+ int i = 0;
+ msg->options[i++] = 53; // DHCP Message Type
+ msg->options[i++] = 1;
+ msg->options[i++] = 1; // - DHCPDISCOVER
+ msg->options[i++] = 255; // End of list
+
+
+ data[0] = 67; data[1] = 0; // Port
+ data[2] = 4; data[3] = 0; // AddrType
+ data[4] = 255; data[5] = 255; data[6] = 255; data[7] = 255;
+
+ write(Iface->SocketFD, data, sizeof(data));
+ Iface->State = STATE_DISCOVER_SENT;
+}
+
+void Send_DHCPREQUEST(tInterface *Iface, void *OfferPacket, int TypeOffset)
+{
+ struct sDHCP_Message *msg;
+ msg = (void*) ((char*)OfferPacket) + 8;
+
+ // Reuses old data :)
+ msg->op = 1;
+ msg->options[TypeOffset+2] = 3; // DHCPREQUEST
+ msg->options[TypeOffset+3] = 255;
+
+ write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + TypeOffset + 4);
+ Iface->State = STATE_REQUEST_SENT;
+}
+
+int Handle_Packet(tInterface *Iface)
+{
+ char data[8+576];
+ struct sDHCP_Message *msg = (void*)(data + 8);
+ int len, i;
+
+ int dhcp_msg_type = 0, dhcp_msg_type_ofs;
+ void *router = NULL;
+ void *subnet_mask = NULL;
+
+ _SysDebug("Doing read on %i", Iface->SocketFD);
+ len = read(Iface->SocketFD, data, sizeof(data));
+ _SysDebug("len = %i", len);
+
+ _SysDebug("*msg = {");
+ _SysDebug(" .op = %i", msg->op);
+ _SysDebug(" .htype = %i", msg->htype);
+ _SysDebug(" .ciaddr = 0x%x", ntohl(msg->ciaddr));
+ _SysDebug(" .yiaddr = 0x%x", ntohl(msg->yiaddr));
+ _SysDebug("}");
+ if( msg->op != 2 ) {
+ // Not a response
+ _SysDebug("Not a response message");
+ return 0;
+ }
+
+ if( htonl(msg->dhcp_magic) != DHCP_MAGIC ) {
+ _SysDebug("DHCP magic doesn't match (got 0x%x, expected 0x%x)",
+ htonl(msg->dhcp_magic), DHCP_MAGIC);
+ return 0;
+ }
+
+ i = 0;
+ while( i < len - sizeof(*msg) - 8 && msg->options[i] != 255 )
+ {
+ if( msg->options[i] == 0 ) {
+ i ++;
+ continue ;
+ }
+ _SysDebug("Option %i, %i bytes long", msg->options[i], msg->options[i+1]);
+ switch(msg->options[i])
+ {
+ case 1:
+ subnet_mask = &msg->options[i+2];
+ break;
+ case 3:
+ router = &msg->options[i+2];
+ break;
+ case 53:
+ dhcp_msg_type_ofs = i;
+ dhcp_msg_type = msg->options[i+2];
+ break;
+ }
+ i += msg->options[i+1]+2;
+ }
+
+ _SysDebug("dhcp_msg_type = %i", dhcp_msg_type);
+
+ switch( dhcp_msg_type )
+ {
+ case 1: // DHCPDISCOVER - wut?
+ break;
+ case 2: // DHCPOFFER
+ // Send out request for this address
+ if( Iface->State != STATE_DISCOVER_SENT ) return 0;
+ Send_DHCPREQUEST(Iface, data, dhcp_msg_type_ofs);
+ break;
+ case 3: // DHCPREQUEST - wut?
+ break;
+ case 4: // DHCPDECLINE - ?
+ break;
+ case 5: // DHCPACK
+ // TODO: Apply address
+ SetAddress(Iface, &msg->yiaddr, subnet_mask, router);
+ return 1;
+ }
+ return 0;
+}
+
+void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router)
+{
+ int mask_bits = 0;
+
+ // Translate the mask
+ if( Mask )
+ {
+ uint8_t *mask = Mask;
+ int i;
+ _SysDebug("Mask %i.%i.%i.%i", mask[0], mask[1], mask[2], mask[3]);
+ for( i = 0; i < 4 && mask[i] == 0xFF; i ++ ) ;
+ mask_bits = i*8;
+ if( i == 4 )
+ {
+ // Wut? /32?
+ }
+ else
+ {
+ switch(mask[i])
+ {
+ case 0x00: mask_bits += 0; break;
+ case 0x80: mask_bits += 1; break;
+ case 0xC0: mask_bits += 2; break;
+ case 0xE0: mask_bits += 3; break;
+ case 0xF0: mask_bits += 4; break;
+ case 0xF8: mask_bits += 5; break;
+ case 0xFC: mask_bits += 6; break;
+ case 0xFE: mask_bits += 7; break;
+ default:
+ // Bad mask!
+ break;
+ }
+ }
+ }
+
+ {
+ uint8_t *addr = Addr;
+ _SysDebug("Addr %i.%i.%i.%i/%i", addr[0], addr[1], addr[2], addr[3], mask_bits);
+
+ printf("Assigned %i.%i.%i.%i/%i to IF#%i (%s)\n",
+ addr[0], addr[1], addr[2], addr[3], mask_bits,
+ Iface->Num, Iface->Adapter
+ );
+ }
+
+ ioctl(Iface->IfaceFD, 6, Addr);
+ ioctl(Iface->IfaceFD, 7, &mask_bits);
+
+ if( Router );
+ {
+ uint8_t *addr = Router;
+ _SysDebug("Router %i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
+
+ // Set default route
+ int fd;
+ fd = open("/Devices/ip/routes/4:00000000:0:0", OPENFLAG_CREATE);
+ if(fd == -1) {
+ fprintf(stderr, "ERROR: Unable to open default route\n");
+ }
+ else {
+ char ifname[snprintf(NULL,0,"%i",Iface->Num)+1];
+ sprintf(ifname, "%i", Iface->Num);
+ ioctl(fd, ioctl(fd, 3, "set_nexthop"), Router);
+ ioctl(fd, ioctl(fd, 3, "set_interface"), ifname);
+ close(fd);
+ }
+ }
+}
+
dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ);
- printf("ID\tType\tNetwork \tGateway \tMetric\tIFace\n");
+ printf("Type\tNetwork \tGateway \tMetric\tIFace\n");
while( readdir(dp, filename) )
{
return ;
}
- type = ioctl(fd, 4, NULL);
-
- // Ignore -1 values
- if( type == -1 ) {
- return ;
+ int ofs = 2;
+ type = atoi(Name);
+
+ int i;
+ int len = Net_GetAddressSize(type);
+ uint8_t net[len], gw[len];
+ int subnet, metric;
+ for( i = 0; i < len; i ++ ) {
+ char tmp[5] = "0x00";
+ tmp[2] = Name[ofs++];
+ tmp[3] = Name[ofs++];
+ net[i] = atoi(tmp);
}
-
- // Number
- printf("%s\t", Name);
+ ofs ++;
+ subnet = atoi(Name+ofs);
+ ofs ++;
+ metric = atoi(Name+ofs);
+ ioctl(fd, ioctl(fd, 3, "get_nexthop"), gw); // Get Gateway/NextHop
// Get the address type
switch(type)
printf("DISABLED\n");
break;
case 4: // IPv4
- {
- uint8_t net[4], addr[4];
- int subnet, metric;
printf("IPv4\t");
- ioctl(fd, ioctl(fd, 3, "get_network"), net); // Get Network
- ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr); // Get Gateway/NextHop
- subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL); // Get Subnet Bits
- metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL); // Get Subnet Bits
- printf("%s/%i\t", Net_PrintAddress(4, net), subnet);
- printf("%s \t", Net_PrintAddress(4, addr));
- printf("%i\t", metric);
- }
break;
case 6: // IPv6
- {
- uint16_t net[8], addr[8];
- int subnet, metric;
printf("IPv6\t");
- ioctl(fd, ioctl(fd, 3, "get_network"), net); // Get Network
- ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr); // Get Gateway/NextHop
- subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL); // Get Subnet Bits
- metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL); // Get Subnet Bits
- printf("%s/%i\t", Net_PrintAddress(6, net), subnet);
- printf("%s\t", Net_PrintAddress(6, addr));
- printf("%i\t", metric);
- }
break;
default: // Unknow
printf("UNKNOWN (%i)\n", type);
break;
}
+ printf("%s/%i\t", Net_PrintAddress(type, net), subnet);
+ printf("%s \t", Net_PrintAddress(type, gw));
+ printf("%i\t", metric);
// Interface
{
{
int fd;
int num;
- char tmp[sizeof(IPSTACK_ROOT"/routes/") + 5]; // enough for 4 digits
char *ifaceToFree = NULL;
// Get interface name
}
// Create route
- fd = open(IPSTACK_ROOT"/routes", 0);
- num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
- close(fd);
-
- // Open route
- sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
- fd = open(tmp, 0);
+ int addrsize = Net_GetAddressSize(AddressType);
+ int len = snprintf(NULL, 0, "/Devices/ip/routes/%i::%i:%i", AddressType, MaskBits, Metric) + addrsize*2;
+ char path[len+1];
+ {
+ int i, ofs;
+ ofs = sprintf(path, "/Devices/ip/routes/%i:", AddressType);
+ for( i = 0; i < addrsize; i ++ )
+ sprintf(path+ofs+i*2, "%02x", ((uint8_t*)Dest)[i]);
+ ofs += addrsize*2;
+ sprintf(path+ofs, ":%i:%i", MaskBits, Metric);
+ }
+
+ fd = open(path, 0);
+ if( fd != -1 ) {
+ close(fd);
+ fprintf(stderr, "Unable to create route '%s', already exists\n", path);
+ return ;
+ }
+ fd = open(path, OPENFLAG_CREATE, 0);
+ if( fd == -1 ) {
+ fprintf(stderr, "Unable to create '%s'\n", path);
+ return ;
+ }
- ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
if( NextHop )
ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
- ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), &MaskBits);
- ioctl(fd, ioctl(fd, 3, "getset_metric"), &Metric);
+ ioctl(fd, ioctl(fd, 3, "set_interface"), (void*)Interface);
close(fd);
/**
* \note Debugging HACK!
- * \brief Autoconfigure the specified device to 10.0.2.55/8 using
- * 10.0.2.1 as the gateway.
+ * \brief Autoconfigure the specified device to 10.0.2.55/24 using
+ * 10.0.2.2 as the gateway.
*/
int DoAutoConfig(const char *Device)
{
#include <net.h>\r
#include <readline.h>\r
\r
-#define BUFSIZ 1023\r
-\r
// === TYPES ===\r
typedef struct sServer {\r
struct sServer *Next;\r
// === PROTOTYPES ===
void PrintUsage(char *ProgName);
void PrintHelp(char *ProgName);
- int GetAddress( char *Address, uint8_t *Addr );
// === GLOBALS ===
int giNumberOfPings = 1;
return 1;
}
- if( !iface )
- {
- iface = Net_GetInterface(type, addr);
- if( !iface ) {
- fprintf(stderr, "Unable to find a route to '%s'\n",
- Net_PrintAddress(type, addr)
- );
- return -1;
- }
-
- printf("iface = '%s'\n", iface);
- }
-
+ if( iface )
{
char *_iface = malloc( sizeof("/Devices/ip/") + strlen(iface) + 1 );
strcpy(_iface, "/Devices/ip/");
free(iface); // TODO: Handle when this is not heap
iface = _iface;
printf("iface = '%s'\n", iface);
+ fd = open(iface, OPENFLAG_EXEC);
+ if(fd == -1) {
+ fprintf(stderr, "ERROR: Unable to open interface '%s'\n", iface);
+ return 1;
+ }
+
}
-
- fd = open(iface, OPENFLAG_EXEC);
- if(fd == -1) {
- fprintf(stderr, "ERROR: Unable to open interface '%s'\n", iface);
- return 1;
+ else
+ {
+ fd = Net_OpenSocket(type, addr, NULL);
+ if( fd == -1 ) {
+ fprintf(stderr, "Unable to find a route to '%s'\n",
+ Net_PrintAddress(type, addr)
+ );
+ return -1;
+ }
}
-
+
call = ioctl(fd, 3, "ping");
if(call == 0) {
fprintf(stderr, "ERROR: '%s' does not have a 'ping' call\n", iface);
fprintf(stderr, " -h\tPrint this message\n");
}
-/**
- * \brief Read an IPv4 Address
- */
-int GetAddress4(char *String, uint8_t *Addr)
-{
- int i = 0;
- int j;
- int val;
-
- for( j = 0; String[i] && j < 4; j ++ )
- {
- val = 0;
- for( ; String[i] && String[i] != '.'; i++ )
- {
- if('0' > String[i] || String[i] > '9') {
- printf("0<c<9 expected, '%c' found\n", String[i]);
- return 0;
- }
- val = val*10 + String[i] - '0';
- }
- if(val > 255) {
- printf("val > 255 (%i)\n", val);
- return 0;
- }
- Addr[j] = val;
-
- if(String[i] == '.')
- i ++;
- }
- if( j != 4 ) {
- printf("4 parts expected, %i found\n", j);
- return 0;
- }
- if(String[i] != '\0') {
- printf("EOS != '\\0', '%c'\n", String[i]);
- return 0;
- }
- return 1;
-}
-
-/**
- * \brief Read an IPv6 Address
- */
-int GetAddress6(char *String, uint8_t *Addr)
-{
- int i = 0;
- int j, k;
- int val, split = -1, end;
- uint16_t hi[8], low[8];
-
- for( j = 0; String[i] && j < 8; j ++ )
- {
- if(String[i] == ':') {
- if(split != -1) {
- printf("Two '::'s\n");
- return 0;
- }
- split = j;
- i ++;
- continue;
- }
-
- val = 0;
- for( k = 0; String[i] && String[i] != ':'; i++, k++ )
- {
- val *= 16;
- if('0' <= String[i] && String[i] <= '9')
- val += String[i] - '0';
- else if('A' <= String[i] && String[i] <= 'F')
- val += String[i] - 'A' + 10;
- else if('a' <= String[i] && String[i] <= 'f')
- val += String[i] - 'a' + 10;
- else {
- printf("%c unexpected\n", String[i]);
- return 0;
- }
- }
-
- if(val > 0xFFFF) {
- printf("val (0x%x) > 0xFFFF\n", val);
- return 0;
- }
-
- if(split == -1)
- hi[j] = val;
- else
- low[j-split] = val;
-
- if( String[i] == ':' ) {
- i ++;
- }
- }
- end = j;
-
- for( j = 0; j < split; j ++ )
- {
- Addr[j*2] = hi[j]>>8;
- Addr[j*2+1] = hi[j]&0xFF;
- }
- for( ; j < 8 - (end - split); j++ )
- {
- Addr[j*2] = 0;
- Addr[j*2+1] = 0;
- }
- k = 0;
- for( ; j < 8; j ++, k++)
- {
- Addr[j*2] = hi[k]>>8;
- Addr[j*2+1] = hi[k]&0xFF;
- }
-
- return 1;
-}
-
-int GetAddress(char *String, uint8_t *Addr)
-{
- if( GetAddress4(String, Addr) )
- return 4;
-
- if( GetAddress6(String, Addr) )
- return 6;
-
- return 0;
-}
#include <readline.h>\r
#include <string.h>\r
\r
-#define BUFSIZ 2048\r
-\r
// === PROTOTYPES ===\r
int main(int argc, char *argv[], char *envp[]);\r
int OpenTCP(const char *AddressString, short PortNumber);\r
--- /dev/null
+# Project: telnetd
+
+-include ../Makefile.cfg
+
+LDFLAGS += -lnet
+
+OBJ = main.o
+BIN = telnetd
+DIR = SBin
+CFLAGS += -std=c99
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ */
+#include <stddef.h>
+#include <net.h>
+#include <unistd.h>
+#include <stdio.h>
+
+// === TYPES ===
+typedef struct sClient
+{
+ int Socket;
+ int stdout;
+ int stdin;
+} tClient;
+
+// === PROTOTYPES ===
+void EventLoop(void);
+void Server_NewClient(int FD);
+void HandleServerBoundData(tClient *Client);
+void HandleClientBoundData(tClient *Client);
+
+// === GLOBALS ===
+// --- Configuration ---
+ int giConfig_MaxClients = 5;
+// --- State ---
+ int giServerFD;
+tClient *gaClients;
+ int giNumClients;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ // TODO: Configure
+
+ // Initialise
+ gaClients = calloc(giConfig_MaxClients, sizeof(tClient));
+
+ // Open server
+ {
+ uint8_t data[16];
+ int addrtype = Net_ParseAddress("10.0.2.10", data);
+ int port = 23;
+ giServerFD = Net_OpenSocket(addrtype, data, "tcps");
+ ioctl(giServerFD, 4, &port); // Set port and start listening
+ }
+
+ // Event loop
+ EventLoop();
+
+ return 0;
+}
+
+void EventLoop(void)
+{
+ fd_set fds;
+ int maxfd;
+
+ void FD_SET_MAX(fd_set *set, int fd, int *maxfd)
+ {
+ FD_SET(fd, set);
+ if(*maxfd < fd) *maxfd = fd;
+ }
+
+ for( ;; )
+ {
+ FD_ZERO(&fds);
+ maxfd = 0;
+ // Fill select
+ FD_SET_MAX(&fds, giServerFD, &maxfd);
+ for( int i = 0; i < giConfig_MaxClients; i ++ )
+ {
+ if( gaClients[i].Socket == 0 ) continue ;
+ _SysDebug("Socket = %i, stdout = %i",
+ gaClients[i].Socket, gaClients[i].stdout);
+ FD_SET_MAX(&fds, gaClients[i].Socket, &maxfd);
+ FD_SET_MAX(&fds, gaClients[i].stdout, &maxfd);
+ }
+
+ // Select!
+ select( maxfd+1, &fds, NULL, NULL, NULL );
+
+ // Check events
+ if( FD_ISSET(giServerFD, &fds) )
+ {
+ Server_NewClient(giServerFD);
+ }
+ for( int i = 0; i < giConfig_MaxClients; i ++ )
+ {
+ if( FD_ISSET(gaClients[i].Socket, &fds) )
+ {
+ // Handle client data
+ HandleServerBoundData(&gaClients[i]);
+ }
+ if( FD_ISSET(gaClients[i].stdout, &fds) )
+ {
+ // Handle output from terminal
+ HandleClientBoundData(&gaClients[i]);
+ }
+ }
+ }
+}
+
+void Server_NewClient(int FD)
+{
+ tClient *clt;
+
+ // TODO: Is this done in the IPStack?
+ if( giNumClients == giConfig_MaxClients )
+ {
+ // Open, reject
+ close( _SysOpenChild(FD, "", O_RDWR) );
+ return ;
+ }
+
+ // Allocate client structure and open socket
+ for( int i = 0; i < giConfig_MaxClients; i ++ )
+ {
+ if( gaClients[i].Socket == 0 ) {
+ clt = &gaClients[i];
+ break;
+ }
+ }
+ // Accept the connection
+ clt->Socket = _SysOpenChild(FD, "", O_RDWR);
+ giNumClients ++;
+
+ // Create stdin/stdout
+ clt->stdin = open("/Devices/fifo/anon", O_RDWR);
+ clt->stdout = open("/Devices/fifo/anon", O_RDWR);
+
+ // TODO: Arguments and envp
+ {
+ int fds[3] = {clt->stdin, clt->stdout, clt->stdout};
+ const char *argv[] = {NULL};
+ _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds);
+ }
+}
+
+void HandleServerBoundData(tClient *Client)
+{
+ char buf[BUFSIZ];
+ int len;
+
+ len = read(Client->Socket, buf, BUFSIZ);
+ if( len <= 0 ) return ;
+ write(Client->stdin, buf, len);
+}
+
+void HandleClientBoundData(tClient *Client)
+{
+ char buf[BUFSIZ];
+ int len;
+
+ len = read(Client->stdout, buf, BUFSIZ);
+ if( len <= 0 ) return ;
+ write(Client->Socket, buf, len);
+}
+
all: $(_BIN) $(_XBIN)
clean:
- $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES)
+ $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES) $(EXTRACLEAN)
install: all
@echo [xCP] $(DISTROOT)/Libs/$(BIN)
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
-ENTRY(_start)
+ENTRY(start)
SEARCH_DIR(__LIBDIR)
INPUT(crt0.o)
SECTIONS
-include ../Makefile.cfg
OBJ := main.o lib.o loadlib.o export.o elf.o pe.o
-OBJ += arch/$(ARCHDIR).ao
+OBJ += arch/$(ARCHDIR).ao_
BIN = ld-acess.so
EXTRABIN := libld-acess.so
+EXTRACLEAN := $(_OBJPREFIX)_stublib.o
CFLAGS = -g -Wall -fno-builtin -fno-leading-underscore -fno-stack-protector -fPIC
CFLAGS += $(CPPFLAGS)
# Override .ao to look in the object prefix for the source
-%.ao: %.$(ASSUFFIX)
+$(_OBJPREFIX)arch/$(ARCHDIR).ao_: $(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX)
@echo [AS] -o $@
@mkdir -p $(dir $@)
@$(AS) $(ASFLAGS) -o $@ $<
-.PRECIOUS: $(OBJ:%.ao=%.asm)
+#.PRECIOUS: $(OBJ:%.ao=%.asm)
# Preprocessing objects if needed
-$(_OBJPREFIX)%: %.h
+$(_OBJPREFIX)arch/$(ARCHDIR).$(ASSUFFIX): arch/$(ARCHDIR).$(ASSUFFIX).h arch/syscalls.s.h
@echo [CPP] -o $@
@mkdir -p $(dir $@)
@$(CPP) $(CPPFLAGS) -P -D__ASSEMBLER__ $< -o $@
+$(_OBJPREFIX)_stublib.o: arch/syscalls.s.h
+
SYSCALL2(kill, SYS_KILL)
SYSCALL0(yield, SYS_YIELD)
SYSCALL0(sleep, SYS_SLEEP)
+SYSCALL1(_SysWaitEvent, SYS_WAITEVENT)
SYSCALL2(waittid, SYS_WAITTID)
SYSCALL0(gettid, SYS_GETTID)
SYSCALL3(SysSendMessage, SYS_SENDMSG)
SYSCALL3(SysGetMessage, SYS_GETMSG)
-SYSCALL3(SysSpawn, SYS_SPAWN)
+SYSCALL5(_SysSpawn, SYS_SPAWN)
SYSCALL3(execve, SYS_EXECVE)
SYSCALL2(SysLoadBin, SYS_LOADBIN)
SYSCALL1(SysUnloadBin, SYS_UNLOADBIN)
SYSCALL1(chdir, SYS_CHDIR) // char*
SYSCALL3(ioctl, SYS_IOCTL) // int, int, void*
SYSCALL4(_SysMount, SYS_MOUNT) // char*, char*, char*, char*
-SYSCALL5(select, SYS_SELECT) // int, fd_set*, fd_set*, fd_set*, tTime*
+SYSCALL6(_SysSelect, SYS_SELECT) // int, fd_set*, fd_set*, fd_set*, tTime*, uint32_t
SYSCALL3(_SysOpenChild, SYS_OPENCHILD)
extern void *SysLoadBin(const char *path, void **entry);
extern int SysUnloadBin(void *Base);
extern void SysSetFaultHandler(int (*Hanlder)(int));
-extern int open(const char *filename, int flags);
+extern int open(const char *filename, int flags, ...);
extern int close(int fd);
// === ELF Loader ===
EXP(kill),
EXP(yield),
EXP(sleep),
+ EXP(_SysWaitEvent),
EXP(waittid),
EXP(gettid),
EXP(getpid),
EXP(SysSendMessage),
EXP(SysGetMessage),
- //EXP(SysSpawn),
+ EXP(_SysSpawn),
EXP(execve),
EXP(SysLoadBin),
EXP(SysUnloadBin),
EXP(chdir),
EXP(ioctl),
EXP(_SysMount),
- EXP(select),
+ EXP(_SysSelect),
EXP(_SysOpenChild),
ASFLAGS +=\r
LDFLAGS += -soname libc.so -Map map.txt -lgcc\r
\r
-OBJ = stub.o heap.o stdlib.o env.o fileIO.o string.o select.o\r
+OBJ = stub.o heap.o stdlib.o env.o fileIO.o string.o select.o rand.o\r
OBJ += arch/$(ARCHDIR).ao\r
# signals.o\r
DEPFILES := $(OBJ:%.o=%.d)\r
--- /dev/null
+/*
+ * Acess2 Lib C
+ * - By John Hodge (thePowersGang)
+ *
+ * rand.c
+ * - srand/rand/rand_p functions
+ */
+#include <stdlib.h>
+
+// === GLOBALS ===
+unsigned int _rand_state_x = 123456789;
+unsigned int _rand_state_y = 362436069;
+unsigned int _rand_state_z = 521288629;
+unsigned int _rand_state_w = 88675123;
+
+// === FUNCTIONS ===
+int rand_p(unsigned int *seedp)
+{
+ const int const_a = 0x731ADE, const_c = 12345;
+ // Linear Congruency
+ *seedp = *seedp * const_a + const_c;
+ return *seedp;
+}
+
+void srand(unsigned int seed)
+{
+ _rand_state_x = rand_p( &seed );
+ _rand_state_y = rand_p( &seed );
+ _rand_state_z = rand_p( &seed );
+ _rand_state_w = rand_p( &seed );
+}
+
+int rand(void)
+{
+ unsigned int t;
+
+ t = _rand_state_x ^ (_rand_state_x << 11);
+ _rand_state_x = _rand_state_y; _rand_state_y = _rand_state_z; _rand_state_z = _rand_state_w;
+ return _rand_state_w = _rand_state_w ^ (_rand_state_w >> 19) ^ t ^ (t >> 8);
+}
+
#include <stdio.h>
#define DEBUG 0
+static inline uint32_t htonl(uint32_t v)
+{
+ return (((v >> 24) & 0xFF) << 0)
+ | (((v >> 16) & 0xFF) << 8)
+ | (((v >> 8) & 0xFF) << 16)
+ | (((v >> 0) & 0xFF) << 24);
+}
+static inline uint16_t htons(uint16_t v)
+{
+ return (((v >> 8) & 0xFF) << 0)
+ | (((v >> 0) & 0xFF) << 8);
+}
+#define htonb(v) v
+#define ntohl(v) htonl(v)
+#define ntohs(v) htons(v)
+#define ntohb(v) v
+
#define __thread // Disable TLS
/**
#endif
sprintf(ret, "%x:%x:%x:%x:%x:%x:%x:%x",
- Address[0], Address[1], Address[2], Address[3],
- Address[4], Address[5], Address[6], Address[7]
+ ntohs(Address[0]), ntohs(Address[1]), ntohs(Address[2]), ntohs(Address[3]),
+ ntohs(Address[4]), ntohs(Address[5]), ntohs(Address[6]), ntohs(Address[7])
);
return ret;
#include <stdlib.h>
#include <stdio.h>
+
// === CODE ===
int SoMain(void)
{
if(Filename)
{
- int len = snprintf(NULL, 100, "/Devices/ip/routes/%i:%s/%s", AddrType, hexAddr, Filename);
+ int len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
char path[len+1];
- snprintf(path, 100, "/Devices/ip/routes/%i:%s/%s", AddrType, hexAddr, Filename);
+ snprintf(path, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
return open(path, OPENFLAG_READ|OPENFLAG_WRITE);
}
else
{
- int len = snprintf(NULL, 100, "/Devices/ip/routes/%i:%s", AddrType, hexAddr);
+ int len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
char path[len+1];
- snprintf(path, 100, "/Devices/ip/routes/%i:%s", AddrType, hexAddr);
+ snprintf(path, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
return open(path, OPENFLAG_READ);
}
}
// Check answer validity
if( routeNum > 0 ) {
- int len = sprintf(NULL, "/Devices/ip/routes/%i", routeNum);
+ int len = sprintf(NULL, "/Devices/ip/routes/#%i", routeNum);
char buf[len+1];
char *ret;
- sprintf(buf, "/Devices/ip/routes/%i", routeNum);
+ sprintf(buf, "/Devices/ip/routes/#%i", routeNum);
// Open route
fd = open(buf, 0);
- if( !fd ) return NULL; // Shouldn't happen :/
+ if( fd == -1 ) {
+ fprintf(stderr, "Net_GetInterface - ERROR: Unabel to open %s\n", buf);
+ return NULL; // Shouldn't happen :/
+ }
// Allocate space for name
ret = malloc( ioctl(fd, ioctl(fd, 3, "get_interface"), NULL) + 1 );
--- /dev/null
+/*
+ */
+#ifndef _ACESS_INTDEFS_H_
+#define _ACESS_INTDEFS_H_
+
+#define INT_MIN -0x80000000
+#define INT_MAX 0x7FFFFFFF
+
+typedef unsigned char __uint8_t;
+typedef unsigned short __uint16_t;
+typedef unsigned int __uint32_t;
+typedef unsigned long long __uint64_t;
+
+typedef signed char __int8_t;
+typedef signed short __int16_t;
+typedef signed int __int32_t;
+typedef signed long long __int64_t;
+
+#if ARCHDIR_is_x86
+typedef __int32_t __intptr_t;
+typedef __uint32_t __uintptr_t;
+#elif ARCHDIR_is_x86_64
+typedef __int64_t __intptr_t;
+typedef __uint64_t __uintptr_t;
+#elif ARCHDIR_is_armv7
+typedef __int32_t __intptr_t;
+typedef __uint32_t __uintptr_t;
+#else
+# error "Unknown pointer size"
+#endif
+
+//typedef uint64_t off_t;
+
+#endif
+
# define NULL ((void*)0)
#endif
+#define THREAD_EVENT_VFS 0x0001
+#define THREAD_EVENT_IPCMSG 0x0002
+#define THREAD_EVENT_SIGNAL 0x0004
+
#define OPENFLAG_EXEC 0x01
#define OPENFLAG_READ 0x02
#define OPENFLAG_WRITE 0x04
extern void sleep(void);
extern void yield(void);
extern int kill(int pid, int sig);
-extern void wait(int miliseconds);
+//extern void wait(int miliseconds);
+extern int _SysWaitEvent(int EventMask);
extern int waittid(int id, int *status);
extern int clone(int flags, void *stack);
extern int execve(char *path, char **argv, char **envp);
+extern int _SysSpawn(const char *Path, const char **argv, const char **envp, int nFDs, int *FDs);
extern int gettid(void);
extern int getpid(void);
extern int _SysSetFaultHandler(int (*Handler)(int));
// --- VFS ---
extern int chdir(const char *dir);
-extern int open(const char *path, int flags);
+extern int open(const char *path, int flags, ...);
extern int reopen(int fd, const char *path, int flags);
extern int close(int fd);
extern uint read(int fd, void *buffer, uint length);
extern int _SysOpenChild(int fd, char *name, int flags);
extern int _SysGetACL(int fd, t_sysACL *dest);
extern int _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options);
-extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errfds, time_t *timeout);
+extern int _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, time_t *timeout, int extraevents);
+#define select(nfs, rdfds, wrfds, erfds, timeout) _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0)
// --- IPC ---
extern int SysSendMessage(pid_t dest, uint length, const void *Data);
// TODO: Fully implement errno.h, make sure it matches the kernel one
+extern int _errno;
#define errno _errno
#define strerror(_x) "Unimplemented"
enum
{
- EINVAL
+ EOK,
+ EINVAL,
+ ERANGE,
+ ENODEV,
+ EBADF,
+ EINTR,
+ EAGAIN,
+ ENOMEM,
+
+ EADDRNOTAVAIL,
+ EINPROGRESS,
+
+ E_LAST
};
#endif
#ifndef _SIGNAL_H_
#define _SIGNAL_H_
+#define SIG_DFL ((void*)0)
+#define SIG_ERR ((void*)-1)
+#define SIGABRT 6
+
+#define SIGPIPE 1001
+#define SIGCHLD 1002
#endif
--- /dev/null
+#ifndef _STDDEF_H_
+#define _STDDEF_H_
+
+#ifndef NULL
+# define NULL ((void*)0)
+#endif
+
+typedef unsigned int size_t;
+
+#endif
#ifndef _STDINT_H_
#define _STDINT_H_
+#include "acess/intdefs.h"
+
#define INT_MIN -0x80000000
#define INT_MAX 0x7FFFFFFF
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef signed long long int64_t;
+typedef __uint8_t uint8_t;
+typedef __uint16_t uint16_t;
+typedef __uint32_t uint32_t;
+typedef __uint64_t uint64_t;
+typedef __int8_t int8_t;
+typedef __int16_t int16_t;
+typedef __int32_t int32_t;
+typedef __int64_t int64_t;
-#if ARCHDIR_is_x86
-typedef int32_t intptr_t;
-typedef uint32_t uintptr_t;
-#elif ARCHDIR_is_x86_64
-typedef int64_t intptr_t;
-typedef uint64_t uintptr_t;
-#elif ARCHDIR_is_armv7
-typedef int32_t intptr_t;
-typedef uint32_t uintptr_t;
-#else
-# error "Unknown pointer size"
-#endif
+typedef __intptr_t intptr_t;
+typedef __uintptr_t uintptr_t;
//typedef uint64_t off_t;
/* === CONSTANTS === */
#define EOF (-1)
+#define BUFSIZ 1024
/* --- Standard IO --- */
extern int printf(const char *format, ...);
extern void *realloc(void *__ptr, size_t __size);\r
extern int IsHeap(void *ptr);\r
\r
+/* --- Random --- */\r
+extern void srand(unsigned int seed);\r
+extern int rand(void);\r
+extern int rand_p(unsigned int *seedp);\r
+\r
#ifndef SEEK_CUR\r
# define SEEK_CUR 0\r
# define SEEK_SET 1\r
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_
-#include <stdint.h> /* Evil */
-#include <stddef.h>
+#include <acess/intdefs.h> /* Evil */
+#include "../stddef.h"
+;
typedef void *dev_t; /* TODO: How to identify a device with Acess */
-typedef uint64_t ino_t;
+typedef __uint64_t ino_t;
typedef unsigned int blksize_t;
-typedef uint64_t blkcnt_t;
+typedef __uint64_t blkcnt_t;
typedef unsigned int nlink_t;
-typedef uint32_t mode_t;
+typedef __uint32_t mode_t;
-typedef uint32_t uid_t;
-typedef uint32_t gid_t;
+typedef __uint32_t uid_t;
+typedef __uint32_t gid_t;
#define S_IFMT 0170000 /* type of file */
#define S_IFDIR 0040000 /* directory */
#ifndef _SYS_TYPES_H
#define _SYS_TYPES_H
+#include <acess/intdefs.h>
+
typedef struct stat t_fstat;
#define FD_SETSIZE 128
extern void FD_SET(int fd, fd_set *fdsetp);
extern int FD_ISSET(int fd, fd_set *fdsetp);
+typedef __uint8_t u_int8_t;
+typedef __uint16_t u_int16_t;
+typedef __uint32_t u_int32_t;
+
#include "../sys/stat.h"
#endif
#ifndef _TIME_H_
#define _TIME_H_
+#include <acess/intdefs.h>
+#include <sys/types.h> // time_t
+
struct tm
{
int tm_sec;
int tm_isdst;
};
+#define CLOCKS_PER_SEC 1000
+
+typedef signed long long clock_t;
+
+extern clock_t clock();
+
#endif
--- /dev/null
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#define O_RDWR (OPENFLAG_READ|OPENFLAG_WRITE)
+
+#include "acess/sys.h"
+
+
+#endif
+