public KPartition( Kernel kernel, uint baseAddress, uint size ) { Kernel = kernel; BaseAddress = baseAddress; Size = size; UpperBound = baseAddress + size; FreeSize = size; Blocks = new FastLinkedList<KMemoryBlock>(); FreeList = new FastLinkedList<KMemoryBlock>(); // Initial empty block KMemoryBlock block = new KMemoryBlock( this, baseAddress, size, true ); Blocks.Enqueue( block ); FreeList.Enqueue( block ); }
public void Delete() { Partition.Free( StackBlock ); if( TlsBlock != null ) Partition.Free( TlsBlock ); StackBlock = null; TlsBlock = null; //Kernel.Cpu.ReleaseContextStorage( ContextID ); ContextID = -1; Kernel.Threads.Remove( this ); }
public KThread( Kernel kernel, KModule module, KPartition partition, string name, uint entryAddress, int priority, KThreadAttributes attributes, uint stackSize ) { Debug.Assert( partition != null ); Kernel = kernel; Name = name; EntryAddress = entryAddress; InitialPriority = priority; Priority = priority; Attributes = attributes; Module = module; State = KThreadState.Stopped; ExitWaiters = new FastLinkedList<KThread>(); NotifiedCallbacks = new FastLinkedList<KCallback>(); //if( stackSize < 65535 ) //{ // Log.WriteLine( Verbosity.Normal, Feature.Bios, "KThread: attempt to allocate thread with a stack of {0} - forcing up to the minimum of 64K", stackSize ); // stackSize = 65535; //} RunClocks = 0; InterruptPreemptionCount = 0; ThreadPreemptionCount = 0; Partition = partition; StackBlock = partition.Allocate( string.Format( "Thread '{0}' Stack", name ), KAllocType.High, 0, stackSize ); Debug.Assert( StackBlock != null ); TlsBlock = partition.Allocate( string.Format( "Thread '{0}' TLS", name ), KAllocType.High, 0, 0x4000 ); // 16k of thread local storage --- enough? Debug.Assert( TlsBlock != null ); }
public bool Free( KMemoryBlock block ) { Debug.Assert( block != null ); LinkedListEntry<KMemoryBlock> e = UsedBlocks.Find( block ); Debug.Assert( e != null ); if( e != null ) { UsedBlocks.Remove( e ); FreeBlocks.Enqueue( block ); return this.WakeWaiter(); } else return false; }
private KMemoryBlock SplitBlock( KMemoryBlock block, uint address, uint size ) { Debug.Assert( size > 0 ); KMemoryBlock newBlock = new KMemoryBlock( this, address, size, false ); LinkedListEntry<KMemoryBlock> blockEntry = Blocks.Find( block ); Debug.Assert( blockEntry != null ); if( address == block.Address ) { // Bottom up - put right before free and shift free up block.Address += size; block.Size -= size; Blocks.InsertBefore( newBlock, blockEntry ); } else if( address == block.UpperBound - size ) { // Top down - put right after and free shift free down block.Size -= size; Blocks.InsertAfter( newBlock, blockEntry ); } else { // Middle - need a real split uint originalSize = block.Size; block.Size = newBlock.Address - block.Address; if( block.Size == 0 ) { // Special case of block replacing block Blocks.InsertAfter( newBlock, blockEntry ); // block will be removed below } else { uint freeAddress = newBlock.Address + newBlock.Size; uint freeSize = originalSize - block.Size - newBlock.Size; KMemoryBlock freeBlock = new KMemoryBlock( this, freeAddress, freeSize, true ); // Add free space after start block if needed if( freeSize > 0 ) { LinkedListEntry<KMemoryBlock> blockEntryFree = FreeList.Find( block ); Blocks.InsertAfter( freeBlock, blockEntry ); FreeList.InsertAfter( freeBlock, blockEntryFree ); } // Add after the block (but before the freeBlock if there was one) Blocks.InsertAfter( newBlock, blockEntry ); } } Debug.Assert( block.Size >= 0 ); // Remove old block if dead if( block.Size == 0 ) { Blocks.Remove( blockEntry ); FreeList.Remove( block ); } return newBlock; }
private void AddToFreeList( KMemoryBlock block ) { // Inserts in to free list at the right place if( FreeList.Count == 0 ) FreeList.Enqueue( block ); else { LinkedListEntry<KMemoryBlock> e = FreeList.HeadEntry; while( e != null ) { if( e.Value.Address > block.Address ) { // Found next block - insert before FreeList.InsertBefore( block, e ); return; } e = e.Next; } // Didn't find - add to tail FreeList.Enqueue( block ); } }
public void Free( KMemoryBlock block ) { Debug.Assert( block != null ); Debug.Assert( block.IsFree == false ); block.UID = 0; block.IsFree = true; FreeSize += block.Size; LinkedListEntry<KMemoryBlock> entry = Blocks.Find( block ); Debug.Assert( entry != null ); // Attempt to coalesce in to previous and or next blocks KMemoryBlock merged = null; LinkedListEntry<KMemoryBlock> prev = entry.Previous; LinkedListEntry<KMemoryBlock> next = entry.Next; if( ( prev != null ) && ( prev.Value.IsFree == true ) ) { // Merge in to previous (kill us) Blocks.Remove( entry ); prev.Value.Size += block.Size; merged = prev.Value; } if( ( next != null ) && ( next.Value.IsFree == true ) ) { // Merge next in to us (kill them) // This takes in to account whether or not we already merged KMemoryBlock nextBlock = next.Value; Blocks.Remove( next ); FreeList.Remove( nextBlock ); if( merged == null ) block.Size += nextBlock.Size; else merged.Size += nextBlock.Size; } if( merged == null ) { // Didn't merge - put back in free list this.AddToFreeList( block ); } }
public LoadResults LoadModule(ModuleType type, Stream moduleStream, LoadParameters parameters) { Elf32_Shdr *[] allocSections = new Elf32_Shdr *[256]; Elf32_Shdr *[] relocSections = new Elf32_Shdr *[256]; int allocSectionsCount = 0; int relocSectionsCount = 0; LoadResults results = new LoadResults(); results.Successful = false; results.Imports = new List <StubImport>(); results.Exports = new List <StubExport>(); results.ExportNames = new List <string>(); results.MissingImports = new FastLinkedList <DelayedImport>(); Debug.Assert(moduleStream != null); Debug.Assert(moduleStream.CanRead == true); if ((moduleStream == null) || (moduleStream.CanRead == false)) { return(results); } Kernel kernel = _bios._kernel; ICpu cpu = kernel.Cpu; MemorySystem memory = kernel.MemorySystem; IntPtr pbuffer = IntPtr.Zero; try { // Load the entire module in to memory - nasty, but it works int length = ( int )moduleStream.Length; byte[] mbuffer = new byte[length]; moduleStream.Read(mbuffer, 0, length); pbuffer = Marshal.AllocHGlobal(length); Debug.Assert(pbuffer != IntPtr.Zero); Marshal.Copy(mbuffer, 0, pbuffer, length); mbuffer = null; byte *buffer = ( byte * )pbuffer.ToPointer(); // Get header Elf32_Ehdr *header = ( Elf32_Ehdr * )buffer; //Debug.Assert( header->e_magic == Elf32_Ehdr.Magic ); if (header->e_magic != Elf32_Ehdr.Magic) { Log.WriteLine(Verbosity.Critical, Feature.Loader, "Module header does not match: {0:X8} != {1:X8}", header->e_magic, Elf32_Ehdr.Magic); return(results); } Debug.Assert(header->e_machine == Elf32_Ehdr.MachineMips); if (header->e_machine != Elf32_Ehdr.MachineMips) { return(results); } /*switch( type ) * { * case ModuleType.Boot: * //Debug.Assert( header->e_type == ELF_EXEC_TYPE ); * break; * case ModuleType.Prx: * //Debug.Assert( header->e_type == ELF_PRX_TYPE ); * break; * }*/ results.EntryAddress = header->e_entry; bool needsRelocation = ( (header->e_entry < 0x08000000) || (header->e_type == ElfType.Prx)); // p-hdrs //for( int n = 0; n < header->e_phnum; n++ ) //{ // Elf32_Phdr* phdr = ( Elf32_Phdr* )( buffer + header->e_phoff + ( header->e_phentsize * n ) ); //} // 0x08900000 //uint defaultLoad = 0x08880000; uint defaultLoad = 0x08800000; //uint defaultLoad = uint.MaxValue; // s-hdrs uint lextents = defaultLoad; uint extents = 0; for (int n = 0; n < header->e_shnum; n++) { Elf32_Shdr *shdr = ( Elf32_Shdr * )(buffer + header->e_shoff + (header->e_shentsize * n)); if ((shdr->sh_flags & ShFlags.Allocate) == ShFlags.Allocate) { allocSections[allocSectionsCount++] = shdr; if ((shdr->sh_addr > 0) && (shdr->sh_addr < lextents)) { lextents = shdr->sh_addr; } uint upperBound = shdr->sh_addr + shdr->sh_size; if (upperBound > extents) { extents = upperBound; } } if ((shdr->sh_type == ShType.SHT_REL) || (shdr->sh_type == ShType.SHT_PRXRELOC)) { relocSections[relocSectionsCount++] = shdr; } } uint bssSize = this.GetBssSize(buffer); extents += bssSize; // Module info Elf32_Shdr *moduleInfoShdr = FindSection(buffer, ".rodata.sceModuleInfo"); Debug.Assert(moduleInfoShdr != null); PspModuleInfo *moduleInfo = ( PspModuleInfo * )(buffer + moduleInfoShdr->sh_offset); results.GlobalPointer = moduleInfo->gp; results.Name = new string( &moduleInfo->name ); // See if this module is already implemented BiosModule existing = _bios.FindModule(results.Name); if (existing != null) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "attempting to load module {0} with BIOS implementation; ignoring", results.Name); results.Successful = true; results.Ignored = true; return(results); } else { Log.WriteLine(Verbosity.Normal, Feature.Loader, "adding new module {0}", results.Name); } uint baseAddress = 0; KMemoryBlock moduleBlock = null; if (needsRelocation == true) { if (type == ModuleType.Boot) { baseAddress = defaultLoad; } else { // Find the next block in RAM moduleBlock = kernel.Partitions[2].Allocate(string.Format("Module {0}", results.Name), KAllocType.Low, 0, extents); baseAddress = moduleBlock.Address; } results.EntryAddress += baseAddress; results.LowerBounds = baseAddress; results.UpperBounds = baseAddress + extents; } else { Debug.Assert(type == ModuleType.Boot); results.LowerBounds = lextents; //0x08900000; results.UpperBounds = extents; } // Allocate space taken by module if (type == ModuleType.Boot) { Debug.Assert(moduleBlock == null); moduleBlock = kernel.Partitions[2].Allocate(string.Format("Module {0}", results.Name), KAllocType.Specific, results.LowerBounds, results.UpperBounds - results.LowerBounds); } else { // Should be done above Debug.Assert(moduleBlock != null); } Debug.Assert(moduleBlock != null); // Allocate sections in memory for (int n = 0; n < allocSectionsCount; n++) { Elf32_Shdr *shdr = allocSections[n]; uint address = baseAddress + shdr->sh_addr; byte * pdest = memory.Translate(address); switch (shdr->sh_type) { case ShType.SHT_NOBITS: // Write zeros? MemorySystem.ZeroMemory(pdest, shdr->sh_size); break; default: case ShType.SHT_PROGBITS: MemorySystem.CopyMemory(buffer + shdr->sh_offset, pdest, shdr->sh_size); break; } } // Zero out BSS if present if (bssSize > 0) { Elf32_Shdr *bssShdr = FindSection(buffer, ".bss"); Debug.Assert(bssShdr != null); if (bssShdr != null) { uint address = baseAddress + bssShdr->sh_addr; byte *pdest = memory.Translate(address); MemorySystem.ZeroMemory(pdest, bssSize); } } // Perform relocations if (needsRelocation == true) { List <HiReloc> hiRelocs = new List <HiReloc>(10); uint Elf32_RelSize = ( uint )sizeof(Elf32_Rel); // Find symbol table Elf32_Shdr *symtabShdr = FindSection(buffer, ".symtab"); byte * symtab = null; if (symtabShdr != null) { symtab = buffer + symtabShdr->sh_offset; } // Gather relocations for (int n = 0; n < header->e_shnum; n++) { Elf32_Shdr *shdr = ( Elf32_Shdr * )(buffer + header->e_shoff + (header->e_shentsize * n)); if ((shdr->sh_type != ShType.SHT_REL) && (shdr->sh_type != ShType.SHT_PRXRELOC)) { continue; } hiRelocs.Clear(); Elf32_Shdr *targetHdr = ( Elf32_Shdr * )(buffer + header->e_shoff + (header->e_shentsize * shdr->sh_info)); // If the target is not allocated, do not perform the relocation if ((targetHdr->sh_flags & ShFlags.Allocate) != ShFlags.Allocate) { continue; } uint count = shdr->sh_size / Elf32_RelSize; for (uint m = 0; m < count; m++) { Elf32_Rel *reloc = ( Elf32_Rel * )(buffer + shdr->sh_offset + (sizeof(Elf32_Rel) * m)); //uint rtype = ELF32_R_TYPE( reloc->r_info ); //uint symbolIndex = ELF32_R_SYM( reloc->r_info ); RelType rtype = ( RelType )(reloc->r_info & 0xFF); uint symbolIndex = reloc->r_info >> 8; uint offset = reloc->r_offset; if (rtype == RelType.None) { continue; } uint basea = baseAddress; offset += baseAddress; if (shdr->sh_type == ShType.SHT_REL) { // Elf style - use symbol table Elf32_Sym *sym = null; if (symbolIndex != 0) { Debug.Assert(symtab != null); sym = ( Elf32_Sym * )(symtab + (sizeof(Elf32_Sym) * symbolIndex)); basea += sym->st_value; } } else if (shdr->sh_type == ShType.SHT_PRXRELOC) { // PRX style - crazy! uint offsetHeaderN = symbolIndex & 0xFF; uint valueHeaderN = (symbolIndex >> 8) & 0xFF; Debug.Assert(offsetHeaderN < header->e_phnum); Debug.Assert(valueHeaderN < header->e_phnum); Elf32_Phdr *offsetHeader = ( Elf32_Phdr * )(buffer + header->e_phoff + (header->e_phentsize * offsetHeaderN)); Elf32_Phdr *valueHeader = ( Elf32_Phdr * )(buffer + header->e_phoff + (header->e_phentsize * valueHeaderN)); basea += valueHeader->p_vaddr; offset += offsetHeader->p_vaddr; } uint *pcode = ( uint * )memory.Translate(offset); Debug.Assert(pcode != null); switch (rtype) { case RelType.MipsHi16: { HiReloc hiReloc = new HiReloc(); hiReloc.Value = basea; hiReloc.CodePointer = ( uint * )pcode; hiRelocs.Add(hiReloc); } break; case RelType.MipsLo16: { uint code = *pcode; uint vallo = ((code & 0x0000FFFF) ^ 0x00008000) - 0x00008000; while (hiRelocs.Count > 0) { HiReloc hiReloc = hiRelocs[hiRelocs.Count - 1]; hiRelocs.RemoveAt(hiRelocs.Count - 1); Debug.Assert(hiReloc.Value == basea); uint value2 = *hiReloc.CodePointer; uint temp = ((value2 & 0x0000FFFF) << 16) + vallo; temp += basea; temp = ((temp >> 16) + (((temp & 0x00008000) != 0) ? ( uint )1 : ( uint )0)) & 0x0000FFFF; value2 = ( uint )((value2 & ~0x0000FFFF) | temp); //Debug.WriteLine( string.Format( " Updating memory at 0x{0:X8} to {1:X8} (from previous HI16)", hiReloc.Address, value2 ) ); *hiReloc.CodePointer = value2; } *pcode = ( uint )((code & ~0x0000FFFF) | ((basea + vallo) & 0x0000FFFF)); } break; case RelType.Mips26: { uint code = *pcode; uint addr = (code & 0x03FFFFFF) << 2; addr += basea; *pcode = (code & unchecked (( uint )~0x03FFFFFF)) | (addr >> 2); } break; case RelType.Mips32: *pcode += basea; break; } } Debug.Assert(hiRelocs.Count == 0); // Finish off hi relocs? } } IDebugDatabase db = null; if (parameters.AppendDatabase == true) { Debug.Assert(Diag.Instance.Database != null); db = Diag.Instance.Database; db.BeginUpdate(); } // Assign ID now so we can use it for symbols/etc uint moduleId = _bios._kernel.AllocateID(); results.ModuleID = moduleId; int variableExportCount = 0; int functionExportCount = 0; // Get exports uint PspModuleExportSize = ( uint )sizeof(PspModuleExport); uint pexports = moduleInfo->exports + ((needsRelocation == true) ? baseAddress : 0); uint exportCount = (moduleInfo->exp_end - moduleInfo->exports) / PspModuleExportSize; for (uint n = 0; n < exportCount; n++) { PspModuleExport *ex = ( PspModuleExport * )memory.Translate(pexports + (PspModuleExportSize * n)); string name = null; if (ex->name != 0x0) { name = kernel.ReadString(ex->name); } // Ignore null names? if (ex->name == 0x0) { continue; } results.ExportNames.Add(name); uint *pnid = ( uint * )memory.Translate(ex->exports); uint *pvalue = ( uint * )memory.Translate(ex->exports + (( uint )(ex->func_count + ex->var_count) * 4)); for (int m = 0; m < (ex->func_count + ex->var_count); m++) { uint nid = *(pnid + m); uint value = *(pvalue + m); StubExport stubExport = new StubExport(); if (m < ex->func_count) { stubExport.Type = StubType.Function; Log.WriteLine(Verbosity.Verbose, Feature.Loader, "export func {0} 0x{1:X8}: {2:X8}", name, nid, value); functionExportCount++; } else { stubExport.Type = StubType.Variable; Log.WriteLine(Verbosity.Verbose, Feature.Loader, "export var {0} 0x{1:X8}: {2:X8}", name, nid, value); variableExportCount++; } stubExport.ModuleName = name; stubExport.NID = nid; stubExport.Address = value; results.Exports.Add(stubExport); } } int nidGoodCount = 0; int nidNotFoundCount = 0; int nidNotImplementedCount = 0; int moduleNotFoundCount = 0; List <string> missingModules = new List <string>(); // Get imports uint PspModuleImportSize = ( uint )sizeof(PspModuleImport); uint pimports = moduleInfo->imports + ((needsRelocation == true) ? baseAddress : 0); uint importCount = (moduleInfo->imp_end - moduleInfo->imports) / PspModuleImportSize; for (uint n = 0; n < importCount; n++) { PspModuleImport *im = ( PspModuleImport * )memory.Translate(pimports + (PspModuleImportSize * n)); string name = null; if (im->name != 0x0) { name = kernel.ReadString(im->name); } Debug.Assert(name != null); BiosModule module = _bios.FindModule(name); if (module == null) { missingModules.Add(name); } uint *pnid = ( uint * )memory.Translate(im->nids); uint *pfuncs = ( uint * )memory.Translate(im->funcs); // Functions & variables at the same time for (int m = 0; m < (im->func_count + im->var_count); m++) { uint nid = *(pnid + m); uint *pcode = (pfuncs + (m * 2)); BiosFunction function = _bios.FindFunction(nid); StubImport stubImport = new StubImport(); if (module == null) { stubImport.Result = StubReferenceResult.ModuleNotFound; moduleNotFoundCount++; results.MissingImports.Enqueue(new DelayedImport(stubImport)); } else if (function == null) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "{0} 0x{1:X8} not found (NID not present)", name, nid); stubImport.Result = StubReferenceResult.NidNotFound; nidNotFoundCount++; results.MissingImports.Enqueue(new DelayedImport(stubImport)); } else if (function.IsImplemented == false) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "0x{1:X8} found and patched at 0x{2:X8} -> {0}::{3} (NI)", name, nid, ( uint )pcode, function.Name); stubImport.Result = StubReferenceResult.NidNotImplemented; nidNotImplementedCount++; } else { Log.WriteLine(Verbosity.Verbose, Feature.Loader, "0x{1:X8} found and patched at 0x{2:X8} -> {0}::{3}", name, nid, ( uint )pcode, function.Name); stubImport.Result = StubReferenceResult.Success; nidGoodCount++; } // Create dummy when needed if (function == null) { function = new BiosFunction(module, nid); _bios.RegisterFunction(function); } if (m < im->func_count) { stubImport.Type = StubType.Function; } else { stubImport.Type = StubType.Variable; } stubImport.ModuleName = name; stubImport.Function = function; stubImport.NID = nid; stubImport.Address = ( uint )pcode; results.Imports.Add(stubImport); function.StubAddress = ( uint )(im->funcs + (m * 2) * 4); // Perform fixup { uint syscall = cpu.RegisterSyscall(nid); *(pcode + 1) = ( uint )((syscall << 6) | 0xC); } // Add to debug database if (db != null) { Method method = new Method(moduleId, MethodType.Bios, function.StubAddress, 8, new BiosFunctionToken(stubImport.Function)); db.AddSymbol(method); } } } // If symbols are present, use those to add methods and variables // Otherwise, we need to try to figure them out (good luck!) if (db != null) { // Find symbol table Elf32_Shdr *symtabShdr = FindSection(buffer, ".symtab"); if ((symtabShdr != null) && (symtabShdr->sh_size > 0x100)) { byte *strtab = FindSectionAddress(buffer, symtabShdr->sh_link); int symbolCount = ( int )symtabShdr->sh_size / sizeof(Elf32_Sym); byte *symtab = buffer + symtabShdr->sh_offset; byte *p = symtab; for (int n = 0; n < symbolCount; n++, p += sizeof(Elf32_Sym)) { Elf32_Sym *sym = ( Elf32_Sym * )p; uint symType = sym->st_info & ( uint )0xF; if ((symType != 0x1) && (symType != 0x2)) { continue; } if (sym->st_size == 0) { continue; } Elf32_Shdr *shdr = FindSection(buffer, sym->st_shndx); Debug.Assert(shdr != null); string name = null; if (sym->st_name != 0) { name = this.GetName(strtab, ( int )sym->st_name); } uint address = baseAddress + sym->st_value; if (needsRelocation == true) { address += shdr->sh_addr; } Symbol symbol = null; if (symType == 0x1) { // OBJECT symbol = new Variable(moduleId, address, sym->st_size, name); } else if (symType == 0x2) { // FUNC symbol = new Method(moduleId, MethodType.User, address, sym->st_size, name); } if (symbol != null) { db.AddSymbol(symbol); } } results.HadSymbols = true; Log.WriteLine(Verbosity.Verbose, Feature.Loader, "Found {0} methods and {1} variables in the symbol table", db.MethodCount, db.VariableCount); } else { // No symbol table found - try to build the symbols Elf32_Shdr *textShdr = FindSection(buffer, ".text"); Debug.Assert(textShdr != null); uint textAddress = baseAddress + textShdr->sh_addr; byte *text = memory.TranslateMainMemory(( int )textAddress); uint size = textShdr->sh_size; this.Analyze(moduleId, db, text, size, textAddress); Log.WriteLine(Verbosity.Verbose, Feature.Loader, "Found {0} methods by analysis", db.MethodCount); } // End update, started above db.EndUpdate(); //foreach( Method method in db.GetMethods() ) // Debug.WriteLine( method.ToString() ); } #if DEBUG // Print stats Log.WriteLine(Verbosity.Critical, Feature.Loader, "Load complete: {0}/{1} ({2}%) NIDs good; {3} not implemented, {4} not found, {5} in missing modules = {6} total", nidGoodCount, results.Imports.Count - moduleNotFoundCount, (nidGoodCount / ( float )(results.Imports.Count - moduleNotFoundCount)) * 100.0f, nidNotImplementedCount, nidNotFoundCount, moduleNotFoundCount, results.Imports.Count); if (missingModules.Count > 0) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "{0} missing modules (contain {1} NIDs ({2}% of total)):", missingModules.Count, moduleNotFoundCount, (moduleNotFoundCount / ( float )results.Imports.Count) * 100.0f); foreach (string moduleName in missingModules) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "\t\t{0}", moduleName); } } if ((functionExportCount > 0) || (variableExportCount > 0)) { Log.WriteLine(Verbosity.Critical, Feature.Loader, "Exported {0} functions and {1} variables", functionExportCount, variableExportCount); } #endif results.Successful = true; if (results.Successful == true) { // If we export things, go back and find previously loaded modules that may need fixing up if ((functionExportCount > 0) || (variableExportCount > 0)) { bool fixupResult = this.FixupDelayedImports(kernel, results); Debug.Assert(fixupResult == true); } // If we are the boot load - we do some special stuff like run start, etc // If we are a PRX, all that is taken care of for us by the user code making calls if (type == ModuleType.Boot) { KModule module = new KModule(kernel, new BiosModule(results.Name, results.Exports.ToArray())); module.UID = moduleId; module.LoadParameters = parameters; module.LoadResults = results; kernel.UserModules.Add(module); Debug.Assert(kernel.MainModule == null); kernel.MainModule = module; kernel.AddHandle(module); // Allocate room for args KMemoryBlock argsBlock = kernel.Partitions[2].Allocate(string.Format("Module {0} args", results.Name), KAllocType.High, 0, 0xFF); // 256b of args - enough? // Set arguments - we put these right below user space, and right above the stack uint args = 0; uint argp = argsBlock.Address; string arg0 = parameters.Path.AbsolutePath.Replace('\\', '/') + "/"; args += ( uint )arg0.Length + 1; kernel.WriteString(argp, arg0); uint envp = argp; // + args; // write envp?? // What we do here simulates what the modulemgr does - it creates a user mode thread that // runs module_start (_start, etc) and then exits when complete. // NOTE: If we are a PRX, the entry address will correspond to module_start, so we don't need to do anything! // Create a thread KThread thread = new KThread(kernel, module, kernel.Partitions[2], "kmodule_thread", results.EntryAddress, 0, KThreadAttributes.User, 0x4000); thread.GlobalPointer = results.GlobalPointer; kernel.AddHandle(thread); thread.Start(args, argp); // Setup handler so that we get the callback when the thread ends and we can kill it cpu.SetContextSafetyCallback(thread.ContextID, new ContextSafetyDelegate(this.KmoduleThreadEnd), ( int )thread.UID); Log.WriteLine(Verbosity.Verbose, Feature.Loader, "starting kmodule loading thread with UID {0:X}", thread.UID); // Schedule so that our thread runs kernel.Schedule(); // If debugging, set start breakpoint if (Diag.IsAttached == true) { Diag.Instance.Client.OnBootModuleLoaded(results.EntryAddress); } if (Diag.IsAttached == true) { Diag.Instance.Client.OnModuleLoaded(); } //kernel.MemorySystem.DumpMainMemory( "startup.bin" ); } } } finally { if (pbuffer != IntPtr.Zero) { Marshal.FreeHGlobal(pbuffer); } } return(results); }
public KMemoryBlock Allocate(string name, KAllocType type, uint address, uint size) { KMemoryBlock newBlock = null; // Round size up to the next word //if( ( size & 0x3 ) != 0 ) // size += 4 - ( size & 0x3 ); if ((type == KAllocType.LowAligned) || (type == KAllocType.HighAligned)) { // TODO: align at 'address' (like 4096, etc) address = 0; // Other logic is the same if (type == KAllocType.LowAligned) { type = KAllocType.Low; } else if (type == KAllocType.HighAligned) { type = KAllocType.High; } } // Quick check to see if we have the space free Debug.Assert(FreeSize >= size); if (FreeSize < size) { return(null); } switch (type) { case KAllocType.Specific: { Debug.Assert(address != 0); LinkedListEntry <KMemoryBlock> e = FreeList.HeadEntry; while (e != null) { if ((address >= e.Value.Address) && (address < e.Value.UpperBound)) { newBlock = this.SplitBlock(e.Value, address, size); break; } e = e.Next; } } break; case KAllocType.Low: { KMemoryBlock targetBlock = null; uint maxContig = 0; if (address != 0) { // Specified lower limit, find the first block that fits LinkedListEntry <KMemoryBlock> e = FreeList.HeadEntry; while (e != null) { if ((address >= e.Value.Address) && (address < e.Value.UpperBound)) { targetBlock = e.Value; break; } maxContig = Math.Max(maxContig, e.Value.Size); e = e.Next; } } else { // No lower limit - pick first free block that fits LinkedListEntry <KMemoryBlock> e = FreeList.HeadEntry; while (e != null) { if (e.Value.Size >= size) { targetBlock = e.Value; break; } maxContig = Math.Max(maxContig, e.Value.Size); e = e.Next; } } Debug.Assert(targetBlock != null); if (targetBlock == null) { // Try again with a smaller size Log.WriteLine(Verbosity.Critical, Feature.Bios, "KPartition::Allocate could not find enough space"); //return this.Allocate( KAllocType.Maximum, 0, maxContig ); return(null); } Debug.Assert(targetBlock.Size >= size); if (targetBlock.Size < size) { return(null); } newBlock = this.SplitBlock(targetBlock, (address != 0) ? address : targetBlock.Address, size); } break; case KAllocType.High: { Debug.Assert(address == 0); KMemoryBlock targetBlock = null; LinkedListEntry <KMemoryBlock> e = FreeList.TailEntry; while (e != null) { if (e.Value.Size >= size) { targetBlock = e.Value; break; } e = e.Previous; } Debug.Assert(targetBlock != null); if (targetBlock == null) { // Try again with a smaller size Log.WriteLine(Verbosity.Critical, Feature.Bios, "KPartition::Allocate could not find enough space"); //return this.Allocate( KAllocType.Maximum, 0, maxContig ); return(null); } Debug.Assert(( int )targetBlock.UpperBound - ( int )size >= 0); newBlock = this.SplitBlock(targetBlock, targetBlock.UpperBound - size, size); } break; } if (newBlock != null) { newBlock.Name = name; newBlock.IsFree = false; FreeSize -= size; } this.Kernel.PrintMemoryInfo(); return(newBlock); }
private KMemoryBlock SplitBlock(KMemoryBlock block, uint address, uint size) { Debug.Assert(size > 0); KMemoryBlock newBlock = new KMemoryBlock(this, address, size, false); LinkedListEntry <KMemoryBlock> blockEntry = Blocks.Find(block); Debug.Assert(blockEntry != null); if (address == block.Address) { // Bottom up - put right before free and shift free up block.Address += size; block.Size -= size; Blocks.InsertBefore(newBlock, blockEntry); } else if (address == block.UpperBound - size) { // Top down - put right after and free shift free down block.Size -= size; Blocks.InsertAfter(newBlock, blockEntry); } else { // Middle - need a real split uint originalSize = block.Size; block.Size = newBlock.Address - block.Address; if (block.Size == 0) { // Special case of block replacing block Blocks.InsertAfter(newBlock, blockEntry); // block will be removed below } else { uint freeAddress = newBlock.Address + newBlock.Size; uint freeSize = originalSize - block.Size - newBlock.Size; KMemoryBlock freeBlock = new KMemoryBlock(this, freeAddress, freeSize, true); // Add free space after start block if needed if (freeSize > 0) { LinkedListEntry <KMemoryBlock> blockEntryFree = FreeList.Find(block); Blocks.InsertAfter(freeBlock, blockEntry); FreeList.InsertAfter(freeBlock, blockEntryFree); } // Add after the block (but before the freeBlock if there was one) Blocks.InsertAfter(newBlock, blockEntry); } } Debug.Assert(block.Size >= 0); // Remove old block if dead if (block.Size == 0) { Blocks.Remove(blockEntry); FreeList.Remove(block); } return(newBlock); }