typedef struct {
Uint EIP, ESP, EBP;
+ Uint32 UserCS, UserEIP;
} tTaskState;
// === FUNCTIONS ===
+extern void Debug_PutCharDebug(char ch);
+extern void Debug_PutStringDebug(const char *String);
+
extern int IS_LOCKED(struct sShortSpinlock *Lock);
extern int CPU_HAS_LOCK(struct sShortSpinlock *Lock);
extern void SHORTLOCK(struct sShortSpinlock *Lock);
#ifndef _PROC_H
#define _PROC_H
-#include <threads.h>
+#include <threads_int.h>
// === TYPES ==
typedef struct sTSS {
* lib.c
*/
#include <acess.h>
-#include <threads.h>
+#include <threads_int.h>
#define TRACE_LOCKS 0
+#define DEBUG_TO_E9 1
+#define DEBUG_TO_SERIAL 1
+#define SERIAL_PORT 0x3F8
+#define GDB_SERIAL_PORT 0x2F8
+
+// === IMPRORTS ===
#if TRACE_LOCKS
extern struct sShortSpinlock glDebug_Lock;
#endif
-
-// === IMPRORTS ===
extern int GetCPUNum(void);
// === PROTOTYPES ==
Uint64 __udivdi3(Uint64 Num, Uint64 Den);
Uint64 __umoddi3(Uint64 Num, Uint64 Den);
+// === GLOBALS ===
+ int gbDebug_SerialSetup = 0;
+ int gbGDB_SerialSetup = 0;
+
// === CODE ===
/**
* \brief Determine if a short spinlock is locked
#endif
}
+// === DEBUG IO ===
+#if USE_GDB_STUB
+int putDebugChar(char ch)
+{
+ if(!gbGDB_SerialSetup) {
+ outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
+ outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
+ outb(GDB_SERIAL_PORT + 1, 0x00); // (base is (hi byte)
+ outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit (8N1)
+ outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
+ outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+ gbDebug_SerialSetup = 1;
+ }
+ while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
+ outb(GDB_SERIAL_PORT, ch);
+ return 0;
+}
+int getDebugChar(void)
+{
+ if(!gbGDB_SerialSetup) {
+ outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
+ outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
+ outb(GDB_SERIAL_PORT + 1, 0x00); // (hi byte)
+ outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
+ outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+ gbDebug_SerialSetup = 1;
+ }
+ while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0) ;
+ return inb(GDB_SERIAL_PORT);
+}
+#endif /* USE_GDB_STUB */
+
+void Debug_PutCharDebug(char ch)
+{
+ #if DEBUG_TO_E9
+ __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
+ #endif
+
+ #if DEBUG_TO_SERIAL
+ if(!gbDebug_SerialSetup) {
+ outb(SERIAL_PORT + 1, 0x00); // Disable all interrupts
+ outb(SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outb(SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
+ outb(SERIAL_PORT + 1, 0x00); // (hi byte)
+ outb(SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outb(SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
+ outb(SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+ gbDebug_SerialSetup = 1;
+ }
+ while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
+ outb(SERIAL_PORT, ch);
+ #endif
+}
+
+void Debug_PutStringDebug(const char *String)
+{
+ while(*String)
+ Debug_PutCharDebug(*String++);
+}
+
// === IO Commands ===
void outb(Uint16 Port, Uint8 Data)
{
push fs
push gs
+ pushf
+ and BYTE [esp+1], 0xFE ; Clear Trap Flag
+ popf
+
mov eax, dr0
push eax ; Debug Register 0, Current Thread
pop ds
popa
- add esp, 4 ; CPU ID
+ add esp, 4*2 ; CPU ID + Dummy error code
; No Error code / int num
iret
; In child, so now set up stack frame
mov ebx, [esp+4] ; Child Function
mov edx, [esp+8] ; Argument
- ; Child
+ ; Child Function
push edx ; Argument
call ebx ; Function
+ ; Kill thread once done
push eax ; Exit Code
push 0 ; Kill this thread
call Threads_Exit ; Kill Thread
.justKillIt:
xor eax, eax
xor ebx, ebx
- dec ebx
+ dec ebx ; EBX = -1
int 0xAC
[global GetCPUNum]
mov eax, dr1
ret
+[extern GetEIP]
+[global GetEIP_Sched]
+[global GetEIP_Sched_ret]
+GetEIP_Sched_ret equ GetEIP_Sched.ret
+GetEIP_Sched:
+ call GetEIP
+GetEIP_Sched.ret:
+ ret
+
; Usermode code exported by the kernel
[section .usertext]
; Export a place for the user to jump to to call a syscall
#endif
// === FLAGS ===
-#define DEBUG_TRACE_SWITCH 0
+#define DEBUG_TRACE_SWITCH 1
#define DEBUG_DISABLE_DOUBLEFAULT 1
// === CONSTANTS ===
extern void APWait(void); // 16-bit AP pause code
extern void APStartup(void); // 16-bit AP startup code
extern Uint GetEIP(void); // start.asm
+extern Uint GetEIP_Sched(void); // proc.asm
extern int GetCPUNum(void); // start.asm
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
extern void Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
extern void scheduler_return; // Return address in SchedulerBase
extern void IRQCommon; // Common IRQ handler code
+extern void IRQCommon_handled; // IRQCommon call return location
+extern void GetEIP_Sched_ret; // GetEIP call return location
// === PROTOTYPES ===
void ArchThreads_Init(void);
#else
giNumCPUs = 1;
gTSSs = &gTSS0;
- MM_FinishVirtualInit();
#endif
#if !DEBUG_DISABLE_DOUBLEFAULT
newThread->SavedState.EBP = ebp;
eip = GetEIP();
if(eip == SWITCH_MAGIC) {
- __asm__ __volatile__ ("mov %0, %%db0" : : "r" (newThread) );
+ //__asm__ __volatile__ ("mov %0, %%db0" : : "r" (newThread) );
#if USE_MP
// ACK the interrupt
if( GetCPUNum() )
new->SavedState.EBP = ebp;
eip = GetEIP();
if(eip == SWITCH_MAGIC) {
- __asm__ __volatile__ ("mov %0, %%db0" : : "r"(new));
+ //__asm__ __volatile__ ("mov %0, %%db0" : : "r"(new));
#if USE_MP
// ACK the interrupt
if(GetCPUNum())
void Proc_DumpThreadCPUState(tThread *Thread)
{
- Uint32 *stack = (void *)Thread->SavedState.EBP; // EBP = ESP after call and PUSH
-
if( Thread->CurCPU > -1 )
{
- Log(" Currently running");
+ int maxBacktraceDistance = 6;
+ tRegs *regs = NULL;
+ Uint32 *stack;
+
+ if( Thread->CurCPU != GetCPUNum() ) {
+ Log(" Currently running");
+ return ;
+ }
+
+ // Backtrace to find the IRQ entrypoint
+ // - This will usually only be called by an IRQ, so this should
+ // work
+ __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
+ while( maxBacktraceDistance -- )
+ {
+ // [ebp] = oldEbp
+ // [ebp+4] = retaddr
+
+ if( stack[1] == (tVAddr)&IRQCommon_handled ) {
+ regs = (void*)stack[2];
+ break;
+ }
+
+ stack = (void*)stack[0];
+ }
+
+ if( !regs ) {
+ Log(" Unable to find IRQ Entry");
+ return ;
+ }
+
+ Log(" at %04x:%08x", regs->cs, regs->eip);
return ;
}
if( diffFromClone > 0 && diffFromClone < 512 ) // When I last checked, GetEIP was at .+0x183
{
- // Just spawned full thread
Log(" Creating full thread");
return ;
}
if( diffFromSpawn > 0 && diffFromSpawn < 512 ) // When I last checked, GetEIP was at .+0x99
{
- // Just spawned worker thread
Log(" Creating worker thread");
return ;
}
if( diffFromScheduler > 0 && diffFromScheduler < 256 ) // When I last checked, GetEIP was at .+0x60
#else
- if( stack[1] == (Uint32)&IRQCommon + 25 )
+ Uint32 data[3];
+ MM_ReadFromAddrSpace(Thread->MemState.CR3, Thread->SavedState.EBP, data, 12);
+ if( data[1] == (Uint32)&IRQCommon + 25 )
{
- tRegs *regs = (void *) stack[2];
+ tRegs *regs = (void *) data[2];
Log(" oldebp = 0x%08x, ret = 0x%08x, regs = 0x%x",
- stack[0], stack[1], stack[2]
+ data[0], data[1], data[2]
);
// [EBP] = old EBP
// [EBP+0x04] = Return Addr
#endif
{
// Scheduled out
- tRegs *regs = (void *) &stack[4];
- Log(" oldebp = 0x%08x, ret = 0x%08x, cpu = %i, thread = 0x%x",
- stack[0], stack[1], stack[2], stack[3]);
- // [EBP] = old EBP
- // [EBP+0x04] = Return Addr
- // [EBP+0x08] = Arg 1 (CPU Number)
- // [EBP+0x0C] = Arg 2 (Thread)
- // [EBP+0x10] = GS (start of tRegs)
- Log(" At %02x:%08x", regs->cs, regs->eip);
+ Log(" At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
return ;
}
- Log(" Just created");
+ Log(" Just created (unknow %p)", Thread->SavedState.EIP);
}
/**
thread = gCurrentThread;
#endif
+ // NOTE:
+ // 2011-04-05
+ // Bug may be caused by DR0 not being maintained somewhere, hence
+ // login is getting loaded with the idle state.
if( thread )
{
+ tRegs *regs;
// Reduce remaining quantum and continue timeslice if non-zero
if( thread->Remaining-- )
return;
thread->SavedState.ESP = esp;
thread->SavedState.EBP = ebp;
thread->SavedState.EIP = eip;
+
+ // TODO: Make this more stable somehow
+ regs = (tRegs*)(ebp+(2+2)*4); // EBP,Ret + CPU,CurThread
+ thread->SavedState.UserCS = regs->cs;
+ thread->SavedState.UserEIP = regs->eip;
+
+ if(thread->bInstrTrace) {
+ regs->eflags |= 0x100; // Set TF
+ Log("%p De-scheduled", thread);
+ }
+ else
+ regs->eflags &= ~0x100; // Clear TF
}
// Get next thread to run
}
#endif
+ if( thread->bInstrTrace ) {
+ Log("%p Scheduled", thread);
+ }
+
#if USE_PAE
# error "Todo: Implement PAE Address space switching"
#else
+ // Set thread pointer
+ __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(thread) );
// Switch threads
__asm__ __volatile__ (
"mov %4, %%cr3\n\t" // Set address space
"mov %1, %%esp\n\t" // Restore ESP
"mov %2, %%ebp\n\t" // and EBP
+ "or %5, 72(%%ebp)\n\t" // or trace flag to eflags (2+2+4+8+2)*4
"jmp *%3" : : // And return to where we saved state (Proc_Clone or Proc_Scheduler)
"a"(SWITCH_MAGIC), "b"(thread->SavedState.ESP),
"d"(thread->SavedState.EBP), "c"(thread->SavedState.EIP),
- "r"(thread->MemState.CR3)
+ "r"(thread->MemState.CR3),
+ "r"(thread->bInstrTrace&&thread->SavedState.EIP==(Uint)&GetEIP_Sched_ret?0x100:0)
);
#endif
for(;;); // Shouldn't reach here
#include <acess.h>
#include <arch.h>
+#define DEBUG_TO_E9 1
+#define DEBUG_TO_SERIAL 1
+#define SERIAL_PORT 0x3F8
+#define GDB_SERIAL_PORT 0x2F8
+
// === IMPORTS ===
extern int GetCPUNum(void);
extern void *Proc_GetCurThread(void);
+// === GLOBALS ===
+ int gbDebug_SerialSetup = 0;
+ int gbGDB_SerialSetup = 0;
+
// === CODE ===
/**
* \brief Determine if a short spinlock is locked
#endif
}
+// === DEBUG IO ===
+int putDebugChar(char ch)
+{
+ if(!gbGDB_SerialSetup) {
+ outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
+ outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
+ outb(GDB_SERIAL_PORT + 1, 0x00); // (base is (hi byte)
+ outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit (8N1)
+ outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
+ outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+ gbDebug_SerialSetup = 1;
+ }
+ while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
+ outb(GDB_SERIAL_PORT, ch);
+ return 0;
+}
+int getDebugChar(void)
+{
+ if(!gbGDB_SerialSetup) {
+ outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
+ outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
+ outb(GDB_SERIAL_PORT + 1, 0x00); // (hi byte)
+ outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
+ outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+ gbDebug_SerialSetup = 1;
+ }
+ while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0) ;
+ return inb(GDB_SERIAL_PORT);
+}
+
+void Debug_PutCharDebug(char ch)
+{
+ #if DEBUG_TO_E9
+ __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
+ #endif
+
+ #if DEBUG_TO_SERIAL
+ if(!gbDebug_SerialSetup) {
+ outb(SERIAL_PORT + 1, 0x00); // Disable all interrupts
+ outb(SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outb(SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
+ outb(SERIAL_PORT + 1, 0x00); // (hi byte)
+ outb(SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outb(SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
+ outb(SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
+ gbDebug_SerialSetup = 1;
+ }
+ while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
+ outb(SERIAL_PORT, ch);
+ #endif
+}
+
+// === PORT IO ===
void outb(Uint16 Port, Uint8 Data)
{
__asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
#include <acess.h>
#include <stdarg.h>
-#define DEBUG_TO_E9 1
-#define DEBUG_TO_SERIAL 1
-#define SERIAL_PORT 0x3F8
-#define GDB_SERIAL_PORT 0x2F8
#define DEBUG_MAX_LINE_LEN 256
#define LOCK_DEBUG_OUTPUT 1
extern void KernelPanic_PutChar(char Ch);
// === PROTOTYPES ===
- int putDebugChar(char ch);
- int getDebugChar(void);
static void Debug_Putchar(char ch);
static void Debug_Puts(int DbgOnly, const char *Str);
void Debug_DbgOnlyFmt(const char *format, va_list args);
// === GLOBALS ===
int gDebug_Level = 0;
int giDebug_KTerm = -1;
- int gbDebug_SerialSetup = 0;
- int gbGDB_SerialSetup = 0;
int gbDebug_IsKPanic = 0;
volatile int gbInPutChar = 0;
#if LOCK_DEBUG_OUTPUT
#endif
// === CODE ===
-int putDebugChar(char ch)
-{
- if(!gbGDB_SerialSetup) {
- outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
- outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
- outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
- outb(GDB_SERIAL_PORT + 1, 0x00); // (base is (hi byte)
- outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit (8N1)
- outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
- outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
- gbDebug_SerialSetup = 1;
- }
- while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
- outb(GDB_SERIAL_PORT, ch);
- return 0;
-}
-int getDebugChar(void)
-{
- if(!gbGDB_SerialSetup) {
- outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
- outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
- outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
- outb(GDB_SERIAL_PORT + 1, 0x00); // (hi byte)
- outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
- outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
- outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
- gbDebug_SerialSetup = 1;
- }
- while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0) ;
- return inb(GDB_SERIAL_PORT);
-}
-
-static void Debug_PutCharDebug(char ch)
-{
- #if DEBUG_TO_E9
- __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
- #endif
-
- #if DEBUG_TO_SERIAL
- if(!gbDebug_SerialSetup) {
- outb(SERIAL_PORT + 1, 0x00); // Disable all interrupts
- outb(SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
- outb(SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
- outb(SERIAL_PORT + 1, 0x00); // (hi byte)
- outb(SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
- outb(SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
- outb(SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
- gbDebug_SerialSetup = 1;
- }
- while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
- outb(SERIAL_PORT, ch);
- #endif
-}
-
static void Debug_Putchar(char ch)
{
Debug_PutCharDebug(ch);
static void Debug_Puts(int UseKTerm, const char *Str)
{
int len = 0;
- while( *Str )
- {
- Debug_PutCharDebug( *Str );
-
- if( gbDebug_IsKPanic )
- KernelPanic_PutChar(*Str);
- len ++;
- Str ++;
- }
- Str -= len;
+ Debug_PutStringDebug(Str);
+
+ if( gbDebug_IsKPanic )
+ {
+ for( len = 0; Str[len]; len ++ )
+ KernelPanic_PutChar( Str[len] );
+ }
+ else
+ for( len = 0; Str[len]; len ++ );
+ // Output to the kernel terminal
if( UseKTerm && !gbDebug_IsKPanic && giDebug_KTerm != -1)
{
if(gbInPutChar) return ;
}
/**
* \fn void Debug(const char *Msg, ...)
- * \brief Print only to the debug channel
+ * \brief Print only to the debug channel (not KTerm)
*/
void Debug(const char *Fmt, ...)
{
#define USE_KERNEL_MAGIC 1
// === IMPORTS ===
-void Threads_Dump(void);
-void Heap_Stats(void);
+extern void Threads_ToggleTrace(int TID);
+extern void Threads_Dump(void);
+extern void Heap_Stats(void);
// === PROTOTYPES ===
int KB_Install(char **Arguments);
case '8': case '9': case 'a': case 'b':
case 'c': case 'd': case 'e': case 'f':
{
- char str[2] = {ch,0};
- if(giKB_MagicAddressPos == BITS/4) break;
+ char str[4] = {'0', 'x', ch, 0};
+ if(giKB_MagicAddressPos == BITS/4) return;
giKB_MagicAddress |= atoi(str) << giKB_MagicAddressPos;
giKB_MagicAddressPos ++;
}
- break;
+ return;
+
+ // Instruction Tracing
+ case 't':
+ Log("Toggle instruction tracing on %i\n", giKB_MagicAddress);
+ Threads_ToggleTrace( giKB_MagicAddress );
+ giKB_MagicAddress = 0; giKB_MagicAddressPos = 0;
+ return;
// Thread List Dump
case 'p': Threads_Dump(); return;
}
#endif
- // Is shift pressed
- // - Darn ugly hacks !!x means (bool)x
- if( !!gbKB_ShiftState ^ gbKB_CapsState)
+ // Capitals required?
+ if( (gbKB_ShiftState != 0) != (gbKB_CapsState != 0))
{
+ // TODO: Move this to the keyboard map header
switch(ch)
{
case 0: break;
child->Node.ReadDir = SysFS_Comm_ReadDir;
child->Node.FindDir = SysFS_Comm_FindDir;
if( !prev ) {
- //if(ent)
+ if(ent)
ent->Node.ImplPtr = child;
- //else
- // gSysFS_DriverInfo.RootNode.ImplPtr = child;
+ else
+ gSysFS_DriverInfo.RootNode.ImplPtr = child;
// ^^^ Impossible (There is already /Version)
}
else
child = ent->Node.ImplPtr;
else
child = gSysFS_DriverInfo.RootNode.ImplPtr;
- for( child = ent->Node.ImplPtr; child; prev = child, child = child->Next )
+ for( ; child; child = child->Next )
{
if( strcmp( &Path[start], child->Name ) == 0 )
break;
parent = file->Parent;
// Remove from file list
- prev->ListNext = file->ListNext;
+ if(prev)
+ prev->ListNext = file->ListNext;
+ else
+ gSysFS_FileList = file->ListNext;
file->Node.Size = 0;
file->Node.ImplPtr = NULL;
#include <errno.h>
#include <semaphore.h>
-#define USE_CTRL_ALT 0
+#define USE_CTRL_ALT 1
// === CONSTANTS ===
#define VERSION ((0<<8)|(50))
int InputRead; //!< Input buffer read position
int InputWrite; //!< Input buffer write position
char InputBuffer[MAX_INPUT_CHARS8];
- tSemaphore InputSemaphore;
+// tSemaphore InputSemaphore;
tVT_Char *Text;
Uint32 *Buffer;
Log_Debug("VTerm", "Argument '%s'", arg);
if( strcmp(opt, "Video") == 0 ) {
- gsVT_OutputDevice = strdup(val);
+ if( !gsVT_OutputDevice && Modules_InitialiseBuiltin( val ) == 0 )
+ gsVT_OutputDevice = strdup(val);
}
else if( strcmp(opt, "Input") == 0 ) {
- gsVT_InputDevice = strdup(val);
+ if( !gsVT_InputDevice && Modules_InitialiseBuiltin( val ) == 0 )
+ gsVT_InputDevice = strdup(val);
}
else if( strcmp(opt, "Width") == 0 ) {
giVT_RealWidth = atoi( val );
}
}
- if(gsVT_OutputDevice) Modules_InitialiseBuiltin( gsVT_OutputDevice );
- if(gsVT_InputDevice) Modules_InitialiseBuiltin( gsVT_InputDevice );
-
// Apply Defaults
if(!gsVT_OutputDevice) gsVT_OutputDevice = strdup(DEFAULT_OUTPUT);
if(!gsVT_InputDevice) gsVT_InputDevice = strdup(DEFAULT_INPUT);
gVT_Terminals[i].Node.Read = VT_Read;
gVT_Terminals[i].Node.Write = VT_Write;
gVT_Terminals[i].Node.IOCtl = VT_Terminal_IOCtl;
- Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
+// Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
}
// Add to DevFS
{
if( gVT_Terminals[i].Mode != TERM_MODE_TEXT ) continue;
+ gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth;
+ gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight;
+
gVT_Terminals[i].Text = realloc(
gVT_Terminals[i].Text,
newBufSize*sizeof(tVT_Char)
#else
case KEY_LALT: gbVT_AltDown &= ~1; break;
case KEY_RALT: gbVT_AltDown &= ~2; break;
- case KEY_LCTRL: gbVT_CtrlDown &= ~1 break;
+ case KEY_LCTRL: gbVT_CtrlDown &= ~1; break;
case KEY_RCTRL: gbVT_CtrlDown &= ~2; break;
#endif
}
default:
Term->Text[ Term->WritePos ].Ch = Ch;
Term->Text[ Term->WritePos ].Colour = Term->CurColour;
+ // Update the line before wrapping
+ if( (Term->WritePos + 1) % Term->TextWidth == 0 )
+ VT_int_UpdateScreen( Term, 0 );
Term->WritePos ++;
break;
}
{
//Debug("Term->WritePos (%i) >= %i",
// Term->WritePos,
- // Term->ViewPos + Term->Width*Term->Height
+ // Term->ViewPos + Term->TextWidth*Term->TextHeight
// );
//Debug("Scrolling screen only");
//Debug("Term->ViewPos = %i", Term->ViewPos);
VT_int_ScrollFramebuffer( Term );
VT_int_UpdateScreen( Term, 0 );
+
+ //VT_int_UpdateScreen( Term, 1 ); // HACK!
}
//LEAVE('-');
break;
case VIDEO_2DOP_BLIT:
- if(rem < 16) return Length-rem;
+ if(rem < 12) return Length-rem;
if(!Handlers->Blit) {
Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
);
rem -= 16;
- stream = (void*)((tVAddr)stream + 16);
+ stream = (void*)((tVAddr)stream + 12);
break;
}
// Print the block info?
#if 1
- Log_Debug("Heap", "%p - 0x%x (%i) Owned by %s:%i",
- head, head->Size, head->ValidSize, head->File, head->Line);
+ Log_Debug("Heap", "%p (0x%x) - 0x%x (%i) Owned by %s:%i",
+ head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size, head->ValidSize, head->File, head->Line);
#endif
}
typedef Sint64 tTimestamp;
typedef Sint64 tTime;
typedef struct sShortSpinlock tShortSpinlock;
-typedef struct sMutex tMutex;
-
-struct sMutex {
- tShortSpinlock Protector; //!< Protector for the lock strucure
- const char *Name; //!< Human-readable name
- struct sThread *volatile Owner; //!< Owner of the lock (set upon getting the lock)
- struct sThread *Waiting; //!< Waiting threads
- struct sThread *LastWaiting; //!< Waiting threads
-};
// --- Helper Macros ---
/**
extern int strcmp(const char *__str1, const char *__str2);
extern int strncmp(const char *Str1, const char *Str2, size_t num);
extern int strucmp(const char *Str1, const char *Str2);
-//extern char *strdup(const char *Str);
-#define strdup(Str) _strdup(_MODULE_NAME_"/"__FILE__, __LINE__, (Str))
+// strdup macro is defined in heap.h
extern char *_strdup(const char *File, int Line, const char *Str);
extern char **str_split(const char *__str, char __ch);
extern char *strchr(const char *__s, int __c);
extern int SpawnTask(tThreadFunction Function, void *Arg);
extern Uint *Threads_GetCfgPtr(int Id);
extern int Threads_SetName(const char *NewName);
-extern int Mutex_Acquire(tMutex *Mutex);
-extern void Mutex_Release(tMutex *Mutex);
-extern int Mutex_IsLocked(tMutex *Mutex);
/**
* \}
*/
#include <binary_ext.h>
#include <vfs_ext.h>
#include <adt.h>
+#include <mutex.h>
#endif
#define free(ptr) Heap_Deallocate((ptr))
#define IsHeap(ptr) Heap_IsHeapAddr((ptr))
+#define strdup(Str) _strdup(_MODULE_NAME_"/"__FILE__, __LINE__, (Str))
+
#endif
--- /dev/null
+/*
+ * Acess2 Kernel
+ * mutex.h
+ * - Mutual Exclusion syncronisation primitive
+ */
+#ifndef _MUTEX_H
+#define _MUTEX_H
+
+#include <acess.h>
+
+typedef struct sMutex tMutex;
+
+struct sMutex
+{
+ tShortSpinlock Protector; //!< Protector for the lock strucure
+ const char *Name; //!< Human-readable name
+ struct sThread *volatile Owner; //!< Owner of the lock (set upon getting the lock)
+ struct sThread *Waiting; //!< Waiting threads
+ struct sThread *LastWaiting; //!< Waiting threads
+};
+
+/**
+ * \brief Acquire a heavy mutex
+ * \param Mutex Mutex to acquire
+ * \return zero on success, -1 if terminated
+ *
+ * This type of mutex checks if the mutex is avaliable, and acquires it
+ * if it is. Otherwise, the current thread is added to the mutex's wait
+ * queue and the thread suspends. When the holder of the mutex completes,
+ * the oldest thread (top thread) on the queue is given the lock and
+ * restarted.
+ */
+extern int Mutex_Acquire(tMutex *Mutex);
+
+/**
+ * \brief Release a held mutex
+ * \param Mutex Mutex to release
+ * \note Releasing a non-held mutex has no effect
+ */
+extern void Mutex_Release(tMutex *Mutex);
+
+/**
+ * \brief Is this mutex locked?
+ * \param Mutex Mutex pointer
+ */
+extern int Mutex_IsLocked(tMutex *Mutex);
+
+#endif
void Threads_AddActive(tThread *Thread);
tThread *Threads_RemActive(void);
#endif
+void Threads_ToggleTrace(int TID);
void Threads_Fault(int Num);
void Threads_SegFault(tVAddr Addr);
#if 0
#endif
void Threads_Dump(void);
void Threads_DumpActive(void);
-
#if 0
int Mutex_Acquire(tMutex *Mutex);
void Mutex_Release(tMutex *Mutex);
{
ArchThreads_Init();
+ Log_Debug("Threads", "Offsets of tThread");
+ Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority));
+
// Create Initial Task
#if SCHEDULER_TYPE == SCHED_RR_PRI
gaActiveThreads[gThreadZero.Priority] = &gThreadZero;
if(Thread == NULL) Thread = Proc_GetCurThread();
// Bounds checking
// - If < 0, set to lowest priority
+ // - Minumum priority is actualy a high number, 0 is highest
if(Pri < 0) Pri = MIN_PRIORITY;
if(Pri > MIN_PRIORITY) Pri = MIN_PRIORITY;
#if SCHEDULER_TYPE == SCHED_LOTTERY
giFreeTickets -= caiTICKET_COUNTS[Thread->Priority] - caiTICKET_COUNTS[Pri];
# if DEBUG_TRACE_TICKETS
- Log("Threads_SetTickets: new giFreeTickets = %i", giFreeTickets);
+ Log("Threads_SetTickets: new giFreeTickets = %i [-%i+%i]",
+ giFreeTickets,
+ caiTICKET_COUNTS[Thread->Priority], caiTICKET_COUNTS[Pri]);
# endif
#endif
Thread->Priority = Pri;
else
Thread->Priority = Pri;
#endif
+
+ #if DEBUG_TRACE_STATE
+ Log("Threads_SetPriority: %p(%i %s) pri set %i",
+ Thread, Thread->TID, Thread->ThreadName,
+ Pri);
+ #endif
}
/**
// Allocate and duplicate
new = malloc(sizeof(tThread));
- if(new == NULL) {
- *Err = -ENOMEM;
- return NULL;
- }
+ if(new == NULL) { *Err = -ENOMEM; return NULL; }
memcpy(new, cur, sizeof(tThread));
new->CurCPU = -1;
// Get Thread ID
new->TID = giNextTID++;
new->Parent = cur;
+ new->bInstrTrace = 0;
// Clone Name
new->ThreadName = strdup(cur->ThreadName);
// Set State
new->Remaining = new->Quantum = cur->Quantum;
new->Priority = cur->Priority;
+ new->bInstrTrace = 0;
// Set Signal Handlers
new->CurFaultNum = 0;
return ret;
}
+void Threads_ToggleTrace(int TID)
+{
+ tThread *thread = Threads_GetThread(TID);
+ if(!thread) return ;
+ thread->bInstrTrace = !thread->bInstrTrace;
+}
+
/**
* \brief Adds a thread to the active queue
*/
Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE);
Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum);
Log(" KStack 0x%x", thread->KernelStack);
+ if( thread->bInstrTrace )
+ Log(" Tracing Enabled");
Proc_DumpThreadCPUState(thread);
}
}
Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum);
Log(" KStack 0x%x", thread->KernelStack);
+ if( thread->bInstrTrace )
+ Log(" Tracing Enabled");
+ Proc_DumpThreadCPUState(thread);
}
}
}
#if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
else
- LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released)\n",
+ LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released,not in pool)\n",
CPU, Last, Last->TID, Last->ThreadName, Last->Status);
#endif
Last->CurCPU = -1;
return thread;
}
-/**
- * \brief Acquire a heavy mutex
- * \param Mutex Mutex to acquire
- *
- * This type of mutex checks if the mutex is avaliable, and acquires it
- * if it is. Otherwise, the current thread is added to the mutex's wait
- * queue and the thread suspends. When the holder of the mutex completes,
- * the oldest thread (top thread) on the queue is given the lock and
- * restarted.
- */
+// Acquire mutex (see mutex.h for documentation)
int Mutex_Acquire(tMutex *Mutex)
{
tThread *us = Proc_GetCurThread();
Mutex->Waiting = us;
Mutex->LastWaiting = us;
}
+
+ #if DEBUG_TRACE_STATE
+ Log("%p (%i %s) waiting on mutex %p",
+ us, us->TID, us->ThreadName, Mutex);
+ #endif
+
#if 0
{
int i = 0;
return 0;
}
-/**
- * \brief Release a held mutex
- * \param Mutex Mutex to release
- * \note Releasing a non-held mutex has no effect
- */
+// Release a mutex
void Mutex_Release(tMutex *Mutex)
{
SHORTLOCK( &Mutex->Protector );
#endif
}
-/**
- * \brief Is this mutex locked?
- * \param Mutex Mutex pointer
- */
+// Check if a mutex is locked
int Mutex_IsLocked(tMutex *Mutex)
{
return Mutex->Owner != NULL;
Sem->LastWaiting = us;
}
+ #if DEBUG_TRACE_STATE
+ Log("%p (%i %s) waiting on semaphore %p %s:%s",
+ us, us->TID, us->ThreadName,
+ Sem, Sem->ModName, Sem->Name);
+ #endif
+
SHORTREL( &glThreadListLock );
SHORTREL( &Sem->Protector );
while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield();
given = Sem->MaxValue - Sem->Value;
Sem->Value -= given;
+
+ #if DEBUG_TRACE_STATE
+ Log("%p (%i %s) woken by wait on %p %s:%s",
+ toWake, toWake->TID, toWake->ThreadName,
+ Sem, Sem->ModName, Sem->Name);
+ #endif
+
// Save the number we gave to the thread's status
toWake->RetStatus = given;
Sem->LastSignaling = us;
}
+ #if DEBUG_TRACE_STATE
+ Log("%p (%i %s) signaling semaphore %p %s:%s",
+ us, us->TID, us->ThreadName,
+ Sem, Sem->ModName, Sem->Name);
+ #endif
+
SHORTREL( &glThreadListLock );
SHORTREL( &Sem->Protector );
while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield();
{
tThread *toWake = Sem->Waiting;
+ // Remove thread from list (double ended, so clear LastWaiting if needed)
Sem->Waiting = Sem->Waiting->Next;
- // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
if( Sem->Waiting == NULL )
Sem->LastWaiting = NULL;
- // Figure out how much to give
+ // Figure out how much to give to woken thread
+ // - Requested count is stored in ->RetStatus
if( toWake->RetStatus && Sem->Value > toWake->RetStatus )
given = toWake->RetStatus;
else
// Save the number we gave to the thread's status
toWake->RetStatus = given;
+ if(toWake->bInstrTrace)
+ Log("%s(%i) given %i from %p", toWake->ThreadName, toWake->TID, given, Sem);
+ #if DEBUG_TRACE_STATE
+ Log("%p (%i %s) woken by signal on %p %s:%s",
+ toWake, toWake->TID, toWake->ThreadName,
+ Sem, Sem->ModName, Sem->Name);
+ #endif
+
// Wake the sleeper
SHORTLOCK( &glThreadListLock );
if( toWake->Status != THREAD_STAT_ACTIVE )
for( ; child && Pos--; child = child->Next ) ;
- if(Pos) return strdup(child->Name);
+ if(child) return strdup(child->Name);
return NULL;
}
strcpy(ret, cwd);
ret[cwdLen] = '/';
strcpy(&ret[cwdLen+1], Path);
- //Log("ret = '%s'\n", ret);
+ //Log("ret = '%s'", ret);
}
// Parse Path
// Get handle
h = VFS_GetHandle(FD);
if(h == NULL) {
- Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x\n", FD);
+ Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD);
return;
}
if( !Timeout || *Timeout > 0 )
{
ret = Semaphore_Wait(&thread_info->SleepHandle, 1);
+ // TODO: Do something with ret
}
// Fill output (modify *Handles)