Esempio n. 1
0
        public static unsafe ulong LoadObject(Virtual_Regions vreg, VirtMem vmem, SymbolTable stab, lib.File s, string name, out ulong tls_size)
        {
            ElfReader.Elf64_Ehdr ehdr = ReadHeader(s);

            /* Load up section headers */
            ulong e_shentsize = ehdr.e_shentsize;
            byte *shdrs       = ReadStructure(s, ehdr.e_shoff, ehdr.e_shnum * e_shentsize);

            /* Load up section string table */
            ElfReader.Elf64_Shdr *shdr_shstr = (ElfReader.Elf64_Shdr *)(shdrs + ehdr.e_shstrndx * e_shentsize);
            byte *sect_shstr = ReadStructure(s, shdr_shstr->sh_offset, shdr_shstr->sh_size);

            /* Iterate through the sections marked SHF_ALLOC, allocating space as we go */
            uint  e_shnum     = (uint)ehdr.e_shnum;
            byte *sect_header = shdrs;

            /* .to files are relocatable but have the entry point set anyway */
            ulong text_section = 0;
            ulong hdr_epoint   = ehdr.e_entry;
            ulong hash_section = 0;
            ulong hash_len     = 0;

            ElfReader.Elf64_Shdr *sym_tab_hdr     = null;
            ElfReader.Elf64_Shdr *sym_tab_str_hdr = null;

            /* Map sections to their load address */
            Dictionary <uint, ulong> sect_map = new Dictionary <uint, ulong>();

            ulong start = 0;

            tls_size = Program.arch.tysos_tls_length;

            for (uint i = 0; i < e_shnum; i++)
            {
                ElfReader.Elf64_Shdr *cur_shdr = (ElfReader.Elf64_Shdr *)sect_header;

                // if this .symtab?
                if (cur_shdr->sh_type == 0x2)
                {
                    sym_tab_hdr = cur_shdr;

                    if (cur_shdr->sh_link != 0)
                    {
                        sym_tab_str_hdr = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_link * e_shentsize);
                    }
                }

                if ((cur_shdr->sh_flags & 0x2) == 0x2)
                {
                    /* SHF_ALLOC */
                    if ((cur_shdr->sh_flags & (1 << 10)) != 0)
                    {
                        // TLS
                        tls_size += cur_shdr->sh_size;
                        continue;
                    }
                    // get its name
                    byte * name_addr = sect_shstr + cur_shdr->sh_name;
                    string sect_name = new string((sbyte *)name_addr);

                    /* Register with gc if writeable and not executable */
                    bool gc_data = false;
                    if (((cur_shdr->sh_flags & 0x1) != 0) && ((cur_shdr->sh_flags & 0x4) == 0))
                    {
                        gc_data = true;
                    }

                    // allocate space for it
                    ulong sect_addr = vreg.AllocRegion(cur_shdr->sh_size, 0x1000,
                                                       name + sect_name, 0,
                                                       Virtual_Regions.Region.RegionType.ModuleSection,
                                                       gc_data).start;
                    cur_shdr->sh_addr = sect_addr;
                    sect_map[i]       = sect_addr;

                    if (sect_addr + cur_shdr->sh_size > 0x7effffffff)
                    {
                        throw new Exception("Object section allocated beyond limit of small code model");
                    }

                    // is this .text?
                    if (sect_name == ".text")
                    {
                        text_section = sect_addr;
                    }

                    // or .hash?
                    if (sect_name == ".hash")
                    {
                        hash_section = sect_addr;
                        hash_len     = cur_shdr->sh_size;
                    }

                    // copy the section to its destination
                    if (cur_shdr->sh_type == 0x1)
                    {
                        /* SHT_PROGBITS */

                        // Convert the VirtualRegion to a managed byte array
                        //byte[] sect_data = libsupcs.TysosArrayType.CreateByteArray((byte*)sect_addr, (int)cur_shdr->sh_size);
                        byte[] sect_data = libsupcs.Array.CreateSZArray <byte>((int)cur_shdr->sh_size, (void *)sect_addr);

                        System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading section data");
                        // Read the section data into it
                        s.Seek((long)cur_shdr->sh_offset, System.IO.SeekOrigin.Begin);
                        s.Read(sect_data, 0, (int)cur_shdr->sh_size);
                        System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading section data");
                    }
                    else if (cur_shdr->sh_type == 0x8)
                    {
                        /* SHT_NOBITS */
                        System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin clearing blank section");

                        libsupcs.MemoryOperations.MemSet((void *)sect_addr, 0, (int)cur_shdr->sh_size);

                        System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end clearing blank section");
                    }
                }

                sect_header += e_shentsize;
            }

            if (hash_section != 0 && hash_len != 0 && sym_tab_hdr != null && sym_tab_str_hdr != null)
            {
                // Load symbol table and hash table
                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading symbol table");
                var sym_data = ReadStructure(s, sym_tab_hdr->sh_offset, sym_tab_hdr->sh_size);
                sym_tab_hdr->sh_addr = (ulong)sym_data;
                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading symbol table");

                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading symbol string table");
                var sym_str_data = ReadStructure(s, sym_tab_str_hdr->sh_offset, sym_tab_str_hdr->sh_size);
                sym_tab_str_hdr->sh_addr = (ulong)sym_str_data;
                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading symbol string table");

                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading hash symbol section");
                var ht = new ElfReader.ElfHashTable(hash_section, (ulong)sym_data, sym_tab_hdr->sh_entsize,
                                                    (ulong)sym_str_data, sect_map, (int)sym_tab_hdr->sh_info, sym_tab_hdr->sh_size);
                stab.symbol_providers.Add(ht);
                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading hash symbol section");
            }
            else
            {
                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin loading symbols");

                /* Iterate through defined symbols, loading them into the symbol table */
                sect_header = shdrs;
                for (uint i = 0; i < e_shnum; i++)
                {
                    ElfReader.Elf64_Shdr *cur_shdr = (ElfReader.Elf64_Shdr *)sect_header;

                    if (cur_shdr->sh_type == 0x2)
                    {
                        /* SHT_SYMTAB */

                        // Load up the section data
                        byte *shdr_data = ReadStructure(s, cur_shdr->sh_offset, cur_shdr->sh_size);
                        ulong offset    = cur_shdr->sh_info * cur_shdr->sh_entsize;
                        cur_shdr->sh_addr = (ulong)shdr_data;

                        while (offset < cur_shdr->sh_size)
                        {
                            ElfReader.Elf64_Sym *cur_sym = (ElfReader.Elf64_Sym *)(shdr_data + offset);

                            bool is_vis  = false;
                            bool is_weak = false;

                            uint st_bind = (cur_sym->st_info_other_shndx >> 4) & 0xf;

                            if (st_bind == 1)
                            {
                                // STB_GLOBAL
                                is_vis = true;
                            }
                            else if (st_bind == 2)
                            {
                                // STB_WEAK
                                is_vis  = true;
                                is_weak = true;
                            }

                            if (is_vis)
                            {
                                /* Get the symbol's name */

                                // If the appropriate string table is not loaded, then load it
                                ElfReader.Elf64_Shdr *strtab = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_link * e_shentsize);
                                if (strtab->sh_addr == 0)
                                {
                                    strtab->sh_addr = (ulong)ReadStructure(s, strtab->sh_offset, strtab->sh_size);
                                }

                                // Get the name
                                string sym_name = new string((sbyte *)(strtab->sh_addr + cur_sym->st_name));

                                uint st_shndx = (cur_sym->st_info_other_shndx >> 16) & 0xffff;

                                if (st_shndx != 0)
                                {
                                    if (is_weak == false || stab.GetAddress(sym_name) == 0)
                                    {
                                        ulong sym_addr = ((ElfReader.Elf64_Shdr *)(shdrs + st_shndx * e_shentsize))->sh_addr +
                                                         cur_sym->st_value;

                                        if (sym_name == "_start")
                                        {
                                            start = sym_addr;
                                        }
                                        else
                                        {
                                            stab.Add(sym_name, sym_addr, cur_sym->st_size);
                                        }
                                    }
                                }
                            }


                            offset += cur_shdr->sh_entsize;
                        }
                    }

                    sect_header += e_shentsize;
                }

                System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end loading symbols");
            }

            System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: begin fixing relocations");

            /* Iterate through relocations, fixing them up as we go */
            sect_header = shdrs;
            for (uint i = 0; i < e_shnum; i++)
            {
                ElfReader.Elf64_Shdr *cur_shdr = (ElfReader.Elf64_Shdr *)sect_header;

                if (cur_shdr->sh_type == 0x9)
                {
                    throw new NotImplementedException("rel sections not supported");
                }
                if (cur_shdr->sh_type == 0x4)
                {
                    /* SHT_RELA */

                    ElfReader.Elf64_Shdr *cur_symtab = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_link * e_shentsize);
                    ElfReader.Elf64_Shdr *rela_sect  = (ElfReader.Elf64_Shdr *)(shdrs + cur_shdr->sh_info * e_shentsize);

                    /* Buffer loaded symbols */
                    ulong[] sym_buf = new ulong[cur_symtab->sh_size / cur_symtab->sh_entsize];

                    /* Load section */
                    byte *shdr_data = ReadStructure(s, cur_shdr->sh_offset, cur_shdr->sh_size);
                    cur_shdr->sh_addr = (ulong)shdr_data;

                    ulong offset = 0;
                    while (offset < cur_shdr->sh_size)
                    {
                        ElfReader.Elf64_Rela *cur_rela = (ElfReader.Elf64_Rela *)(shdr_data + offset);

                        ulong r_offset = rela_sect->sh_addr + cur_rela->r_offset;
                        ulong r_sym    = cur_rela->r_info >> 32;
                        ulong r_type   = cur_rela->r_info & 0xffffffff;
                        long  r_addend = cur_rela->r_addend;

                        ElfReader.Elf64_Sym *rela_sym = (ElfReader.Elf64_Sym *)(cur_symtab->sh_addr + r_sym * cur_symtab->sh_entsize);
                        uint st_bind = (rela_sym->st_info_other_shndx >> 4) & 0xf;

                        ulong S = 0;

                        /* Can use direct relocation via the symbol table if:
                         *   - not weak
                         *   - is defined
                         */
                        if ((st_bind == 0 || st_bind == 1) &&
                            rela_sym->st_shndx != 0)
                        {
                            /* STB_LOCAL symbols have not been loaded into the symbol table
                             * We need to use the value stored in the symbol table */
                            uint st_shndx = (rela_sym->st_info_other_shndx >> 16) & 0xffff;
                            S = ((ElfReader.Elf64_Shdr *)(shdrs + e_shentsize * st_shndx))->sh_addr +
                                rela_sym->st_value;
                        }
                        else
                        {
                            /* Get the symbol address from the symbol table if not already loaded */
                            if (sym_buf[r_sym] == 0)
                            {
                                ElfReader.Elf64_Shdr *link_sect = (ElfReader.Elf64_Shdr *)(shdrs + cur_symtab->sh_link * e_shentsize);
                                string sym_name = new string((sbyte *)(link_sect->sh_addr + rela_sym->st_name));

                                S = stab.GetAddress(sym_name);
                                if (S == 0)
                                {
                                    throw new Exception("undefined reference to " + sym_name);
                                }

                                sym_buf[r_sym] = S;
                            }
                            else
                            {
                                S = sym_buf[r_sym];
                            }
                        }

                        /* Perform the relocation */
                        switch (r_type)
                        {
                        case 1:
                            // R_X86_64_64: S + A
                        {
                            ulong c = S;
                            if (r_addend > 0)
                            {
                                c += (ulong)r_addend;
                            }
                            else
                            {
                                c -= (ulong)(-r_addend);
                            }
                            *(ulong *)r_offset = c;
                        }
                        break;

                        case 2:
                            // R_X86_64_PC32: S + A - P
                        {
                            if (S > (ulong)long.MaxValue)
                            {
                                throw new Exception("S too large");
                            }
                            if (r_offset > (ulong)long.MaxValue)
                            {
                                throw new Exception("P too large");
                            }
                            long c = (long)S + r_addend - (long)r_offset;

                            if (c < int.MinValue || c > int.MaxValue)
                            {
                                throw new Exception("Relocation truncated to fit");
                            }
                            *(int *)r_offset = (int)c;
                        }
                        break;

                        case 10:
                            // R_X86_64_32: S + A
                        {
                            if (S > (ulong)long.MaxValue)
                            {
                                throw new Exception("S too large");
                            }
                            long c = (long)S + r_addend;

                            if (c < 0 || c > uint.MaxValue)
                            {
                                throw new Exception("Relocation truncated to fit");
                            }
                            *(uint *)r_offset = (uint)c;
                        }
                        break;

                        case 11:
                            // R_X86_64_32S: S + A
                        {
                            if (S > (ulong)long.MaxValue)
                            {
                                throw new Exception("S too large");
                            }
                            long c = (long)S + r_addend;

                            if (c < int.MinValue || c > int.MaxValue)
                            {
                                throw new Exception("Relocation truncated to fit");
                            }
                            *(int *)r_offset = (int)c;
                        }
                        break;

                        default:
                            throw new Exception("Unsupported relocation type: " +
                                                r_type.ToString());
                        }

                        offset += cur_shdr->sh_entsize;
                    }
                }

                sect_header += e_shentsize;
            }

            System.Diagnostics.Debugger.Log(0, null, "ElfFileReader.LoadObject: end fixing relocations");


            if (start == 0)
            {
                // assume .to file - use entry point in header
                start = text_section + hdr_epoint;
            }
            return(start);
        }
