Kernel/x86_64 - Implemented SYSCALL in x86_64 port
[tpg/acess2.git] / Kernel / arch / x86_64 / proc.c
index 5739470..f7d6f92 100644 (file)
@@ -5,20 +5,22 @@
 #include <acess.h>
 #include <proc.h>
 #include <threads.h>
+#include <threads_int.h>
 #include <desctab.h>
 #include <mm_virt.h>
 #include <errno.h>
 #if USE_MP
 # include <mp.h>
 #endif
+#include <arch_config.h>
+#include <hal_proc.h>
 
 // === FLAGS ===
 #define DEBUG_TRACE_SWITCH     0
+//#define BREAK_ON_SWITCH      1       // Break into bochs debugger on a task switch
 
 // === CONSTANTS ===
 #define        SWITCH_MAGIC    0x55ECAFFF##FFFACE55    // There is no code in this area
-// Base is 1193182
-#define TIMER_DIVISOR  11931   //~100Hz
 
 // === TYPES ===
 typedef struct sCPU
@@ -42,27 +44,32 @@ extern int  giNextTID;
 extern int     giTotalTickets;
 extern int     giNumActiveThreads;
 extern tThread gThreadZero;
-//extern tThread       *Threads_GetNextToRun(int CPU);
 extern void    Threads_Dump(void);
-extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
 extern void    Proc_ReturnToUser(void);
-extern int     GetCPUNum(void);
+extern void    Time_UpdateTimestamp(void);
 
 // === PROTOTYPES ===
-void   ArchThreads_Init(void);
+//void ArchThreads_Init(void);
 #if USE_MP
 void   MP_StartAP(int CPU);
 void   MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
 #endif
-void   Proc_Start(void);
-tThread        *Proc_GetCurThread(void);
+//void Proc_Start(void);
+//tThread      *Proc_GetCurThread(void);
 void   Proc_ChangeStack(void);
- int   Proc_Clone(Uint *Err, Uint Flags);
+// int Proc_Clone(Uint *Err, Uint Flags);
+// int Proc_SpawnWorker(void);
+Uint   Proc_MakeUserStack(void);
+//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
 void   Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP);
-void   Proc_CallFaultHandler(tThread *Thread);
+ int   Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
+//void Proc_CallFaultHandler(tThread *Thread);
+//void Proc_DumpThreadCPUState(tThread *Thread);
 void   Proc_Scheduler(int CPU);
 
 // === GLOBALS ===
+//!\brief Used by desctab.asm in SyscallStub
+const int ci_offsetof_tThread_KernelStack = offsetof(tThread, KernelStack);
 // --- Multiprocessing ---
 #if USE_MP
 volatile int   giNumInitingCPUs = 0;
@@ -283,10 +290,10 @@ void ArchThreads_Init(void)
        #if USE_MP
        }
        for(pos=0;pos<giNumCPUs;pos++) {
-       #endif
                __asm__ __volatile__ ("ltr %%ax"::"a"(0x38+pos*16));
-       #if USE_MP
        }
+       #else
+       __asm__ __volatile__ ("ltr %%ax"::"a"(0x38));
        #endif
        
        // Set Debug registers
@@ -300,11 +307,14 @@ void ArchThreads_Init(void)
        
        // Set timer frequency
        outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
-       outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
-       outb(0x40, (TIMER_DIVISOR>>8)&0xFF);    // High Byte
+       outb(0x40, PIT_TIMER_DIVISOR&0xFF);     // Low Byte of Divisor
+       outb(0x40, (PIT_TIMER_DIVISOR>>8)&0xFF);        // High Byte
        
        // Create Per-Process Data Block
-       MM_Allocate(MM_PPD_CFG);
+       if( !MM_Allocate(MM_PPD_CFG) )
+       {
+               Warning("Oh, hell, Unable to allocate PPD for Thread#0");
+       }
        
        // Change Stacks
        Proc_ChangeStack();
@@ -383,10 +393,10 @@ void Proc_Start(void)
        while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
        #else
        // Create Idle Task
