示例#1
0
        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 );
        }
示例#2
0
        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 );
        }
示例#3
0
        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 );
        }
示例#4
0
        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;
        }
示例#5
0
        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;
        }
示例#6
0
 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 );
     }
 }
示例#7
0
        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 );
            }
        }
示例#8
0
        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);
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }