Kernel/armv7 - Bugfixing, can get to user relocation now
authorJohn Hodge <[email protected]>
Sat, 15 Oct 2011 00:19:45 +0000 (08:19 +0800)
committerJohn Hodge <[email protected]>
Sat, 15 Oct 2011 00:19:45 +0000 (08:19 +0800)
Kernel/arch/armv7/include/mm_virt.h
Kernel/arch/armv7/include/proc.h
Kernel/arch/armv7/mm_virt.c
Kernel/arch/armv7/proc.S
Kernel/arch/armv7/proc.c
Kernel/arch/armv7/start.S

index dc1ed3c..c1f10de 100644 (file)
@@ -7,13 +7,17 @@
 
 #include "options.h"
 
+#define USER_STACK_COMM    0x04000     // Pages to allocate up front
+#define USER_STACK_SIZE           0x10000      // Stack space
+#define USER_STACK_TOP 0x78000000
+
 #define MM_USER_MIN    0x00001000
 #define USER_LIB_MAX   0x70000000
-#define MM_KSTACK_BASE 0x70000000
-#define MM_KSTACK_END  0x7F000000
 #define MM_PPD_HANDLES 0x7F800000
 #define MM_TABLE1USER  0x7FC00000      // 2 GiB - 4 MiB
 #define MM_TABLE0USER  0x7FE00000      // 2 GiB - 2 MiB
+#define MM_KSTACK_BASE 0x7FE00000
+#define MM_KSTACK_END  0x80000000
 
 // Page Blocks are 12-bits wide (12 address bits used)
 // Hence, the table is 16KiB large (and must be so aligned)
index 4d48f54..d6ef3d5 100644 (file)
@@ -37,10 +37,6 @@ typedef struct {
        Uint32  Arg4;
        Uint32  Arg5;
        Uint32  Arg6;   // R6
-       Uint32  Unused[13-6];
-       Uint32  StackPointer;   // R13
-       Uint32  _lr;
-       Uint32  _ip;
 } tSyscallRegs;
 
 // === MACROS ===
index 1f10cd5..2555b8a 100644 (file)
@@ -9,10 +9,11 @@
 #include <mm_virt.h>
 #include <hal_proc.h>
 
-#define AP_KRW_ONLY    0x1
-#define AP_KRO_ONLY    0x5
-#define AP_RW_BOTH     0x3
-#define AP_RO_BOTH     0x6
+#define AP_KRW_ONLY    1       // Kernel page
+#define AP_KRO_ONLY    5       // Kernel RO page
+#define AP_RW_BOTH     3       // Standard RW
+#define AP_RO_BOTH     6       // COW Page
+#define AP_RO_USER     2       // User RO Page
 #define PADDR_MASK_LVL1        0xFFFFFC00
 
 // === IMPORTS ===
@@ -41,6 +42,8 @@ void  MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
  int   MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
  int   MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
  int   MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+tVAddr MM_NewUserStack(void);
+tPAddr MM_AllocateZero(tVAddr VAddr);
 tPAddr MM_AllocateRootTable(void);
 void   MM_int_CloneTable(Uint32 *DestEnt, int Table);
 tPAddr MM_Clone(void);
@@ -49,6 +52,7 @@ void  MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
 //void MM_DumpTables(tVAddr Start, tVAddr End);
 
 // === GLOBALS ===
+tPAddr giMM_ZeroPage;
 
 // === CODE ===
 int MM_InitialiseVirtual(void)
@@ -325,6 +329,8 @@ Uint MM_GetFlags(tVAddr VAddr)
        
        switch(pi.AP)
        {
+       case 0:
+               break;
        case AP_KRW_ONLY:
                ret |= MM_PFLAG_KERNEL;
                break;
@@ -334,6 +340,9 @@ Uint MM_GetFlags(tVAddr VAddr)
        case AP_RW_BOTH:
                break;
        case AP_RO_BOTH:
+               ret |= MM_PFLAG_COW;
+               break;
+       case AP_RO_USER:
                ret |= MM_PFLAG_RO;
                break;
        }
@@ -345,8 +354,37 @@ Uint MM_GetFlags(tVAddr VAddr)
 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
 {
        tMM_PageInfo    pi;
+       Uint    curFlags;
+       
        if( MM_int_GetPageInfo(VAddr, &pi) )
-               return;
+               return ;
+       
+       curFlags = MM_GetPhysAddr(VAddr);
+       if( (curFlags & Mask) == Flags )
+               return ;
+       curFlags &= ~Mask;
+       curFlags |= Flags;
+
+       if( curFlags & MM_PFLAG_COW )
+               pi.AP = AP_RO_BOTH;
+       else
+       {
+               switch(curFlags & (MM_PFLAG_KERNEL|MM_PFLAG_RO) )
+               {
+               case 0:
+                       pi.AP = AP_RW_BOTH;     break;
+               case MM_PFLAG_KERNEL:
+                       pi.AP = AP_KRW_ONLY;    break;
+               case MM_PFLAG_RO:
+                       pi.AP = AP_RO_USER;     break;
+               case MM_PFLAG_KERNEL|MM_PFLAG_RO:
+                       pi.AP = AP_KRO_ONLY;    break;
+               }
+       }
+       
+       pi.bExecutable = !!(curFlags & MM_PFLAG_EXEC);
+
+       MM_int_SetPageInfo(VAddr, &pi);
 }
 
 int MM_Map(tVAddr VAddr, tPAddr PAddr)
