From: John Hodge Date: Wed, 8 Feb 2012 06:59:58 +0000 (+0800) Subject: Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2 X-Git-Tag: rel0.15~789 X-Git-Url: https://git.ucc.asn.au/?p=tpg%2Facess2.git;a=commitdiff_plain;h=51ab5f489bc356940c95cc936fd0508e8f07ea97;hp=-c Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2 --- 51ab5f489bc356940c95cc936fd0508e8f07ea97 diff --combined KernelLand/Kernel/arch/armv7/mm_virt.c index 00000000,460b334f..90655b63 mode 000000,100644..100644 --- a/KernelLand/Kernel/arch/armv7/mm_virt.c +++ b/KernelLand/Kernel/arch/armv7/mm_virt.c @@@ -1,0 -1,1078 +1,1078 @@@ + /* + * Acess2 + * + * ARM7 Virtual Memory Manager + * - arch/arm7/mm_virt.c + */ + #define DEBUG 0 + #include + #include + #include + + #define TRACE_MAPS 0 + + #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 7 // COW Page + #define AP_RO_USER 2 // User RO Page + #define PADDR_MASK_LVL1 0xFFFFFC00 + + // === IMPORTS === + extern Uint32 kernel_table0[]; + + // === TYPES === + typedef struct + { + tPAddr PhysAddr; + Uint8 Size; + Uint8 Domain; + BOOL bExecutable; + BOOL bGlobal; + BOOL bShared; + int AP; + } tMM_PageInfo; + + //#define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>20)]) + #define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>22)]) + #define USRFRACTAL(addr) (*((Uint32*)(0x7FDFF000) + ((addr)>>22))) + #define TLBIALL() __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0)) -#define TLBIMVA(addr) __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1;dsb;isb" : : "r" ((addr)&~0xFFF):"memory") ++#define TLBIMVA(addr) __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1;dsb;isb" : : "r" (((addr)&~0xFFF)|1):"memory") + #define DCCMVAC(addr) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" ((addr)&~0xFFF)) + + // === PROTOTYPES === + 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); + tVAddr MM_NewKStack(int bGlobal); + void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info); + //void MM_DumpTables(tVAddr Start, tVAddr End); + void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch); + + // === GLOBALS === + tPAddr giMM_ZeroPage; + + // === CODE === + int MM_InitialiseVirtual(void) + { + return 0; + } + + void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1) + { + if(VAddr & 0x80000000) { + *Table0 = (void*)&kernel_table0; // Level 0 + *Table1 = (void*)MM_TABLE1KERN; // Level 1 + } + else { + *Table0 = (void*)MM_TABLE0USER; + *Table1 = (void*)MM_TABLE1USER; + } + } + + int MM_int_AllocateCoarse(tVAddr VAddr, int Domain) + { + Uint32 *table0, *table1; + Uint32 *desc; + tPAddr paddr; + + ENTER("xVAddr iDomain", VAddr, Domain); + + MM_int_GetTables(VAddr, &table0, &table1); + + VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page + + desc = &table0[ VAddr>>20]; + LOG("desc = %p", desc); + + // table0: 4 bytes = 1 MiB + + LOG("desc[0] = %x", desc[0]); + LOG("desc[1] = %x", desc[1]); + LOG("desc[2] = %x", desc[2]); + LOG("desc[3] = %x", desc[3]); + + if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0 + || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 ) + { + // Error? + LEAVE('i', 1); + return 1; + } + + paddr = MM_AllocPhys(); + if( !paddr ) + { + // Error + LEAVE('i', 2); + return 2; + } + + *desc = paddr | (Domain << 5) | 1; + desc[1] = desc[0] + 0x400; + desc[2] = desc[0] + 0x800; + desc[3] = desc[0] + 0xC00; + + if( VAddr < 0x80000000 ) { + USRFRACTAL(VAddr) = paddr | 0x13; + } + else { + FRACTAL(table1, VAddr) = paddr | 0x13; + } + + // TLBIALL + TLBIALL(); + + memset( (void*)&table1[ (VAddr >> 12) & ~(1024-1) ], 0, 0x1000 ); + + LEAVE('i', 0); + return 0; + } + + int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi) + { + Uint32 *table0, *table1; + Uint32 *desc; + + ENTER("pVAddr ppi", VAddr, pi); + + MM_int_GetTables(VAddr, &table0, &table1); + + desc = &table0[ VAddr >> 20 ]; + LOG("desc = %p", desc); + + switch(pi->Size) + { + case 12: // Small Page + case 16: // Large Page + LOG("Page"); + if( (*desc & 3) == 0 ) { + MM_int_AllocateCoarse( VAddr, pi->Domain ); + } + desc = &table1[ VAddr >> 12 ]; + LOG("desc (2) = %p", desc); + if( pi->Size == 12 ) + { + // Small page + // - Error if overwriting a large page + if( (*desc & 3) == 1 ) LEAVE_RET('i', 1); + if( pi->PhysAddr == 0 ) { + *desc = 0; + TLBIMVA( VAddr ); + DCCMVAC( (tVAddr) desc ); - #warning "HACK: TLBIALL" - TLBIALL(); ++// #warning "HACK: TLBIALL" ++// TLBIALL(); + LEAVE('i', 0); + return 0; + } + + *desc = (pi->PhysAddr & 0xFFFFF000) | 2; + if(!pi->bExecutable) *desc |= 1; // XN + if(!pi->bGlobal) *desc |= 1 << 11; // nG + if( pi->bShared) *desc |= 1 << 10; // S + *desc |= (pi->AP & 3) << 4; // AP + *desc |= ((pi->AP >> 2) & 1) << 9; // APX + TLBIMVA( VAddr ); - #warning "HACK: TLBIALL" - TLBIALL(); ++// #warning "HACK: TLBIALL" ++// TLBIALL(); + DCCMVAC( (tVAddr) desc ); + LEAVE('i', 0); + return 0; + } + else + { + // Large page + Log_Warning("MMVirt", "TODO: Implement large pages in MM_int_SetPageInfo"); + } + break; + case 20: // Section or unmapped + Log_Warning("MMVirt", "TODO: Implement sections in MM_int_SetPageInfo"); + break; + case 24: // Supersection + // Error if not aligned + if( VAddr & 0xFFFFFF ) { + LEAVE('i', 1); + return 1; + } + if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18))) ) + { + if( pi->PhysAddr == 0 ) { + *desc = 0; + } + else { + // Apply + *desc = pi->PhysAddr & 0xFF000000; + // *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20; + // *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5; + *desc |= 2 | (1 << 18); + } + // TODO: Apply to all entries + Log_Warning("MMVirt", "TODO: Apply changes to all entries of supersections"); + LEAVE('i', 0); + return 0; + } + // TODO: What here? + Log_Warning("MMVirt", "TODO: 24-bit not on supersection?"); + LEAVE('i', 1); + return 1; + } + + LEAVE('i', 1); + return 1; + } + + int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi) + { + Uint32 *table0, *table1; + Uint32 desc; + + // LogF("MM_int_GetPageInfo: VAddr=%p, pi=%p\n", VAddr, pi); + + MM_int_GetTables(VAddr, &table0, &table1); + + desc = table0[ VAddr >> 20 ]; + + // if( VAddr > 0x90000000) + // LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc); + + pi->bExecutable = 1; + pi->bGlobal = 0; + pi->bShared = 0; + pi->AP = 0; + + switch( (desc & 3) ) + { + // 0: Unmapped + case 0: + pi->PhysAddr = 0; + pi->Size = 20; + pi->Domain = 0; + return 1; + + // 1: Coarse page table + case 1: + // Domain from top level table + pi->Domain = (desc >> 5) & 7; + // Get next level + desc = table1[ VAddr >> 12 ]; + // LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc); + switch( desc & 3 ) + { + // 0: Unmapped + case 0: + pi->Size = 12; + return 1; + // 1: Large Page (64KiB) + case 1: + pi->Size = 16; + pi->PhysAddr = desc & 0xFFFF0000; + pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2); + pi->bExecutable = !(desc & 0x8000); + pi->bShared = (desc >> 10) & 1; + return 0; + // 2/3: Small page + case 2: + case 3: + pi->Size = 12; + pi->PhysAddr = desc & 0xFFFFF000; + pi->bExecutable = !(desc & 1); + pi->bGlobal = !(desc >> 11); + pi->bShared = (desc >> 10) & 1; + pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2); + return 0; + } + return 1; + + // 2: Section (or Supersection) + case 2: + if( desc & (1 << 18) ) { + // Supersection + pi->PhysAddr = desc & 0xFF000000; + pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32; + pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36; + pi->Size = 24; + pi->Domain = 0; // Supersections default to zero + pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2); + return 0; + } + + // Section + pi->PhysAddr = desc & 0xFFF80000; + pi->Size = 20; + pi->Domain = (desc >> 5) & 7; + pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2); + return 0; + + // 3: Reserved (invalid) + case 3: + pi->PhysAddr = 0; + pi->Size = 20; + pi->Domain = 0; + return 2; + } + return 2; + } + + // --- Exports --- + tPAddr MM_GetPhysAddr(tVAddr VAddr) + { + tMM_PageInfo pi; + if( MM_int_GetPageInfo(VAddr, &pi) ) + return 0; + return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1)); + } + + Uint MM_GetFlags(tVAddr VAddr) + { + tMM_PageInfo pi; + int ret; + + if( MM_int_GetPageInfo(VAddr, &pi) ) + return 0; + + ret = 0; + + switch(pi.AP) + { + case 0: + break; + case AP_KRW_ONLY: + ret |= MM_PFLAG_KERNEL; + break; + case AP_KRO_ONLY: + ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO; + break; + case AP_RW_BOTH: + break; + case AP_RO_BOTH: + ret |= MM_PFLAG_COW; + break; + case AP_RO_USER: + ret |= MM_PFLAG_RO; + break; + } + + if( pi.bExecutable ) ret |= MM_PFLAG_EXEC; + return ret; + } + + void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask) + { + tMM_PageInfo pi; + Uint curFlags; + + if( MM_int_GetPageInfo(VAddr, &pi) ) + return ; + + curFlags = MM_GetFlags(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_IsValidBuffer(tVAddr Addr, size_t Size) + { + tMM_PageInfo pi; + int bUser = 0; + + Size += Addr & (PAGE_SIZE-1); + Addr &= ~(PAGE_SIZE-1); + + if( MM_int_GetPageInfo(Addr, &pi) ) return 0; + Addr += PAGE_SIZE; + + if(pi.AP != AP_KRW_ONLY && pi.AP != AP_KRO_ONLY) + bUser = 1; + + while( Size >= PAGE_SIZE ) + { + if( MM_int_GetPageInfo(Addr, &pi) ) + return 0; + if(bUser && (pi.AP == AP_KRW_ONLY || pi.AP == AP_KRO_ONLY)) + return 0; + Addr += PAGE_SIZE; + Size -= PAGE_SIZE; + } + + return 1; + } + + int MM_Map(tVAddr VAddr, tPAddr PAddr) + { + tMM_PageInfo pi = {0}; + #if TRACE_MAPS + Log("MM_Map %P=>%p", PAddr, VAddr); + #endif + + pi.PhysAddr = PAddr; + pi.Size = 12; + 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); + return 0; + } + return pi.PhysAddr; + } + + tPAddr MM_Allocate(tVAddr VAddr) + { + tMM_PageInfo pi = {0}; + + ENTER("pVAddr", VAddr); + + pi.PhysAddr = MM_AllocPhys(); + if( pi.PhysAddr == 0 ) LEAVE_RET('i', 0); + pi.Size = 12; + if(VAddr < USER_STACK_TOP) + pi.AP = AP_RW_BOTH; + else + pi.AP = AP_KRW_ONLY; + pi.bExecutable = 0; + if( MM_int_SetPageInfo(VAddr, &pi) ) { + MM_DerefPhys(pi.PhysAddr); + LEAVE('i', 0); + return 0; + } + LEAVE('x', pi.PhysAddr); + 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; + + if( MM_int_GetPageInfo(VAddr, &pi) ) return ; + if( pi.PhysAddr == 0 ) return; + MM_DerefPhys(pi.PhysAddr); + + pi.PhysAddr = 0; + pi.AP = 0; + pi.bExecutable = 0; + MM_int_SetPageInfo(VAddr, &pi); + } + + tPAddr MM_AllocateRootTable(void) + { + tPAddr ret; + + ret = MM_AllocPhysRange(2, -1); + if( ret & 0x1000 ) { + MM_DerefPhys(ret); + MM_DerefPhys(ret+0x1000); + ret = MM_AllocPhysRange(3, -1); + if( ret & 0x1000 ) { + MM_DerefPhys(ret); + ret += 0x1000; + // Log("MM_AllocateRootTable: Second try not aligned, %P", ret); + } + else { + MM_DerefPhys(ret + 0x2000); + // Log("MM_AllocateRootTable: Second try aligned, %P", ret); + } + } + // else + // Log("MM_AllocateRootTable: Got it in one, %P", ret); + return ret; + } + + void MM_int_CloneTable(Uint32 *DestEnt, int Table) + { + tPAddr table; + Uint32 *tmp_map; + Uint32 *cur = (void*)MM_TABLE1USER; + // Uint32 *cur = &FRACTAL(MM_TABLE1USER,0); + int i; + + table = MM_AllocPhys(); + if(!table) return ; + + cur += 256*Table; + + tmp_map = (void*)MM_MapTemp(table); + + for( i = 0; i < 1024; i ++ ) + { + // Log_Debug("MMVirt", "cur[%i] (%p) = %x", Table*256+i, &cur[Table*256+i], cur[Table*256+i]); + switch(cur[i] & 3) + { + case 0: tmp_map[i] = 0; break; + case 1: + tmp_map[i] = 0; + Log_Error("MMVirt", "TODO: Support large pages in MM_int_CloneTable (%p)", (Table*256+i)*0x1000); + // Large page? + break; + case 2: + case 3: + // Small page + // - If full RW + // Debug("%p cur[%i] & 0x230 = 0x%x", Table*256*0x1000, i, cur[i] & 0x230); + if( (cur[i] & 0x230) == 0x010 ) + { + void *dst, *src; + tPAddr newpage; + newpage = MM_AllocPhys(); + src = (void*)( (Table*256+i)*0x1000 ); + dst = (void*)MM_MapTemp(newpage); + // Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF); + memcpy(dst, src, PAGE_SIZE); + MM_FreeTemp( (tVAddr)dst ); + tmp_map[i] = newpage | (cur[i] & 0xFFF); + } + else + { + if( (cur[i] & 0x230) == 0x030 ) + cur[i] |= 0x200; // Set to full RO (Full RO=COW, User RO = RO) + tmp_map[i] = cur[i]; + MM_RefPhys( tmp_map[i] & ~0xFFF ); + } + break; + } + } + MM_FreeTemp( (tVAddr) tmp_map ); + + DestEnt[0] = table + 0*0x400 + 1; + DestEnt[1] = table + 1*0x400 + 1; + DestEnt[2] = table + 2*0x400 + 1; + DestEnt[3] = table + 3*0x400 + 1; + } + + tPAddr MM_Clone(void) + { + tPAddr ret; + Uint32 *new_lvl1_1, *new_lvl1_2, *cur; + Uint32 *tmp_map; + int i; + + // MM_DumpTables(0, KERNEL_BASE); + + ret = MM_AllocateRootTable(); + + cur = (void*)MM_TABLE0USER; + new_lvl1_1 = (void*)MM_MapTemp(ret); + new_lvl1_2 = (void*)MM_MapTemp(ret+0x1000); + tmp_map = new_lvl1_1; + for( i = 0; i < 0x800-4; i ++ ) + { + // HACK! Ignore the original identity mapping + if( i == 0 && Threads_GetTID() == 0 ) { + tmp_map[0] = 0; + continue; + } + if( i == 0x400 ) + tmp_map = &new_lvl1_2[-0x400]; + switch( cur[i] & 3 ) + { + case 0: tmp_map[i] = 0; break; + case 1: + MM_int_CloneTable(&tmp_map[i], i); + i += 3; // Tables are alocated in blocks of 4 + break; + case 2: + case 3: + Log_Error("MMVirt", "TODO: Support Sections/Supersections in MM_Clone (i=%i)", i); + tmp_map[i] = 0; + break; + } + } + + // Allocate Fractal table + { + int j, num; + tPAddr tmp = MM_AllocPhys(); + Uint32 *table = (void*)MM_MapTemp(tmp); + Uint32 sp; + register Uint32 __SP asm("sp"); + + // Map table to last 4MiB of user space + new_lvl1_2[0x3FC] = tmp + 0*0x400 + 1; + new_lvl1_2[0x3FD] = tmp + 1*0x400 + 1; + new_lvl1_2[0x3FE] = tmp + 2*0x400 + 1; + new_lvl1_2[0x3FF] = tmp + 3*0x400 + 1; + + tmp_map = new_lvl1_1; + for( j = 0; j < 512; j ++ ) + { + if( j == 256 ) + tmp_map = &new_lvl1_2[-0x400]; + if( (tmp_map[j*4] & 3) == 1 ) + { + table[j] = tmp_map[j*4] & PADDR_MASK_LVL1;// 0xFFFFFC00; + table[j] |= 0x813; // nG, Kernel Only, Small page, XN + } + else + table[j] = 0; + } + // Fractal + table[j++] = (ret + 0x0000) | 0x813; + table[j++] = (ret + 0x1000) | 0x813; + // Nuke the rest + for( ; j < 1024; j ++ ) + table[j] = 0; + + // Get kernel stack bottom + sp = __SP & ~(MM_KSTACK_SIZE-1); + j = (sp / 0x1000) % 1024; + num = MM_KSTACK_SIZE/0x1000; + + // Log("num = %i, sp = %p, j = %i", num, sp, j); + + // Copy stack pages + for(; num--; j ++, sp += 0x1000) + { + tVAddr page; + void *tmp_page; + + page = MM_AllocPhys(); + // Log("page = %P", page); + table[j] = page | 0x813; + + tmp_page = (void*)MM_MapTemp(page); + memcpy(tmp_page, (void*)sp, 0x1000); + MM_FreeTemp( (tVAddr) tmp_page ); + } + + MM_FreeTemp( (tVAddr)table ); + } + + MM_FreeTemp( (tVAddr)new_lvl1_1 ); + MM_FreeTemp( (tVAddr)new_lvl1_2 ); + + // Log("MM_Clone: ret = %P", ret); + + return ret; + } + + void MM_ClearUser(void) + { + int i, j; + const int user_table_count = USER_STACK_TOP / (256*0x1000); + Uint32 *cur = (void*)MM_TABLE0USER; + Uint32 *tab; + + // MM_DumpTables(0, 0x80000000); + + // Log("user_table_count = %i (as opposed to %i)", user_table_count, 0x800-4); + + for( i = 0; i < user_table_count; i ++ ) + { + switch( cur[i] & 3 ) + { + case 0: break; // Already unmapped + case 1: // Sub pages + tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32)); + for( j = 0; j < 1024; j ++ ) + { + switch( tab[j] & 3 ) + { + case 0: break; // Unmapped + case 1: + Log_Error("MMVirt", "TODO: Support large pages in MM_ClearUser"); + break; + case 2: + case 3: + MM_DerefPhys( tab[j] & ~(PAGE_SIZE-1) ); + break; + } + } + MM_DerefPhys( cur[i] & ~(PAGE_SIZE-1) ); + cur[i+0] = 0; + cur[i+1] = 0; + cur[i+2] = 0; + i += 3; + break; + case 2: + case 3: + Log_Error("MMVirt", "TODO: Implement sections/supersections in MM_ClearUser"); + break; + } + cur[i] = 0; + } + + // Final block of 4 tables are KStack + i = 0x800 - 4; + + // Clear out unused stacks + { + register Uint32 __SP asm("sp"); + int cur_stack_base = ((__SP & ~(MM_KSTACK_SIZE-1)) / PAGE_SIZE) % 1024; + + tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32)); + + // First 512 is the Table1 mapping + 2 for Table0 mapping + for( j = 512+2; j < 1024; j ++ ) + { + // Skip current stack + if( j == cur_stack_base ) { + j += (MM_KSTACK_SIZE / PAGE_SIZE) - 1; + continue ; + } + if( !(tab[j] & 3) ) continue; + ASSERT( (tab[j] & 3) == 2 ); + MM_DerefPhys( tab[j] & ~(PAGE_SIZE) ); + tab[j] = 0; + } + } + + + // MM_DumpTables(0, 0x80000000); + } + + tVAddr MM_MapTemp(tPAddr PAddr) + { + tVAddr ret; + tMM_PageInfo pi; + + for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE ) + { + if( MM_int_GetPageInfo(ret, &pi) == 0 ) + continue; + + // Log("MapTemp %P at %p by %p", PAddr, ret, __builtin_return_address(0)); + MM_RefPhys(PAddr); // Counter the MM_Deallocate in FreeTemp + MM_Map(ret, PAddr); + + return ret; + } + Log_Warning("MMVirt", "MM_MapTemp: All slots taken"); + return 0; + } + + void MM_FreeTemp(tVAddr VAddr) + { + if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) { + Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr); + return ; + } + + MM_Deallocate(VAddr); + } + + tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages) + { + tVAddr ret; + int i; + tMM_PageInfo pi; + + ENTER("xPAddr iNPages", PAddr, NPages); + + // Scan for a location + for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE ) + { + // LOG("checking %p", ret); + // Check if there is `NPages` free pages + for( i = 0; i < NPages; i ++ ) + { + if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 ) + break; + } + // Nope, jump to after the used page found and try again + // LOG("i = %i, ==? %i", i, NPages); + if( i != NPages ) { + ret += i * PAGE_SIZE; + continue ; + } + + // Map the pages + for( i = 0; i < NPages; i ++ ) + MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAGE_SIZE); + // and return + LEAVE('p', ret); + return ret; + } + Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages); + LEAVE('p', 0); + return 0; + } + + tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr) + { + tPAddr phys; + tVAddr ret; + + phys = MM_AllocPhysRange(Pages, MaxBits); + if(!phys) { + Log_Warning("MMVirt", "No space left for a %i page block (MM_AllocDMA)", Pages); + return 0; + } + + ret = MM_MapHWPages(phys, Pages); + *PAddr = phys; + + return ret; + } + + void MM_UnmapHWPages(tVAddr Vaddr, Uint Number) + { + Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages"); + } + + tVAddr MM_NewKStack(int bShared) + { + tVAddr min_addr, max_addr; + tVAddr addr, ofs; + + if( bShared ) { + min_addr = MM_GLOBALSTACKS; + max_addr = MM_GLOBALSTACKS_END; + } + else { + min_addr = MM_KSTACK_BASE; + max_addr = MM_KSTACK_END; + } + + // Locate a free slot + for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE ) + { + tMM_PageInfo pi; + if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) ) break; + } + + // Check for an error + if(addr >= max_addr) { + return 0; + } + + // 1 guard page + for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE ) + { + if( MM_Allocate(addr + ofs) == 0 ) + { + while(ofs) + { + ofs -= PAGE_SIZE; + MM_Deallocate(addr + ofs); + } + Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate"); + return 0; + } + } + 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) + { + if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage ) + { + Debug("%p => %8s - 0x%7x %i %x %s", + Start, "ZERO", Len, + Info->Domain, Info->AP, + Info->bGlobal ? "G" : "nG" + ); + } + else + { + Debug("%p => %8x - 0x%7x %i %x %s", + Start, Info->PhysAddr-Len, Len, + Info->Domain, Info->AP, + Info->bGlobal ? "G" : "nG" + ); + } + } + + void MM_DumpTables(tVAddr Start, tVAddr End) + { + tVAddr range_start = 0, addr; + tMM_PageInfo pi, pi_old; + int i = 0, inRange=0; + + memset(&pi_old, 0, sizeof(pi_old)); + + Debug("Page Table Dump (%p to %p):", Start, End); + range_start = Start; + for( addr = Start; i == 0 || (addr && addr < End); i = 1 ) + { + int rv; + // Log("addr = %p", addr); + rv = MM_int_GetPageInfo(addr, &pi); + if( rv + || 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) { + MM_int_DumpTableEnt(range_start, addr - range_start, &pi_old); + } + addr &= ~((1 << pi.Size)-1); + range_start = addr; + } + + pi_old = pi; + // 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); + } + if(inRange) + MM_int_DumpTableEnt(range_start, addr - range_start, &pi); + Debug("Done"); + } + + // NOTE: Runs in abort context, not much difference, just a smaller stack + void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch) + { + int rv; + tMM_PageInfo pi; + + rv = MM_int_GetPageInfo(Addr, &pi); + + // Check for COW + if( rv == 0 && pi.AP == AP_RO_BOTH ) + { + pi.AP = AP_RW_BOTH; + if( giMM_ZeroPage && pi.PhysAddr == giMM_ZeroPage ) + { + tPAddr newpage; + newpage = MM_AllocPhys(); + if( !newpage ) { + Log_Error("MMVirt", "Unable to allocate new page for COW of ZERO"); + for(;;); + } + + #if TRACE_COW + Log_Notice("MMVirt", "COW %p caused by %p, ZERO duped to %P (RefCnt(%i)--)", Addr, PC, + newpage, MM_GetRefCount(pi.PhysAddr)); + #endif + + MM_DerefPhys(pi.PhysAddr); + pi.PhysAddr = newpage; + pi.AP = AP_RW_BOTH; + MM_int_SetPageInfo(Addr, &pi); + + memset( (void*)(Addr & ~(PAGE_SIZE-1)), 0, PAGE_SIZE ); + + return ; + } + else if( MM_GetRefCount(pi.PhysAddr) > 1 ) + { + // Duplicate the page + tPAddr newpage; + void *dst, *src; + + newpage = MM_AllocPhys(); + if(!newpage) { + Log_Error("MMVirt", "Unable to allocate new page for COW"); + for(;;); + } + dst = (void*)MM_MapTemp(newpage); + src = (void*)(Addr & ~(PAGE_SIZE-1)); + memcpy( dst, src, PAGE_SIZE ); + MM_FreeTemp( (tVAddr)dst ); + + #if TRACE_COW + Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC, + pi.PhysAddr, newpage, MM_GetRefCount(pi.PhysAddr)); + #endif + + MM_DerefPhys(pi.PhysAddr); + pi.PhysAddr = newpage; + } + #if TRACE_COW + else { + Log_Notice("MMVirt", "COW %p caused by %p, took last reference to %P", + Addr, PC, pi.PhysAddr); + } + #endif + // Unset COW + pi.AP = AP_RW_BOTH; + MM_int_SetPageInfo(Addr, &pi); + return ; + } + + + Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR, + (bPrefetch ? " - Prefetch" : "") + ); + if( Addr < 0x80000000 ) + MM_DumpTables(0, 0x80000000); + else + MM_DumpTables(0x80000000, -1); + for(;;); + } + diff --combined KernelLand/Kernel/arch/armv7/proc.S index 00000000,531de299..8711dee6 mode 000000,100644..100644 --- a/KernelLand/Kernel/arch/armv7/proc.S +++ b/KernelLand/Kernel/arch/armv7/proc.S @@@ -1,0 -1,104 +1,104 @@@ + /* + * Acess2 ARM + * - By John Hodge (thePowersGang) + * + * arch/arm7/proc.S + * - Process management assembly + */ + + #include "include/assembly.h" + + .globl KernelThreadHeader + @ SP+12: Argument 1 + @ SP+8: Argument Count + @ SP+4: Function + @ SP+0: Thread Pointer + KernelThreadHeader: + ldr r0, [sp],#4 + @ TODO: Do something with the thread pointer + + ldr r4, [sp],#4 @ Function + @ Get argument + ldr r0, [sp],#4 + + blx r4 + + ldr r0, =0 + bl Threads_Exit + b . + + .globl SwitchTask + @ R0: New stack + @ R1: Pointer to where to save old stack + @ R2: New IP + @ R3: Pointer to save old IP + @ SP+0: New address space + SwitchTask: + push {r4-r12,lr} + + @ Save IP + ldr r4, =.return + str r4, [r3] + @ Save SP + str sp, [r1] + + @ Only update TTBR0 if the task has an explicit address space + ldr r1, [sp,#4*10] + tst r1, r1 + mcrne p15, 0, r1, c2, c0, 0 @ Set TTBR0 to r0 - mov r1, #0 - mcrne p15, 0, r1, c8, c7, 0 @ TLBIALL - Invalidate all ++# mov r1, #1 ++ mcrne p15, 0, r1, c8, c7, 0 @ TLBIALL - Invalid user space + + @ Restore SP + mov sp, r0 + + bx r2 + + .return: + pop {r4-r12,pc} + + .extern MM_Clone + .extern MM_DumpTables + .globl Proc_CloneInt + Proc_CloneInt: + @ R0: SP Destination + @ R1: Mem Destination + push {r4-r12,lr} + mov r4, r1 @ Save mem destination + str sp, [r0] @ Save SP to SP dest + + bl MM_Clone + str r0, [r4] @ Save clone return to Mem Dest + + ldr r0, =Proc_CloneInt_new + pop {r4-r12,pc} + Proc_CloneInt_new: + mov r0, #0 + pop {r4-r12,pc} + + @ R0: New user SP + @ Return: Old user SP + .globl Proc_int_SwapUserSP + Proc_int_SwapUserSP: + cps #31 @ Go to system mode + mov r1, sp + tst r0, r0 @ Only update if non-zero + movne sp, r0 + mov r0, r1 + cps #19 + mov pc, lr + + .section .usertext, "ax" + .globl Proc_int_DropToUser + @ R0: User IP + @ R1: User SP + Proc_int_DropToUser: + cps #16 + mov sp, r1 + mov pc, r0 + + .section .rodata + csProc_CloneInt_NewTaskMessage: + .asciz "New task PC=%p, R4=%p, sp=%p" + csProc_CloneInt_OldTaskMessage: + .asciz "Parent task PC=%p, R4=%p, SP=%p" diff --combined KernelLand/Kernel/arch/armv7/start.S index 00000000,8d9f3e4d..113c8a43 mode 000000,100644..100644 --- a/KernelLand/Kernel/arch/armv7/start.S +++ b/KernelLand/Kernel/arch/armv7/start.S @@@ -1,0 -1,367 +1,366 @@@ + + #include "include/assembly.h" + #include "include/options.h" + + @ + @ Exception defs taken from ARM DDI 0406B + @ + .section .init + interrupt_vector_table: + ivt_reset: b _start @ 0x00 Reset + ivt_undef: b Undef_Handler @ 0x04 #UD + ivt_svc: b SVC_Handler @ 0x08 SVC (used to be called SWI) + ivt_prefetch: b PrefetchAbort @ 0x0C Prefetch abort + ivt_data: b DataAbort @ 0x10 Data abort + ivt_unused: b . @ 0x14 Not Used + ivt_irq: b IRQHandler @ 0x18 IRQ + ivt_fiq: b . @ 0x1C FIQ (Fast interrupt) + + .globl _start + _start: + ldr r2, =UART0_PADDR + mov r1, #'A' + str r1, [r2] + + ldr r0, =kernel_table0-KERNEL_BASE + mcr p15, 0, r0, c2, c0, 1 @ Set TTBR1 to r0 + mcr p15, 0, r0, c2, c0, 0 @ Set TTBR0 to r0 too (for identity) + + mov r1, #'c' + str r1, [r2] + + mov r0, #1 + mcr p15, 0, r0, c2, c0, 2 @ Set TTCR to 1 (50/50 split) + + mov r1, #'e' + str r1, [r2] + + mov r0, #3 + mcr p15, 0, r0, c3, c0, 0 @ Set Domain 0 to Manager + + mov r1, #'s' + str r1, [r2] + + @ Enable VMSA + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #1 + orr r0, r0, #1 << 23 - mvn r1, #1 << 2 - and r0, r0, r1 + mcr p15, 0, r0, c1, c0, 0 + - @ HACK! Disable caching - mrc p15, 0, r1, c1, c0, 0 ++ @ HACK: Set ASID to non zero ++ mov r0, #1 ++ MCR p15,0,r0,c13,c0,1 + + ldr r2, =0xF1000000 + mov r1, #'s' + str r1, [r2] + + @ Enable access faults on domains 0 & 1 + mov r0, #0x55 @ 01010101b + mcr p15, 0, r0, c3, c0, 0 + + mov r1, #'2' + str r1, [r2] + + @ + @ Check for security extensions + @ + mrc p15, 0, r0, c0, c1, 1 + and r0, #0xF0 + @ - Present + ldrne r0,=KERNEL_BASE + mcrne p15, 0, r0, c12, c0, 0 @ Set the VBAR (brings exceptions into high memory) + @ - Absent + mrceq p15, 0, r0, c1, c0, 0 @ Set SCTLR.V + orreq r0, #0x2000 + mcreq p15, 0, r0, c1, c0, 0 + + mov r1, #'-' + str r1, [r2] + + @ Prepare for interrupts + cps #18 @ IRQ Mode + ldr sp, =irqstack+0x1000 @ Set up stack + cps #23 @ Abort Mode + ldr sp, =abortstack+0x1000 + cps #19 + + mov r1, #'a' + str r1, [r2] + mov r1, #'r' + str r1, [r2] + mov r1, #'m' + str r1, [r2] + mov r1, #13 + str r1, [r2] + mov r1, #10 + str r1, [r2] + + .extern bss_start + .extern bss_size_div_4 + .zero_bss: + ldr r0, =bss_start + ldr r1, =bss_end + mov r3, #0 + .zero_bss_loop: + str r3, [r0],#4 + cmp r0, r1 + bls .zero_bss_loop + + .goto_c: + ldr sp, =0x80000000-8 @ Set up stack (top of user range) + ldr r0, =kmain + mov pc, r0 + 1: b 1b @ Infinite loop + + .comm irqstack, 0x1000 @ ; 4KiB Stack + .comm abortstack, 0x1000 @ ; 4KiB Stack + + .extern SyscallHandler + SVC_Handler: + @ sub lr, #4 + srsdb sp!, #19 @ Save state to stack + cpsie ifa, #19 @ Ensure we're in supervisor with interrupts enabled (should already be there) + push {r0-r12} + + ldr r4, [lr,#-4] + mvn r5, #0xFF000000 + and r4, r5 + + tst r4, #0x1000 + bne .arm_specifics + + push {r4} + + mov r0, sp + ldr r4, =SyscallHandler + blx r4 + + @ ldr r0, =csSyscallPrintRetAddr + @ ldr r1, [sp,#9*4+5*4] + @ ldr r4, =Log + @ 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) + .arm_specifics: + and r4, #0xFF + mov r0, r4 @ Number + mov r1, sp @ Arguments + + ldr r4, =ARMv7_int_HandleSyscalls + blx r4 + + add sp, #4*4 + pop {r4-r12} + rfeia sp! + + + .globl gpIRQHandler + gpIRQHandler: .long 0 + IRQ_saved_sp: .long 0 + IRQ_saved_lr: .long 0 + .globl IRQHandler + IRQHandler: + sub lr, #4 @ Adjust LR to the correct value + srsdb sp!, #19 @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD) + cps #19 + + PUSH_GPRS + + @ ldr r0, =csIRQ_Tag + @ ldr r1, =csIRQ_Fmt + @ ldr r4, =Log_Debug + @ blx r4 + + @ Call the registered handler + ldr r0, gpIRQHandler + blx r0 + + @ Restore CPU state + POP_GPRS + cpsie i + rfeia sp! @ Pop state (actually RFEFD) + bx lr + + .globl DataAbort + DataAbort: + sub lr, #8 @ Adjust LR to the correct value + srsdb sp!, #23 @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD) + @ cpsid ifa, #19 + PUSH_GPRS + + mov r3, #0 @ not a prefetch abort + mrc p15, 0, r2, c5, c0, 0 @ Read DFSR (Data Fault Status Register) to R2 + mrc p15, 0, r1, c6, c0, 0 @ Read DFAR (Data Fault Address Register) into R1 + mov r0, lr @ PC + ldr r4, =MM_PageFault + blx r4 + + POP_GPRS + rfeia sp! @ Pop state (actually RFEFD) + + .globl PrefetchAbort + PrefetchAbort: + sub lr, #4 @ Adjust LR to the correct value + srsdb sp!, #23 @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD) + @ cpsid ifa, #19 + PUSH_GPRS + + ldr r0, =csAbort_Tag + ldr r1, =csPrefetchAbort_Fmt + # mov r2, lr + mrc p15, 0, r2, c6, c0, 2 @ Read IFAR (Instruction Fault Address Register) into R3 + mrc p15, 0, r3, c5, c0, 1 @ Read IFSR (Instruction Fault Status Register) into R3 + ldr r5, =Log_Error + blx r5 + + .loop: + wfi + b .loop + .globl Undef_Handler + Undef_Handler: + wfi + b Undef_Handler + + + + .section .rodata + csIRQ_Tag: + csAbort_Tag: + .asciz "ARMv7" + csIRQ_Fmt: + .asciz "IRQ" + csDataAbort_Fmt: + .asciz "Data Abort - %p accessed %p, DFSR=%x Unk:%x Unk:%x" + csPrefetchAbort_Fmt: + .asciz "Prefetch Abort at %p, IFSR=%x" + csSyscallPrintRetAddr: + .asciz "Syscall ret to %p" + + .section .padata + .globl kernel_table0 + + kernel_table0: + .long 0x00000402 @ Identity map the first 1 MiB + .rept 0x7FC - 1 + .long 0 + .endr + .long user_table1_map + 0x000 - KERNEL_BASE + 1 @ 0x7FC00000 + .long user_table1_map + 0x400 - KERNEL_BASE + 1 @ 0x7FD00000 + .long user_table1_map + 0x800 - KERNEL_BASE + 1 @ KStacks + .long user_table1_map + 0xC00 - KERNEL_BASE + 1 + @ 0x80000000 - User/Kernel split + .long 0x00000402 @ Map first 4 MiB to 2GiB (KRW only) + .long 0x00100402 @ + .long 0x00200402 @ + .long 0x00300402 @ + .rept 0xF00 - 0x800 - 4 + .long 0 + .endr + #if PCI_PADDR + .long PCI_PADDR + 0*(1 << 20) + 0x402 @ Map PCI config space + .long PCI_PADDR + 1*(1 << 20) + 0x402 + .long PCI_PADDR + 2*(1 << 20) + 0x402 + .long PCI_PADDR + 3*(1 << 20) + 0x402 + .long PCI_PADDR + 4*(1 << 20) + 0x402 + .long PCI_PADDR + 5*(1 << 20) + 0x402 + .long PCI_PADDR + 6*(1 << 20) + 0x402 + .long PCI_PADDR + 7*(1 << 20) + 0x402 + .long PCI_PADDR + 8*(1 << 20) + 0x402 + .long PCI_PADDR + 9*(1 << 20) + 0x402 + .long PCI_PADDR + 10*(1 << 20) + 0x402 + .long PCI_PADDR + 11*(1 << 20) + 0x402 + .long PCI_PADDR + 12*(1 << 20) + 0x402 + .long PCI_PADDR + 13*(1 << 20) + 0x402 + .long PCI_PADDR + 14*(1 << 20) + 0x402 + .long PCI_PADDR + 15*(1 << 20) + 0x402 + #else + .rept 16 + .long 0 + .endr + #endif + .long hwmap_table_0 + 0x000 - KERNEL_BASE + 1 + .long hwmap_table_0 + 0x400 - KERNEL_BASE + 1 + .long hwmap_table_0 + 0x800 - KERNEL_BASE + 1 + .long hwmap_table_0 + 0xC00 - KERNEL_BASE + 1 + .rept 0xFF8 - 0xF00 - 16 - 4 + .long 0 + .endr + @ Page fractals + .long kernel_table1_map + 0x000 - KERNEL_BASE + 1 + .long kernel_table1_map + 0x400 - KERNEL_BASE + 1 + .long kernel_table1_map + 0x800 - KERNEL_BASE + 1 + .long kernel_table1_map + 0xC00 - KERNEL_BASE + 1 + .long kernel_exception_map + 0x000 - KERNEL_BASE + 1 + .long kernel_exception_map + 0x400 - KERNEL_BASE + 1 + .long kernel_exception_map + 0x800 - KERNEL_BASE + 1 + .long kernel_exception_map + 0xC00 - KERNEL_BASE + 1 + + @ PID0 user table + .globl user_table1_map + @ User table1 data table (only the first half is needed) + @ - Abused to provide kernel stacks in the unused half of the table + user_table1_map: @ Size = 4KiB (only 2KiB used) + .rept 0x800/4-1 + .long 0 + .endr + .long user_table1_map - KERNEL_BASE + 0x13 @ ...1FF000 = 0x7FDFF000 + @ Kernel stack zone + .long kernel_table0 + 0x0000 - KERNEL_BASE + 0x13 @ ...200000 = 0x7FE00000 + .long kernel_table0 + 0x1000 - KERNEL_BASE + 0x13 @ ...201000 = 0x7FE01000 + .rept (0x800/4)-(MM_KSTACK_SIZE/0x1000)-2 + .long 0 + .endr + #if MM_KSTACK_SIZE != 0x2000 + #error Kernel stack size not changed in start.S + #endif + .long stack + 0x0000 - KERNEL_BASE + 0x13 @ Kernel Stack + .long stack + 0x1000 - KERNEL_BASE + 0x13 @ + + .globl kernel_table1_map + kernel_table1_map: @ Size = 4KiB + .rept (0xF00+16)/4 + .long 0 + .endr + .long hwmap_table_0 - KERNEL_BASE + 0x13 + .rept 0xFF8/4 - (0xF00+16)/4 - 1 + .long 0 + .endr + .long kernel_table1_map - KERNEL_BASE + 0x13 + .long kernel_exception_map - KERNEL_BASE + 0x13 + + @ Hardware mappings + .globl hwmap_table_0 + hwmap_table_0: + .long UART0_PADDR + 0x13 @ UART0 + .rept 1024 - 1 + .long 0 + .endr + .globl kernel_exception_map + kernel_exception_map: + @ Padding + .rept 1024-256 + .long 0 + .endr + @ Align to nearly the end + .rept 256-16 + .long 0 + .endr + .long 0x212 @ Map first page for exceptions (Kernel RO, Execute) + .rept 16-1-2 + .long 0 + .endr + .long gUsertextPhysStart + 0x22 @ User .text (User RO, Kernel RW, because both is COW) + .long 0 + + .section .padata + stack: + .space MM_KSTACK_SIZE, 0 @ Original kernel stack + + // vim: ts=8 ft=armv7 + diff --combined KernelLand/Kernel/drv/vterm.c index 00000000,2ae38ee8..71c4d4a8 mode 000000,100644..100644 --- a/KernelLand/Kernel/drv/vterm.c +++ b/KernelLand/Kernel/drv/vterm.c @@@ -1,0 -1,764 +1,767 @@@ + /* + * Acess2 Virtual Terminal Driver + */ + #define DEBUG 0 + #include "vterm.h" + #include + #include + #include + #include + #include + #include + + // === CONSTANTS === + #define VERSION ((0<<8)|(50)) + + #define NUM_VTS 8 + //#define DEFAULT_OUTPUT "BochsGA" + #define DEFAULT_OUTPUT "Vesa" + #define FALLBACK_OUTPUT "x86_VGAText" + #define DEFAULT_INPUT "PS2Keyboard" + #define DEFAULT_WIDTH 640 + #define DEFAULT_HEIGHT 480 + #define DEFAULT_SCROLLBACK 2 // 2 Screens of text + current screen + //#define DEFAULT_SCROLLBACK 0 + + // === TYPES === + + // === IMPORTS === + extern void Debug_SetKTerminal(const char *File); + + // === PROTOTYPES === + int VT_Install(char **Arguments); + 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, const void *Buffer); + int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data); + + // === CONSTANTS === + + // === GLOBALS === -MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_INPUT, NULL); ++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", + { + .Flags = VFS_FFLAG_DIRECTORY, + .Size = NUM_VTS, + .Inode = -1, + .NumACLs = 0, + .Type = &gVT_RootNodeType + } + }; + // --- Terminals --- + tVTerm gVT_Terminals[NUM_VTS]; + int giVT_CurrentTerminal = 0; + tVTerm *gpVT_CurTerm = &gVT_Terminals[0]; + // --- Video State --- + short giVT_RealWidth = DEFAULT_WIDTH; //!< Screen Width + short giVT_RealHeight = DEFAULT_HEIGHT; //!< Screen Height + int giVT_Scrollback = DEFAULT_SCROLLBACK; + // --- Driver Handles --- + char *gsVT_OutputDevice = NULL; + char *gsVT_InputDevice = NULL; + int giVT_OutputDevHandle = -2; + int giVT_InputDevHandle = -2; + + // === CODE === + /** + * \fn int VT_Install(char **Arguments) + * \brief Installs the Virtual Terminal Driver + */ + int VT_Install(char **Arguments) + { + int i; + + // Scan Arguments + if(Arguments) + { + char **args; + const char *arg; + for(args = Arguments; (arg = *args); args++ ) + { + char data[strlen(arg)+1]; + char *opt = data; + char *val; + + val = strchr(arg, '='); + strcpy(data, arg); + if( val ) { + data[ val - arg ] = '\0'; + val ++; + } + Log_Debug("VTerm", "Argument '%s'", arg); + + if( strcmp(opt, "Video") == 0 ) { + if( !gsVT_OutputDevice ) + gsVT_OutputDevice = strdup(val); + } + else if( strcmp(opt, "Input") == 0 ) { + if( !gsVT_InputDevice ) + gsVT_InputDevice = strdup(val); + } + else if( strcmp(opt, "Width") == 0 ) { + giVT_RealWidth = atoi( val ); + } + else if( strcmp(opt, "Height") == 0 ) { + giVT_RealHeight = atoi( val ); + } + else if( strcmp(opt, "Scrollback") == 0 ) { + giVT_Scrollback = atoi( val ); + } + } + } + + // Apply Defaults + if(!gsVT_OutputDevice) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT; + else if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT; + if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)FALLBACK_OUTPUT; + if( Module_EnsureLoaded( gsVT_OutputDevice ) ) { + Log_Error("VTerm", "Fallback video '%s' is not avaliable, giving up", FALLBACK_OUTPUT); + return MODULE_ERR_MISC; + } + + if(!gsVT_InputDevice) gsVT_InputDevice = (char*)DEFAULT_INPUT; + else if( Module_EnsureLoaded( gsVT_InputDevice ) ) gsVT_InputDevice = (char*)DEFAULT_INPUT; ++ if( Module_EnsureLoaded( gsVT_OutputDevice ) ) { ++ Log_Error("VTerm", "Fallback input '%s' is not avaliable, input will not be avaliable", DEFAULT_INPUT); ++ } + + // Create device paths + { + char *tmp; + tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 ); + strcpy(tmp, "/Devices/"); + strcpy(&tmp[9], gsVT_OutputDevice); + gsVT_OutputDevice = tmp; + + tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 ); + strcpy(tmp, "/Devices/"); + strcpy(&tmp[9], gsVT_InputDevice); + gsVT_InputDevice = tmp; + } + + Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice); + Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice); + + VT_InitOutput(); + VT_InitInput(); + + // Create Nodes + for( i = 0; i < NUM_VTS; i++ ) + { + gVT_Terminals[i].Mode = TERM_MODE_TEXT; + gVT_Terminals[i].Flags = 0; + // gVT_Terminals[i].Flags = VT_FLAG_HIDECSR; //HACK - Stop all those memcpy calls + gVT_Terminals[i].CurColour = DEFAULT_COLOUR; + gVT_Terminals[i].WritePos = 0; + gVT_Terminals[i].AltWritePos = 0; + gVT_Terminals[i].ViewPos = 0; + gVT_Terminals[i].ReadingThread = -1; + gVT_Terminals[i].ScrollHeight = 0; + + // Initialise + VT_int_ChangeMode( &gVT_Terminals[i], + TERM_MODE_TEXT, giVT_RealWidth, giVT_RealHeight ); + + gVT_Terminals[i].Name[0] = '0'+i; + gVT_Terminals[i].Name[1] = '\0'; + 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.Type = &gVT_TermNodeType; + // Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name); + } + + // Add to DevFS + DevFS_AddDevice( &gVT_DrvInfo ); + + // Set kernel output to VT0 + Debug_SetKTerminal("/Devices/VTerm/0"); + + return MODULE_ERR_OK; + } + + /** + * \brief Set the video resolution + * \param Width New screen width + * \param Height New screen height + */ + void VT_SetResolution(int Width, int Height) + { + tVideo_IOCtl_Mode mode = {0}; + int tmp; + int i; + + // Create the video mode + mode.width = Width; + mode.height = Height; + mode.bpp = 32; + mode.flags = 0; + + // Set video mode + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode ); + tmp = mode.id; + if( Width != mode.width || Height != mode.height ) + { + Log_Warning("VTerm", + "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)", + giVT_RealWidth, giVT_RealHeight, + mode.width, mode.height + ); + giVT_RealWidth = mode.width; + giVT_RealHeight = mode.height; + } + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp ); + + // Resize text terminals if needed + if( gVT_Terminals[0].Text && (giVT_RealWidth != mode.width || giVT_RealHeight != mode.height) ) + { + int newBufSize = (giVT_RealWidth/giVT_CharWidth) + *(giVT_RealHeight/giVT_CharHeight) + *(giVT_Scrollback+1); + //tVT_Char *tmp; + // Resize the text terminals + Log_Debug("VTerm", "Resizing terminals to %ix%i", + giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight); + for( i = 0; i < NUM_VTS; i ++ ) + { + 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].ScrollHeight = gVT_Terminals[i].TextHeight; + + gVT_Terminals[i].Text = realloc( + gVT_Terminals[i].Text, + newBufSize*sizeof(tVT_Char) + ); + } + } + } + + /** + * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos) + * \brief Read from the VTerm Directory + */ + char *VT_ReadDir(tVFS_Node *Node, int Pos) + { + if(Pos < 0) return NULL; + if(Pos >= NUM_VTS) return NULL; + return strdup( gVT_Terminals[Pos].Name ); + } + + /** + * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name) + * \brief Find an item in the VTerm directory + * \param Node Root node + * \param Name Name (number) of the terminal + */ + tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name) + { + int num; + + ENTER("pNode sName", Node, Name); + + // Open the input and output files if needed + if(giVT_OutputDevHandle == -2) VT_InitOutput(); + if(giVT_InputDevHandle == -2) VT_InitInput(); + + // Sanity check name + if(Name[0] < '0' || Name[0] > '9' || Name[1] != '\0') { + LEAVE('n'); + return NULL; + } + // Get index + num = Name[0] - '0'; + if(num >= NUM_VTS) { + LEAVE('n'); + return NULL; + } + // Return node + LEAVE('p', &gVT_Terminals[num].Node); + return &gVT_Terminals[num].Node; + } + + /** + * \fn int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) + * \brief Control the VTerm Driver + */ + int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) + { + int len; + switch(Id) + { + case DRV_IOCTL_TYPE: return DRV_TYPE_MISC; + case DRV_IOCTL_IDENT: memcpy(Data, "VT\0\0", 4); return 0; + case DRV_IOCTL_VERSION: return VERSION; + case DRV_IOCTL_LOOKUP: return 0; + + case 4: // Get Video Driver + if(Data) strcpy(Data, gsVT_OutputDevice); + return strlen(gsVT_OutputDevice); + + case 5: // Set Video Driver + if(!Data) return -EINVAL; + if(Threads_GetUID() != 0) return -EACCES; + + len = strlen(Data); + + // TODO: Check if the string used is a heap string + + free(gsVT_OutputDevice); + + gsVT_OutputDevice = malloc(len+1); + strcpy(gsVT_OutputDevice, Data); + + VFS_Close(giVT_OutputDevHandle); + giVT_OutputDevHandle = -1; + + VT_InitOutput(); + return 1; + } + return 0; + } + + /** + * \brief Read from a virtual terminal + */ + Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + { + int pos = 0; + int avail; + tVTerm *term = &gVT_Terminals[ Node->Inode ]; + Uint32 *codepoint_buf = Buffer; + Uint32 *codepoint_in; + + Mutex_Acquire( &term->ReadingLock ); + + // Check current mode + switch(term->Mode) + { + // Text Mode (UTF-8) + case TERM_MODE_TEXT: + VT_int_UpdateCursor(term, 1); + + VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UTF-8)"); + + avail = term->InputWrite - term->InputRead; + if(avail < 0) + avail += MAX_INPUT_CHARS8; + if(avail > Length - pos) + avail = Length - pos; + + while( avail -- ) + { + ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead]; + pos ++; + term->InputRead ++; + while(term->InputRead >= MAX_INPUT_CHARS8) + term->InputRead -= MAX_INPUT_CHARS8; + } + break; + + //case TERM_MODE_FB: + // Other - UCS-4 + default: + VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)"); + + avail = term->InputWrite - term->InputRead; + if(avail < 0) + avail += MAX_INPUT_CHARS32; + Length /= 4; + if(avail > Length - pos) + avail = Length - pos; + + codepoint_in = (void*)term->InputBuffer; + codepoint_buf = Buffer; + + while( avail -- ) + { + codepoint_buf[pos] = codepoint_in[term->InputRead]; + pos ++; + term->InputRead ++; + while(term->InputRead >= MAX_INPUT_CHARS32) + term->InputRead -= MAX_INPUT_CHARS32; + } + pos *= 4; + break; + } + + // Mark none avaliable if buffer empty + if( term->InputRead == term->InputWrite ) + VFS_MarkAvaliable(&term->Node, 0); + + term->ReadingThread = -1; + + // VT_int_UpdateCursor(term, term->Mode == TERM_MODE_TEXT); + + Mutex_Release( &term->ReadingLock ); + + return pos; + } + + /** + * \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, const void *Buffer) + { + tVTerm *term = &gVT_Terminals[ Node->Inode ]; + int size; + + // Write + switch( term->Mode ) + { + // Print Text + case TERM_MODE_TEXT: + VT_int_PutString(term, Buffer, Length); + break; + + // Framebuffer :) + case TERM_MODE_FB: + // - Sanity Checking + size = term->Width*term->Height*4; + if( Offset > size ) { + Log_Notice("VTerm", "VT_Write: Offset (0x%llx) > FBSize (0x%x)", + Offset, size); + return 0; + } + if( Offset + Length > size ) { + Log_Notice("VTerm", "VT_Write: Offset+Length (0x%llx) > FBSize (0x%x)", + Offset+Length, size); + Length = size - Offset; + } + + // Update screen if needed + if( Node->Inode == giVT_CurrentTerminal ) + { + if( giVT_RealHeight > term->Height ) + Offset += (giVT_RealHeight - term->Height) / 2 * term->Width * 4; + // Handle undersized virtual terminals + if( giVT_RealWidth > term->Width ) + { + // No? :( Well, just center it + int x, y, w, h; + Uint dst_ofs; + // TODO: Fix to handle the final line correctly? + x = Offset/4; y = x / term->Width; x %= term->Width; + w = Length/4+x; h = w / term->Width; w %= term->Width; + + // Center + x += (giVT_RealWidth - term->Width) / 2; + dst_ofs = (x + y * giVT_RealWidth) * 4; + while(h--) + { + VFS_WriteAt( giVT_OutputDevHandle, + dst_ofs, + term->Width * 4, + Buffer + ); + Buffer = (void*)( (Uint)Buffer + term->Width*4 ); + dst_ofs += giVT_RealWidth * 4; + } + return 0; + } + else + { + return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer ); + } + } + else + { + if( !term->Buffer ) + term->Buffer = malloc( term->Width * term->Height * 4 ); + // Copy to the local cache + memcpy( (char*)term->Buffer + (Uint)Offset, Buffer, Length ); + } + break; + // Just pass on (for now) + // TODO: Handle locally too to ensure no information is lost on + // VT Switch (and to isolate terminals from each other) + case TERM_MODE_2DACCEL: + //case TERM_MODE_3DACCEL: + if( Node->Inode == giVT_CurrentTerminal ) + { + VFS_Write( giVT_OutputDevHandle, Length, Buffer ); + } + break; + } + + return 0; + } + + /** + * \fn int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) + * \brief Call an IO Control on a virtual terminal + */ + int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) + { + int *iData = Data; + int ret; + tVTerm *term = Node->ImplPtr; + ENTER("pNode iId pData", Node, Id, Data); + + if(Id >= DRV_IOCTL_LOOKUP) { + // Only root can fiddle with graphics modes + // TODO: Remove this and replace with user ownership + if( Threads_GetUID() != 0 ) return -1; + } + + switch(Id) + { + // --- Core Defined + case DRV_IOCTL_TYPE: + LEAVE('i', DRV_TYPE_TERMINAL); + return DRV_TYPE_TERMINAL; + case DRV_IOCTL_IDENT: + memcpy(Data, "VT\0\0", 4); + LEAVE('i', 0); + return 0; + case DRV_IOCTL_VERSION: + LEAVE('x', VERSION); + return VERSION; + case DRV_IOCTL_LOOKUP: + LEAVE('i', 0); + return 0; + + // Get/Set the mode (and apply any changes) + case TERM_IOCTL_MODETYPE: + if(Data != NULL) + { + if( CheckMem(Data, sizeof(int)) == 0 ) { + LEAVE('i', -1); + return -1; + } + Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData); + + // Update mode if needed + if( term->Mode != *iData || term->NewWidth || term->NewHeight) + { + // Adjust for text mode + if( *iData == TERM_MODE_TEXT ) { + term->NewHeight *= giVT_CharHeight; + term->NewWidth *= giVT_CharWidth; + } + // Fill unchanged dimensions + if(term->NewHeight == 0) term->NewHeight = term->Height; + if(term->NewWidth == 0) term->NewWidth = term->Width; + // Set new mode + VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight); + // Clear unapplied dimensions + term->NewWidth = 0; + term->NewHeight = 0; + } + + // Update the screen dimensions + if(Node->Inode == giVT_CurrentTerminal) + VT_SetTerminal( giVT_CurrentTerminal ); + } + LEAVE('i', term->Mode); + return term->Mode; + + // Get/set the terminal width + case TERM_IOCTL_WIDTH: + if(Data != NULL) { + if( CheckMem(Data, sizeof(int)) == 0 ) { + LEAVE('i', -1); + return -1; + } + term->NewWidth = *iData; + } + if( term->NewWidth ) + ret = term->NewWidth; + else if( term->Mode == TERM_MODE_TEXT ) + ret = term->TextWidth; + else + ret = term->Width; + LEAVE('i', ret); + return ret; + + // Get/set the terminal height + case TERM_IOCTL_HEIGHT: + if(Data != NULL) { + if( CheckMem(Data, sizeof(int)) == 0 ) { + LEAVE('i', -1); + return -1; + } + term->NewHeight = *iData; + } + if( term->NewHeight ) + ret = term->NewHeight; + else if( term->Mode == TERM_MODE_TEXT ) + ret = term->TextHeight; + else + ret = term->Height; + LEAVE('i', ret); + return ret; + + case TERM_IOCTL_FORCESHOW: + Log_Log("VTerm", "Thread %i forced VTerm %i to be shown", + Threads_GetTID(), (int)Node->Inode); + VT_SetTerminal( Node->Inode ); + LEAVE('i', 1); + return 1; + + case TERM_IOCTL_GETSETCURSOR: + if(Data != NULL) + { + tVideo_IOCtl_Pos *pos = Data; + if( !CheckMem(Data, sizeof(*pos)) ) { + errno = -EINVAL; + LEAVE('i', -1); + return -1; + } + + if( term->Mode == TERM_MODE_TEXT ) + { + if(term->Flags & VT_FLAG_ALTBUF) + term->AltWritePos = pos->x + pos->y * term->TextWidth; + else + term->WritePos = pos->x + pos->y * term->TextWidth + term->ViewPos; + VT_int_UpdateCursor(term, 0); + } + else + { + term->VideoCursorX = pos->x; + term->VideoCursorY = pos->y; + VT_int_UpdateCursor(term, 1); + } + } + ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos; + LEAVE('i', ret); + return ret; + + case TERM_IOCTL_SETCURSORBITMAP: { + tVideo_IOCtl_Bitmap *bmp = Data; + if( Data == NULL ) + { + free( term->VideoCursor ); + term->VideoCursor = NULL; + LEAVE('i', 0); + return 0; + } + + // Sanity check bitmap + if( !CheckMem(bmp, sizeof(tVideo_IOCtl_Bitmap)) ) { + Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp); + errno = -EINVAL; + LEAVE_RET('i', -1); + } + if( !CheckMem(bmp->Data, bmp->W*bmp->H*sizeof(Uint32)) ) { + Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp); + errno = -EINVAL; + LEAVE_RET('i', -1); + } + + // Reallocate if needed + if(term->VideoCursor) + { + if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) { + free(term->VideoCursor); + term->VideoCursor = NULL; + } + } + if(!term->VideoCursor) { + term->VideoCursor = malloc(sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32)); + if(!term->VideoCursor) { + Log_Error("VTerm", "Unable to allocate memory for cursor"); + errno = -ENOMEM; + LEAVE_RET('i', -1); + } + } + + memcpy(term->VideoCursor, bmp, sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32)); + + Log_Debug("VTerm", "Set VT%i's cursor to %p %ix%i", + (int)term->Node.Inode, bmp, bmp->W, bmp->H); + + if(gpVT_CurTerm == term) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, term->VideoCursor); + + LEAVE('i', 0); + return 0; } + } + LEAVE('i', -1); + return -1; + } + + /** + * \fn void VT_SetTerminal(int ID) + * \brief Set the current terminal + */ + void VT_SetTerminal(int ID) + { + // Copy the screen state + if( ID != giVT_CurrentTerminal && gpVT_CurTerm->Mode != TERM_MODE_TEXT ) + { + if( !gpVT_CurTerm->Buffer ) + gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 ); + if( gpVT_CurTerm->Width < giVT_RealWidth ) + { + int line; + Uint ofs = 0; + Uint32 *dest = gpVT_CurTerm->Buffer; + // Slower scanline copy + for( line = 0; line < gpVT_CurTerm->Height; line ++ ) + { + VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest); + ofs += giVT_RealWidth * 4; + dest += gpVT_CurTerm->Width; + } + } + else + { + VFS_ReadAt(giVT_OutputDevHandle, + 0, gpVT_CurTerm->Height*giVT_RealWidth*4, + gpVT_CurTerm->Buffer + ); + } + } + + // Update current terminal ID + Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID); + giVT_CurrentTerminal = ID; + gpVT_CurTerm = &gVT_Terminals[ID]; + + if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) + { + VT_SetMode( VIDEO_BUFFMT_TEXT ); + } + else + { + // Update the cursor image + if(gpVT_CurTerm->VideoCursor) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor); + VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER ); + } + + if(gpVT_CurTerm->Buffer) + { + // TODO: Handle non equal sized + VFS_WriteAt( + giVT_OutputDevHandle, + 0, + gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32), + gpVT_CurTerm->Buffer + ); + } + + VT_int_UpdateCursor(gpVT_CurTerm, 1); + // Update the screen + VT_int_UpdateScreen(gpVT_CurTerm, 1); + } diff --combined KernelLand/Modules/Display/Tegra2Vid/main.c index 00000000,d9405be0..72ac697b mode 000000,100644..100644 --- a/KernelLand/Modules/Display/Tegra2Vid/main.c +++ b/KernelLand/Modules/Display/Tegra2Vid/main.c @@@ -1,0 -1,326 +1,343 @@@ + /** + * main.c + * - Driver core + */ + #define DEBUG 0 + #define VERSION ((0<<8)|10) + #include + #include + #include + #include + #include + #include + #include + #include + #include // ARM Arch + #include "tegra2.h" + + #define ABS(a) ((a)>0?(a):-(a)) + + // === PROTOTYPES === + // Driver + int Tegra2Vid_Install(char **Arguments); + void Tegra2Vid_Uninstall(); + // Internal + // Filesystem + Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); + Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); + int Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data); + // -- Internals + int Tegra2Vid_int_SetMode(int Mode); + + // === GLOBALS === + MODULE_DEFINE(0, VERSION, Tegra2Vid, Tegra2Vid_Install, NULL, NULL); + tDevFS_Driver gTegra2Vid_DriverStruct = { + NULL, "Tegra2Vid", + { + .Read = Tegra2Vid_Read, + .Write = Tegra2Vid_Write, + .IOCtl = Tegra2Vid_IOCtl + } + }; + // -- Options + tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE; + int gbTegra2Vid_IsVersatile = 1; + // -- KeyVal parse rules + const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = { + NULL, + { + {"Base", "P", &gTegra2Vid_PhysBase}, + {NULL, NULL, NULL} + } + }; + // -- Driver state + int giTegra2Vid_CurrentMode = 0; + int giTegra2Vid_BufferMode; + size_t giTegra2Vid_FramebufferSize; + Uint32 *gpTegra2Vid_IOMem; + tPAddr gTegra2Vid_FramebufferPhys; + void *gpTegra2Vid_Framebuffer; + // -- Misc + tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo; + tVideo_IOCtl_Pos gTegra2Vid_CursorPos; + + // === CODE === + /** + */ + int Tegra2Vid_Install(char **Arguments) + { ++ return MODULE_ERR_NOTNEEDED; + // KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments); + + gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4); + { + Log_Debug("Tegra2Vid", "Display CMD Registers"); + for( int i = 0x000; i <= 0x01A; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + for( int i = 0x028; i <= 0x043; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + Log_Debug("Tegra2Vid", "Display COM Registers"); + for( int i = 0x300; i <= 0x329; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + Log_Debug("Tegra2Vid", "Display DISP Registers"); + for( int i = 0x400; i <= 0x446; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + for( int i = 0x480; i <= 0x484; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + for( int i = 0x4C0; i <= 0x4C1; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + + Log_Debug("Tegra2Vid", "WINC_A Registers"); + for( int i = 0x700; i <= 0x714; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + Log_Debug("Tegra2Vid", "WINBUF_A"); + for( int i = 0x800; i <= 0x80A; i ++ ) + Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]); + } + // return 1; - ++ ++ // HACK!!! ++// { ++// int w = 1980, h = 1080; ++// gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (h << 16) | w; ++// gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w; ++// gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w; ++// } ++ + giTegra2Vid_FramebufferSize = + (gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]&0xFFFF) + *(gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0]>>16)*4; + + Log_Debug("Tegra2Vid", "giTegra2Vid_FramebufferSize = 0x%x", giTegra2Vid_FramebufferSize); + gpTegra2Vid_Framebuffer = MM_MapHWPages( + gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0], + (giTegra2Vid_FramebufferSize+PAGE_SIZE-1)/PAGE_SIZE + ); - memset(gpTegra2Vid_Framebuffer, 0x1F, 0x1000); ++ memset(gpTegra2Vid_Framebuffer, 0xFF, 0x1000); ++ ++ gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] &= ~0x40; ++ gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB) ++ gTegra2Vid_DrvUtil_BufInfo.Width = 1024; ++ gTegra2Vid_DrvUtil_BufInfo.Height = 768; ++ gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4; ++ gTegra2Vid_DrvUtil_BufInfo.Depth = 32; ++ gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer; + + + // Tegra2Vid_int_SetMode(4); + + DevFS_AddDevice( &gTegra2Vid_DriverStruct ); + + return 0; + } + + /** + * \brief Clean up resources for driver unloading + */ + void Tegra2Vid_Uninstall() + { + } + + /** + * \brief Read from the framebuffer + */ + Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer) + { + return 0; + } + + /** + * \brief Write to the framebuffer + */ + Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + { + gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode; + return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer); + } + + const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL}; + + /** + * \brief Handle messages to the device + */ + int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data) + { + int ret = -2; + ENTER("pNode iID pData", Node, ID, Data); + + switch(ID) + { + BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls); + + case VIDEO_IOCTL_SETBUFFORMAT: + DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo ); + ret = giTegra2Vid_BufferMode; + if(Data) giTegra2Vid_BufferMode = *(int*)Data; + if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT) + DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor ); + break; + + case VIDEO_IOCTL_GETSETMODE: + if(Data) + { + int newMode; + + if( !CheckMem(Data, sizeof(int)) ) + LEAVE_RET('i', -1); + + newMode = *(int*)Data; + + if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount) + LEAVE_RET('i', -1); + + if(newMode != giTegra2Vid_CurrentMode) + { + giTegra2Vid_CurrentMode = newMode; + Tegra2Vid_int_SetMode( newMode ); + } + } + ret = giTegra2Vid_CurrentMode; + break; + + case VIDEO_IOCTL_FINDMODE: + { + tVideo_IOCtl_Mode *mode = Data; + int closest, closestArea, reqArea = 0; + if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode))) + LEAVE_RET('i', -1); + if( mode->bpp != 32 ) + LEAVE_RET('i', 0); + if( mode->flags != 0 ) + LEAVE_RET('i', 0); + + ret = 0; + + for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ ) + { + int area; + if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) { + mode->id = i; + ret = 1; + break; + } + + area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H; + if(!reqArea) { + reqArea = mode->width * mode->height; + closest = i; + closestArea = area; + } + else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) { + closest = i; + closestArea = area; + } + } + + if( ret == 0 ) + { + mode->id = closest; + ret = 1; + } + mode->width = caTegra2Vid_Modes[mode->id].W; + mode->height = caTegra2Vid_Modes[mode->id].H; + break; + } + + case VIDEO_IOCTL_MODEINFO: + { + tVideo_IOCtl_Mode *mode = Data; + if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode))) + LEAVE_RET('i', -1); + if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount) + LEAVE_RET('i', 0); + + + mode->bpp = 32; + mode->flags = 0; + mode->width = caTegra2Vid_Modes[mode->id].W; + mode->height = caTegra2Vid_Modes[mode->id].H; + + ret = 1; + break; + } + + case VIDEO_IOCTL_SETCURSOR: + if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) ) + LEAVE_RET('i', -1); + + DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo ); + + gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data; + if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT) + DrvUtil_Video_DrawCursor( + &gTegra2Vid_DrvUtil_BufInfo, + gTegra2Vid_CursorPos.x*giVT_CharWidth, + gTegra2Vid_CursorPos.y*giVT_CharHeight + ); + else + DrvUtil_Video_DrawCursor( + &gTegra2Vid_DrvUtil_BufInfo, + gTegra2Vid_CursorPos.x, + gTegra2Vid_CursorPos.y + ); + break; + + default: + LEAVE('i', -2); + return -2; + } + + LEAVE('i', ret); + return ret; + } + + // + // + // + + int Tegra2Vid_int_SetMode(int Mode) + { + const struct sTegra2_Disp_Mode *mode = &caTegra2Vid_Modes[Mode]; + int w = mode->W, h = mode->H; // Horizontal/Vertical Active + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (mode->HS << 16) | mode->HS; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0) = (mode->VBP << 16) | mode->HBP; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16) | mode->W; + + *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0; - *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (mode->H << 16) | mode->W; ++ *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (h << 16) | w; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8; // BASE888 + *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12; // Could be 13 (BGR/RGB) - *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (mode->H << 16) | mode->W; ++ *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (h << 16) | w; + + Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h); + + if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize ) + { + if( gpTegra2Vid_Framebuffer ) + { + // TODO: Free framebuffer for reallocation + } + + giTegra2Vid_FramebufferSize = w*h*4; + + gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA( + (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE, + 32, + &gTegra2Vid_FramebufferPhys + ); + // TODO: Catch allocation failures + Log_Debug("Tegra2Vid", "0x%x byte framebuffer at %p (%P phys)", + giTegra2Vid_FramebufferSize, + gpTegra2Vid_Framebuffer, + gTegra2Vid_FramebufferPhys + ); + + // Tell hardware + *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys; + *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0; // Y offset + *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0; // X offset + } + + return 0; + } diff --combined KernelLand/Modules/Display/Tegra2Vid/tegra2.h index 00000000,a3f126b6..c36b05e7 mode 000000,100644..100644 --- a/KernelLand/Modules/Display/Tegra2Vid/tegra2.h +++ b/KernelLand/Modules/Display/Tegra2Vid/tegra2.h @@@ -1,0 -1,75 +1,174 @@@ + /* + * Acess2 NVidia Tegra2 Display Driver + * - By John Hodge (thePowersGang) + * + * tegra2.h + * - Driver definitions + */ + #ifndef _TEGRA2_DISP_H_ + #define _TEGRA2_DISP_H_ + + #define TEGRA2VID_BASE 0x54200000 // 0x40000 Large (256 KB) + + const struct sTegra2_Disp_Mode + { + Uint16 W, H; + Uint16 HFP, VFP; + Uint16 HS, VS; + Uint16 HBP, VBP; + } caTegra2Vid_Modes[] = { + // TODO: VESA timings - {720, 487, 16,33, 63, 33, 59, 133}, // NTSC 2 - {720, 576, 12,33, 63, 33, 69, 193}, // PAL 2 (VFP shown as 2/33, used 33) - {720, 483, 16, 6, 63, 6, 59, 30}, // 480p - {1280, 720, 70, 5, 804, 6, 220, 20}, // 720p - {1920,1080, 44, 4, 884, 5, 148, 36}, // 1080p ++// {720, 487, 16,33, 63, 33, 59, 133}, // NTSC 2 ++// {720, 576, 12,33, 63, 33, 69, 193}, // PAL 2 (VFP shown as 2/33, used 33) ++// {720, 483, 16, 6, 63, 6, 59, 30}, // 480p ++// {1280, 720, 70, 5, 804, 6, 220, 20}, // 720p ++// {1920,1080, 44, 4, 884, 5, 148, 36}, // 1080p + // TODO: Can all but HA/VA be constant and those select the resolution? + }; + const int ciTegra2Vid_ModeCount = sizeof(caTegra2Vid_Modes)/sizeof(caTegra2Vid_Modes[0]); + + enum eTegra2_Disp_Regs + { ++ DC_CMD_STATE_CONTROL_0 = 0x041, ++ DC_CMD_DISPLAY_WINDOW_HEADER_0, // 042 ++ DC_CMD_REG_ACT_CONTROL_0, // 043 ++ ++ DC_COM_CRC_CONTROL_0 = 0x300, ++ DC_COM_CRC_CHECKSUM_0, // 301 ++ DC_COM_PIN_OUTPUT_ENABLE0_0, // 302 ++ DC_COM_PIN_OUTPUT_ENABLE1_0, // 303 ++ DC_COM_PIN_OUTPUT_ENABLE2_0, // 304 ++ DC_COM_PIN_OUTPUT_ENABLE3_0, // 305 ++ DC_COM_PIN_OUTPUT_POLARITY0_0, // 306 ++ DC_COM_PIN_OUTPUT_POLARITY1_0, // 307 ++ DC_COM_PIN_OUTPUT_POLARITY2_0, // 308 ++ DC_COM_PIN_OUTPUT_POLARITY3_0, // 309 ++ DC_COM_PIN_OUTPUT_DATA0_0, // 30A ++ DC_COM_PIN_OUTPUT_DATA1_0, // 30B ++ DC_COM_PIN_OUTPUT_DATA2_0, // 30C ++ DC_COM_PIN_OUTPUT_DATA3_0, // 30D ++ DC_COM_PIN_INPUT_ENABLE0_0, // 30E ++ DC_COM_PIN_INPUT_ENABLE1_0, // 30F ++ DC_COM_PIN_INPUT_ENABLE2_0, // 310 ++ DC_COM_PIN_INPUT_ENABLE3_0, // 311 ++ DC_COM_PIN_INPUT_DATA0_0, // 312 ++ DC_COM_PIN_INPUT_DATA1_0, // 313 ++ DC_COM_PIN_OUTPUT_SELECT0_0, // 314 ++ DC_COM_PIN_OUTPUT_SELECT1_0, // 315 ++ DC_COM_PIN_OUTPUT_SELECT2_0, // 316 ++ DC_COM_PIN_OUTPUT_SELECT3_0, // 317 ++ DC_COM_PIN_OUTPUT_SELECT4_0, // 318 ++ DC_COM_PIN_OUTPUT_SELECT5_0, // 319 ++ DC_COM_PIN_OUTPUT_SELECT6_0, // 31A ++ DC_COM_PIN_MISC_CONTROL_0, // 31B ++ // TODO: Complete ++ + DC_DISP_DISP_SIGNAL_OPTIONS0_0 = 0x400, + DC_DISP_DISP_SIGNAL_OPTIONS1_0, // 401 + DC_DISP_DISP_WIN_OPTIONS_0, // 402 + DC_DISP_MEM_HIGH_PRIORITY_0, // 403 + DC_DISP_MEM_HIGH_PRIORITY_TIMER_0, // 404 + DC_DISP_DISP_TIMING_OPTIONS_0, // 405 + DC_DISP_REF_TO_SYNC_0, // 406 (TrimSlice 0x0001 000B) + DC_DISP_SYNC_WIDTH_0, // 407 (TrimSlice 0x0004 003A) + DC_DISP_BACK_PORCH_0, // 408 (TrimSlice 0x0004 003A) + DC_DISP_DISP_ACTIVE_0, // 409 (TrimSlice 0x0300 0400) + DC_DISP_FRONT_PORCH_0, // 40A (TrimSlice 0x0004 003A) - + DC_DISP_H_PULSE0_CONTROL_0, // 40B ++ DC_DISP_H_PULSE0_POSITION_A_0, // 40C ++ DC_DISP_H_PULSE0_POSITION_B_0, // 40D ++ DC_DISP_H_PULSE0_POSITION_C_0, // 40E ++ DC_DISP_H_PULSE0_POSITION_D_0, // 40F ++ DC_DISP_H_PULSE1_CONTROL_0, // 410 ++ DC_DISP_H_PULSE1_POSITION_A_0, // 411 ++ DC_DISP_H_PULSE1_POSITION_B_0, // 412 ++ DC_DISP_H_PULSE1_POSITION_C_0, // 413 ++ DC_DISP_H_PULSE1_POSITION_D_0, // 414 ++ DC_DISP_H_PULSE2_CONTROL_0, // 415 ++ DC_DISP_H_PULSE2_POSITION_A_0, // 416 ++ DC_DISP_H_PULSE2_POSITION_B_0, // 417 ++ DC_DISP_H_PULSE2_POSITION_C_0, // 418 ++ DC_DISP_H_PULSE2_POSITION_D_0, // 419 ++ DC_DISP_V_PULSE0_CONTROL_0, // 41A ++ DC_DISP_V_PULSE0_POSITION_A_0, // 41B ++ DC_DISP_V_PULSE0_POSITION_B_0, // 41C ++ DC_DISP_V_PULSE0_POSITION_C_0, // 41D ++ DC_DISP_V_PULSE1_CONTROL_0, // 41E ++ DC_DISP_V_PULSE1_POSITION_A_0, // 41F ++ DC_DISP_V_PULSE1_POSITION_B_0, // 420 ++ DC_DISP_V_PULSE1_POSITION_C_0, // 421 ++ DC_DISP_V_PULSE2_CONTROL_0, // 422 ++ DC_DISP_V_PULSE2_POSITION_A_0, // 423 ++ DC_DISP_V_PULSE3_CONTROL_0, // 424 ++ DC_DISP_V_PULSE3_POSITION_A_0, // 425 ++ DC_DISP_M0_CONTROL_0, // 426 ++ DC_DISP_M1_CONTROL_0, // 427 ++ DC_DISP_DI_CONTROL_0, // 428 ++ DC_DISP_PP_CONTROL_0, // 429 ++ DC_DISP_PP_SELECT_A_0, // 42A ++ DC_DISP_PP_SELECT_B_0, // 42B ++ DC_DISP_PP_SELECT_C_0, // 42C ++ DC_DISP_PP_SELECT_D_0, // 42D ++ DC_DISP_DISP_CLOCK_CONTROL_0, // 42E ++ DC_DISP_DISP_INTERFACE_CONTROL_0,//42F ++ DC_DISP_DISP_COLOR_CONTROL_0, // 430 ++ DC_DISP_SHIFT_CLOCK_OPTIONS_0, // 431 ++ DC_DISP_DATA_ENABLE_OPTIONS_0, // 432 ++ DC_DISP_SERIAL_INTERFACE_OPTIONS_0, // 433 ++ DC_DISP_LCD_SPI_OPTIONS_0, // 434 ++ DC_DISP_BORDER_COLOR_0, // 435 ++ DC_DISP_COLOR_KEY0_LOWER_0, // 436 ++ DC_DISP_COLOR_KEY0_UPPER_0, // 437 ++ DC_DISP_COLOR_KEY1_LOWER_0, // 438 ++ DC_DISP_COLOR_KEY1_UPPER_0, // 439 ++ _DC_DISP_UNUSED_43A, ++ _DC_DISP_UNUSED_43B, ++ DC_DISP_CURSOR_FOREGROUND_0, // 43C - IMPORTANT ++ DC_DISP_CURSOR_BACKGROUND_0, // 43D - IMPORTANT ++ DC_DISP_CURSOR_START_ADDR_0, // 43E - IMPORTANT ++ DC_DISP_CURSOR_START_ADDR_NS_0, // 43F - IMPORTANT ++ DC_DISP_CURSOR_POSITION_0, // 440 - IMPORTANT ++ DC_DISP_CURSOR_POSITION_NS_0, // 441 - IMPORTANT ++ DC_DISP_INIT_SEQ_CONTROL_0, // 442 ++ DC_DISP_SPI_INIT_SEQ_DATA_A_0, // 443 ++ DC_DISP_SPI_INIT_SEQ_DATA_B_0, // 444 ++ DC_DISP_SPI_INIT_SEQ_DATA_C_0, // 445 ++ DC_DISP_SPI_INIT_SEQ_DATA_D_0, // 446 ++ ++ DC_DISP_DC_MCCIF_FIFOCTRL_0 = 0x480, ++ DC_DISP_MCCIF_DISPLAY0A_HYST_0, // 481 ++ DC_DISP_MCCIF_DISPLAY0B_HYST_0, // 482 ++ DC_DISP_MCCIF_DISPLAY0C_HYST_0, // 483 ++ DC_DISP_MCCIF_DISPLAY1B_HYST_0, // 484 ++ ++ DC_DISP_DAC_CRT_CTRL_0 = 0x4C0, ++ DC_DISP_DISP_MISC_CONTROL_0, // 4C1 + - DC_DISP_DISP_COLOR_CONTROL_0 = 0x430, - + DC_WINC_A_COLOR_PALETTE_0 = 0x500, + DC_WINC_A_PALETTE_COLOR_EXT_0 = 0x600, + DC_WIN_A_WIN_OPTIONS_0 = 0x700, + DC_WIN_A_BYTE_SWAP_0, // 701 + DC_WIN_A_BUFFER_CONTROL_0, // 702 + DC_WIN_A_COLOR_DEPTH_0, // 703 + DC_WIN_A_POSITION_0, // 704 + DC_WIN_A_SIZE_0, // 705 (TrimSlice 0x0300 0400) + DC_WIN_A_PRESCALED_SIZE_0, + DC_WIN_A_H_INITIAL_DDA_0, + DC_WIN_A_V_INITIAL_DDA_0, + DC_WIN_A_DDA_INCREMENT_0, + DC_WIN_A_LINE_STRIDE_0, + DC_WIN_A_BUF_STRIDE_0, + DC_WIN_A_BUFFER_ADDR_MODE_0, + DC_WIN_A_DV_CONTROL_0, + DC_WIN_A_BLEND_NOKEY_0, + + DC_WINBUF_A_START_ADDR_0 = 0x800, + DC_WINBUF_A_START_ADDR_NS_0, + DC_WINBUF_A_ADDR_H_OFFSET_0, + DC_WINBUF_A_ADDR_H_OFFSET_NS_0, + DC_WINBUF_A_ADDR_V_OFFSET_0, + DC_WINBUF_A_ADDR_V_OFFSET_NS_0, + }; + + #endif + diff --combined KernelLand/Modules/Input/PS2KbMouse/pl050.c index 00000000,839c0bda..a8dd0743 mode 000000,100644..100644 --- a/KernelLand/Modules/Input/PS2KbMouse/pl050.c +++ b/KernelLand/Modules/Input/PS2KbMouse/pl050.c @@@ -1,0 -1,129 +1,129 @@@ + /* + * Acess2 + * - By thePowersGang (John Hodge) + * + * PL050 (or comaptible) Driver + */ + #define DEBUG 1 + + #include + #include "common.h" + + // === CONSTANTS === + #define PL050_TXBUSY 0x20 + + // === PROTOTYPES === + void PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ); + void PL050_KeyboardHandler(int IRQ, void *Ptr); + void PL050_MouseHandler(int IRQ, void *Ptr); + void PL050_EnableMouse(void); + static inline void PL050_WriteMouseData(Uint8 data); + static inline void PL050_WriteKeyboardData(Uint8 data); + static inline Uint8 PL050_ReadMouseData(void); + static inline Uint8 PL050_ReadKeyboardData(void); + + // === GLOBALS === + Uint32 *gpPL050_KeyboardBase; + Uint32 *gpPL050_MouseBase; + + // === CODE === + void PL050_Init(Uint32 KeyboardBase, Uint8 KeyboardIRQ, Uint32 MouseBase, Uint8 MouseIRQ) + { + if( KeyboardBase ) { + LOG("KeyboardBase = 0x%x", KeyboardBase); + gpPL050_KeyboardBase = (void*)MM_MapHWPages(KeyboardBase, 1); + LOG("gpPL050_KeyboardBase = %p", gpPL050_KeyboardBase); + IRQ_AddHandler(KeyboardIRQ, PL050_KeyboardHandler, NULL); + + gpPL050_KeyboardBase[0] = 0x10; + } + if( MouseBase ) { + gpPL050_MouseBase = (void*)MM_MapHWPages(MouseBase, 1); + IRQ_AddHandler(MouseIRQ, PL050_MouseHandler, NULL); + + gpPL050_MouseBase[0] = 0x10; + } + } + + void PL050_KeyboardHandler(int IRQ, void *Ptr) + { + Uint8 scancode; + + scancode = PL050_ReadKeyboardData(); + KB_HandleScancode( scancode ); + } + + void PL050_MouseHandler(int IRQ, void *Ptr) + { + PS2Mouse_HandleInterrupt( PL050_ReadMouseData() ); + } + + void PL050_SetLEDs(Uint8 leds) + { + PL050_WriteKeyboardData(0xED); + PL050_WriteKeyboardData(leds); + } + + void PL050_EnableMouse(void) + { + Log_Log("PL050", "Enabling Mouse..."); + + //PL050_WriteMouseData(0xD4); + //PL050_WriteMouseData(0xF6); // Set Default Settings - PL050_WriteMouseData(0xD4); - PL050_WriteMouseData(0xF4); // Enable Packets ++// PL050_WriteMouseData(0xD4); ++// PL050_WriteMouseData(0xF4); // Enable Packets + LOG("Done"); + } + + static inline void PL050_WriteMouseData(Uint8 Data) + { + int timeout = 10000; + + if( !gpPL050_MouseBase ) { + Log_Error("PL050", "Mouse disabled (gpPL050_MouseBase = NULL)"); + return ; + } + + ENTER("xData", Data); + + while( --timeout && (gpPL050_MouseBase[1] & PL050_TXBUSY) ); + if(timeout) + gpPL050_MouseBase[2] = Data; + else + Log_Error("PL050", "Write to mouse timed out"); + LEAVE('-'); + } + + static inline Uint8 PL050_ReadMouseData(void) + { + if( !gpPL050_MouseBase ) { + Log_Error("PL050", "Mouse disabled (gpPL050_MouseBase = NULL)"); + return 0; + } + return gpPL050_MouseBase[2]; + } + static inline void PL050_WriteKeyboardData(Uint8 Data) + { + int timeout = 10000; + + if( !gpPL050_KeyboardBase ) { + Log_Error("PL050", "Keyboard disabled (gpPL050_KeyboardBase = NULL)"); + return ; + } + + while( --timeout && gpPL050_KeyboardBase[1] & PL050_TXBUSY ); + if(timeout) + gpPL050_KeyboardBase[2] = Data; + else + Log_Error("PL050", "Write to keyboard timed out"); + } + static inline Uint8 PL050_ReadKeyboardData(void) + { + if( !gpPL050_KeyboardBase ) { + Log_Error("PL050", "Keyboard disabled (gpPL050_KeyboardBase = NULL)"); + return 0; + } + + return gpPL050_KeyboardBase[2]; + } +