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); }
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) { ; } }