@@ -356,7 +394,10 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr)
        
        pi.PhysAddr = PAddr;
        pi.Size = 12;
-       pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
+       if(VAddr < USER_STACK_TOP)
+               pi.AP = AP_RW_BOTH;
+       else
+               pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
        pi.bExecutable = 1;
        if( MM_int_SetPageInfo(VAddr, &pi) ) {
                MM_DerefPhys(pi.PhysAddr);
@@ -374,7 +415,10 @@ tPAddr MM_Allocate(tVAddr VAddr)
        pi.PhysAddr = MM_AllocPhys();
        if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
        pi.Size = 12;
-       pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
+       if(VAddr < USER_STACK_TOP)
+               pi.AP = AP_RW_BOTH;
+       else
+               pi.AP = AP_KRW_ONLY;
        pi.bExecutable = 1;
        if( MM_int_SetPageInfo(VAddr, &pi) ) {
                MM_DerefPhys(pi.PhysAddr);
@@ -385,6 +429,21 @@ tPAddr MM_Allocate(tVAddr VAddr)
        return pi.PhysAddr;
 }
 
+tPAddr MM_AllocateZero(tVAddr VAddr)
+{
+       if( !giMM_ZeroPage ) {
+               giMM_ZeroPage = MM_Allocate(VAddr);
+               MM_RefPhys(giMM_ZeroPage);
+               memset((void*)VAddr, 0, PAGE_SIZE);
+       }
+       else {
+               MM_RefPhys(giMM_ZeroPage);
+               MM_Map(VAddr, giMM_ZeroPage);
+       }
+       MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
+       return giMM_ZeroPage;
+}
+
 void MM_Deallocate(tVAddr VAddr)
 {
        tMM_PageInfo    pi;
@@ -687,13 +746,59 @@ tVAddr MM_NewKStack(int bShared)
        return addr + ofs;
 }
 
+tVAddr MM_NewUserStack(void)
+{
+       tVAddr  addr, ofs;
+
+       addr = USER_STACK_TOP - USER_STACK_SIZE;
+       if( MM_GetPhysAddr(addr + PAGE_SIZE) ) {
+               Log_Error("MMVirt", "Unable to create initial user stack, addr %p taken",
+                       addr + PAGE_SIZE
+                       );
+               return 0;
+       }
+
+       // 1 guard page
+       for( ofs = PAGE_SIZE; ofs < USER_STACK_SIZE; ofs += PAGE_SIZE )
+       {
+               tPAddr  rv;
+               if(ofs >= USER_STACK_SIZE - USER_STACK_COMM)
+                       rv = MM_Allocate(addr + ofs);
+               else
+                       rv = MM_AllocateZero(addr + ofs);
+               if(rv == 0)
+               {
+                       while(ofs)
+                       {
+                               ofs -= PAGE_SIZE;
+                               MM_Deallocate(addr + ofs);
+                       }
+                       Log_Warning("MMVirt", "MM_NewUserStack: Unable to allocate");
+                       return 0;
+               }
+               MM_SetFlags(addr+ofs, 0, MM_PFLAG_KERNEL);
+       }
+       Log("Return %p", addr + ofs);
+       MM_DumpTables(0, 0x80000000);
+       return addr + ofs;
+}
+
 void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
 {
-       Log("%p => %8x - 0x%7x %i %x",
-               Start, Info->PhysAddr-Len, Len,
-               Info->Domain,
-               Info->AP
-               );
+       if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
+       {
+               Log("%p => %8s - 0x%7x %i %x",
+                       Start, "ZERO", Len,
+                       Info->Domain, Info->AP
+                       );
+       }
+       else
+       {
+               Log("%p => %8x - 0x%7x %i %x",
+                       Start, Info->PhysAddr-Len, Len,
+                       Info->Domain, Info->AP
+                       );
+       }
 }
 
 void MM_DumpTables(tVAddr Start, tVAddr End)
@@ -724,7 +829,9 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
                }
                
                pi_old = pi;
