From f4ea8dd4c261e7a3a10d768c01cd3a121b42a045 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 15 Oct 2011 08:19:45 +0800 Subject: [PATCH 1/1] Kernel/armv7 - Bugfixing, can get to user relocation now --- Kernel/arch/armv7/include/mm_virt.h | 8 +- Kernel/arch/armv7/include/proc.h | 4 - Kernel/arch/armv7/mm_virt.c | 133 +++++++++++++++++++++++++--- Kernel/arch/armv7/proc.S | 10 ++- Kernel/arch/armv7/proc.c | 40 ++++++++- Kernel/arch/armv7/start.S | 27 +++++- 6 files changed, 195 insertions(+), 27 deletions(-) diff --git a/Kernel/arch/armv7/include/mm_virt.h b/Kernel/arch/armv7/include/mm_virt.h index dc1ed3cf..c1f10deb 100644 --- a/Kernel/arch/armv7/include/mm_virt.h +++ b/Kernel/arch/armv7/include/mm_virt.h @@ -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) diff --git a/Kernel/arch/armv7/include/proc.h b/Kernel/arch/armv7/include/proc.h index 4d48f544..d6ef3d55 100644 --- a/Kernel/arch/armv7/include/proc.h +++ b/Kernel/arch/armv7/include/proc.h @@ -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 === diff --git a/Kernel/arch/armv7/mm_virt.c b/Kernel/arch/armv7/mm_virt.c index 1f10cd5c..2555b8a1 100644 --- a/Kernel/arch/armv7/mm_virt.c +++ b/Kernel/arch/armv7/mm_virt.c @@ -9,10 +9,11 @@ #include #include -#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); } diff --git a/Kernel/arch/armv7/proc.S b/Kernel/arch/armv7/proc.S index d1bb091f..801909c9 100644 --- a/Kernel/arch/armv7/proc.S +++ b/Kernel/arch/armv7/proc.S @@ -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 diff --git a/Kernel/arch/armv7/proc.c b/Kernel/arch/armv7/proc.c index ffc4b570..d61160f0 100644 --- a/Kernel/arch/armv7/proc.c +++ b/Kernel/arch/armv7/proc.c @@ -13,8 +13,11 @@ 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) diff --git a/Kernel/arch/armv7/start.S b/Kernel/arch/armv7/start.S index 089ead5d..ef6ac76a 100644 --- a/Kernel/arch/armv7/start.S +++ b/Kernel/arch/armv7/start.S @@ -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 -- 2.20.1