Esempio n. 2
0
        public static void KMain(Multiboot.Header mboot)
        {
            // Disable profiling until we have enabled the arch.DebugOutput port
            do_profile = false;

            // Get the multiboot header
            mboot_header = mboot;

            /* Create a temporary heap, then initialize the architecture
             * which will set up the permanent heap.  Then initialize the garbage collector */
            ulong arch_data_length = 0;

            switch (mboot.machine_major_type)
            {
            case (uint)Multiboot.MachineMajorType.x86_64:
                arch_data_length = tysos.x86_64.Arch.GetRecommendedChunkLength();
                break;

            default:
                return;
            }

            ulong heap_start = mboot.heap_start + arch_data_length;

            //ulong heap_len = mboot.heap_end - heap_start;
            gc.gc.Heap = gc.gc.HeapType.Startup;
            gc.simple_heap.Init(heap_start, mboot.heap_end);

            log_lock = new object();

            /* Set up the default startup thread */
            StartupThread = new System.Threading.Thread(null_func);

            /* Initialize the architecture */
            UIntPtr chunk_vaddr  = new UIntPtr(mboot.heap_start);
            UIntPtr chunk_length = new UIntPtr(arch_data_length);

            switch (mboot.machine_major_type)
            {
            case (uint)Multiboot.MachineMajorType.x86_64:
                //libsupcs.OtherOperations.AsmBreakpoint();
                arch = new tysos.x86_64.Arch();
                break;
            }
            arch.Init(chunk_vaddr, chunk_length, mboot);

            do_profile = true;

            /* Parse the kernel command line */
            kernel_cmd_line = mboot.cmdline.Split(' ');

            //while (true) ;

            // test dynamic types
            //if (test_dynamic() == null)
            //    throw new Exception("test_dynamic failed");
            //if (test_dynamic2() == null)
            //    throw new Exception("test_dynamic2 failed");

            // Say hi
            Formatter.WriteLine("Tysos v0.2.0", arch.BootInfoOutput);
            Formatter.WriteLine("Tysos v0.2.0", arch.DebugOutput);
            Formatter.Write("mboot @ ", arch.DebugOutput);
            Formatter.Write(libsupcs.CastOperations.ReinterpretAsUlong(mboot), "X", arch.DebugOutput);
            Formatter.WriteLine(arch.DebugOutput);
            Formatter.Write("Loaded by ", arch.DebugOutput);
            Formatter.WriteLine(mboot.loader_name, arch.DebugOutput);
            Formatter.Write("Command line: ", arch.DebugOutput);
            Formatter.WriteLine(mboot.cmdline, arch.DebugOutput);
            bool do_debug = false;

            if (GetCmdLine("debug"))
            {
                Formatter.Write("Kernel debug: ", arch.BootInfoOutput);
                Formatter.WriteLine("Kernel debug requested", arch.DebugOutput);

                if (arch.InitGDBStub())
                {
                    Formatter.WriteLine("enabled", arch.BootInfoOutput);
                    Formatter.WriteLine("Kernel debug started", arch.DebugOutput);
                    do_debug = true;
                }
                else
                {
                    Formatter.WriteLine("not supported by current architecture", arch.BootInfoOutput);
                    Formatter.WriteLine("Kernel debug not supported by current architecture", arch.DebugOutput);
                }
            }


            /* Map in the ELF image of the kernel, so we can load its symbols */
            ulong tysos_vaddr = map_in(mboot.tysos_paddr, mboot.tysos_size, "tysos binary");

            /* Trigger a breakpoint to synchronize with gdb */
            if (do_debug)
            {
                Formatter.WriteLine("Synchronizing with debugger...", arch.BootInfoOutput);
                Formatter.WriteLine("Synchronizing with debugger...", arch.DebugOutput);
                System.Diagnostics.Debugger.Break();
            }

            /* Set up a default environment */
            env = new Environment();
            env.env_vars.Add("OS", "tysos");
            env.env_vars.Add("OSVER", "v0.2.0");
            env.env_vars.Add("NUMBER_OF_PROCESSORS", "1");

#if NO_BOEHM
            gc.heap_arena.debug = true;
#endif  // NO_BOEHM

            /* Load up the symbol table for tysos */
            if (GetCmdLine("skip_kernel_syms") == false)
            {
                ulong sym_vaddr = Program.map_in(mboot.tysos_sym_tab_paddr, mboot.tysos_sym_tab_size,
                                                 "tysos_sym_tab");
                ulong str_vaddr = Program.map_in(mboot.tysos_str_tab_paddr, mboot.tysos_str_tab_size,
                                                 "tysos_str_tab");

                stab = new SymbolTable();
                Formatter.Write("Loading kernel symbols... ", arch.BootInfoOutput);
                Formatter.Write("Loading kernel symbols.  Tysos base: ", arch.DebugOutput);
                Formatter.Write(tysos_vaddr, "X", arch.DebugOutput);
                Formatter.WriteLine(arch.DebugOutput);

                var hr = new ElfReader.ElfHashTable((ulong)tysos_hash, sym_vaddr, mboot.tysos_sym_tab_entsize, str_vaddr,
                                                    null, 0, mboot.tysos_sym_tab_size);
                stab.symbol_providers.Add(hr);

                Formatter.WriteLine("done", arch.BootInfoOutput);
            }

            /* Test the garbage collector */
            if (GetCmdLine("skip_test_gc") == false)
            {
                Formatter.Write("Testing garbage collector... ", arch.BootInfoOutput);
                gc.gc.DoCollection();
                Formatter.WriteLine("done", arch.BootInfoOutput);
            }

            /* Start the scheduler */
            Formatter.Write("Starting scheduler... ", arch.DebugOutput);
            arch.CurrentCpu.CurrentScheduler = new Scheduler();
            if (GetCmdLine("ignore_timer") == false)
            {
                arch.SchedulerTimer.Callback = new Timer.TimerCallback(Scheduler.TimerProc);
            }
            Formatter.WriteLine("done", arch.DebugOutput);

            /* Store the process info */
            running_processes = new Dictionary <string, Process>(new MyGenericEqualityComparer <string>());

            /* Add in threads for GC collections */
            Formatter.Write("Starting GC collection threads... ", arch.DebugOutput);
            Thread t_max = Thread.Create("gc_max_alloc", new System.Threading.ThreadStart(gc.gengc.MaxAllocCollectThreadProc),
                                         new object[] { });
            t_max.priority = 10;
            arch.CurrentCpu.CurrentScheduler.Reschedule(t_max);

            Thread t_min = Thread.Create("gc_min_alloc", new System.Threading.ThreadStart(gc.gengc.MinAllocCollectThreadProc),
                                         new object[] { });
            t_min.priority = 0;
            arch.CurrentCpu.CurrentScheduler.Reschedule(t_min);

            Thread t_request = Thread.Create("gc_request", new System.Threading.ThreadStart(gc.gengc.OnRequestCollectThreadProc),
                                             new object[] { });
            t_min.priority = 10;
            arch.CurrentCpu.CurrentScheduler.Reschedule(t_request);
            Formatter.WriteLine("done", arch.DebugOutput);


            /* Init vfs signatures */
            lib.File.InitSigs();



            /* Load the logger */
            Formatter.Write("Starting logger... ", arch.DebugOutput);
            Process logger = LoadELFModule("logger", mboot, stab, running_processes, 0x8000,
                                           new object[] { });

            Process debugprint = LoadELFModule("debugprint", mboot, stab, running_processes,
                                               0x8000, new object[] { });

            logger.Start();
            //debugprint.Start();
            Formatter.WriteLine("done", arch.DebugOutput);

            /* Load the vfs */
            Formatter.Write("Starting vfs... ", arch.DebugOutput);
            Process vfs = LoadELFModule("vfs", mboot, stab, running_processes, 0x8000, new object[] { });
            vfs.Start();
            Formatter.WriteLine("done", arch.DebugOutput);

            /* Load the gui */
            Formatter.Write("Starting gui... ", arch.DebugOutput);
            Process gui = LoadELFModule("gui", mboot, stab, running_processes, 0x8000, new object[] { });
            gui.Start();
            Formatter.WriteLine("done", arch.DebugOutput);

            /* Load the network subsystem */
            Formatter.Write("Starting net... ", arch.DebugOutput);
            Process net = LoadELFModule("net", mboot, stab, running_processes, 0x8000, new object[] { });
            net.Start();
            Formatter.WriteLine("done", arch.DebugOutput);

            /* Startup thread does the rest as we need to wait for the Vfs to come up */
            Process kernel_startup = Process.Create("kernel_startup", stab.GetAddress("_ZN11tysos#2Edll5tysos7Program_11SetupThread_Rv_P0"), 0x1000, arch.VirtualRegions, stab, new object[] { }, Program.arch.tysos_tls_length);
            arch.CurrentCpu.CurrentScheduler.Reschedule(kernel_startup.startup_thread);
            kernel_startup.started = true;



            if (do_debug)
            {
                System.Diagnostics.Debugger.Break();
            }

            //libsupcs.OtherOperations.AsmBreakpoint();

            //arch.EnableMultitasking();
            Syscalls.SchedulerFunctions.Yield();

            while (true)
            {
                ;
            }



            // Halt here
            libsupcs.OtherOperations.Halt();


            /* Create kernel threads */
            CreateKernelThreads();

            /* Dump the current virtual region table */
            arch.VirtualRegions.Dump(arch.DebugOutput);



            /* Start the processes */
            Formatter.WriteLine("Going multitasking...", arch.BootInfoOutput);
            arch.EnableMultitasking();
            while (true)
            {
                ;
            }
        }