-       if(Proc_Clone(0, 0) == 0)
+       if(Proc_Clone(0) == 0)
        {
                gaCPUs[0].IdleThread = Proc_GetCurThread();
-               gaCPUs[0].IdleThread->ThreadName = "Idle Thread";
+               gaCPUs[0].IdleThread->ThreadName = (char*)"Idle Thread";
                Threads_SetPriority( gaCPUs[0].IdleThread, -1 );        // Never called randomly
                gaCPUs[0].IdleThread->Quantum = 1;      // 1 slice quantum
                for(;;) HALT(); // Just yeilds
@@ -469,10 +479,10 @@ void Proc_ChangeStack(void)
 }
 
 /**
- * \fn int Proc_Clone(Uint *Err, Uint Flags)
+ * \fn int Proc_Clone(Uint Flags)
  * \brief Clone the current process
  */
-int Proc_Clone(Uint *Err, Uint Flags)
+int Proc_Clone(Uint Flags)
 {
        tThread *newThread;
        tThread *cur = Proc_GetCurThread();
@@ -481,7 +491,7 @@ int Proc_Clone(Uint *Err, Uint Flags)
        __asm__ __volatile__ ("mov %%rsp, %0": "=r"(rsp));
        __asm__ __volatile__ ("mov %%rbp, %0": "=r"(rbp));
        
-       newThread = Threads_CloneTCB(Err, Flags);
+       newThread = Threads_CloneTCB(NULL, Flags);
        if(!newThread)  return -1;
        
        Log("Proc_Clone: newThread = %p", newThread);
@@ -491,6 +501,7 @@ int Proc_Clone(Uint *Err, Uint Flags)
                Log("Proc_Clone: Cloning VM");
                newThread->MemState.CR3 = MM_Clone();
                newThread->KernelStack = cur->KernelStack;
+//             MAGIC_BREAK();
        } else {
                Uint    tmp_rbp, old_rsp = rsp;
 
@@ -534,6 +545,8 @@ int Proc_Clone(Uint *Err, Uint Flags)
        rip = GetRIP();
        if(rip == SWITCH_MAGIC) {
                outb(0x20, 0x20);       // ACK Timer and return as child
+               __asm__ __volatile__ ("sti");
+//             MAGIC_BREAK();
                return 0;
        }
        
@@ -582,13 +595,14 @@ int Proc_SpawnWorker(void)
        rip = GetRIP();
        if(rip == SWITCH_MAGIC) {
                outb(0x20, 0x20);       // ACK Timer and return as child
+               __asm__ __volatile__ ("sti");
                return 0;
        }
        
        // Set EIP as parent
        new->SavedState.RIP = rip;
        // Mark as active
-       new->Status = THREAD_STAT_ACTIVE;
+       new->Status = THREAD_STAT_PREINIT;
        Threads_AddActive( new );
        
        return new->TID;
@@ -611,8 +625,17 @@ Uint Proc_MakeUserStack(void)
        if(i != -1)     return 0;
        
        // Allocate Stack - Allocate incrementally to clean up MM_Dump output
-       for( i = 0; i < USER_STACK_SZ/4069; i++ )
-               MM_Allocate( base + (i<<12) );
+       for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
+       {
+               if( !MM_Allocate( base + (i<<12) ) )
+               {
+                       // Error
+                       Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
+                       while( i -- )
+                               MM_Deallocate( base + (i<<12) );
+                       return 0;
+               }
+       }
        
        return base + USER_STACK_SZ;
 }
@@ -666,20 +689,22 @@ void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
        *--stack = CS;          //Code Segment
        *--stack = IP;  //EIP
        //PUSHAD
-       *--stack = 0xAAAAAAAA;  // eax
-       *--stack = 0xCCCCCCCC;  // ecx
-       *--stack = 0xDDDDDDDD;  // edx
-       *--stack = 0xBBBBBBBB;  // ebx
-       *--stack = 0xD1D1D1D1;  // edi
-       *--stack = 0x54545454;  // rsp - NOT POPED
-       *--stack = 0x51515151;  // esi
-       *--stack = 0xB4B4B4B4;  // rbp
+//     *--stack = 0xAAAAAAAA;  // rax
+//     *--stack = 0xCCCCCCCC;  // rcx
+//     *--stack = 0xDDDDDDDD;  // rdx
+//     *--stack = 0xBBBBBBBB;  // rbx
+//     *--stack = 0xD1D1D1D1;  // rdi
+//     *--stack = 0x54545454;  // rsp - NOT POPED
+//     *--stack = 0x51515151;  // rsi
+//     *--stack = 0xB4B4B4B4;  // rbp
        //Individual PUSHs
-       *--stack = SS;  // ds
-       
+//     *--stack = SS;  // ds
+
+       MAGIC_BREAK();  
        __asm__ __volatile__ (
-       "mov %%rax,%%rsp;\n\t"  // Set stack pointer
-       "iret;\n\t" : : "a" (stack));
+               "mov %%rax,%%rsp;\n\t"  // Set stack pointer
+               "iretq;\n\t" : : "a" (stack)
+               );
        for(;;);
 }
 
@@ -724,6 +749,11 @@ void Proc_CallFaultHandler(tThread *Thread)
        for(;;);
 }
 
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       Log("  At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
+}
+
 /**
  * \fn void Proc_Scheduler(int CPU)
  * \brief Swap current thread and clears dead threads
@@ -732,29 +762,46 @@ void Proc_Scheduler(int CPU)
 {
        Uint    rsp, rbp, rip;
        tThread *thread;
+
+       if( CPU == 0 )
+               Time_UpdateTimestamp();
        
        // If the spinlock is set, let it complete
        if(IS_LOCKED(&glThreadListLock))        return;
        
        // Get current thread
        thread = gaCPUs[CPU].Current;
-       
-       // Reduce remaining quantum and continue timeslice if non-zero
-       if(thread->Remaining--) return;
-       // Reset quantum for next call
-       thread->Remaining = thread->Quantum;
-       
-       // Get machine state
-       __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
-       __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
-       rip = GetRIP();
-       if(rip == SWITCH_MAGIC) return; // Check if a switch happened
-       
-       // Save machine state
-       thread->SavedState.RSP = rsp;
-       thread->SavedState.RBP = rbp;
-       thread->SavedState.RIP = rip;
-       
+
+       if( thread )
+       {
+               tRegs   *regs;
+               // Reduce remaining quantum and continue timeslice if non-zero
+               if(thread->Remaining--) return;
+               // Reset quantum for next call
+               thread->Remaining = thread->Quantum;
+       
+               // Get machine state
+               __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
+               __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
+               rip = GetRIP();
+               if(rip == SWITCH_MAGIC) return; // Check if a switch happened
+               
+               // Save machine state
+               thread->SavedState.RSP = rsp;
+               thread->SavedState.RBP = rbp;
+               thread->SavedState.RIP = rip;
+               
+               // TODO: Make this more stable somehow
+               regs = (tRegs*)(rbp+(2+1)*8);   // RBP,Ret + CurThread
+               thread->SavedState.UserCS = regs->CS;
+               thread->SavedState.UserRIP = regs->RIP;
+       }
+
+       #if BREAK_ON_SWITCH
+       {
+       tThread *oldthread = thread;
+       #endif
+
        // Get next thread
        thread = Threads_GetNextToRun(CPU, thread);
        
@@ -762,9 +809,18 @@ void Proc_Scheduler(int CPU)
        if(thread == NULL) {
                thread = gaCPUs[CPU].IdleThread;
                //Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
-               //LogF("Zzzzz.\n");
-               return;
+//             LogF("Zzzzz.\n");
+               //return;
+       }
+       if(thread == NULL ) {
+               return ;
        }
+       #if BREAK_ON_SWITCH
+       if( thread != oldthread ) {
+               MAGIC_BREAK();
+       }
+       }
+       #endif
        
        #if DEBUG_TRACE_SWITCH
        LogF("Switching to task %i, CR3 = 0x%x, RIP = %p",
@@ -783,16 +839,15 @@ void Proc_Scheduler(int CPU)
        // Update Kernel Stack pointer
        gTSSs[CPU].RSP0 = thread->KernelStack-4;
        
-       // Set address space
-       __asm__ __volatile__ ("mov %0, %%cr3"::"a"(thread->MemState.CR3));
-       
        // Switch threads
        __asm__ __volatile__ (
+               "mov %4, %%cr3\n\t"
                "mov %1, %%rsp\n\t"     // Restore RSP
                "mov %2, %%rbp\n\t"     // and RBP
                "jmp *%3" : :   // And return to where we saved state (Proc_Clone or Proc_Scheduler)
-               "a"(SWITCH_MAGIC), "b"(thread->SavedState.RSP),
-               "d"(thread->SavedState.RBP), "c"(thread->SavedState.RIP)
+               "a"(SWITCH_MAGIC), "r"(thread->SavedState.RSP),
+               "r"(thread->SavedState.RBP), "r"(thread->SavedState.RIP),
+               "r"(thread->MemState.CR3)
                );
        for(;;);        // Shouldn't reach here
 }

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