-               pi_old.PhysAddr += 1 << pi_old.Size;
+               // Handle the zero page
+               if( !giMM_ZeroPage || pi_old.Size != 12 || pi_old.PhysAddr != giMM_ZeroPage )
+                       pi_old.PhysAddr += 1 << pi_old.Size;
                addr += 1 << pi_old.Size;
                inRange = (rv == 0);
        }
index d1bb091..801909c 100644 (file)
@@ -35,6 +35,14 @@ KernelThreadHeader:
        bl Threads_Exit
        b .
 
+.globl Proc_int_DropToUser
+@ R0: User IP
+@ R1: User SP
+Proc_int_DropToUser:
+       cps #16
+       mov sp, r1
+       mov pc, r0
+
 .globl SwitchTask
 @ R0: New stack
 @ R1: Pointer to where to save old stack
@@ -61,7 +69,7 @@ SwitchTask:
        bx r2
 
 .return:
-       push {r4-r12,pc}
+       pop {r4-r12,pc}
 
 .extern MM_Clone
 .extern MM_DumpTables
index ffc4b57..d61160f 100644 (file)
 extern tThread gThreadZero;
 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;
 extern Uint32  Proc_CloneInt(Uint32 *SP, Uint32 *MemPtr);
 extern tVAddr  MM_NewKStack(int bGlobal);      // TODO: Move out into a header
+extern tVAddr  MM_NewUserStack(void);
+extern char    kernel_table0[];
 
 // === PROTOTYPES ===
 void   Proc_IdleThread(void *unused);
@@ -27,6 +30,7 @@ tThread *gpIdleThread = NULL;
 // === CODE ===
 void ArchThreads_Init(void)
 {
+       gThreadZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
 }
 
 void Proc_IdleThread(void *unused)
@@ -57,11 +61,39 @@ tThread *Proc_GetCurThread(void)
        return gpCurrentThread;
 }
 
-void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
 {
-       Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Bases=%p, ArgC=%i, ...)",
-               Entrypoint, Bases, ArgC);
-       Log_Error("Proc", "TODO: Implement Proc_StartUser");
+       Uint32  *usr_sp;
+        int    i;
+       char    **envp;
+       tVAddr  delta;
+
+       Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
+               Entrypoint, Base, ArgC, ArgV, DataSize);
+
+       // Write data to the user's stack
+       usr_sp = (void*)MM_NewUserStack();
+       usr_sp -= (DataSize+3)/4;
+       memcpy(usr_sp, ArgV, DataSize);
+       free(ArgV);
+
+       // Adjust user's copy of the arguments
+       delta = (tVAddr)usr_sp -  (tVAddr)ArgV;
+       Log("delta = %x", delta);
+       ArgV = (void*)usr_sp;
+       for(i = 0; ArgV[i]; i ++)       ArgV[i] += delta;
+       envp = &ArgV[i+1];
+       for(i = 0; envp[i]; i ++)       envp[i] += delta;
+       Log("envp = %p", envp);
+       
+       *--usr_sp = (Uint32)envp;
+       *--usr_sp = (Uint32)ArgV;
+       *--usr_sp = (Uint32)ArgC;
+       *--usr_sp = Base;
+       
+       // Drop to user code
+       Log_Debug("Proc", "Proc_int_DropToUser(%p, %p)", Entrypoint, usr_sp);
+       Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
 }
 
 tTID Proc_Clone(Uint Flags)
index 089ead5..ef6ac76 100644 (file)
@@ -9,7 +9,7 @@
 interrupt_vector_table:
 ivt_reset:     b _start @ Reset
 ivt_undef:     b .     @ #UD
-ivt_svc:       b SyscallHandler @ SVC (SWI assume)
+ivt_svc:       b SVC_Handler @ SVC (used to be called SWI)
 ivt_prefetch:  b PrefetchAbort @ Prefetch abort
 ivt_data:      b DataAbort     @ Data abort
 ivt_unused:    b .     @ Not Used
@@ -65,8 +65,29 @@ _ptr_kmain:
 .comm irqstack, 0x1000 @ ; 4KiB Stack
 .comm abortstack, 0x1000       @ ; 4KiB Stack
 
-SyscallHandler:
-       b .
+.extern SyscallHandler
+SVC_Handler:
+@      sub lr, #4
+       srsdb sp!, #19  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+       cpsid ifa, #19
+       push {r0-r12}
+
+       ldr r4, [lr,#-4]
+       mvn r5, #0xFF000000
+       and r4, r5
+
+       push {r4}
+
+       mov r0, sp
+       ldr r4, =SyscallHandler
+       blx r4
+       
+       pop {r2}        @ errno
+       pop {r0,r1}     @ Ret/RetHi
+       add sp, #2*4    @ Saved r2/r3
+       
+       pop {r4-r12}
+       rfeia sp!       @ Pop state (actually RFEFD)
 
 .globl gpIRQHandler
 gpIRQHandler:  .long   0

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